diff --git a/.travis.yml b/.travis.yml index 87197a37f1d4..0abd858d8228 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ services: # our configure script, so disable auto submodule management. git: submodules: false + depth: 1 before_install: - docker build -t rust -f src/etc/Dockerfile src/etc diff --git a/configure b/configure index d2ec457a1c8b..29f16da05812 100755 --- a/configure +++ b/configure @@ -609,7 +609,7 @@ opt dist-host-only 0 "only install bins for the host architecture" opt inject-std-version 1 "inject the current compiler version of libstd into programs" opt llvm-version-check 1 "check if the LLVM version is supported, build anyway" opt rustbuild 0 "use the rust and cargo based build system" -opt orbit 0 "get MIR where it belongs - everywhere; most importantly, in orbit" +opt orbit 1 "get MIR where it belongs - everywhere; most importantly, in orbit" opt codegen-tests 1 "run the src/test/codegen tests" opt option-checking 1 "complain about unrecognized options in this configure script" opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)" @@ -733,7 +733,7 @@ if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTION if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi -if [ -n "$CFG_ENABLE_ORBIT" ]; then putvar CFG_ENABLE_ORBIT; fi +if [ -n "$CFG_DISABLE_ORBIT" ]; then putvar CFG_DISABLE_ORBIT; fi step_msg "looking for build programs" @@ -1020,6 +1020,12 @@ then err "bad LLVM version: $LLVM_VERSION, need >=3.7" ;; esac + + if "$CFG_LLVM_ROOT/bin/llvm-mc" -help | grep -- "-relocation-model"; then + msg "found older llvm-mc" + CFG_LLVM_MC_HAS_RELOCATION_MODEL=1 + putvar CFG_LLVM_MC_HAS_RELOCATION_MODEL + fi fi # Even when the user overrides the choice of CC, still try to detect @@ -1192,7 +1198,7 @@ do ;; - x86_64-*-musl) + x86_64-*-musl | arm-*-musleabi) if [ ! -f $CFG_MUSL_ROOT/lib/libc.a ] then err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found" diff --git a/mk/cfg/aarch64-apple-ios.mk b/mk/cfg/aarch64-apple-ios.mk index 8cd09fa9043c..5d822f1b1aba 100644 --- a/mk/cfg/aarch64-apple-ios.mk +++ b/mk/cfg/aarch64-apple-ios.mk @@ -17,7 +17,7 @@ CFG_STATIC_LIB_NAME_aarch64-apple-ios=lib$(1).a CFG_LIB_DSYM_GLOB_aarch64-apple-ios = lib$(1)-*.a.dSYM CFG_CFLAGS_aarch64-apple-ios := $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios) CFG_JEMALLOC_CFLAGS_aarch64-apple-ios := $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios) -CFG_GCCISH_CFLAGS_aarch64-apple-ios := -Wall -Werror -fPIC $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios) +CFG_GCCISH_CFLAGS_aarch64-apple-ios := -fPIC $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios) CFG_GCCISH_CXXFLAGS_aarch64-apple-ios := -fno-rtti $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios) -I$(CFG_IOS_SDK_aarch64-apple-ios)/usr/include/c++/4.2.1 CFG_GCCISH_LINK_FLAGS_aarch64-apple-ios := -lpthread -syslibroot $(CFG_IOS_SDK_aarch64-apple-ios) -Wl,-no_compact_unwind CFG_GCCISH_DEF_FLAG_aarch64-apple-ios := -Wl,-exported_symbols_list, diff --git a/mk/cfg/arm-unknown-linux-musleabi.mk b/mk/cfg/arm-unknown-linux-musleabi.mk new file mode 100644 index 000000000000..8120250150d4 --- /dev/null +++ b/mk/cfg/arm-unknown-linux-musleabi.mk @@ -0,0 +1,3 @@ +# This file is intentially left empty to indicate that, while this target is +# supported, it's not supported using plain GNU Make builds. Use a --rustbuild +# instead. \ No newline at end of file diff --git a/mk/cfg/arm-unknown-linux-musleabihf.mk b/mk/cfg/arm-unknown-linux-musleabihf.mk new file mode 100644 index 000000000000..8120250150d4 --- /dev/null +++ b/mk/cfg/arm-unknown-linux-musleabihf.mk @@ -0,0 +1,3 @@ +# This file is intentially left empty to indicate that, while this target is +# supported, it's not supported using plain GNU Make builds. Use a --rustbuild +# instead. \ No newline at end of file diff --git a/mk/cfg/armv7-apple-ios.mk b/mk/cfg/armv7-apple-ios.mk index d4696976574e..34ca4de6563e 100644 --- a/mk/cfg/armv7-apple-ios.mk +++ b/mk/cfg/armv7-apple-ios.mk @@ -15,7 +15,7 @@ CFG_INSTALL_ONLY_RLIB_armv7-apple-ios = 1 CFG_STATIC_LIB_NAME_armv7-apple-ios=lib$(1).a CFG_LIB_DSYM_GLOB_armv7-apple-ios = lib$(1)-*.a.dSYM CFG_JEMALLOC_CFLAGS_armv7-apple-ios := -arch armv7 -mfpu=vfp3 $(CFG_IOS_SDK_FLAGS_armv7-apple-ios) -CFG_GCCISH_CFLAGS_armv7-apple-ios := -Wall -Werror -g -fPIC $(CFG_IOS_SDK_FLAGS_armv7-apple-ios) -mfpu=vfp3 -arch armv7 +CFG_GCCISH_CFLAGS_armv7-apple-ios := -g -fPIC $(CFG_IOS_SDK_FLAGS_armv7-apple-ios) -mfpu=vfp3 -arch armv7 CFG_GCCISH_CXXFLAGS_armv7-apple-ios := -fno-rtti $(CFG_IOS_SDK_FLAGS_armv7-apple-ios) -I$(CFG_IOS_SDK_armv7-apple-ios)/usr/include/c++/4.2.1 CFG_GCCISH_LINK_FLAGS_armv7-apple-ios := -lpthread -syslibroot $(CFG_IOS_SDK_armv7-apple-ios) -Wl,-no_compact_unwind CFG_GCCISH_DEF_FLAG_armv7-apple-ios := -Wl,-exported_symbols_list, diff --git a/mk/cfg/armv7-unknown-linux-musleabihf.mk b/mk/cfg/armv7-unknown-linux-musleabihf.mk new file mode 100644 index 000000000000..8120250150d4 --- /dev/null +++ b/mk/cfg/armv7-unknown-linux-musleabihf.mk @@ -0,0 +1,3 @@ +# This file is intentially left empty to indicate that, while this target is +# supported, it's not supported using plain GNU Make builds. Use a --rustbuild +# instead. \ No newline at end of file diff --git a/mk/cfg/armv7s-apple-ios.mk b/mk/cfg/armv7s-apple-ios.mk index efad43d25627..6da7905a7003 100644 --- a/mk/cfg/armv7s-apple-ios.mk +++ b/mk/cfg/armv7s-apple-ios.mk @@ -15,7 +15,7 @@ CFG_INSTALL_ONLY_RLIB_armv7s-apple-ios = 1 CFG_STATIC_LIB_NAME_armv7s-apple-ios=lib$(1).a CFG_LIB_DSYM_GLOB_armv7s-apple-ios = lib$(1)-*.a.dSYM CFG_JEMALLOC_CFLAGS_armv7s-apple-ios := -arch armv7s $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios) -CFG_GCCISH_CFLAGS_armv7s-apple-ios := -Wall -Werror -g -fPIC $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios) -arch armv7s +CFG_GCCISH_CFLAGS_armv7s-apple-ios := -g -fPIC $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios) -arch armv7s CFG_GCCISH_CXXFLAGS_armv7s-apple-ios := -fno-rtti $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios) -I$(CFG_IOS_SDK_armv7s-apple-ios)/usr/include/c++/4.2.1 CFG_GCCISH_LINK_FLAGS_armv7s-apple-ios := -lpthread -syslibroot $(CFG_IOS_SDK_armv7s-apple-ios) -Wl,-no_compact_unwind CFG_GCCISH_DEF_FLAG_armv7s-apple-ios := -Wl,-exported_symbols_list, diff --git a/mk/cfg/asmjs-unknown-emscripten.mk b/mk/cfg/asmjs-unknown-emscripten.mk index 9c98c0a6b4c9..a98a51b06b5d 100644 --- a/mk/cfg/asmjs-unknown-emscripten.mk +++ b/mk/cfg/asmjs-unknown-emscripten.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_asmjs-unknown-emscripten=lib$(1).a CFG_LIB_GLOB_asmjs-unknown-emscripten=lib$(1)-*.so CFG_LIB_DSYM_GLOB_asmjs-unknown-emscripten=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_asmjs-unknown-emscripten := -m32 $(CFLAGS) -CFG_GCCISH_CFLAGS_asmjs-unknown-emscripten := -Wall -Werror -g -fPIC -m32 $(CFLAGS) +CFG_GCCISH_CFLAGS_asmjs-unknown-emscripten := -g -fPIC -m32 $(CFLAGS) CFG_GCCISH_CXXFLAGS_asmjs-unknown-emscripten := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_asmjs-unknown-emscripten := -shared -fPIC -ldl -pthread -lrt -g -m32 CFG_GCCISH_DEF_FLAG_asmjs-unknown-emscripten := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/i386-apple-ios.mk b/mk/cfg/i386-apple-ios.mk index 373e2e3b65d1..bfb7fa281f24 100644 --- a/mk/cfg/i386-apple-ios.mk +++ b/mk/cfg/i386-apple-ios.mk @@ -14,7 +14,7 @@ CFG_LIB_GLOB_i386-apple-ios = lib$(1)-*.dylib CFG_INSTALL_ONLY_RLIB_i386-apple-ios = 1 CFG_STATIC_LIB_NAME_i386-apple-ios=lib$(1).a CFG_LIB_DSYM_GLOB_i386-apple-ios = lib$(1)-*.dylib.dSYM -CFG_GCCISH_CFLAGS_i386-apple-ios := -Wall -Werror -g -fPIC -m32 $(CFG_IOSSIM_FLAGS_i386-apple-ios) +CFG_GCCISH_CFLAGS_i386-apple-ios := -g -fPIC -m32 $(CFG_IOSSIM_FLAGS_i386-apple-ios) CFG_GCCISH_CXXFLAGS_i386-apple-ios := -fno-rtti $(CFG_IOSSIM_FLAGS_i386-apple-ios) -I$(CFG_IOSSIM_SDK_i386-apple-ios)/usr/include/c++/4.2.1 CFG_GCCISH_LINK_FLAGS_i386-apple-ios := -lpthread -m32 -Wl,-no_compact_unwind -m32 -Wl,-syslibroot $(CFG_IOSSIM_SDK_i386-apple-ios) CFG_GCCISH_DEF_FLAG_i386-apple-ios := -Wl,-exported_symbols_list, diff --git a/mk/cfg/i586-unknown-linux-gnu.mk b/mk/cfg/i586-unknown-linux-gnu.mk index 2b28550320d8..14b9ebfdba66 100644 --- a/mk/cfg/i586-unknown-linux-gnu.mk +++ b/mk/cfg/i586-unknown-linux-gnu.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_i586-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_i586-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_i586-unknown-linux-gnu=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_i586-unknown-linux-gnu := -m32 $(CFLAGS) -march=pentium -CFG_GCCISH_CFLAGS_i586-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32 $(CFLAGS) -march=pentium +CFG_GCCISH_CFLAGS_i586-unknown-linux-gnu := -g -fPIC -m32 $(CFLAGS) -march=pentium CFG_GCCISH_CXXFLAGS_i586-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) -march=pentium CFG_GCCISH_LINK_FLAGS_i586-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m32 CFG_GCCISH_DEF_FLAG_i586-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/i686-apple-darwin.mk b/mk/cfg/i686-apple-darwin.mk index 7ebb492bb21f..e4b3431e8b67 100644 --- a/mk/cfg/i686-apple-darwin.mk +++ b/mk/cfg/i686-apple-darwin.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_i686-apple-darwin=lib$(1).a CFG_LIB_GLOB_i686-apple-darwin=lib$(1)-*.dylib CFG_LIB_DSYM_GLOB_i686-apple-darwin=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_i686-apple-darwin := -m32 -arch i386 $(CFLAGS) -CFG_GCCISH_CFLAGS_i686-apple-darwin := -Wall -Werror -g -fPIC -m32 -arch i386 $(CFLAGS) +CFG_GCCISH_CFLAGS_i686-apple-darwin := -g -fPIC -m32 -arch i386 $(CFLAGS) CFG_GCCISH_CXXFLAGS_i686-apple-darwin := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_i686-apple-darwin := -dynamiclib -pthread -framework CoreServices -m32 CFG_GCCISH_DEF_FLAG_i686-apple-darwin := -Wl,-exported_symbols_list, diff --git a/mk/cfg/i686-pc-windows-gnu.mk b/mk/cfg/i686-pc-windows-gnu.mk index 3426b30aeeb8..50c2b8c98acd 100644 --- a/mk/cfg/i686-pc-windows-gnu.mk +++ b/mk/cfg/i686-pc-windows-gnu.mk @@ -9,7 +9,7 @@ CFG_STATIC_LIB_NAME_i686-pc-windows-gnu=$(1).lib CFG_LIB_GLOB_i686-pc-windows-gnu=$(1)-*.dll CFG_LIB_DSYM_GLOB_i686-pc-windows-gnu=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_i686-pc-windows-gnu := -march=i686 -m32 -D_WIN32_WINNT=0x0600 -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS) -CFG_GCCISH_CFLAGS_i686-pc-windows-gnu := -Wall -Werror -g -m32 -D_WIN32_WINNT=0x0600 -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS) +CFG_GCCISH_CFLAGS_i686-pc-windows-gnu := -g -m32 -D_WIN32_WINNT=0x0600 -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS) CFG_GCCISH_CXXFLAGS_i686-pc-windows-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_i686-pc-windows-gnu := -shared -g -m32 CFG_GCCISH_DEF_FLAG_i686-pc-windows-gnu := diff --git a/mk/cfg/i686-unknown-freebsd.mk b/mk/cfg/i686-unknown-freebsd.mk index bbc0c2d6f396..a9d4446d5d49 100644 --- a/mk/cfg/i686-unknown-freebsd.mk +++ b/mk/cfg/i686-unknown-freebsd.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_i686-unknown-freebsd=lib$(1).a CFG_LIB_GLOB_i686-unknown-freebsd=lib$(1)-*.so CFG_LIB_DSYM_GLOB_i686-unknown-freebsd=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_i686-unknown-freebsd := -m32 -I/usr/local/include $(CFLAGS) -CFG_GCCISH_CFLAGS_i686-unknown-freebsd := -Wall -Werror -g -fPIC -m32 -arch i386 -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_i686-unknown-freebsd := -g -fPIC -m32 -arch i386 -I/usr/local/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_i686-unknown-freebsd := -m32 -shared -fPIC -g -pthread -lrt CFG_GCCISH_DEF_FLAG_i686-unknown-freebsd := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_i686-unknown-freebsd := diff --git a/mk/cfg/i686-unknown-linux-gnu.mk b/mk/cfg/i686-unknown-linux-gnu.mk index 129af8ac6960..9e2312008a10 100644 --- a/mk/cfg/i686-unknown-linux-gnu.mk +++ b/mk/cfg/i686-unknown-linux-gnu.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_i686-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_i686-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_i686-unknown-linux-gnu=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_i686-unknown-linux-gnu := -m32 $(CFLAGS) -CFG_GCCISH_CFLAGS_i686-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32 $(CFLAGS) -march=i686 +CFG_GCCISH_CFLAGS_i686-unknown-linux-gnu := -g -fPIC -m32 $(CFLAGS) -march=i686 CFG_GCCISH_CXXFLAGS_i686-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_i686-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m32 CFG_GCCISH_DEF_FLAG_i686-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/i686-unknown-linux-musl.mk b/mk/cfg/i686-unknown-linux-musl.mk index c1cd20a843ce..80918728316a 100644 --- a/mk/cfg/i686-unknown-linux-musl.mk +++ b/mk/cfg/i686-unknown-linux-musl.mk @@ -8,7 +8,7 @@ CFG_LIB_NAME_i686-unknown-linux-musl=lib$(1).so CFG_STATIC_LIB_NAME_i686-unknown-linux-musl=lib$(1).a CFG_LIB_GLOB_i686-unknown-linux-musl=lib$(1)-*.so CFG_JEMALLOC_CFLAGS_i686-unknown-linux-musl := -m32 -Wl,-melf_i386 -CFG_GCCISH_CFLAGS_i686-unknown-linux-musl := -Wall -Werror -g -fPIC -m32 -Wl,-melf_i386 +CFG_GCCISH_CFLAGS_i686-unknown-linux-musl := -g -fPIC -m32 -Wl,-melf_i386 CFG_GCCISH_CXXFLAGS_i686-unknown-linux-musl := CFG_GCCISH_LINK_FLAGS_i686-unknown-linux-musl := CFG_GCCISH_DEF_FLAG_i686-unknown-linux-musl := diff --git a/mk/cfg/powerpc-unknown-linux-gnu.mk b/mk/cfg/powerpc-unknown-linux-gnu.mk index dda957673eba..9c5720de4b31 100644 --- a/mk/cfg/powerpc-unknown-linux-gnu.mk +++ b/mk/cfg/powerpc-unknown-linux-gnu.mk @@ -9,7 +9,7 @@ CFG_STATIC_LIB_NAME_powerpc-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_powerpc-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_powerpc-unknown-linux-gnu=lib$(1)-*.dylib.dSYM CFG_CFLAGS_powerpc-unknown-linux-gnu := -m32 $(CFLAGS) -CFG_GCCISH_CFLAGS_powerpc-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32 $(CFLAGS) +CFG_GCCISH_CFLAGS_powerpc-unknown-linux-gnu := -g -fPIC -m32 $(CFLAGS) CFG_GCCISH_CXXFLAGS_powerpc-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_powerpc-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m32 CFG_GCCISH_DEF_FLAG_powerpc-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/powerpc64-unknown-linux-gnu.mk b/mk/cfg/powerpc64-unknown-linux-gnu.mk index f6e6436f6157..389bb6f0cab4 100644 --- a/mk/cfg/powerpc64-unknown-linux-gnu.mk +++ b/mk/cfg/powerpc64-unknown-linux-gnu.mk @@ -10,7 +10,7 @@ CFG_LIB_GLOB_powerpc64-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_powerpc64-unknown-linux-gnu=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_powerpc64-unknown-linux-gnu := -m64 CFG_CFLAGS_powerpc64-unknown-linux-gnu := -m64 $(CFLAGS) -CFG_GCCISH_CFLAGS_powerpc64-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64 $(CFLAGS) +CFG_GCCISH_CFLAGS_powerpc64-unknown-linux-gnu := -g -fPIC -m64 $(CFLAGS) CFG_GCCISH_CXXFLAGS_powerpc64-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_powerpc64-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m64 CFG_GCCISH_DEF_FLAG_powerpc64-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/powerpc64le-unknown-linux-gnu.mk b/mk/cfg/powerpc64le-unknown-linux-gnu.mk index a2049331ab2e..6884fa11e741 100644 --- a/mk/cfg/powerpc64le-unknown-linux-gnu.mk +++ b/mk/cfg/powerpc64le-unknown-linux-gnu.mk @@ -9,7 +9,7 @@ CFG_STATIC_LIB_NAME_powerpc64le-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_powerpc64le-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_powerpc64le-unknown-linux-gnu=lib$(1)-*.dylib.dSYM CFG_CFLAGS_powerpc64le-unknown-linux-gnu := -m64 $(CFLAGS) -CFG_GCCISH_CFLAGS_powerpc64le-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64 $(CFLAGS) +CFG_GCCISH_CFLAGS_powerpc64le-unknown-linux-gnu := -g -fPIC -m64 $(CFLAGS) CFG_GCCISH_CXXFLAGS_powerpc64le-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_powerpc64le-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m64 CFG_GCCISH_DEF_FLAG_powerpc64le-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/x86_64-apple-darwin.mk b/mk/cfg/x86_64-apple-darwin.mk index 4c68d3dcf37b..8af47b671a85 100644 --- a/mk/cfg/x86_64-apple-darwin.mk +++ b/mk/cfg/x86_64-apple-darwin.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_x86_64-apple-darwin=lib$(1).a CFG_LIB_GLOB_x86_64-apple-darwin=lib$(1)-*.dylib CFG_LIB_DSYM_GLOB_x86_64-apple-darwin=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-apple-darwin := -m64 -arch x86_64 $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-apple-darwin := -Wall -Werror -g -fPIC -m64 -arch x86_64 $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-apple-darwin := -g -fPIC -m64 -arch x86_64 $(CFLAGS) CFG_GCCISH_CXXFLAGS_x86_64-apple-darwin := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-apple-darwin := -dynamiclib -pthread -framework CoreServices -m64 CFG_GCCISH_DEF_FLAG_x86_64-apple-darwin := -Wl,-exported_symbols_list, diff --git a/mk/cfg/x86_64-apple-ios.mk b/mk/cfg/x86_64-apple-ios.mk index dd6080fdb0ba..764cdc15996d 100644 --- a/mk/cfg/x86_64-apple-ios.mk +++ b/mk/cfg/x86_64-apple-ios.mk @@ -16,7 +16,7 @@ CFG_STATIC_LIB_NAME_x86_64-apple-ios=lib$(1).a CFG_LIB_DSYM_GLOB_x86_64-apple-ios = lib$(1)-*.a.dSYM CFG_CFLAGS_x86_64-apple-ios := $(CFG_IOSSIM_FLAGS_x86_64-apple-ios) CFG_JEMALLOC_CFLAGS_x86_64-apple-ios := $(CFG_IOSSIM_FLAGS_x86_64-apple-ios) -CFG_GCCISH_CFLAGS_x86_64-apple-ios := -Wall -Werror -fPIC $(CFG_IOSSIM_FLAGS_x86_64-apple-ios) +CFG_GCCISH_CFLAGS_x86_64-apple-ios := -fPIC $(CFG_IOSSIM_FLAGS_x86_64-apple-ios) CFG_GCCISH_CXXFLAGS_x86_64-apple-ios := -fno-rtti $(CFG_IOSSIM_FLAGS_x86_64-apple-ios) -I$(CFG_IOSSIM_SDK_x86_64-apple-ios)/usr/include/c++/4.2.1 CFG_GCCISH_LINK_FLAGS_x86_64-apple-ios := -lpthread -Wl,-no_compact_unwind -m64 -Wl,-syslibroot $(CFG_IOSSIM_SDK_x86_64-apple-ios) CFG_GCCISH_DEF_FLAG_x86_64-apple-ios := -Wl,-exported_symbols_list, diff --git a/mk/cfg/x86_64-pc-windows-gnu.mk b/mk/cfg/x86_64-pc-windows-gnu.mk index f0732d08c71e..82e7b23279fb 100644 --- a/mk/cfg/x86_64-pc-windows-gnu.mk +++ b/mk/cfg/x86_64-pc-windows-gnu.mk @@ -9,7 +9,7 @@ CFG_STATIC_LIB_NAME_x86_64-pc-windows-gnu=$(1).lib CFG_LIB_GLOB_x86_64-pc-windows-gnu=$(1)-*.dll CFG_LIB_DSYM_GLOB_x86_64-pc-windows-gnu=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-pc-windows-gnu := -m64 -D_WIN32_WINNT=0x0600 -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-pc-windows-gnu := -Wall -Werror -g -m64 -D_WIN32_WINNT=0x0600 -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-pc-windows-gnu := -g -m64 -D_WIN32_WINNT=0x0600 -D__USE_MINGW_ANSI_STDIO=1 $(CFLAGS) CFG_GCCISH_CXXFLAGS_x86_64-pc-windows-gnu := -fno-rtti $(CXXFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-pc-windows-gnu := -shared -g -m64 CFG_GCCISH_DEF_FLAG_x86_64-pc-windows-gnu := diff --git a/mk/cfg/x86_64-rumprun-netbsd.mk b/mk/cfg/x86_64-rumprun-netbsd.mk index 1b5aa12274d4..53d58b9fceaa 100644 --- a/mk/cfg/x86_64-rumprun-netbsd.mk +++ b/mk/cfg/x86_64-rumprun-netbsd.mk @@ -9,7 +9,7 @@ CFG_LIB_NAME_x86_64-rumprun-netbsd=lib$(1).so CFG_STATIC_LIB_NAME_x86_64-rumprun-netbsd=lib$(1).a CFG_LIB_GLOB_x86_64-rumprun-netbsd=lib$(1)-*.so CFG_JEMALLOC_CFLAGS_x86_64-rumprun-netbsd := -m64 -CFG_GCCISH_CFLAGS_x86_64-rumprun-netbsd := -Wall -Werror -g -fPIC -m64 +CFG_GCCISH_CFLAGS_x86_64-rumprun-netbsd := -g -fPIC -m64 CFG_GCCISH_CXXFLAGS_x86_64-rumprun-netbsd := CFG_GCCISH_LINK_FLAGS_x86_64-rumprun-netbsd := CFG_GCCISH_DEF_FLAG_x86_64-rumprun-netbsd := diff --git a/mk/cfg/x86_64-sun-solaris.mk b/mk/cfg/x86_64-sun-solaris.mk index 0a09a5cf72d9..7fc323b234ae 100644 --- a/mk/cfg/x86_64-sun-solaris.mk +++ b/mk/cfg/x86_64-sun-solaris.mk @@ -9,7 +9,7 @@ CFG_STATIC_LIB_NAME_x86_64-sun-solaris=lib$(1).a CFG_LIB_GLOB_x86_64-sun-solaris=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-sun-solaris=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-sun-solaris := -I/usr/local/include $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-sun-solaris := -Wall -Werror -g -D_POSIX_PTHREAD_SEMANTICS -fPIC -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-sun-solaris := -g -D_POSIX_PTHREAD_SEMANTICS -fPIC -I/usr/local/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-sun-solaris := -shared -fPIC -g -pthread -lrt CFG_GCCISH_DEF_FLAG_x86_64-sun-solaris := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_x86_64-sun-solaris := diff --git a/mk/cfg/x86_64-unknown-bitrig.mk b/mk/cfg/x86_64-unknown-bitrig.mk index 76b39b450254..8ac31c176188 100644 --- a/mk/cfg/x86_64-unknown-bitrig.mk +++ b/mk/cfg/x86_64-unknown-bitrig.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_x86_64-unknown-bitrig=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-bitrig=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-unknown-bitrig=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-unknown-bitrig := -m64 -I/usr/include $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-unknown-bitrig := -Wall -Werror -fPIE -fPIC -m64 -I/usr/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-bitrig := -fPIE -fPIC -m64 -I/usr/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-unknown-bitrig := -shared -pic -pthread -m64 $(LDFLAGS) CFG_GCCISH_DEF_FLAG_x86_64-unknown-bitrig := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_x86_64-unknown-bitrig := diff --git a/mk/cfg/x86_64-unknown-dragonfly.mk b/mk/cfg/x86_64-unknown-dragonfly.mk index 4015293826e1..579a9a809e20 100644 --- a/mk/cfg/x86_64-unknown-dragonfly.mk +++ b/mk/cfg/x86_64-unknown-dragonfly.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_x86_64-unknown-dragonfly=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-dragonfly=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-unknown-dragonfly=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-unknown-dragonfly := -m64 -I/usr/include -I/usr/local/include $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-unknown-dragonfly := -Wall -Werror -g -fPIC -m64 -I/usr/include -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-dragonfly := -g -fPIC -m64 -I/usr/include -I/usr/local/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-unknown-dragonfly := -shared -fPIC -g -pthread -lrt -m64 CFG_GCCISH_DEF_FLAG_x86_64-unknown-dragonfly := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_x86_64-unknown-dragonfly := diff --git a/mk/cfg/x86_64-unknown-freebsd.mk b/mk/cfg/x86_64-unknown-freebsd.mk index 1bd43168b4f6..c700601eac7a 100644 --- a/mk/cfg/x86_64-unknown-freebsd.mk +++ b/mk/cfg/x86_64-unknown-freebsd.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_x86_64-unknown-freebsd=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-freebsd=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-unknown-freebsd=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-unknown-freebsd := -I/usr/local/include $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-unknown-freebsd := -Wall -Werror -g -fPIC -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-freebsd := -g -fPIC -I/usr/local/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-unknown-freebsd := -shared -fPIC -g -pthread -lrt CFG_GCCISH_DEF_FLAG_x86_64-unknown-freebsd := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_x86_64-unknown-freebsd := diff --git a/mk/cfg/x86_64-unknown-linux-gnu.mk b/mk/cfg/x86_64-unknown-linux-gnu.mk index 044c687c9fc4..817ce22e4f59 100644 --- a/mk/cfg/x86_64-unknown-linux-gnu.mk +++ b/mk/cfg/x86_64-unknown-linux-gnu.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_x86_64-unknown-linux-gnu=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-linux-gnu=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-unknown-linux-gnu=lib$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-unknown-linux-gnu := -m64 -CFG_GCCISH_CFLAGS_x86_64-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64 +CFG_GCCISH_CFLAGS_x86_64-unknown-linux-gnu := -g -fPIC -m64 CFG_GCCISH_CXXFLAGS_x86_64-unknown-linux-gnu := -fno-rtti CFG_GCCISH_LINK_FLAGS_x86_64-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m64 CFG_GCCISH_DEF_FLAG_x86_64-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= diff --git a/mk/cfg/x86_64-unknown-linux-musl.mk b/mk/cfg/x86_64-unknown-linux-musl.mk index dfe9de18f578..6f707ac3b3fb 100644 --- a/mk/cfg/x86_64-unknown-linux-musl.mk +++ b/mk/cfg/x86_64-unknown-linux-musl.mk @@ -7,8 +7,8 @@ CFG_INSTALL_ONLY_RLIB_x86_64-unknown-linux-musl = 1 CFG_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).so CFG_STATIC_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-linux-musl=lib$(1)-*.so -CFG_JEMALLOC_CFLAGS_x86_64-unknown-linux-musl := -m64 -CFG_GCCISH_CFLAGS_x86_64-unknown-linux-musl := -Wall -Werror -g -fPIC -m64 +CFG_JEMALLOC_CFLAGS_x86_64-unknown-linux-musl := -m64 -Wa,-mrelax-relocations=no +CFG_GCCISH_CFLAGS_x86_64-unknown-linux-musl := -g -fPIC -m64 -Wa,-mrelax-relocations=no CFG_GCCISH_CXXFLAGS_x86_64-unknown-linux-musl := CFG_GCCISH_LINK_FLAGS_x86_64-unknown-linux-musl := CFG_GCCISH_DEF_FLAG_x86_64-unknown-linux-musl := diff --git a/mk/cfg/x86_64-unknown-netbsd.mk b/mk/cfg/x86_64-unknown-netbsd.mk index a77c5fa542eb..93bb2d672653 100644 --- a/mk/cfg/x86_64-unknown-netbsd.mk +++ b/mk/cfg/x86_64-unknown-netbsd.mk @@ -9,7 +9,7 @@ CFG_STATIC_LIB_NAME_x86_64-unknown-netbsd=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-netbsd=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-unknown-netbsd=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-unknown-netbsd := -I/usr/local/include $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-unknown-netbsd := -Wall -Werror -g -fPIC -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-netbsd := -g -fPIC -I/usr/local/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-unknown-netbsd := -shared -fPIC -g -pthread -lrt CFG_GCCISH_DEF_FLAG_x86_64-unknown-netbsd := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_x86_64-unknown-netbsd := diff --git a/mk/cfg/x86_64-unknown-openbsd.mk b/mk/cfg/x86_64-unknown-openbsd.mk index f1e45d764099..7cca1f7b18b3 100644 --- a/mk/cfg/x86_64-unknown-openbsd.mk +++ b/mk/cfg/x86_64-unknown-openbsd.mk @@ -8,7 +8,7 @@ CFG_STATIC_LIB_NAME_x86_64-unknown-openbsd=lib$(1).a CFG_LIB_GLOB_x86_64-unknown-openbsd=lib$(1)-*.so CFG_LIB_DSYM_GLOB_x86_64-unknown-openbsd=$(1)-*.dylib.dSYM CFG_JEMALLOC_CFLAGS_x86_64-unknown-openbsd := -m64 -I/usr/include $(CFLAGS) -CFG_GCCISH_CFLAGS_x86_64-unknown-openbsd := -Wall -Werror -g -fPIC -m64 -I/usr/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-openbsd := -g -fPIC -m64 -I/usr/include $(CFLAGS) CFG_GCCISH_LINK_FLAGS_x86_64-unknown-openbsd := -shared -fPIC -g -pthread -m64 CFG_GCCISH_DEF_FLAG_x86_64-unknown-openbsd := -Wl,--export-dynamic,--dynamic-list= CFG_LLC_FLAGS_x86_64-unknown-openbsd := diff --git a/mk/main.mk b/mk/main.mk index fd12bf26dfc7..c6c3e70abc37 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -162,9 +162,10 @@ ifdef CFG_ENABLE_DEBUGINFO CFG_RUSTC_FLAGS += -g endif -ifdef CFG_ENABLE_ORBIT - $(info cfg: launching MIR (CFG_ENABLE_ORBIT)) - CFG_RUSTC_FLAGS += -Z orbit +ifdef CFG_DISABLE_ORBIT + $(info cfg: HOLD HOLD HOLD (CFG_DISABLE_ORBIT)) + RUSTFLAGS_STAGE1 += -Z orbit=off + RUSTFLAGS_STAGE2 += -Z orbit=off endif ifdef SAVE_TEMPS diff --git a/mk/platform.mk b/mk/platform.mk index c2644621c571..d601cab7221f 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -221,12 +221,19 @@ define CFG_MAKE_TOOLCHAIN LLVM_MC_RELOCATION_MODEL="default" endif + # LLVM changed this flag in 3.9 + ifdef CFG_LLVM_MC_HAS_RELOCATION_MODEL + LLVM_MC_RELOC_FLAG := -relocation-model=$$(LLVM_MC_RELOCATION_MODEL) + else + LLVM_MC_RELOC_FLAG := -position-independent + endif + # We're using llvm-mc as our assembler because it supports # .cfi pseudo-ops on mac CFG_ASSEMBLE_$(1)=$$(CPP_$(1)) -E $$(2) | \ $$(LLVM_MC_$$(CFG_BUILD)) \ -assemble \ - -relocation-model=$$(LLVM_MC_RELOCATION_MODEL) \ + $$(LLVM_MC_RELOC_FLAG) \ -filetype=obj \ -triple=$(1) \ -o=$$(1) diff --git a/mk/rt.mk b/mk/rt.mk index 8113b6838074..e86aec60893e 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -223,147 +223,377 @@ endif # compiler-rt ################################################################################ -ifdef CFG_ENABLE_FAST_MAKE -COMPRT_DEPS := $(S)/.gitmodules -else -COMPRT_DEPS := $(wildcard \ - $(S)src/compiler-rt/* \ - $(S)src/compiler-rt/*/* \ - $(S)src/compiler-rt/*/*/* \ - $(S)src/compiler-rt/*/*/*/*) -endif - -# compiler-rt's build system is a godawful mess. Here we figure out -# the ridiculous platform-specific values and paths necessary to get -# useful artifacts out of it. +# Everything below is a manual compilation of compiler-rt, disregarding its +# build system. See comments in `src/bootstrap/native.rs` for more information. COMPRT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt) COMPRT_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(COMPRT_NAME_$(1)) COMPRT_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/compiler-rt -COMPRT_ARCH_$(1) := $$(word 1,$$(subst -, ,$(1))) - -# All this is to figure out the path to the compiler-rt bin -ifeq ($$(findstring windows-msvc,$(1)),windows-msvc) -COMPRT_DIR_$(1) := windows/Release -COMPRT_LIB_NAME_$(1) := clang_rt.builtins-$$(patsubst i%86,i386,$$(COMPRT_ARCH_$(1))) -endif - -ifeq ($$(findstring windows-gnu,$(1)),windows-gnu) -COMPRT_DIR_$(1) := windows -COMPRT_LIB_NAME_$(1) := clang_rt.builtins-$$(COMPRT_ARCH_$(1)) -endif - -ifeq ($$(findstring darwin,$(1)),darwin) -COMPRT_DIR_$(1) := builtins -COMPRT_LIB_NAME_$(1) := clang_rt.builtins_$$(patsubst i686,i386,$$(COMPRT_ARCH_$(1)))_osx -endif - -ifeq ($$(findstring ios,$(1)),ios) -COMPRT_DIR_$(1) := builtins -COMPRT_ARCH_$(1) := $$(patsubst armv7s,armv7em,$$(COMPRT_ARCH_$(1))) -COMPRT_LIB_NAME_$(1) := clang_rt.hard_pic_$$(COMPRT_ARCH_$(1))_macho_embedded -ifeq ($$(COMPRT_ARCH_$(1)),aarch64) -COMPRT_LIB_NAME_$(1) := clang_rt.builtins_arm64_ios -endif -COMPRT_DEFINES_$(1) := -DCOMPILER_RT_ENABLE_IOS=ON -endif - -ifndef COMPRT_DIR_$(1) -# NB: FreeBSD and NetBSD output to "linux"... -COMPRT_DIR_$(1) := linux -COMPRT_ARCH_$(1) := $$(patsubst i586,i386,$$(COMPRT_ARCH_$(1))) - -ifeq ($$(findstring android,$(1)),android) -ifeq ($$(findstring arm,$$(COMPRT_ARCH_$(1))),arm) -COMPRT_ARCH_$(1) := armhf -endif -endif - -ifeq ($$(findstring eabihf,$(1)),eabihf) -ifeq ($$(findstring armv7,$(1)),) -COMPRT_LIB_NAME_$(1) := clang_rt.builtins-armhf -endif -endif - -ifndef COMPRT_LIB_NAME_$(1) -COMPRT_LIB_NAME_$(1) := clang_rt.builtins-$$(COMPRT_ARCH_$(1)) -endif -endif - - -ifeq ($$(findstring windows-gnu,$(1)),windows-gnu) -COMPRT_LIB_FILE_$(1) := lib$$(COMPRT_LIB_NAME_$(1)).a -endif - -ifeq ($$(findstring android,$(1)),android) -ifeq ($$(findstring arm,$(1)),arm) -COMPRT_LIB_FILE_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$$(COMPRT_LIB_NAME_$(1))-android) -endif -endif - -ifndef COMPRT_LIB_FILE_$(1) -COMPRT_LIB_FILE_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$$(COMPRT_LIB_NAME_$(1))) -endif - -COMPRT_OUTPUT_$(1) := $$(COMPRT_BUILD_DIR_$(1))/lib/$$(COMPRT_DIR_$(1))/$$(COMPRT_LIB_FILE_$(1)) - -ifeq ($$(findstring windows-msvc,$(1)),windows-msvc) -COMPRT_BUILD_ARGS_$(1) := //v:m //nologo -COMPRT_BUILD_TARGET_$(1) := lib/builtins/builtins -COMPRT_BUILD_CC_$(1) := -else -COMPRT_BUILD_ARGS_$(1) := -ifndef COMPRT_BUILD_TARGET_$(1) -COMPRT_BUILD_TARGET_$(1) := $$(COMPRT_LIB_NAME_$(1)) -endif -COMPRT_BUILD_CC_$(1) := -DCMAKE_C_COMPILER=$$(call FIND_COMPILER,$$(CC_$(1))) \ - -DCMAKE_CXX_COMPILER=$$(call FIND_COMPILER,$$(CXX_$(1))) +# GENERIC_SOURCES in CMakeLists.txt +COMPRT_OBJS_$(1) := \ + absvdi2.o \ + absvsi2.o \ + adddf3.o \ + addsf3.o \ + addvdi3.o \ + addvsi3.o \ + apple_versioning.o \ + ashldi3.o \ + ashrdi3.o \ + clear_cache.o \ + clzdi2.o \ + clzsi2.o \ + cmpdi2.o \ + comparedf2.o \ + comparesf2.o \ + ctzdi2.o \ + ctzsi2.o \ + divdc3.o \ + divdf3.o \ + divdi3.o \ + divmoddi4.o \ + divmodsi4.o \ + divsc3.o \ + divsf3.o \ + divsi3.o \ + divxc3.o \ + extendsfdf2.o \ + extendhfsf2.o \ + ffsdi2.o \ + fixdfdi.o \ + fixdfsi.o \ + fixsfdi.o \ + fixsfsi.o \ + fixunsdfdi.o \ + fixunsdfsi.o \ + fixunssfdi.o \ + fixunssfsi.o \ + fixunsxfdi.o \ + fixunsxfsi.o \ + fixxfdi.o \ + floatdidf.o \ + floatdisf.o \ + floatdixf.o \ + floatsidf.o \ + floatsisf.o \ + floatundidf.o \ + floatundisf.o \ + floatundixf.o \ + floatunsidf.o \ + floatunsisf.o \ + int_util.o \ + lshrdi3.o \ + moddi3.o \ + modsi3.o \ + muldc3.o \ + muldf3.o \ + muldi3.o \ + mulodi4.o \ + mulosi4.o \ + muloti4.o \ + mulsc3.o \ + mulsf3.o \ + mulvdi3.o \ + mulvsi3.o \ + mulxc3.o \ + negdf2.o \ + negdi2.o \ + negsf2.o \ + negvdi2.o \ + negvsi2.o \ + paritydi2.o \ + paritysi2.o \ + popcountdi2.o \ + popcountsi2.o \ + powidf2.o \ + powisf2.o \ + powixf2.o \ + subdf3.o \ + subsf3.o \ + subvdi3.o \ + subvsi3.o \ + truncdfhf2.o \ + truncdfsf2.o \ + truncsfhf2.o \ + ucmpdi2.o \ + udivdi3.o \ + udivmoddi4.o \ + udivmodsi4.o \ + udivsi3.o \ + umoddi3.o \ + umodsi3.o ifeq ($$(findstring ios,$(1)),) -COMPRT_BUILD_CC_$(1) := $$(COMPRT_BUILD_CC_$(1)) \ - -DCMAKE_C_FLAGS="$$(CFG_GCCISH_CFLAGS_$(1)) -Wno-error" +COMPRT_OBJS_$(1) += \ + absvti2.o \ + addtf3.o \ + addvti3.o \ + ashlti3.o \ + ashrti3.o \ + clzti2.o \ + cmpti2.o \ + ctzti2.o \ + divtf3.o \ + divti3.o \ + ffsti2.o \ + fixdfti.o \ + fixsfti.o \ + fixunsdfti.o \ + fixunssfti.o \ + fixunsxfti.o \ + fixxfti.o \ + floattidf.o \ + floattisf.o \ + floattixf.o \ + floatuntidf.o \ + floatuntisf.o \ + floatuntixf.o \ + lshrti3.o \ + modti3.o \ + multf3.o \ + multi3.o \ + mulvti3.o \ + negti2.o \ + negvti2.o \ + parityti2.o \ + popcountti2.o \ + powitf2.o \ + subtf3.o \ + subvti3.o \ + trampoline_setup.o \ + ucmpti2.o \ + udivmodti4.o \ + udivti3.o \ + umodti3.o endif +ifeq ($$(findstring apple,$(1)),apple) +COMPRT_OBJS_$(1) += \ + atomic_flag_clear.o \ + atomic_flag_clear_explicit.o \ + atomic_flag_test_and_set.o \ + atomic_flag_test_and_set_explicit.o \ + atomic_signal_fence.o \ + atomic_thread_fence.o +endif + + +ifeq ($$(findstring windows,$(1)),) +COMPRT_OBJS_$(1) += emutls.o +endif + +ifeq ($$(findstring msvc,$(1)),) + +ifeq ($$(findstring freebsd,$(1)),) +COMPRT_OBJS_$(1) += gcc_personality_v0.o +endif + +COMPRT_OBJS_$(1) += emutls.o + +ifeq ($$(findstring x86_64,$(1)),x86_64) +COMPRT_OBJS_$(1) += \ + x86_64/chkstk.o \ + x86_64/chkstk2.o \ + x86_64/floatdidf.o \ + x86_64/floatdisf.o \ + x86_64/floatdixf.o \ + x86_64/floatundidf.o \ + x86_64/floatundisf.o \ + x86_64/floatundixf.o +endif + +ifeq ($$(findstring i686,$$(patsubts i%86,i686,$(1))),i686) +COMPRT_OBJS_$(1) += \ + i386/ashldi3.o \ + i386/ashrdi3.o \ + i386/chkstk.o \ + i386/chkstk2.o \ + i386/divdi3.o \ + i386/floatdidf.o \ + i386/floatdisf.o \ + i386/floatdixf.o \ + i386/floatundidf.o \ + i386/floatundisf.o \ + i386/floatundixf.o \ + i386/lshrdi3.o \ + i386/moddi3.o \ + i386/muldi3.o \ + i386/udivdi3.o \ + i386/umoddi3.o +endif + +else + +ifeq ($$(findstring x86_64,$(1)),x86_64) +COMPRT_OBJS_$(1) += \ + x86_64/floatdidf.o \ + x86_64/floatdisf.o \ + x86_64/floatdixf.o +endif + +endif + +# Generic ARM sources, nothing compiles on iOS though +ifeq ($$(findstring arm,$(1)),arm) +ifeq ($$(findstring ios,$(1)),) +COMPRT_OBJS_$(1) += \ + arm/aeabi_cdcmp.o \ + arm/aeabi_cdcmpeq_check_nan.o \ + arm/aeabi_cfcmp.o \ + arm/aeabi_cfcmpeq_check_nan.o \ + arm/aeabi_dcmp.o \ + arm/aeabi_div0.o \ + arm/aeabi_drsub.o \ + arm/aeabi_fcmp.o \ + arm/aeabi_frsub.o \ + arm/aeabi_idivmod.o \ + arm/aeabi_ldivmod.o \ + arm/aeabi_memcmp.o \ + arm/aeabi_memcpy.o \ + arm/aeabi_memmove.o \ + arm/aeabi_memset.o \ + arm/aeabi_uidivmod.o \ + arm/aeabi_uldivmod.o \ + arm/bswapdi2.o \ + arm/bswapsi2.o \ + arm/clzdi2.o \ + arm/clzsi2.o \ + arm/comparesf2.o \ + arm/divmodsi4.o \ + arm/divsi3.o \ + arm/modsi3.o \ + arm/switch16.o \ + arm/switch32.o \ + arm/switch8.o \ + arm/switchu8.o \ + arm/sync_synchronize.o \ + arm/udivmodsi4.o \ + arm/udivsi3.o \ + arm/umodsi3.o +endif +endif + +# Thumb sources +ifeq ($$(findstring armv7,$(1)),armv7) +COMPRT_OBJS_$(1) += \ + arm/sync_fetch_and_add_4.o \ + arm/sync_fetch_and_add_8.o \ + arm/sync_fetch_and_and_4.o \ + arm/sync_fetch_and_and_8.o \ + arm/sync_fetch_and_max_4.o \ + arm/sync_fetch_and_max_8.o \ + arm/sync_fetch_and_min_4.o \ + arm/sync_fetch_and_min_8.o \ + arm/sync_fetch_and_nand_4.o \ + arm/sync_fetch_and_nand_8.o \ + arm/sync_fetch_and_or_4.o \ + arm/sync_fetch_and_or_8.o \ + arm/sync_fetch_and_sub_4.o \ + arm/sync_fetch_and_sub_8.o \ + arm/sync_fetch_and_umax_4.o \ + arm/sync_fetch_and_umax_8.o \ + arm/sync_fetch_and_umin_4.o \ + arm/sync_fetch_and_umin_8.o \ + arm/sync_fetch_and_xor_4.o \ + arm/sync_fetch_and_xor_8.o +endif + +# VFP sources +ifeq ($$(findstring eabihf,$(1)),eabihf) +COMPRT_OBJS_$(1) += \ + arm/adddf3vfp.o \ + arm/addsf3vfp.o \ + arm/divdf3vfp.o \ + arm/divsf3vfp.o \ + arm/eqdf2vfp.o \ + arm/eqsf2vfp.o \ + arm/extendsfdf2vfp.o \ + arm/fixdfsivfp.o \ + arm/fixsfsivfp.o \ + arm/fixunsdfsivfp.o \ + arm/fixunssfsivfp.o \ + arm/floatsidfvfp.o \ + arm/floatsisfvfp.o \ + arm/floatunssidfvfp.o \ + arm/floatunssisfvfp.o \ + arm/gedf2vfp.o \ + arm/gesf2vfp.o \ + arm/gtdf2vfp.o \ + arm/gtsf2vfp.o \ + arm/ledf2vfp.o \ + arm/lesf2vfp.o \ + arm/ltdf2vfp.o \ + arm/ltsf2vfp.o \ + arm/muldf3vfp.o \ + arm/mulsf3vfp.o \ + arm/negdf2vfp.o \ + arm/negsf2vfp.o \ + arm/nedf2vfp.o \ + arm/nesf2vfp.o \ + arm/restore_vfp_d8_d15_regs.o \ + arm/save_vfp_d8_d15_regs.o \ + arm/subdf3vfp.o \ + arm/subsf3vfp.o \ + arm/truncdfsf2vfp.o \ + arm/unorddf2vfp.o \ + arm/unordsf2vfp.o +endif + +ifeq ($$(findstring aarch64,$(1)),aarch64) +COMPRT_OBJS_$(1) += \ + comparetf2.o \ + extenddftf2.o \ + extendsftf2.o \ + fixtfdi.o \ + fixtfsi.o \ + fixtfti.o \ + fixunstfdi.o \ + fixunstfsi.o \ + fixunstfti.o \ + floatditf.o \ + floatsitf.o \ + floatunditf.o \ + floatunsitf.o \ + multc3.o \ + trunctfdf2.o \ + trunctfsf2.o +endif + +ifeq ($$(findstring msvc,$(1)),msvc) +$$(COMPRT_BUILD_DIR_$(1))/%.o: CFLAGS += -Zl -D__func__=__FUNCTION__ +else +$$(COMPRT_BUILD_DIR_$(1))/%.o: CFLAGS += -fno-builtin -fvisibility=hidden \ + -fomit-frame-pointer -ffreestanding +endif + +COMPRT_OBJS_$(1) := $$(COMPRT_OBJS_$(1):%=$$(COMPRT_BUILD_DIR_$(1))/%) + +$$(COMPRT_BUILD_DIR_$(1))/%.o: $(S)src/compiler-rt/lib/builtins/%.c + @mkdir -p $$(@D) + @$$(call E, compile: $$@) + $$(Q)$$(call CFG_COMPILE_C_$(1),$$@,$$<) + +$$(COMPRT_BUILD_DIR_$(1))/%.o: $(S)src/compiler-rt/lib/builtins/%.S \ + $$(LLVM_CONFIG_$$(CFG_BUILD)) + @mkdir -p $$(@D) + @$$(call E, compile: $$@) + $$(Q)$$(call CFG_ASSEMBLE_$(1),$$@,$$<) + +ifeq ($$(findstring msvc,$(1)),msvc) +$$(COMPRT_BUILD_DIR_$(1))/%.o: \ + export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(1))) endif ifeq ($$(findstring emscripten,$(1)),emscripten) - # FIXME: emscripten doesn't use compiler-rt and can't build it without # further hacks -$$(COMPRT_LIB_$(1)): - touch $$@ - -else - -$$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS) $$(LLVM_CONFIG_$$(CFG_BUILD)) - @$$(call E, cmake: compiler-rt) - $$(Q)rm -rf $$(COMPRT_BUILD_DIR_$(1)) - $$(Q)mkdir $$(COMPRT_BUILD_DIR_$(1)) - $$(Q)cd "$$(COMPRT_BUILD_DIR_$(1))"; \ - $$(CFG_CMAKE) "$(S)src/compiler-rt" \ - -DCMAKE_BUILD_TYPE=$$(LLVM_BUILD_CONFIG_MODE) \ - -DLLVM_CONFIG_PATH=$$(LLVM_CONFIG_$$(CFG_BUILD)) \ - -DCOMPILER_RT_DEFAULT_TARGET_TRIPLE=$(1) \ - -DCOMPILER_RT_BUILD_SANITIZERS=OFF \ - -DCOMPILER_RT_BUILD_EMUTLS=OFF \ - $$(COMPRT_DEFINES_$(1)) \ - $$(COMPRT_BUILD_CC_$(1)) \ - -G"$$(CFG_CMAKE_GENERATOR)" -ifneq ($$(CFG_NINJA),) - $$(CFG_CMAKE) --build "$$(COMPRT_BUILD_DIR_$(1))" \ - --target $$(COMPRT_BUILD_TARGET_$(1)) \ - --config $$(LLVM_BUILD_CONFIG_MODE) \ - -- $$(COMPRT_BUILD_ARGS_$(1)) -else - $$(Q)$$(CFG_CMAKE) --build "$$(COMPRT_BUILD_DIR_$(1))" \ - --target $$(COMPRT_BUILD_TARGET_$(1)) \ - --config $$(LLVM_BUILD_CONFIG_MODE) \ - -- $$(COMPRT_BUILD_ARGS_$(1)) $$(MFLAGS) +COMPRT_OBJS_$(1) := endif - $$(Q)cp "$$(COMPRT_OUTPUT_$(1))" $$@ -endif +$$(COMPRT_LIB_$(1)): $$(COMPRT_OBJS_$(1)) + @$$(call E, link: $$@) + $$(Q)$$(call CFG_CREATE_ARCHIVE_$(1),$$@) $$^ ################################################################################ # libbacktrace diff --git a/mk/rustllvm.mk b/mk/rustllvm.mk index 26b593c8c47b..2d63f69960f7 100644 --- a/mk/rustllvm.mk +++ b/mk/rustllvm.mk @@ -24,7 +24,7 @@ LLVM_EXTRA_INCDIRS_$(1)= $$(call CFG_CC_INCLUDE_$(1),$(S)src/llvm/include) \ endif RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, \ - ExecutionEngineWrapper.cpp RustWrapper.cpp PassWrapper.cpp \ + RustWrapper.cpp PassWrapper.cpp \ ArchiveWrapper.cpp) RUSTLLVM_INCS_$(1) = $$(LLVM_EXTRA_INCDIRS_$(1)) \ diff --git a/mk/tests.mk b/mk/tests.mk index ed443147d466..201e4cae51d6 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -277,7 +277,8 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \ check-stage$(1)-T-$(2)-H-$(3)-ui-exec \ check-stage$(1)-T-$(2)-H-$(3)-doc-exec \ check-stage$(1)-T-$(2)-H-$(3)-doc-error-index-exec \ - check-stage$(1)-T-$(2)-H-$(3)-pretty-exec + check-stage$(1)-T-$(2)-H-$(3)-pretty-exec \ + check-stage$(1)-T-$(2)-H-$(3)-mir-opt-exec ifndef CFG_DISABLE_CODEGEN_TESTS check-stage$(1)-T-$(2)-H-$(3)-exec: \ @@ -458,6 +459,7 @@ UI_RS := $(call rwildcard,$(S)src/test/ui/,*.rs) \ $(call rwildcard,$(S)src/test/ui/,*.stdout) \ $(call rwildcard,$(S)src/test/ui/,*.stderr) RUSTDOCCK_RS := $(call rwildcard,$(S)src/test/rustdoc/,*.rs) +MIR_OPT_RS := $(call rwildcard,$(S)src/test/mir-opt/,*.rs) RPASS_TESTS := $(RPASS_RS) RPASS_VALGRIND_TESTS := $(RPASS_VALGRIND_RS) @@ -475,6 +477,7 @@ CODEGEN_UNITS_TESTS := $(CODEGEN_UNITS_RS) INCREMENTAL_TESTS := $(INCREMENTAL_RS) RMAKE_TESTS := $(RMAKE_RS) UI_TESTS := $(UI_RS) +MIR_OPT_TESTS := $(MIR_OPT_RS) RUSTDOCCK_TESTS := $(RUSTDOCCK_RS) CTEST_SRC_BASE_rpass = run-pass @@ -552,6 +555,11 @@ CTEST_BUILD_BASE_ui = ui CTEST_MODE_ui = ui CTEST_RUNTOOL_ui = $(CTEST_RUNTOOL) +CTEST_SRC_BASE_mir-opt = mir-opt +CTEST_BUILD_BASE_mir-opt = mir-opt +CTEST_MODE_mir-opt = mir-opt +CTEST_RUNTOOL_mir-opt = $(CTEST_RUNTOOL) + CTEST_SRC_BASE_rustdocck = rustdoc CTEST_BUILD_BASE_rustdocck = rustdoc CTEST_MODE_rustdocck = rustdoc @@ -684,6 +692,7 @@ CTEST_DEPS_incremental_$(1)-T-$(2)-H-$(3) = $$(INCREMENTAL_TESTS) CTEST_DEPS_rmake_$(1)-T-$(2)-H-$(3) = $$(RMAKE_TESTS) \ $$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3)) CTEST_DEPS_ui_$(1)-T-$(2)-H-$(3) = $$(UI_TESTS) +CTEST_DEPS_mir-opt_$(1)-T-$(2)-H-$(3) = $$(MIR_OPT_TESTS) CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \ $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \ $(S)src/etc/htmldocck.py @@ -755,7 +764,7 @@ endef CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \ debuginfo-gdb debuginfo-lldb codegen codegen-units rustdocck incremental \ - rmake ui + rmake ui mir-opt $(foreach host,$(CFG_HOST), \ $(eval $(foreach target,$(CFG_TARGET), \ @@ -964,6 +973,7 @@ TEST_GROUPS = \ pretty-rfail-full \ pretty-rfail \ pretty-pretty \ + mir-opt \ $(NULL) define DEF_CHECK_FOR_STAGE_AND_TARGET_AND_HOST diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 39c7a3750112..02698d6f7a12 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -5,10 +5,10 @@ dependencies = [ "build_helper 0.1.0", "cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -25,7 +25,7 @@ name = "cmake" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -33,12 +33,17 @@ name = "filetime" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "gcc" -version = "0.3.26" +version = "0.3.31" +source = "git+https://github.com/alexcrichton/gcc-rs#b8e2400883f1a2749b323354dad372cdd1c838c7" + +[[package]] +name = "gcc" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -48,7 +53,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "kernel32-sys" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -57,7 +62,7 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -70,7 +75,7 @@ name = "num_cpus" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index cde4a825be1f..02746034cca6 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -29,6 +29,6 @@ getopts = "0.2" rustc-serialize = "0.3" winapi = "0.2" kernel32-sys = "0.2" -gcc = "0.3.17" +gcc = { git = "https://github.com/alexcrichton/gcc-rs" } libc = "0.2" md5 = "0.1" diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 31915b116919..9e1ee7ccd1e1 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -92,8 +92,7 @@ pub fn std_link(build: &Build, } add_to_sysroot(&out_dir, &libdir); - if target.contains("musl") && - (target.contains("x86_64") || target.contains("i686")) { + if target.contains("musl") && !target.contains("mips") { copy_third_party_objects(build, target, &libdir); } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index e64d7e5a437e..aafbf68d1b7b 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -72,6 +72,7 @@ pub struct Config { // libstd features pub debug_jemalloc: bool, pub use_jemalloc: bool, + pub backtrace: bool, // support for RUST_BACKTRACE // misc pub channel: String, @@ -134,6 +135,7 @@ struct Rust { debuginfo: Option, debug_jemalloc: Option, use_jemalloc: Option, + backtrace: Option, default_linker: Option, default_ar: Option, channel: Option, @@ -158,6 +160,7 @@ impl Config { let mut config = Config::default(); config.llvm_optimize = true; config.use_jemalloc = true; + config.backtrace = true; config.rust_optimize = true; config.rust_optimize_tests = true; config.submodules = true; @@ -230,6 +233,7 @@ impl Config { set(&mut config.rust_rpath, rust.rpath); set(&mut config.debug_jemalloc, rust.debug_jemalloc); set(&mut config.use_jemalloc, rust.use_jemalloc); + set(&mut config.backtrace, rust.backtrace); set(&mut config.channel, rust.channel.clone()); config.rustc_default_linker = rust.default_linker.clone(); config.rustc_default_ar = rust.default_ar.clone(); diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 6f0658423283..2894adafef62 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -99,6 +99,9 @@ # Whether or not jemalloc is built with its debug option set #debug-jemalloc = false +# Whether or not `panic!`s generate backtraces (RUST_BACKTRACE) +#backtrace = true + # The default linker that will be used by the generated compiler. Note that this # is not the linker used to link said compiler. #default-linker = "cc" diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index caa6ea17ea05..acb7e0fadd90 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -388,6 +388,10 @@ impl Build { check::compiletest(self, &compiler, target.target, "pretty", "run-pass-valgrind"); } + CheckMirOpt { compiler } => { + check::compiletest(self, &compiler, target.target, + "mir-opt", "mir-opt"); + } CheckCodegen { compiler } => { check::compiletest(self, &compiler, target.target, "codegen", "codegen"); @@ -648,6 +652,9 @@ impl Build { if self.config.use_jemalloc { features.push_str(" jemalloc"); } + if self.config.backtrace { + features.push_str(" backtrace"); + } return features } @@ -848,6 +855,12 @@ impl Build { base.push("-stdlib=libc++".into()); base.push("-mmacosx-version-min=10.7".into()); } + // This is a hack, because newer binutils broke things on some vms/distros + // (i.e., linking against unknown relocs disabled by the following flag) + // See: https://github.com/rust-lang/rust/issues/34978 + if target == "x86_64-unknown-linux-musl" { + base.push("-Wa,-mrelax-relocations=no".into()); + } return base } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 83e9393fbaef..a78cef4f409b 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -133,86 +133,397 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) { /// Compiles the `compiler-rt` library, or at least the builtins part of it. /// -/// This uses the CMake build system and an existing LLVM build directory to -/// compile the project. +/// Note that while compiler-rt has a build system associated with it, we +/// specifically don't use it here. The compiler-rt build system, written in +/// CMake, is actually *very* difficult to work with in terms of getting it to +/// compile on all the relevant platforms we want it to compile on. In the end +/// it became so much pain to work with local patches, work around the oddities +/// of the build system, etc, that we're just building everything by hand now. +/// +/// In general compiler-rt is just a bunch of intrinsics that are in practice +/// *very* stable. We just need to make sure that all the relevant functions and +/// such are compiled somewhere and placed in an object file somewhere. +/// Eventually, these should all be written in Rust! +/// +/// So below you'll find a listing of every single file in the compiler-rt repo +/// that we're compiling. We just reach in and compile with the `gcc` crate +/// which should have all the relevant flags and such already configured. +/// +/// The risk here is that if we update compiler-rt we may need to compile some +/// new intrinsics, but to be honest we surely don't use all of the intrinsics +/// listed below today so the likelihood of us actually needing a new intrinsic +/// is quite low. The failure case is also just that someone reports a link +/// error (if any) and then we just add it to the list. Overall, that cost is +/// far far less than working with compiler-rt's build system over time. pub fn compiler_rt(build: &Build, target: &str) { - let dst = build.compiler_rt_out(target); - let arch = target.split('-').next().unwrap(); - let mode = if build.config.rust_optimize {"Release"} else {"Debug"}; - - let build_llvm_config = build.llvm_config(&build.config.build); - let mut cfg = cmake::Config::new(build.src.join("src/compiler-rt")); - cfg.target(target) - .host(&build.config.build) - .out_dir(&dst) - .profile(mode) - .define("LLVM_CONFIG_PATH", build_llvm_config) - .define("COMPILER_RT_DEFAULT_TARGET_TRIPLE", target) - .define("COMPILER_RT_BUILD_SANITIZERS", "OFF") - .define("COMPILER_RT_BUILD_EMUTLS", "OFF") - // inform about c/c++ compilers, the c++ compiler isn't actually used but - // it's needed to get the initial configure to work on all platforms. - .define("CMAKE_C_COMPILER", build.cc(target)) - .define("CMAKE_CXX_COMPILER", build.cc(target)); - - let (dir, build_target, libname) = if target.contains("linux") || - target.contains("freebsd") || - target.contains("netbsd") { - let os_extra = if target.contains("android") && target.contains("arm") { - "-android" - } else { - "" - }; - let builtins_arch = match arch { - "i586" => "i386", - "arm" | "armv7" if target.contains("android") => "armhf", - "arm" if target.contains("eabihf") => "armhf", - _ => arch, - }; - let target = format!("clang_rt.builtins-{}", builtins_arch); - ("linux".to_string(), - target.clone(), - format!("{}{}", target, os_extra)) - } else if target.contains("apple-darwin") { - let builtins_arch = match arch { - "i686" => "i386", - _ => arch, - }; - let target = format!("clang_rt.builtins_{}_osx", builtins_arch); - ("builtins".to_string(), target.clone(), target) - } else if target.contains("apple-ios") { - cfg.define("COMPILER_RT_ENABLE_IOS", "ON"); - let target = match arch { - "armv7s" => "hard_pic_armv7em_macho_embedded".to_string(), - "aarch64" => "builtins_arm64_ios".to_string(), - _ => format!("hard_pic_{}_macho_embedded", arch), - }; - ("builtins".to_string(), target.clone(), target) - } else if target.contains("windows-gnu") { - let target = format!("clang_rt.builtins-{}", arch); - ("windows".to_string(), target.clone(), target) - } else if target.contains("windows-msvc") { - let builtins_arch = match arch { - "i586" | "i686" => "i386", - _ => arch, - }; - (format!("windows/{}", mode), - "lib/builtins/builtins".to_string(), - format!("clang_rt.builtins-{}", builtins_arch)) - } else { - panic!("can't get os from target: {}", target) - }; - let output = dst.join("build/lib").join(dir) - .join(staticlib(&libname, target)); + let build_dir = build.compiler_rt_out(target); + let output = build_dir.join(staticlib("compiler-rt", target)); build.compiler_rt_built.borrow_mut().insert(target.to_string(), output.clone()); - if fs::metadata(&output).is_ok() { + t!(fs::create_dir_all(&build_dir)); + + let mut cfg = gcc::Config::new(); + cfg.cargo_metadata(false) + .out_dir(&build_dir) + .target(target) + .host(&build.config.build) + .opt_level(2) + .debug(false); + + if target.contains("msvc") { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + + // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP + cfg.define("__func__", Some("__FUNCTION__")); + } else { + // Turn off various features of gcc and such, mostly copying + // compiler-rt's build system already + cfg.flag("-fno-builtin"); + cfg.flag("-fvisibility=hidden"); + cfg.flag("-fomit-frame-pointer"); + cfg.flag("-ffreestanding"); + } + + let mut sources = vec![ + "absvdi2.c", + "absvsi2.c", + "adddf3.c", + "addsf3.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "ashldi3.c", + "ashrdi3.c", + "clear_cache.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "comparedf2.c", + "comparesf2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divdf3.c", + "divdi3.c", + "divmoddi4.c", + "divmodsi4.c", + "divsc3.c", + "divsf3.c", + "divsi3.c", + "divxc3.c", + "extendsfdf2.c", + "extendhfsf2.c", + "ffsdi2.c", + "fixdfdi.c", + "fixdfsi.c", + "fixsfdi.c", + "fixsfsi.c", + "fixunsdfdi.c", + "fixunsdfsi.c", + "fixunssfdi.c", + "fixunssfsi.c", + "fixunsxfdi.c", + "fixunsxfsi.c", + "fixxfdi.c", + "floatdidf.c", + "floatdisf.c", + "floatdixf.c", + "floatsidf.c", + "floatsisf.c", + "floatundidf.c", + "floatundisf.c", + "floatundixf.c", + "floatunsidf.c", + "floatunsisf.c", + "int_util.c", + "lshrdi3.c", + "moddi3.c", + "modsi3.c", + "muldc3.c", + "muldf3.c", + "muldi3.c", + "mulodi4.c", + "mulosi4.c", + "muloti4.c", + "mulsc3.c", + "mulsf3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powidf2.c", + "powisf2.c", + "powixf2.c", + "subdf3.c", + "subsf3.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c", + "udivdi3.c", + "udivmoddi4.c", + "udivmodsi4.c", + "udivsi3.c", + "umoddi3.c", + "umodsi3.c", + ]; + + if !target.contains("ios") { + sources.extend(vec![ + "absvti2.c", + "addtf3.c", + "addvti3.c", + "ashlti3.c", + "ashrti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "divtf3.c", + "divti3.c", + "ffsti2.c", + "fixdfti.c", + "fixsfti.c", + "fixunsdfti.c", + "fixunssfti.c", + "fixunsxfti.c", + "fixxfti.c", + "floattidf.c", + "floattisf.c", + "floattixf.c", + "floatuntidf.c", + "floatuntisf.c", + "floatuntixf.c", + "lshrti3.c", + "modti3.c", + "multf3.c", + "multi3.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "powitf2.c", + "subtf3.c", + "subvti3.c", + "trampoline_setup.c", + "ucmpti2.c", + "udivmodti4.c", + "udivti3.c", + "umodti3.c", + ]); + } + + if target.contains("apple") { + sources.extend(vec![ + "atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c", + ]); + } + + if !target.contains("windows") { + sources.push("emutls.c"); + } + + if target.contains("msvc") { + if target.contains("x86_64") { + sources.extend(vec![ + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + ]); + } + } else { + if !target.contains("freebsd") { + sources.push("gcc_personality_v0.c"); + } + + if target.contains("x86_64") { + sources.extend(vec![ + "x86_64/chkstk.S", + "x86_64/chkstk2.S", + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S", + ]); + } + + if target.contains("i386") || + target.contains("i586") || + target.contains("i686") { + sources.extend(vec![ + "i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/chkstk.S", + "i386/chkstk2.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S", + ]); + } + } + + if target.contains("arm") && !target.contains("ios") { + sources.extend(vec![ + "arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + "arm/aeabi_dcmp.S", + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_fcmp.S", + "arm/aeabi_frsub.c", + "arm/aeabi_idivmod.S", + "arm/aeabi_ldivmod.S", + "arm/aeabi_memcmp.S", + "arm/aeabi_memcpy.S", + "arm/aeabi_memmove.S", + "arm/aeabi_memset.S", + "arm/aeabi_uidivmod.S", + "arm/aeabi_uldivmod.S", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/comparesf2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S", + ]); + } + + if target.contains("armv7") { + sources.extend(vec![ + "arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S", + ]); + } + + if target.contains("eabihf") { + sources.extend(vec![ + "arm/adddf3vfp.S", + "arm/addsf3vfp.S", + "arm/divdf3vfp.S", + "arm/divsf3vfp.S", + "arm/eqdf2vfp.S", + "arm/eqsf2vfp.S", + "arm/extendsfdf2vfp.S", + "arm/fixdfsivfp.S", + "arm/fixsfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssidfvfp.S", + "arm/floatunssisfvfp.S", + "arm/gedf2vfp.S", + "arm/gesf2vfp.S", + "arm/gtdf2vfp.S", + "arm/gtsf2vfp.S", + "arm/ledf2vfp.S", + "arm/lesf2vfp.S", + "arm/ltdf2vfp.S", + "arm/ltsf2vfp.S", + "arm/muldf3vfp.S", + "arm/mulsf3vfp.S", + "arm/negdf2vfp.S", + "arm/negsf2vfp.S", + "arm/nedf2vfp.S", + "arm/nesf2vfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/subdf3vfp.S", + "arm/subsf3vfp.S", + "arm/truncdfsf2vfp.S", + "arm/unorddf2vfp.S", + "arm/unordsf2vfp.S", + ]); + } + + if target.contains("aarch64") { + sources.extend(vec![ + "comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "multc3.c", + "trunctfdf2.c", + "trunctfsf2.c", + ]); + } + + let mut out_of_date = false; + for src in sources { + let src = build.src.join("src/compiler-rt/lib/builtins").join(src); + out_of_date = out_of_date || !up_to_date(&src, &output); + cfg.file(src); + } + if !out_of_date { return } - let _ = fs::remove_dir_all(&dst); - t!(fs::create_dir_all(&dst)); - cfg.build_target(&build_target); - cfg.build(); + cfg.compile("libcompiler-rt.a"); } /// Compiles the `rust_test_helpers.c` library which we used in various diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 7c0f09c322f2..09f96782e718 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -31,6 +31,15 @@ use Build; pub fn check(build: &mut Build) { let mut checked = HashSet::new(); let path = env::var_os("PATH").unwrap_or(OsString::new()); + // On Windows, quotes are invalid characters for filename paths, and if + // one is present as part of the PATH then that can lead to the system + // being unable to identify the files properly. See + // https://github.com/rust-lang/rust/issues/34959 for more details. + if cfg!(windows) { + if path.to_string_lossy().contains("\"") { + panic!("PATH contains invalid character '\"'"); + } + } let mut need_cmd = |cmd: &OsStr| { if !checked.insert(cmd.to_owned()) { return @@ -100,7 +109,7 @@ pub fn check(build: &mut Build) { } // Make sure musl-root is valid if specified - if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) { + if target.contains("musl") && !target.contains("mips") { match build.config.musl_root { Some(ref root) => { if fs::metadata(root.join("lib/libc.a")).is_err() { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 82ae70d22ca0..f715ceb16d71 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -124,6 +124,7 @@ macro_rules! targets { (check_codegen_units, CheckCodegenUnits { compiler: Compiler<'a> }), (check_incremental, CheckIncremental { compiler: Compiler<'a> }), (check_ui, CheckUi { compiler: Compiler<'a> }), + (check_mir_opt, CheckMirOpt { compiler: Compiler<'a> }), (check_debuginfo, CheckDebuginfo { compiler: Compiler<'a> }), (check_rustdoc, CheckRustdoc { compiler: Compiler<'a> }), (check_docs, CheckDocs { compiler: Compiler<'a> }), @@ -347,9 +348,7 @@ impl<'a> Step<'a> { vec![self.libstd(compiler), self.target(host).rustc(compiler.stage)] } - Source::CompilerRt { _dummy } => { - vec![self.llvm(()).target(&build.config.build)] - } + Source::CompilerRt { _dummy } => Vec::new(), Source::Llvm { _dummy } => Vec::new(), Source::TestHelpers { _dummy } => Vec::new(), Source::DebuggerScripts { stage: _ } => Vec::new(), @@ -452,6 +451,7 @@ impl<'a> Step<'a> { self.check_pretty_rfail_full(compiler), self.check_rpass_valgrind(compiler), self.check_rmake(compiler), + self.check_mir_opt(compiler), // crates self.check_crate_rustc(compiler), @@ -479,6 +479,7 @@ impl<'a> Step<'a> { Source::CheckTidy { stage } => { vec![self.tool_tidy(stage)] } + Source::CheckMirOpt { compiler} | Source::CheckPrettyRPass { compiler } | Source::CheckPrettyRFail { compiler } | Source::CheckRFail { compiler } | diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 3ef7f8cab2d1..b5230132bcb6 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -103,7 +103,10 @@ pub fn add_lib_path(path: Vec, cmd: &mut Command) { /// Uses last-modified time checks to verify this. pub fn up_to_date(src: &Path, dst: &Path) -> bool { let threshold = mtime(dst); - let meta = t!(fs::metadata(src)); + let meta = match fs::metadata(src) { + Ok(meta) => meta, + Err(e) => panic!("source {:?} failed to get metadata: {}", src, e), + }; if meta.is_dir() { dir_up_to_date(src, &threshold) } else { diff --git a/src/compiler-rt b/src/compiler-rt index ac3d1cda612e..8598065bd965 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit ac3d1cda612edccb6f1da53cbf7716e248405f3b +Subproject commit 8598065bd965d9713bfafb6c1e766d63a7b17b89 diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md index 666d0946ecc8..1470eac98295 100644 --- a/src/doc/book/closures.md +++ b/src/doc/book/closures.md @@ -223,6 +223,7 @@ trait system to overload operators. Calling functions is no different. We have three separate traits to overload with: ```rust +# #![feature(unboxed_closures)] # mod foo { pub trait Fn : FnMut { extern "rust-call" fn call(&self, args: Args) -> Self::Output; @@ -291,9 +292,9 @@ isn’t interesting. The next part is: # some_closure(1) } ``` -Because `Fn` is a trait, we can bound our generic with it. In this case, our -closure takes a `i32` as an argument and returns an `i32`, and so the generic -bound we use is `Fn(i32) -> i32`. +Because `Fn` is a trait, we can use it as a bound for our generic type. In +this case, our closure takes a `i32` as an argument and returns an `i32`, and +so the generic bound we use is `Fn(i32) -> i32`. There’s one other key point here: because we’re bounding a generic with a trait, this will get monomorphized, and therefore, we’ll be doing static diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 3cbe5d602677..ca104ff29ace 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -575,16 +575,69 @@ against `libc` and `libm` by default. # The "nullable pointer optimization" -Certain types are defined to not be NULL. This includes references (`&T`, -`&mut T`), boxes (`Box`), and function pointers (`extern "abi" fn()`). -When interfacing with C, pointers that might be NULL are often used. -As a special case, a generic `enum` that contains exactly two variants, one of -which contains no data and the other containing a single field, is eligible -for the "nullable pointer optimization". When such an enum is instantiated -with one of the non-nullable types, it is represented as a single pointer, -and the non-data variant is represented as the NULL pointer. So -`Option c_int>` is how one represents a nullable -function pointer using the C ABI. +Certain Rust types are defined to never be `null`. This includes references (`&T`, +`&mut T`), boxes (`Box`), and function pointers (`extern "abi" fn()`). When +interfacing with C, pointers that might be `null` are often used, which would seem to +require some messy `transmute`s and/or unsafe code to handle conversions to/from Rust types. +However, the language provides a workaround. + +As a special case, an `enum` is eligible for the "nullable pointer optimization" if it contains +exactly two variants, one of which contains no data and the other contains a field of one of the +non-nullable types listed above. This means no extra space is required for a discriminant; rather, +the empty variant is represented by putting a `null` value into the non-nullable field. This is +called an "optimization", but unlike other optimizations it is guaranteed to apply to eligible +types. + +The most common type that takes advantage of the nullable pointer optimization is `Option`, +where `None` corresponds to `null`. So `Option c_int>` is a correct way +to represent a nullable function pointer using the C ABI (corresponding to the C type +`int (*)(int)`). + +Here is a contrived example. Let's say some C library has a facility for registering a +callback, which gets called in certain situations. The callback is passed a function pointer +and an integer and it is supposed to run the function with the integer as a parameter. So +we have function pointers flying across the FFI boundary in both directions. + +```rust +# #![feature(libc)] +extern crate libc; +use libc::c_int; + +# #[cfg(hidden)] +extern "C" { + /// Register the callback. + fn register(cb: Option c_int>, c_int) -> c_int>); +} +# unsafe fn register(_: Option c_int>, +# c_int) -> c_int>) +# {} + +/// This fairly useless function receives a function pointer and an integer +/// from C, and returns the result of calling the function with the integer. +/// In case no function is provided, it squares the integer by default. +extern "C" fn apply(process: Option c_int>, int: c_int) -> c_int { + match process { + Some(f) => f(int), + None => int * int + } +} + +fn main() { + unsafe { + register(Some(apply)); + } +} +``` + +And the code on the C side looks like this: + +```c +void register(void (*f)(void (*)(int), int)) { + ... +} +``` + +No `transmute` required! # Calling Rust code from C diff --git a/src/doc/book/guessing-game.md b/src/doc/book/guessing-game.md index 6ce75efd1031..22cf6068e4d5 100644 --- a/src/doc/book/guessing-game.md +++ b/src/doc/book/guessing-game.md @@ -365,7 +365,7 @@ numbers. A bare number like above is actually shorthand for `^0.3.0`, meaning "anything compatible with 0.3.0". If we wanted to use only `0.3.0` exactly, we could say `rand="=0.3.0"` (note the two equal signs). -And if we wanted to use the latest version we could use `*`. +And if we wanted to use the latest version we could use `rand="*"`. We could also use a range of versions. [Cargo’s documentation][cargodoc] contains more details. diff --git a/src/doc/book/inline-assembly.md b/src/doc/book/inline-assembly.md index a8340d9d31e7..62e196a7ccdf 100644 --- a/src/doc/book/inline-assembly.md +++ b/src/doc/book/inline-assembly.md @@ -60,6 +60,8 @@ asm!("xor %eax, %eax" : "eax" ); # } } +# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +# fn main() {} ``` Whitespace also doesn't matter: @@ -70,6 +72,8 @@ Whitespace also doesn't matter: # fn main() { unsafe { asm!("xor %eax, %eax" ::: "eax"); # } } +# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +# fn main() {} ``` ## Operands @@ -129,6 +133,8 @@ stay valid. // Put the value 0x200 in eax asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax"); # } } +# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +# fn main() {} ``` Input and output registers need not be listed since that information @@ -164,6 +170,8 @@ unsafe { } println!("eax is currently {}", result); # } +# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +# fn main() {} ``` ## More Information diff --git a/src/doc/book/lang-items.md b/src/doc/book/lang-items.md index b948567ac5b7..72a3c08225d0 100644 --- a/src/doc/book/lang-items.md +++ b/src/doc/book/lang-items.md @@ -15,7 +15,7 @@ For example, `Box` pointers require two lang items, one for allocation and one for deallocation. A freestanding program that uses the `Box` sugar for dynamic allocations via `malloc` and `free`: -```rust +```rust,ignore #![feature(lang_items, box_syntax, start, libc)] #![no_std] diff --git a/src/doc/book/loops.md b/src/doc/book/loops.md index e681d1bee061..e4cb861d3b0f 100644 --- a/src/doc/book/loops.md +++ b/src/doc/book/loops.md @@ -105,19 +105,19 @@ When you need to keep track of how many times you already looped, you can use th #### On ranges: ```rust -for (i, j) in (5..10).enumerate() { - println!("i = {} and j = {}", i, j); +for (index, value) in (5..10).enumerate() { + println!("index = {} and value = {}", index, value); } ``` Outputs: ```text -i = 0 and j = 5 -i = 1 and j = 6 -i = 2 and j = 7 -i = 3 and j = 8 -i = 4 and j = 9 +index = 0 and value = 5 +index = 1 and value = 6 +index = 2 and value = 7 +index = 3 and value = 8 +index = 4 and value = 9 ``` Don't forget to add the parentheses around the range. diff --git a/src/doc/book/syntax-index.md b/src/doc/book/syntax-index.md index 3e889f51f542..0259db221b6b 100644 --- a/src/doc/book/syntax-index.md +++ b/src/doc/book/syntax-index.md @@ -94,7 +94,7 @@ * `|` (`|…| expr`): closures. See [Closures]. * `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`). * `||` (`expr || expr`): logical or. -* `_`: "ignored" pattern binding. See [Patterns (Ignoring bindings)]. +* `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]). ## Other Syntax @@ -231,6 +231,7 @@ [Primitive Types (Tuples)]: primitive-types.html#tuples [Raw Pointers]: raw-pointers.html [Reference (Byte String Literals)]: ../reference.html#byte-string-literals +[Reference (Integer literals)]: ../reference.html#integer-literals [Reference (Raw Byte String Literals)]: ../reference.html#raw-byte-string-literals [Reference (Raw String Literals)]: ../reference.html#raw-string-literals [References and Borrowing]: references-and-borrowing.html diff --git a/src/doc/book/the-stack-and-the-heap.md b/src/doc/book/the-stack-and-the-heap.md index a1f6a065a252..aee45299cf22 100644 --- a/src/doc/book/the-stack-and-the-heap.md +++ b/src/doc/book/the-stack-and-the-heap.md @@ -26,6 +26,8 @@ The stack is very fast, and is where memory is allocated in Rust by default. But the allocation is local to a function call, and is limited in size. The heap, on the other hand, is slower, and is explicitly allocated by your program. But it’s effectively unlimited in size, and is globally accessible. +Note this meaning of heap, which allocates arbitrary-sized blocks of memory in arbitrary +order, is quite different from the heap data structure. # The Stack diff --git a/src/doc/book/trait-objects.md b/src/doc/book/trait-objects.md index b31a34a0425a..b1aee579aabc 100644 --- a/src/doc/book/trait-objects.md +++ b/src/doc/book/trait-objects.md @@ -123,7 +123,6 @@ dispatch with trait objects by casting: # trait Foo { fn method(&self) -> String; } # impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } # impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } - fn do_something(x: &Foo) { x.method(); } @@ -140,7 +139,6 @@ or by coercing: # trait Foo { fn method(&self) -> String; } # impl Foo for u8 { fn method(&self) -> String { format!("u8: {}", *self) } } # impl Foo for String { fn method(&self) -> String { format!("string: {}", *self) } } - fn do_something(x: &Foo) { x.method(); } diff --git a/src/doc/nomicon/phantom-data.md b/src/doc/nomicon/phantom-data.md index d565532017a6..189695716deb 100644 --- a/src/doc/nomicon/phantom-data.md +++ b/src/doc/nomicon/phantom-data.md @@ -50,7 +50,7 @@ struct Vec { } ``` -Unlike the previous example it *appears* that everything is exactly as we +Unlike the previous example, it *appears* that everything is exactly as we want. Every generic argument to Vec shows up in at least one field. Good to go! @@ -84,4 +84,3 @@ standard library made a utility for itself called `Unique` which: * includes a `PhantomData` * auto-derives Send/Sync as if T was contained * marks the pointer as NonZero for the null-pointer optimization - diff --git a/src/doc/reference.md b/src/doc/reference.md index b8509321e3d1..f4ffe5774d27 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1653,14 +1653,43 @@ the Rust ABI and the foreign ABI. A number of [attributes](#ffi-attributes) control the behavior of external blocks. By default external blocks assume that the library they are calling uses the -standard C "cdecl" ABI. Other ABIs may be specified using an `abi` string, as -shown here: +standard C ABI on the specific platform. Other ABIs may be specified using an +`abi` string, as shown here: ```ignore // Interface to the Windows API extern "stdcall" { } ``` +There are three ABI strings which are cross-platform, and which all compilers +are guaranteed to support: + +* `extern "Rust"` -- The default ABI when you write a normal `fn foo()` in any + Rust code. +* `extern "C"` -- This is the same as `extern fn foo()`; whatever the default + your C compiler supports. +* `extern "system"` -- Usually the same as `extern "C"`, except on Win32, in + which case it's `"stdcall"`, or what you should use to link to the Windows API + itself + +There are also some platform-specific ABI strings: + +* `extern "cdecl"` -- The default for x86\_32 C code. +* `extern "stdcall"` -- The default for the Win32 API on x86\_32. +* `extern "win64"` -- The default for C code on x86\_64 Windows. +* `extern "aapcs"` -- The default for ARM. +* `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's + `__fastcall` and GCC and clang's `__attribute__((fastcall))` +* `extern "vectorcall"` -- The `vectorcall` ABI -- corresponds to MSVC's + `__vectorcall` and clang's `__attribute__((vectorcall))` + +Finally, there are some rustc-specific ABI strings: + +* `extern "rust-intrinsic"` -- The ABI of rustc intrinsics. +* `extern "rust-call"` -- The ABI of the Fn::call trait functions. +* `extern "platform-intrinsic"` -- Specific platform intrinsics -- like, for + example, `sqrt` -- have this ABI. You should never have to deal with it. + The `link` attribute allows the name of the library to be specified. When specified the compiler will attempt to link against the native library of the specified name. @@ -3020,7 +3049,8 @@ as == != < > <= >= && || -= .. +.. ... += ``` Operators at the same precedence level are evaluated left-to-right. [Unary diff --git a/src/etc/Dockerfile b/src/etc/Dockerfile index 94be84a3ebd4..83d54789ff35 100644 --- a/src/etc/Dockerfile +++ b/src/etc/Dockerfile @@ -23,11 +23,5 @@ RUN apt-get update && apt-get -y install \ libedit-dev zlib1g-dev \ llvm-3.7-tools cmake -# When we compile compiler-rt we pass it the llvm-config we just installed on -# the system, but unfortunately it doesn't infer correctly where -# LLVMConfig.cmake is so we need to coerce it a bit... -RUN mkdir -p /usr/lib/llvm-3.7/build/share/llvm -RUN ln -s /usr/share/llvm-3.7/cmake /usr/lib/llvm-3.7/build/share/llvm/cmake - RUN mkdir /build WORKDIR /build diff --git a/src/etc/char_private.py b/src/etc/char_private.py new file mode 100644 index 000000000000..3566d143529b --- /dev/null +++ b/src/etc/char_private.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python +# +# Copyright 2011-2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +# This script uses the following Unicode tables: +# - Categories.txt + +import os +import subprocess + +def to_ranges(iter): + current = None + for i in iter: + if current is None or i != current[1] or i in (0x10000, 0x20000): + if current is not None: + yield tuple(current) + current = [i, i + 1] + else: + current[1] += 1 + if current is not None: + yield tuple(current) + +def get_escaped(dictionary): + for i in range(0x110000): + if dictionary.get(i, "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and i != ord(' '): + yield i + +def get_file(f): + try: + return open(os.path.basename(f)) + except FileNotFoundError: + subprocess.run(["curl", "-O", f], check=True) + return open(os.path.basename(f)) + +def main(): + file = get_file("http://www.unicode.org/notes/tn36/Categories.txt") + + dictionary = {int(line.split()[0], 16): line.split()[1] for line in file} + + CUTOFF=0x10000 + singletons0 = [] + singletons1 = [] + normal0 = [] + normal1 = [] + extra = [] + + for a, b in to_ranges(get_escaped(dictionary)): + if a > 2 * CUTOFF: + extra.append((a, b - a)) + elif a == b - 1: + if a & CUTOFF: + singletons1.append(a & ~CUTOFF) + else: + singletons0.append(a) + elif a == b - 2: + if a & CUTOFF: + singletons1.append(a & ~CUTOFF) + singletons1.append((a + 1) & ~CUTOFF) + else: + singletons0.append(a) + singletons0.append(a + 1) + else: + if a >= 2 * CUTOFF: + extra.append((a, b - a)) + elif a & CUTOFF: + normal1.append((a & ~CUTOFF, b - a)) + else: + normal0.append((a, b - a)) + + print("""\ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "src/etc/char_private.py", +// do not edit directly! + +use slice::SliceExt; + +fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool { + for &s in singletons { + if x == s { + return false; + } else if x < s { + break; + } + } + for w in normal.chunks(2) { + let start = w[0]; + let len = w[1]; + let difference = (x as i32) - (start as i32); + if 0 <= difference { + if difference < len as i32 { + return false; + } + } else { + break; + } + } + true +} + +pub fn is_printable(x: char) -> bool { + let x = x as u32; + let lower = x as u16; + if x < 0x10000 { + check(lower, SINGLETONS0, NORMAL0) + } else if x < 0x20000 { + check(lower, SINGLETONS1, NORMAL1) + } else {\ +""") + for a, b in extra: + print(" if 0x{:x} <= x && x < 0x{:x} {{".format(a, a + b)) + print(" return false;") + print(" }") + print("""\ + true + } +}\ +""") + print() + print("const SINGLETONS0: &'static [u16] = &[") + for s in singletons0: + print(" 0x{:x},".format(s)) + print("];") + print("const SINGLETONS1: &'static [u16] = &[") + for s in singletons1: + print(" 0x{:x},".format(s)) + print("];") + print("const NORMAL0: &'static [u16] = &[") + for a, b in normal0: + print(" 0x{:x}, 0x{:x},".format(a, b)) + print("];") + print("const NORMAL1: &'static [u16] = &[") + for a, b in normal1: + print(" 0x{:x}, 0x{:x},".format(a, b)) + print("];") + +if __name__ == '__main__': + main() diff --git a/src/etc/local_stage0.sh b/src/etc/local_stage0.sh index 354be34b6a29..f5f39d264a6b 100755 --- a/src/etc/local_stage0.sh +++ b/src/etc/local_stage0.sh @@ -58,6 +58,7 @@ case "$TARG_DIR" in cp ${PREFIX}/bin/rustc${BIN_SUF} ${TARG_DIR}/stage0/bin/ cp ${PREFIX}/${LIB_DIR}/${RUSTLIBDIR}/${TARG_DIR}/${LIB_DIR}/* ${TARG_DIR}/stage0/${LIB_DIR}/ +cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}arena*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}extra*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}rust*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}std*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ diff --git a/src/etc/mklldeps.py b/src/etc/mklldeps.py index 8381e4f70409..24b007576aa2 100644 --- a/src/etc/mklldeps.py +++ b/src/etc/mklldeps.py @@ -77,6 +77,13 @@ for lib in out.strip().replace("\n", ' ').split(' '): lib = lib.strip()[2:] elif lib[0] == '-': lib = lib.strip()[1:] + # If this actually points at a literal file then we're on MSVC which now + # prints full paths, so get just the name of the library and strip off the + # trailing ".lib" + elif os.path.exists(lib): + lib = os.path.basename(lib)[:-4] + elif lib[-4:] == '.lib': + lib = lib[:-4] f.write("#[link(name = \"" + lib + "\"") if not llvm_shared and 'LLVM' in lib: f.write(", kind = \"static\"") diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index e762e4d8ce9a..64b780413f88 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -21,6 +21,10 @@ //! //! Sharing some immutable data between threads: //! +// Note that we **do not** run these tests here. The windows builders get super +// unhappy of a thread outlives the main thread and then exits at the same time +// (something deadlocks) so we just avoid this entirely by not running these +// tests. //! ```no_run //! use std::sync::Arc; //! use std::thread; @@ -97,7 +101,8 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// by putting it inside `Mutex` and then share `Mutex` immutably /// with `Arc` as shown below. /// -/// ``` +// See comment at the top of this file for why the test is no_run +/// ```no_run /// use std::sync::{Arc, Mutex}; /// use std::thread; /// diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml index 768a0c2c0a54..25b3c8a3a0a8 100644 --- a/src/liballoc_jemalloc/Cargo.toml +++ b/src/liballoc_jemalloc/Cargo.toml @@ -16,7 +16,7 @@ libc = { path = "../rustc/libc_shim" } [build-dependencies] build_helper = { path = "../build_helper" } -gcc = "0.3.17" +gcc = "0.3.27" [features] debug = [] diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index d1b3583d256b..dc1b8d6ea983 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -73,7 +73,16 @@ fn main() { .replace("\\", "/")) .current_dir(&build_dir) .env("CC", compiler.path()) - .env("EXTRA_CFLAGS", cflags) + .env("EXTRA_CFLAGS", cflags.clone()) + // jemalloc generates Makefile deps using GCC's "-MM" flag. This means + // that GCC will run the preprocessor, and only the preprocessor, over + // jemalloc's source files. If we don't specify CPPFLAGS, then at least + // on ARM that step fails with a "Missing implementation for 32-bit + // atomic operations" error. This is because no "-march" flag will be + // passed to GCC, and then GCC won't define the + // "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to + // select an atomic operation implementation. + .env("CPPFLAGS", cflags.clone()) .env("AR", &ar) .env("RANLIB", format!("{} s", ar.display())); diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index aea7a1c13a28..c3a7d4023754 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -313,6 +313,10 @@ pub struct RangeMut<'a, K: 'a, V: 'a> { } /// A view into a single entry in a map, which may either be vacant or occupied. +/// This enum is constructed from the [`entry`] method on [`BTreeMap`]. +/// +/// [`BTreeMap`]: struct.BTreeMap.html +/// [`entry`]: struct.BTreeMap.html#method.entry #[stable(feature = "rust1", since = "1.0.0")] pub enum Entry<'a, K: 'a, V: 'a> { /// A vacant Entry @@ -326,7 +330,23 @@ pub enum Entry<'a, K: 'a, V: 'a> { OccupiedEntry<'a, K, V>), } -/// A vacant Entry. +#[stable(feature= "debug_btree_map", since = "1.12.0")] +impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for Entry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry") + .field(v) + .finish(), + Occupied(ref o) => f.debug_tuple("Entry") + .field(o) + .finish(), + } + } +} + +/// A vacant Entry. It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { key: K, @@ -337,7 +357,18 @@ pub struct VacantEntry<'a, K: 'a, V: 'a> { _marker: PhantomData<&'a mut (K, V)>, } -/// An occupied Entry. +#[stable(feature= "debug_btree_map", since = "1.12.0")] +impl<'a, K: 'a + Debug + Ord, V: 'a> Debug for VacantEntry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("VacantEntry") + .field(self.key()) + .finish() + } +} + +/// An occupied Entry. It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { handle: Handle, K, V, marker::LeafOrInternal>, marker::KV>, @@ -348,6 +379,16 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> { _marker: PhantomData<&'a mut (K, V)>, } +#[stable(feature= "debug_btree_map", since = "1.12.0")] +impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + // An iterator for merging two sorted sequences into one struct MergeIter> { left: Peekable, @@ -1857,6 +1898,17 @@ impl BTreeMap { impl<'a, K: Ord, V> Entry<'a, K, V> { /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn or_insert(self, default: V) -> &'a mut V { match self { @@ -1867,6 +1919,19 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { /// Ensures a value is in the entry by inserting the result of the default function if empty, /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, String> = BTreeMap::new(); + /// let s = "hoho".to_owned(); + /// + /// map.entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_owned()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn or_insert_with V>(self, default: F) -> &'a mut V { match self { @@ -1876,6 +1941,15 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { } /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { match *self { @@ -1888,12 +1962,36 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// Gets a reference to the key that would be used when inserting a value /// through the VacantEntry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { &self.key } /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_entry_recover_keys)] + /// + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("poneyland") { + /// v.into_key(); + /// } + /// ``` #[unstable(feature = "map_entry_recover_keys", issue = "34285")] pub fn into_key(self) -> K { self.key @@ -1901,6 +1999,21 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut count: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// // count the number of occurrences of letters in the vec + /// for x in vec!["a","b","a","c","a","b"] { + /// *count.entry(x).or_insert(0) += 1; + /// } + /// + /// assert_eq!(count["a"], 3); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { *self.length += 1; @@ -1946,30 +2059,106 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { self.handle.reborrow().into_kv().0 } /// Take ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_entry_recover_keys)] + /// + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_pair(); + /// } + /// + /// // If now try to get the value, it will panic: + /// // println!("{}", map["poneyland"]); + /// ``` #[unstable(feature = "map_entry_recover_keys", issue = "34285")] pub fn remove_pair(self) -> (K, V) { self.remove_kv() } /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get(&self) -> &V { self.handle.reborrow().into_kv().1 } /// Gets a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// } + /// assert_eq!(map["poneyland"], 22); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut V { self.handle.kv_mut().1 } /// Converts the entry into a mutable reference to its value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// assert_eq!(map["poneyland"], 22); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_mut(self) -> &'a mut V { self.handle.into_kv_mut().1 @@ -1977,12 +2166,43 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// Sets the value of the entry with the OccupiedEntry's key, /// and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// assert_eq!(map["poneyland"], 15); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, value: V) -> V { mem::replace(self.get_mut(), value) } /// Takes the value of the entry out of the map, and returns it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// // If we try to get "poneyland"'s value, it'll panic: + /// // println!("{}", map["poneyland"]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(self) -> V { self.remove_kv().1 diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index 15de0dd802d9..be0ef85d6b11 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -409,8 +409,8 @@ //! ## Precision //! //! For non-numeric types, this can be considered a "maximum width". If the resulting string is -//! longer than this width, then it is truncated down to this many characters and only those are -//! emitted. +//! longer than this width, then it is truncated down to this many characters and that truncated +//! value is emitted with proper `fill`, `alignment` and `width` if those parameters are set. //! //! For integral types, this is ignored. //! @@ -434,42 +434,37 @@ //! in this case, if one uses the format string `{:.*}`, then the `` part refers //! to the *value* to print, and the `precision` must come in the input preceding ``. //! -//! For example, these: +//! For example, the following calls all print the same thing `Hello x is 0.01000`: //! //! ``` -//! // Hello {arg 0 (x)} is {arg 1 (0.01) with precision specified inline (5)} +//! // Hello {arg 0 ("x")} is {arg 1 (0.01) with precision specified inline (5)} //! println!("Hello {0} is {1:.5}", "x", 0.01); //! -//! // Hello {arg 1 (x)} is {arg 2 (0.01) with precision specified in arg 0 (5)} +//! // Hello {arg 1 ("x")} is {arg 2 (0.01) with precision specified in arg 0 (5)} //! println!("Hello {1} is {2:.0$}", 5, "x", 0.01); //! -//! // Hello {arg 0 (x)} is {arg 2 (0.01) with precision specified in arg 1 (5)} +//! // Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)} //! println!("Hello {0} is {2:.1$}", "x", 5, 0.01); //! -//! // Hello {next arg (x)} is {second of next two args (0.01) with precision +//! // Hello {next arg ("x")} is {second of next two args (0.01) with precision //! // specified in first of next two args (5)} //! println!("Hello {} is {:.*}", "x", 5, 0.01); //! -//! // Hello {next arg (x)} is {arg 2 (0.01) with precision +//! // Hello {next arg ("x")} is {arg 2 (0.01) with precision //! // specified in its predecessor (5)} //! println!("Hello {} is {2:.*}", "x", 5, 0.01); //! -//! // Hello {next arg (x)} is {arg "number" (0.01) with precision specified +//! // Hello {next arg ("x")} is {arg "number" (0.01) with precision specified //! // in arg "prec" (5)} //! println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01); //! ``` //! -//! All print the same thing: -//! -//! ```text -//! Hello x is 0.01000 -//! ``` -//! //! While these: //! //! ``` //! println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56); //! println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56"); +//! println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56"); //! ``` //! //! print two significantly different things: @@ -477,6 +472,7 @@ //! ```text //! Hello, `1234.560` has 3 fractional digits //! Hello, `123` has 3 characters +//! Hello, ` 123` has 3 right-aligned characters //! ``` //! //! # Escaping diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index f027d074cb6f..21387a1aa955 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -33,6 +33,7 @@ #![feature(allow_internal_unstable)] #![feature(box_patterns)] #![feature(box_syntax)] +#![cfg_attr(not(test), feature(char_escape_debug))] #![feature(core_intrinsics)] #![feature(dropck_parametricity)] #![feature(fmt_internals)] @@ -48,7 +49,6 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(step_by)] -#![feature(unboxed_closures)] #![feature(unicode)] #![feature(unique)] #![feature(unsafe_no_drop_flag)] diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index dbede94f0bf1..6842f02e0e19 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -172,6 +172,14 @@ impl Default for LinkedList { impl LinkedList { /// Creates an empty `LinkedList`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let list: LinkedList = LinkedList::new(); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Self { @@ -195,19 +203,22 @@ impl LinkedList { /// ``` /// use std::collections::LinkedList; /// - /// let mut a = LinkedList::new(); - /// let mut b = LinkedList::new(); - /// a.push_back(1); - /// a.push_back(2); - /// b.push_back(3); - /// b.push_back(4); + /// let mut list1 = LinkedList::new(); + /// list1.push_back('a'); /// - /// a.append(&mut b); + /// let mut list2 = LinkedList::new(); + /// list2.push_back('b'); + /// list2.push_back('c'); /// - /// for e in &a { - /// println!("{}", e); // prints 1, then 2, then 3, then 4 - /// } - /// println!("{}", b.len()); // prints 0 + /// list1.append(&mut list2); + /// + /// let mut iter = list1.iter(); + /// assert_eq!(iter.next(), Some(&'a')); + /// assert_eq!(iter.next(), Some(&'b')); + /// assert_eq!(iter.next(), Some(&'c')); + /// assert!(iter.next().is_none()); + /// + /// assert!(list2.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn append(&mut self, other: &mut Self) { @@ -226,6 +237,24 @@ impl LinkedList { } /// Provides a forward iterator. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// let mut iter = list.iter(); + /// assert_eq!(iter.next(), Some(&0)); + /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), None); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter { @@ -238,6 +267,28 @@ impl LinkedList { } /// Provides a forward iterator with mutable references. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// for element in list.iter_mut() { + /// *element += 10; + /// } + /// + /// let mut iter = list.iter(); + /// assert_eq!(iter.next(), Some(&10)); + /// assert_eq!(iter.next(), Some(&11)); + /// assert_eq!(iter.next(), Some(&12)); + /// assert_eq!(iter.next(), None); + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter_mut(&mut self) -> IterMut { @@ -289,7 +340,6 @@ impl LinkedList { /// /// dl.push_back(3); /// assert_eq!(dl.len(), 3); - /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -316,7 +366,6 @@ impl LinkedList { /// dl.clear(); /// assert_eq!(dl.len(), 0); /// assert_eq!(dl.front(), None); - /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -326,6 +375,23 @@ impl LinkedList { /// Returns `true` if the `LinkedList` contains an element equal to the /// given value. + /// + /// # Examples + /// + /// ``` + /// #![feature(linked_list_contains)] + /// + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// assert_eq!(list.contains(&0), true); + /// assert_eq!(list.contains(&10), false); + /// ``` #[unstable(feature = "linked_list_contains", reason = "recently added", issue = "32630")] pub fn contains(&self, x: &T) -> bool @@ -347,7 +413,6 @@ impl LinkedList { /// /// dl.push_front(1); /// assert_eq!(dl.front(), Some(&1)); - /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -374,7 +439,6 @@ impl LinkedList { /// Some(x) => *x = 5, /// } /// assert_eq!(dl.front(), Some(&5)); - /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -395,7 +459,6 @@ impl LinkedList { /// /// dl.push_back(1); /// assert_eq!(dl.back(), Some(&1)); - /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -422,7 +485,6 @@ impl LinkedList { /// Some(x) => *x = 5, /// } /// assert_eq!(dl.back(), Some(&5)); - /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -446,7 +508,6 @@ impl LinkedList { /// /// dl.push_front(1); /// assert_eq!(dl.front().unwrap(), &1); - /// /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn push_front(&mut self, elt: T) { @@ -471,9 +532,7 @@ impl LinkedList { /// assert_eq!(d.pop_front(), Some(3)); /// assert_eq!(d.pop_front(), Some(1)); /// assert_eq!(d.pop_front(), None); - /// /// ``` - /// #[stable(feature = "rust1", since = "1.0.0")] pub fn pop_front(&mut self) -> Option { self.pop_front_node().map(Node::into_element) diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs index 4e39191b472e..1badc72aed07 100644 --- a/src/libcollections/range.rs +++ b/src/libcollections/range.rs @@ -23,6 +23,22 @@ pub trait RangeArgument { /// Start index (inclusive) /// /// Return start value if present, else `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(collections)] + /// #![feature(collections_range)] + /// + /// extern crate collections; + /// + /// # fn main() { + /// use collections::range::RangeArgument; + /// + /// assert_eq!((..10).start(), None); + /// assert_eq!((3..10).start(), Some(&3)); + /// # } + /// ``` fn start(&self) -> Option<&T> { None } @@ -30,6 +46,22 @@ pub trait RangeArgument { /// End index (exclusive) /// /// Return end value if present, else `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(collections)] + /// #![feature(collections_range)] + /// + /// extern crate collections; + /// + /// # fn main() { + /// use collections::range::RangeArgument; + /// + /// assert_eq!((3..).end(), None); + /// assert_eq!((3..10).end(), Some(&10)); + /// # } + /// ``` fn end(&self) -> Option<&T> { None } diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 2c54dc13c8d0..ff2b8cdea227 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -544,14 +544,21 @@ impl [T] { /// /// # Example /// - /// Print the adjacent pairs of a slice (i.e. `[1,2]`, `[2,3]`, - /// `[3,4]`): + /// ``` + /// let slice = ['r', 'u', 's', 't']; + /// let mut iter = slice.windows(2); + /// assert_eq!(iter.next().unwrap(), &['r', 'u']); + /// assert_eq!(iter.next().unwrap(), &['u', 's']); + /// assert_eq!(iter.next().unwrap(), &['s', 't']); + /// assert!(iter.next().is_none()); + /// ``` /// - /// ```rust - /// let v = &[1, 2, 3, 4]; - /// for win in v.windows(2) { - /// println!("{:?}", win); - /// } + /// If the slice is shorter than `size`: + /// + /// ``` + /// let slice = ['f', 'o', 'o']; + /// let mut iter = slice.windows(4); + /// assert!(iter.next().is_none()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -570,15 +577,13 @@ impl [T] { /// /// # Example /// - /// Print the slice two elements at a time (i.e. `[1,2]`, - /// `[3,4]`, `[5]`): - /// - /// ```rust - /// let v = &[1, 2, 3, 4, 5]; - /// - /// for chunk in v.chunks(2) { - /// println!("{:?}", chunk); - /// } + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.chunks(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['m']); + /// assert!(iter.next().is_none()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -684,15 +689,40 @@ impl [T] { /// /// # Examples /// - /// Print the slice split by numbers divisible by 3 (i.e. `[10, 40]`, - /// `[20]`, `[50]`): + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the first element is matched, an empty slice will be the first item + /// returned by the iterator. Similarly, if the last element in the slice + /// is matched, an empty slice will be the last item returned by the + /// iterator: /// /// ``` - /// let v = [10, 40, 30, 20, 60, 50]; + /// let slice = [10, 40, 33]; + /// let mut iter = slice.split(|num| num % 3 == 0); /// - /// for group in v.split(|num| *num % 3 == 0) { - /// println!("{:?}", group); - /// } + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If two matched elements are directly adjacent, an empty slice will be + /// present between them: + /// + /// ``` + /// let slice = [10, 6, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 55308a46f0ac..4c64019de097 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1697,6 +1697,14 @@ impl str { return s; } + /// Escapes each char in `s` with `char::escape_debug`. + #[unstable(feature = "str_escape", + reason = "return type may change to be an iterator", + issue = "27791")] + pub fn escape_debug(&self) -> String { + self.chars().flat_map(|c| c.escape_debug()).collect() + } + /// Escapes each char in `s` with `char::escape_default`. #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index eedf4c2c11f3..06952253ef3b 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -59,7 +59,7 @@ use core::fmt; use core::hash; use core::iter::FromIterator; use core::mem; -use core::ops::{self, Add, Index, IndexMut}; +use core::ops::{self, Add, AddAssign, Index, IndexMut}; use core::ptr; use core::str::pattern::Pattern; use rustc_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; @@ -701,6 +701,12 @@ impl String { /// Violating these may cause problems like corrupting the allocator's /// internal datastructures. /// + /// The ownership of `ptr` is effectively transferred to the + /// `String` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// /// # Examples /// /// Basic usage: @@ -1126,18 +1132,62 @@ impl String { assert!(idx <= len); assert!(self.is_char_boundary(idx)); let bits = ch.encode_utf8(); - let bits = bits.as_slice(); - let amt = bits.len(); - self.vec.reserve(amt); unsafe { - ptr::copy(self.vec.as_ptr().offset(idx as isize), - self.vec.as_mut_ptr().offset((idx + amt) as isize), - len - idx); - ptr::copy(bits.as_ptr(), - self.vec.as_mut_ptr().offset(idx as isize), - amt); - self.vec.set_len(len + amt); + self.insert_bytes(idx, bits.as_slice()); + } + } + + unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) { + let len = self.len(); + let amt = bytes.len(); + self.vec.reserve(amt); + + ptr::copy(self.vec.as_ptr().offset(idx as isize), + self.vec.as_mut_ptr().offset((idx + amt) as isize), + len - idx); + ptr::copy(bytes.as_ptr(), + self.vec.as_mut_ptr().offset(idx as isize), + amt); + self.vec.set_len(len + amt); + } + + /// Inserts a string into this `String` at a byte position. + /// + /// This is an `O(n)` operation as it requires copying every element in the + /// buffer. + /// + /// # Panics + /// + /// Panics if `idx` is larger than the `String`'s length, or if it does not + /// lie on a [`char`] boundary. + /// + /// [`char`]: ../../std/primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(insert_str)] + /// + /// let mut s = String::from("bar"); + /// + /// s.insert_str(0, "foo"); + /// + /// assert_eq!("foobar", s); + /// ``` + #[inline] + #[unstable(feature = "insert_str", + reason = "recent addition", + issue = "0")] + pub fn insert_str(&mut self, idx: usize, string: &str) { + let len = self.len(); + assert!(idx <= len); + assert!(self.is_char_boundary(idx)); + + unsafe { + self.insert_bytes(idx, string.as_bytes()); } } @@ -1559,6 +1609,14 @@ impl<'a> Add<&'a str> for String { } } +#[stable(feature = "stringaddassign", since = "1.12.0")] +impl<'a> AddAssign<&'a str> for String { + #[inline] + fn add_assign(&mut self, other: &str) { + self.push_str(other); + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for String { type Output = str; @@ -1823,6 +1881,26 @@ impl Into> for String { } } +#[stable(feature = "stringfromchars", since = "1.12.0")] +impl<'a> From<&'a [char]> for String { + #[inline] + fn from(v: &'a [char]) -> String { + let mut s = String::with_capacity(v.len()); + for c in v { + s.push(*c); + } + s + } +} + +#[stable(feature = "stringfromchars", since = "1.12.0")] +impl From> for String { + #[inline] + fn from(v: Vec) -> String { + String::from(v.as_slice()) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Write for String { #[inline] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 7a3c9bc3bb21..8b4fce158de4 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -73,6 +73,7 @@ use core::mem; use core::ops::{Index, IndexMut}; use core::ops; use core::ptr; +use core::ptr::Shared; use core::slice; use super::SpecExtend; @@ -342,12 +343,18 @@ impl Vec { /// /// * `ptr` needs to have been previously allocated via `String`/`Vec` /// (at least, it's highly likely to be incorrect if it wasn't). - /// * `length` needs to be the length that less than or equal to `capacity`. + /// * `length` needs to be less than or equal to `capacity`. /// * `capacity` needs to be the capacity that the pointer was allocated with. /// /// Violating these may cause problems like corrupting the allocator's /// internal datastructures. /// + /// The ownership of `ptr` is effectively transferred to the + /// `Vec` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// /// # Examples /// /// ``` @@ -469,6 +476,25 @@ impl Vec { /// Note that this will drop any excess capacity. Calling this and /// converting back to a vector with `into_vec()` is equivalent to calling /// `shrink_to_fit()`. + /// + /// # Examples + /// + /// ``` + /// let v = vec![1, 2, 3]; + /// + /// let slice = v.into_boxed_slice(); + /// ``` + /// + /// Any excess capacity is removed: + /// + /// ``` + /// let mut vec = Vec::with_capacity(10); + /// vec.extend([1, 2, 3].iter().cloned()); + /// + /// assert_eq!(vec.capacity(), 10); + /// let slice = vec.into_boxed_slice(); + /// assert_eq!(slice.into_vec().capacity(), 3); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_boxed_slice(mut self) -> Box<[T]> { unsafe { @@ -479,18 +505,45 @@ impl Vec { } } - /// Shorten a vector to be `len` elements long, dropping excess elements. + /// Shortens the vector, keeping the first `len` elements and dropping + /// the rest. /// /// If `len` is greater than the vector's current length, this has no /// effect. /// + /// The [`drain`] method can emulate `truncate`, but causes the excess + /// elements to be returned instead of dropped. + /// /// # Examples /// + /// Truncating a five element vector to two elements: + /// /// ``` /// let mut vec = vec![1, 2, 3, 4, 5]; /// vec.truncate(2); /// assert_eq!(vec, [1, 2]); /// ``` + /// + /// No truncation occurs when `len` is greater than the vector's current + /// length: + /// + /// ``` + /// let mut vec = vec![1, 2, 3]; + /// vec.truncate(8); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + /// + /// Truncating when `len == 0` is equivalent to calling the [`clear`] + /// method. + /// + /// ``` + /// let mut vec = vec![1, 2, 3]; + /// vec.truncate(0); + /// assert_eq!(vec, []); + /// ``` + /// + /// [`clear`]: #method.clear + /// [`drain`]: #method.drain #[stable(feature = "rust1", since = "1.0.0")] pub fn truncate(&mut self, len: usize) { unsafe { @@ -508,6 +561,14 @@ impl Vec { /// Extracts a slice containing the entire vector. /// /// Equivalent to `&s[..]`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{self, Write}; + /// let buffer = vec![1, 2, 3, 5, 8]; + /// io::sink().write(buffer.as_slice()).unwrap(); + /// ``` #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] pub fn as_slice(&self) -> &[T] { @@ -517,6 +578,14 @@ impl Vec { /// Extracts a mutable slice of the entire vector. /// /// Equivalent to `&mut s[..]`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{self, Read}; + /// let mut buffer = vec![0; 3]; + /// io::repeat(0b101).read_exact(buffer.as_mut_slice()).unwrap(); + /// ``` #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] pub fn as_mut_slice(&mut self) -> &mut [T] { @@ -532,9 +601,38 @@ impl Vec { /// # Examples /// /// ``` - /// let mut v = vec![1, 2, 3, 4]; + /// use std::ptr; + /// + /// let mut vec = vec!['r', 'u', 's', 't']; + /// /// unsafe { - /// v.set_len(1); + /// ptr::drop_in_place(&mut vec[3]); + /// vec.set_len(3); + /// } + /// assert_eq!(vec, ['r', 'u', 's']); + /// ``` + /// + /// In this example, there is a memory leak since the memory locations + /// owned by the inner vectors were not freed prior to the `set_len` call: + /// + /// ``` + /// let mut vec = vec![vec![1, 0, 0], + /// vec![0, 1, 0], + /// vec![0, 0, 1]]; + /// unsafe { + /// vec.set_len(0); + /// } + /// ``` + /// + /// In this example, the vector gets expanded from zero to four items + /// without any memory allocations occurring, resulting in vector + /// values of unallocated memory: + /// + /// ``` + /// let mut vec: Vec = Vec::new(); + /// + /// unsafe { + /// vec.set_len(4); /// } /// ``` #[inline] @@ -821,8 +919,8 @@ impl Vec { Drain { tail_start: end, tail_len: len - end, - iter: range_slice.iter_mut(), - vec: self as *mut _, + iter: range_slice.iter(), + vec: Shared::new(self as *mut _), } } } @@ -1728,8 +1826,8 @@ pub struct Drain<'a, T: 'a> { /// Length of tail tail_len: usize, /// Current remaining range to remove - iter: slice::IterMut<'a, T>, - vec: *mut Vec, + iter: slice::Iter<'a, T>, + vec: Shared>, } #[stable(feature = "drain", since = "1.6.0")] @@ -1767,7 +1865,7 @@ impl<'a, T> Drop for Drain<'a, T> { if self.tail_len > 0 { unsafe { - let source_vec = &mut *self.vec; + let source_vec = &mut **self.vec; // memmove back untouched tail, update to new length let start = source_vec.len(); let tail = self.tail_start; diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 84a0bbbd2498..9c3792afa2f1 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -365,12 +365,28 @@ impl VecDeque { impl VecDeque { /// Creates an empty `VecDeque`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let vector: VecDeque = VecDeque::new(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> VecDeque { VecDeque::with_capacity(INITIAL_CAPACITY) } /// Creates an empty `VecDeque` with space for at least `n` elements. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let vector: VecDeque = VecDeque::with_capacity(10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(n: usize) -> VecDeque { // +1 since the ringbuffer always leaves one space empty @@ -386,6 +402,8 @@ impl VecDeque { /// Retrieves an element in the `VecDeque` by index. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -409,6 +427,8 @@ impl VecDeque { /// Retrieves an element in the `VecDeque` mutably by index. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -440,6 +460,8 @@ impl VecDeque { /// /// Fails if there is no element with either index. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -696,6 +718,25 @@ impl VecDeque { /// Returns a pair of slices which contain, in order, the contents of the /// `VecDeque`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut vector: VecDeque = VecDeque::new(); + /// + /// vector.push_back(0); + /// vector.push_back(1); + /// vector.push_back(2); + /// + /// assert_eq!(vector.as_slices(), (&[0u32, 1, 2] as &[u32], &[] as &[u32])); + /// + /// vector.push_front(10); + /// vector.push_front(9); + /// + /// assert_eq!(vector.as_slices(), (&[9u32, 10] as &[u32], &[0u32, 1, 2] as &[u32])); + /// ``` #[inline] #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn as_slices(&self) -> (&[T], &[T]) { @@ -715,6 +756,24 @@ impl VecDeque { /// Returns a pair of slices which contain, in order, the contents of the /// `VecDeque`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut vector: VecDeque = VecDeque::new(); + /// + /// vector.push_back(0); + /// vector.push_back(1); + /// + /// vector.push_front(10); + /// vector.push_front(9); + /// + /// vector.as_mut_slices().0[0] = 42; + /// vector.as_mut_slices().1[0] = 24; + /// assert_eq!(vector.as_slices(), (&[42u32, 10] as &[u32], &[24u32, 1] as &[u32])); + /// ``` #[inline] #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) { @@ -789,7 +848,7 @@ impl VecDeque { /// /// ``` /// use std::collections::VecDeque; - + /// /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); /// assert_eq!(vec![3].into_iter().collect::>(), v.drain(2..).collect()); /// assert_eq!(vec![1, 2].into_iter().collect::>(), v); @@ -875,6 +934,22 @@ impl VecDeque { /// Returns `true` if the `VecDeque` contains an element equal to the /// given value. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_contains)] + /// + /// use std::collections::VecDeque; + /// + /// let mut vector: VecDeque = VecDeque::new(); + /// + /// vector.push_back(0); + /// vector.push_back(1); + /// + /// assert_eq!(vector.contains(&1), true); + /// assert_eq!(vector.contains(&10), false); + /// ``` #[unstable(feature = "vec_deque_contains", reason = "recently added", issue = "32630")] pub fn contains(&self, x: &T) -> bool @@ -1111,6 +1186,8 @@ impl VecDeque { /// /// Returns `None` if `index` is out of bounds. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -1145,6 +1222,8 @@ impl VecDeque { /// /// Returns `None` if `index` is out of bounds. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples /// /// ``` @@ -1176,6 +1255,8 @@ impl VecDeque { /// end is closer to the insertion point will be moved to make room, /// and all the affected elements will be moved to new positions. /// + /// Element at index 0 is the front of the queue. + /// /// # Panics /// /// Panics if `index` is greater than `VecDeque`'s length @@ -1403,7 +1484,10 @@ impl VecDeque { /// room, and all the affected elements will be moved to new positions. /// Returns `None` if `index` is out of bounds. /// + /// Element at index 0 is the front of the queue. + /// /// # Examples + /// /// ``` /// use std::collections::VecDeque; /// @@ -1581,6 +1665,8 @@ impl VecDeque { /// /// Note that the capacity of `self` does not change. /// + /// Element at index 0 is the front of the queue. + /// /// # Panics /// /// Panics if `at > len` diff --git a/src/libcollectionstest/binary_heap.rs b/src/libcollectionstest/binary_heap.rs index be933abe41fe..e2a57bd8d386 100644 --- a/src/libcollectionstest/binary_heap.rs +++ b/src/libcollectionstest/binary_heap.rs @@ -9,6 +9,7 @@ // except according to those terms. use std::collections::BinaryHeap; +use std::collections::binary_heap::Drain; #[test] fn test_iterator() { @@ -292,3 +293,8 @@ fn test_extend_specialization() { assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]); } + +#[allow(dead_code)] +fn assert_covariance() { + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d } +} diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 07428f3f8b2d..a61925cd3be5 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -703,16 +703,32 @@ fn test_escape_unicode() { assert_eq!("\u{1d4ea}\r".escape_unicode(), "\\u{1d4ea}\\u{d}"); } +#[test] +fn test_escape_debug() { + assert_eq!("abc".escape_debug(), "abc"); + assert_eq!("a c".escape_debug(), "a c"); + assert_eq!("éèê".escape_debug(), "éèê"); + assert_eq!("\r\n\t".escape_debug(), "\\r\\n\\t"); + assert_eq!("'\"\\".escape_debug(), "\\'\\\"\\\\"); + assert_eq!("\u{7f}\u{ff}".escape_debug(), "\\u{7f}\u{ff}"); + assert_eq!("\u{100}\u{ffff}".escape_debug(), "\u{100}\\u{ffff}"); + assert_eq!("\u{10000}\u{10ffff}".escape_debug(), "\u{10000}\\u{10ffff}"); + assert_eq!("ab\u{200b}".escape_debug(), "ab\\u{200b}"); + assert_eq!("\u{10d4ea}\r".escape_debug(), "\\u{10d4ea}\\r"); +} + #[test] fn test_escape_default() { assert_eq!("abc".escape_default(), "abc"); assert_eq!("a c".escape_default(), "a c"); + assert_eq!("éèê".escape_default(), "\\u{e9}\\u{e8}\\u{ea}"); assert_eq!("\r\n\t".escape_default(), "\\r\\n\\t"); assert_eq!("'\"\\".escape_default(), "\\'\\\"\\\\"); + assert_eq!("\u{7f}\u{ff}".escape_default(), "\\u{7f}\\u{ff}"); assert_eq!("\u{100}\u{ffff}".escape_default(), "\\u{100}\\u{ffff}"); assert_eq!("\u{10000}\u{10ffff}".escape_default(), "\\u{10000}\\u{10ffff}"); - assert_eq!("ab\u{fb00}".escape_default(), "ab\\u{fb00}"); - assert_eq!("\u{1d4ea}\r".escape_default(), "\\u{1d4ea}\\r"); + assert_eq!("ab\u{200b}".escape_default(), "ab\\u{200b}"); + assert_eq!("\u{10d4ea}\r".escape_default(), "\\u{10d4ea}\\r"); } #[test] diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs index 7f0fd282ae5e..1652fb5a88d8 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollectionstest/string.rs @@ -192,6 +192,17 @@ fn test_push_str() { assert_eq!(&s[0..], "abcประเทศไทย中华Việt Nam"); } +#[test] +fn test_add_assign() { + let mut s = String::new(); + s += ""; + assert_eq!(s.as_str(), ""); + s += "abc"; + assert_eq!(s.as_str(), "abc"); + s += "ประเทศไทย中华Việt Nam"; + assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam"); +} + #[test] fn test_push() { let mut data = String::from("ประเทศไทย中"); diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index cb99659cc0ea..7a6bd958a5f8 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -11,6 +11,7 @@ use std::borrow::Cow; use std::iter::{FromIterator, repeat}; use std::mem::size_of; +use std::vec::Drain; use test::Bencher; @@ -510,6 +511,11 @@ fn test_cow_from() { } } +#[allow(dead_code)] +fn assert_covariance() { + fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d } +} + #[bench] fn bench_new(b: &mut Bencher) { b.iter(|| { diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 65cb1aaaff6f..06af200e4783 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -847,6 +847,20 @@ impl<'b, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for RefM /// The `UnsafeCell` type is the only legal way to obtain aliasable data that is considered /// mutable. In general, transmuting an `&T` type into an `&mut T` is considered undefined behavior. /// +/// The compiler makes optimizations based on the knowledge that `&T` is not mutably aliased or +/// mutated, and that `&mut T` is unique. When building abstractions like `Cell`, `RefCell`, +/// `Mutex`, etc, you need to turn these optimizations off. `UnsafeCell` is the only legal way +/// to do this. When `UnsafeCell` is immutably aliased, it is still safe to obtain a mutable +/// reference to its interior and/or to mutate it. However, it is up to the abstraction designer +/// to ensure that no two mutable references obtained this way are active at the same time, and +/// that there are no active mutable references or mutations when an immutable reference is obtained +/// from the cell. This is often done via runtime checks. +/// +/// Note that while mutating or mutably aliasing the contents of an `& UnsafeCell` is +/// okay (provided you enforce the invariants some other way); it is still undefined behavior +/// to have multiple `&mut UnsafeCell` aliases. +/// +/// /// Types like `Cell` and `RefCell` use this type to wrap their internal data. /// /// # Examples @@ -916,6 +930,11 @@ impl UnsafeCell { impl UnsafeCell { /// Gets a mutable pointer to the wrapped value. /// + /// This can be cast to a pointer of any kind. + /// Ensure that the access is unique when casting to + /// `&mut T`, and ensure that there are no mutations or mutable + /// aliases going on when casting to `&T` + /// /// # Examples /// /// ``` diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 0e7f04c77582..a3440fe8aa64 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -17,6 +17,7 @@ use prelude::v1::*; +use char_private::is_printable; use mem::transmute; // UTF-8 ranges and tags for encoding characters @@ -263,6 +264,8 @@ pub trait CharExt { fn escape_unicode(self) -> EscapeUnicode; #[stable(feature = "core", since = "1.6.0")] fn escape_default(self) -> EscapeDefault; + #[unstable(feature = "char_escape_debug", issue = "35068")] + fn escape_debug(self) -> EscapeDebug; #[stable(feature = "core", since = "1.6.0")] fn len_utf8(self) -> usize; #[stable(feature = "core", since = "1.6.0")] @@ -326,6 +329,19 @@ impl CharExt for char { EscapeDefault { state: init_state } } + #[inline] + fn escape_debug(self) -> EscapeDebug { + let init_state = match self { + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + c if is_printable(c) => EscapeDefaultState::Char(c), + c => EscapeDefaultState::Unicode(c.escape_unicode()), + }; + EscapeDebug(EscapeDefault { state: init_state }) + } + #[inline] fn len_utf8(self) -> usize { let code = self as u32; @@ -600,6 +616,27 @@ impl ExactSizeIterator for EscapeDefault { } } +/// An iterator that yields the literal escape code of a `char`. +/// +/// This `struct` is created by the [`escape_debug()`] method on [`char`]. See its +/// documentation for more. +/// +/// [`escape_debug()`]: ../../std/primitive.char.html#method.escape_debug +/// [`char`]: ../../std/primitive.char.html +#[unstable(feature = "char_escape_debug", issue = "35068")] +#[derive(Clone, Debug)] +pub struct EscapeDebug(EscapeDefault); + +#[unstable(feature = "char_escape_debug", issue = "35068")] +impl Iterator for EscapeDebug { + type Item = char; + fn next(&mut self) -> Option { self.0.next() } + fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } +} + +#[unstable(feature = "char_escape_debug", issue = "35068")] +impl ExactSizeIterator for EscapeDebug { } + /// An iterator over `u8` entries represending the UTF-8 encoding of a `char` /// value. /// diff --git a/src/libcore/char_private.rs b/src/libcore/char_private.rs new file mode 100644 index 000000000000..1d8f95cd4b81 --- /dev/null +++ b/src/libcore/char_private.rs @@ -0,0 +1,695 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// NOTE: The following code was generated by "src/etc/char_private.py", +// do not edit directly! + +use slice::SliceExt; + +fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool { + for &s in singletons { + if x == s { + return false; + } else if x < s { + break; + } + } + for w in normal.chunks(2) { + let start = w[0]; + let len = w[1]; + let difference = (x as i32) - (start as i32); + if 0 <= difference { + if difference < len as i32 { + return false; + } + } else { + break; + } + } + true +} + +pub fn is_printable(x: char) -> bool { + let x = x as u32; + let lower = x as u16; + if x < 0x10000 { + check(lower, SINGLETONS0, NORMAL0) + } else if x < 0x20000 { + check(lower, SINGLETONS1, NORMAL1) + } else { + if 0x20000 <= x && x < 0x2f800 { + return false; + } + if 0x2fa1e <= x && x < 0xe0100 { + return false; + } + if 0xe01f0 <= x && x < 0x110000 { + return false; + } + true + } +} + +const SINGLETONS0: &'static [u16] = &[ + 0xad, + 0x378, + 0x379, + 0x38b, + 0x38d, + 0x3a2, + 0x557, + 0x558, + 0x560, + 0x588, + 0x590, + 0x61c, + 0x61d, + 0x6dd, + 0x70e, + 0x70f, + 0x74b, + 0x74c, + 0x82e, + 0x82f, + 0x83f, + 0x85c, + 0x85d, + 0x8a1, + 0x8ff, + 0x978, + 0x980, + 0x984, + 0x98d, + 0x98e, + 0x991, + 0x992, + 0x9a9, + 0x9b1, + 0x9ba, + 0x9bb, + 0x9c5, + 0x9c6, + 0x9c9, + 0x9ca, + 0x9de, + 0x9e4, + 0x9e5, + 0xa04, + 0xa11, + 0xa12, + 0xa29, + 0xa31, + 0xa34, + 0xa37, + 0xa3a, + 0xa3b, + 0xa3d, + 0xa49, + 0xa4a, + 0xa5d, + 0xa84, + 0xa8e, + 0xa92, + 0xaa9, + 0xab1, + 0xab4, + 0xaba, + 0xabb, + 0xac6, + 0xaca, + 0xace, + 0xacf, + 0xae4, + 0xae5, + 0xb04, + 0xb0d, + 0xb0e, + 0xb11, + 0xb12, + 0xb29, + 0xb31, + 0xb34, + 0xb3a, + 0xb3b, + 0xb45, + 0xb46, + 0xb49, + 0xb4a, + 0xb5e, + 0xb64, + 0xb65, + 0xb84, + 0xb91, + 0xb9b, + 0xb9d, + 0xbc9, + 0xbce, + 0xbcf, + 0xc04, + 0xc0d, + 0xc11, + 0xc29, + 0xc34, + 0xc45, + 0xc49, + 0xc57, + 0xc64, + 0xc65, + 0xc80, + 0xc81, + 0xc84, + 0xc8d, + 0xc91, + 0xca9, + 0xcb4, + 0xcba, + 0xcbb, + 0xcc5, + 0xcc9, + 0xcdf, + 0xce4, + 0xce5, + 0xcf0, + 0xd04, + 0xd0d, + 0xd11, + 0xd3b, + 0xd3c, + 0xd45, + 0xd49, + 0xd64, + 0xd65, + 0xd80, + 0xd81, + 0xd84, + 0xdb2, + 0xdbc, + 0xdbe, + 0xdbf, + 0xdd5, + 0xdd7, + 0xe83, + 0xe85, + 0xe86, + 0xe89, + 0xe8b, + 0xe8c, + 0xe98, + 0xea0, + 0xea4, + 0xea6, + 0xea8, + 0xea9, + 0xeac, + 0xeba, + 0xebe, + 0xebf, + 0xec5, + 0xec7, + 0xece, + 0xecf, + 0xeda, + 0xedb, + 0xf48, + 0xf98, + 0xfbd, + 0xfcd, + 0x10c6, + 0x10ce, + 0x10cf, + 0x1249, + 0x124e, + 0x124f, + 0x1257, + 0x1259, + 0x125e, + 0x125f, + 0x1289, + 0x128e, + 0x128f, + 0x12b1, + 0x12b6, + 0x12b7, + 0x12bf, + 0x12c1, + 0x12c6, + 0x12c7, + 0x12d7, + 0x1311, + 0x1316, + 0x1317, + 0x135b, + 0x135c, + 0x1680, + 0x170d, + 0x176d, + 0x1771, + 0x17de, + 0x17df, + 0x180e, + 0x180f, + 0x196e, + 0x196f, + 0x1a1c, + 0x1a1d, + 0x1a5f, + 0x1a7d, + 0x1a7e, + 0x1f16, + 0x1f17, + 0x1f1e, + 0x1f1f, + 0x1f46, + 0x1f47, + 0x1f4e, + 0x1f4f, + 0x1f58, + 0x1f5a, + 0x1f5c, + 0x1f5e, + 0x1f7e, + 0x1f7f, + 0x1fb5, + 0x1fc5, + 0x1fd4, + 0x1fd5, + 0x1fdc, + 0x1ff0, + 0x1ff1, + 0x1ff5, + 0x2072, + 0x2073, + 0x208f, + 0x2700, + 0x2c2f, + 0x2c5f, + 0x2d26, + 0x2d2e, + 0x2d2f, + 0x2da7, + 0x2daf, + 0x2db7, + 0x2dbf, + 0x2dc7, + 0x2dcf, + 0x2dd7, + 0x2ddf, + 0x2e9a, + 0x3040, + 0x3097, + 0x3098, + 0x318f, + 0x321f, + 0x32ff, + 0xa78f, + 0xa9ce, + 0xaa4e, + 0xaa4f, + 0xaa5a, + 0xaa5b, + 0xab07, + 0xab08, + 0xab0f, + 0xab10, + 0xab27, + 0xabee, + 0xabef, + 0xfa6e, + 0xfa6f, + 0xfb37, + 0xfb3d, + 0xfb3f, + 0xfb42, + 0xfb45, + 0xfd90, + 0xfd91, + 0xfdfe, + 0xfdff, + 0xfe53, + 0xfe67, + 0xfe75, + 0xffc8, + 0xffc9, + 0xffd0, + 0xffd1, + 0xffd8, + 0xffd9, + 0xffe7, + 0xfffe, + 0xffff, +]; +const SINGLETONS1: &'static [u16] = &[ + 0xc, + 0x27, + 0x3b, + 0x3e, + 0x4e, + 0x4f, + 0x31f, + 0x39e, + 0x49e, + 0x49f, + 0x806, + 0x807, + 0x809, + 0x836, + 0x83d, + 0x83e, + 0x856, + 0xa04, + 0xa14, + 0xa18, + 0xb56, + 0xb57, + 0x10bd, + 0x1135, + 0xd127, + 0xd128, + 0xd455, + 0xd49d, + 0xd4a0, + 0xd4a1, + 0xd4a3, + 0xd4a4, + 0xd4a7, + 0xd4a8, + 0xd4ad, + 0xd4ba, + 0xd4bc, + 0xd4c4, + 0xd506, + 0xd50b, + 0xd50c, + 0xd515, + 0xd51d, + 0xd53a, + 0xd53f, + 0xd545, + 0xd551, + 0xd6a6, + 0xd6a7, + 0xd7cc, + 0xd7cd, + 0xee04, + 0xee20, + 0xee23, + 0xee25, + 0xee26, + 0xee28, + 0xee33, + 0xee38, + 0xee3a, + 0xee48, + 0xee4a, + 0xee4c, + 0xee50, + 0xee53, + 0xee55, + 0xee56, + 0xee58, + 0xee5a, + 0xee5c, + 0xee5e, + 0xee60, + 0xee63, + 0xee65, + 0xee66, + 0xee6b, + 0xee73, + 0xee78, + 0xee7d, + 0xee7f, + 0xee8a, + 0xeea4, + 0xeeaa, + 0xf0af, + 0xf0b0, + 0xf0bf, + 0xf0c0, + 0xf0d0, + 0xf12f, + 0xf336, + 0xf3c5, + 0xf43f, + 0xf441, + 0xf4f8, + 0xf53e, + 0xf53f, +]; +const NORMAL0: &'static [u16] = &[ + 0x0, 0x20, + 0x7f, 0x22, + 0x37f, 0x5, + 0x528, 0x9, + 0x58b, 0x4, + 0x5c8, 0x8, + 0x5eb, 0x5, + 0x5f5, 0x11, + 0x7b2, 0xe, + 0x7fb, 0x5, + 0x85f, 0x41, + 0x8ad, 0x37, + 0x9b3, 0x3, + 0x9cf, 0x8, + 0x9d8, 0x4, + 0x9fc, 0x5, + 0xa0b, 0x4, + 0xa43, 0x4, + 0xa4e, 0x3, + 0xa52, 0x7, + 0xa5f, 0x7, + 0xa76, 0xb, + 0xad1, 0xf, + 0xaf2, 0xf, + 0xb4e, 0x8, + 0xb58, 0x4, + 0xb78, 0xa, + 0xb8b, 0x3, + 0xb96, 0x3, + 0xba0, 0x3, + 0xba5, 0x3, + 0xbab, 0x3, + 0xbba, 0x4, + 0xbc3, 0x3, + 0xbd1, 0x6, + 0xbd8, 0xe, + 0xbfb, 0x6, + 0xc3a, 0x3, + 0xc4e, 0x7, + 0xc5a, 0x6, + 0xc70, 0x8, + 0xcce, 0x7, + 0xcd7, 0x7, + 0xcf3, 0xf, + 0xd4f, 0x8, + 0xd58, 0x8, + 0xd76, 0x3, + 0xd97, 0x3, + 0xdc7, 0x3, + 0xdcb, 0x4, + 0xde0, 0x12, + 0xdf5, 0xc, + 0xe3b, 0x4, + 0xe5c, 0x25, + 0xe8e, 0x6, + 0xee0, 0x20, + 0xf6d, 0x4, + 0xfdb, 0x25, + 0x10c8, 0x5, + 0x137d, 0x3, + 0x139a, 0x6, + 0x13f5, 0xb, + 0x169d, 0x3, + 0x16f1, 0xf, + 0x1715, 0xb, + 0x1737, 0x9, + 0x1754, 0xc, + 0x1774, 0xc, + 0x17ea, 0x6, + 0x17fa, 0x6, + 0x181a, 0x6, + 0x1878, 0x8, + 0x18ab, 0x5, + 0x18f6, 0xa, + 0x191d, 0x3, + 0x192c, 0x4, + 0x193c, 0x4, + 0x1941, 0x3, + 0x1975, 0xb, + 0x19ac, 0x4, + 0x19ca, 0x6, + 0x19db, 0x3, + 0x1a8a, 0x6, + 0x1a9a, 0x6, + 0x1aae, 0x52, + 0x1b4c, 0x4, + 0x1b7d, 0x3, + 0x1bf4, 0x8, + 0x1c38, 0x3, + 0x1c4a, 0x3, + 0x1c80, 0x40, + 0x1cc8, 0x8, + 0x1cf7, 0x9, + 0x1de7, 0x15, + 0x1fff, 0x11, + 0x2028, 0x8, + 0x205f, 0x11, + 0x209d, 0x3, + 0x20ba, 0x16, + 0x20f1, 0xf, + 0x218a, 0x6, + 0x23f4, 0xc, + 0x2427, 0x19, + 0x244b, 0x15, + 0x2b4d, 0x3, + 0x2b5a, 0xa6, + 0x2cf4, 0x5, + 0x2d28, 0x5, + 0x2d68, 0x7, + 0x2d71, 0xe, + 0x2d97, 0x9, + 0x2e3c, 0x44, + 0x2ef4, 0xc, + 0x2fd6, 0x1a, + 0x2ffc, 0x5, + 0x3100, 0x5, + 0x312e, 0x3, + 0x31bb, 0x5, + 0x31e4, 0xc, + 0x3400, 0x19c0, + 0x4e00, 0x5200, + 0xa48d, 0x3, + 0xa4c7, 0x9, + 0xa62c, 0x14, + 0xa698, 0x7, + 0xa6f8, 0x8, + 0xa794, 0xc, + 0xa7ab, 0x4d, + 0xa82c, 0x4, + 0xa83a, 0x6, + 0xa878, 0x8, + 0xa8c5, 0x9, + 0xa8da, 0x6, + 0xa8fc, 0x4, + 0xa954, 0xb, + 0xa97d, 0x3, + 0xa9da, 0x4, + 0xa9e0, 0x20, + 0xaa37, 0x9, + 0xaa7c, 0x4, + 0xaac3, 0x18, + 0xaaf7, 0xa, + 0xab17, 0x9, + 0xab2f, 0x91, + 0xabfa, 0x2bb6, + 0xd7c7, 0x4, + 0xd7fc, 0x2104, + 0xfada, 0x26, + 0xfb07, 0xc, + 0xfb18, 0x5, + 0xfbc2, 0x11, + 0xfd40, 0x10, + 0xfdc8, 0x28, + 0xfe1a, 0x6, + 0xfe27, 0x9, + 0xfe6c, 0x4, + 0xfefd, 0x4, + 0xffbf, 0x3, + 0xffdd, 0x3, + 0xffef, 0xd, +]; +const NORMAL1: &'static [u16] = &[ + 0x5e, 0x22, + 0xfb, 0x5, + 0x103, 0x4, + 0x134, 0x3, + 0x18b, 0x5, + 0x19c, 0x34, + 0x1fe, 0x82, + 0x29d, 0x3, + 0x2d1, 0x2f, + 0x324, 0xc, + 0x34b, 0x35, + 0x3c4, 0x4, + 0x3d6, 0x2a, + 0x4aa, 0x356, + 0x839, 0x3, + 0x860, 0xa0, + 0x91c, 0x3, + 0x93a, 0x5, + 0x940, 0x40, + 0x9b8, 0x6, + 0x9c0, 0x40, + 0xa07, 0x5, + 0xa34, 0x4, + 0xa3b, 0x4, + 0xa48, 0x8, + 0xa59, 0x7, + 0xa80, 0x80, + 0xb36, 0x3, + 0xb73, 0x5, + 0xb80, 0x80, + 0xc49, 0x217, + 0xe7f, 0x181, + 0x104e, 0x4, + 0x1070, 0x10, + 0x10c2, 0xe, + 0x10e9, 0x7, + 0x10fa, 0x6, + 0x1144, 0x3c, + 0x11c9, 0x7, + 0x11da, 0x4a6, + 0x16b8, 0x8, + 0x16ca, 0x936, + 0x236f, 0x91, + 0x2463, 0xd, + 0x2474, 0xb8c, + 0x342f, 0x33d1, + 0x6a39, 0x4c7, + 0x6f45, 0xb, + 0x6f7f, 0x10, + 0x6fa0, 0x4060, + 0xb002, 0x1ffe, + 0xd0f6, 0xa, + 0xd173, 0x8, + 0xd1de, 0x22, + 0xd246, 0xba, + 0xd357, 0x9, + 0xd372, 0x8e, + 0xd547, 0x3, + 0xd800, 0x1600, + 0xee3c, 0x6, + 0xee43, 0x4, + 0xee9c, 0x5, + 0xeebc, 0x34, + 0xeef2, 0x10e, + 0xf02c, 0x4, + 0xf094, 0xc, + 0xf0e0, 0x20, + 0xf10b, 0x5, + 0xf16c, 0x4, + 0xf19b, 0x4b, + 0xf203, 0xd, + 0xf23b, 0x5, + 0xf249, 0x7, + 0xf252, 0xae, + 0xf321, 0xf, + 0xf37d, 0x3, + 0xf394, 0xc, + 0xf3cb, 0x15, + 0xf3f1, 0xf, + 0xf4fd, 0x3, + 0xf544, 0xc, + 0xf568, 0x93, + 0xf641, 0x4, + 0xf650, 0x30, + 0xf6c6, 0x3a, + 0xf774, 0x88c, +]; diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 895a679fc3dc..173c55e35d51 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -980,15 +980,19 @@ impl<'a> Formatter<'a> { return self.buf.write_str(s); } // The `precision` field can be interpreted as a `max-width` for the - // string being formatted - if let Some(max) = self.precision { - // If there's a maximum width and our string is longer than - // that, then we must always have truncation. This is the only - // case where the maximum length will matter. + // string being formatted. + let s = if let Some(max) = self.precision { + // If our string is longer that the precision, then we must have + // truncation. However other flags like `fill`, `width` and `align` + // must act as always. if let Some((i, _)) = s.char_indices().skip(max).next() { - return self.buf.write_str(&s[..i]) + &s[..i] + } else { + &s } - } + } else { + &s + }; // The `width` field is more of a `min-width` parameter at this point. match self.width { // If we're under the maximum length, and there's no minimum length @@ -1379,7 +1383,7 @@ impl Debug for str { f.write_char('"')?; let mut from = 0; for (i, c) in self.char_indices() { - let esc = c.escape_default(); + let esc = c.escape_debug(); // If char needs escaping, flush backlog so far and write, else skip if esc.len() != 1 { f.write_str(&self[from..i])?; @@ -1405,7 +1409,7 @@ impl Display for str { impl Debug for char { fn fmt(&self, f: &mut Formatter) -> Result { f.write_char('\'')?; - for c in self.escape_default() { + for c in self.escape_debug() { f.write_char(c)? } f.write_char('\'') diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 9e3f7a4a84a8..27fdbd383017 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -234,6 +234,16 @@ pub trait BuildHasher { type Hasher: Hasher; /// Creates a new hasher. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::RandomState; + /// use std::hash::BuildHasher; + /// + /// let s = RandomState::new(); + /// let new_s = s.build_hasher(); + /// ``` #[stable(since = "1.7.0", feature = "build_hasher")] fn build_hasher(&self) -> Self::Hasher; } diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1bdcc5bfe119..c645608dda79 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -277,17 +277,200 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. pub fn forget(_: T) -> (); - /// Unsafely transforms a value of one type into a value of another type. + /// Reinterprets the bits of a value of one type as another type; both types + /// must have the same size. Neither the original, nor the result, may be an + /// [invalid value] (../../nomicon/meet-safe-and-unsafe.html). /// - /// Both types must have the same size. + /// `transmute` is semantically equivalent to a bitwise move of one type + /// into another. It copies the bits from the destination type into the + /// source type, then forgets the original. It's equivalent to C's `memcpy` + /// under the hood, just like `transmute_copy`. + /// + /// `transmute` is incredibly unsafe. There are a vast number of ways to + /// cause undefined behavior with this function. `transmute` should be + /// the absolute last resort. + /// + /// The [nomicon](../../nomicon/transmutes.html) has additional + /// documentation. /// /// # Examples /// - /// ``` - /// use std::mem; + /// There are a few things that `transmute` is really useful for. /// - /// let array: &[u8] = unsafe { mem::transmute("Rust") }; - /// assert_eq!(array, [82, 117, 115, 116]); + /// Getting the bitpattern of a floating point type (or, more generally, + /// type punning, when `T` and `U` aren't pointers): + /// + /// ``` + /// let bitpattern = unsafe { + /// std::mem::transmute::(1.0) + /// }; + /// assert_eq!(bitpattern, 0x3F800000); + /// ``` + /// + /// Turning a pointer into a function pointer: + /// + /// ``` + /// fn foo() -> i32 { + /// 0 + /// } + /// let pointer = foo as *const (); + /// let function = unsafe { + /// std::mem::transmute::<*const (), fn() -> i32>(pointer) + /// }; + /// assert_eq!(function(), 0); + /// ``` + /// + /// Extending a lifetime, or shortening an invariant lifetime; this is + /// advanced, very unsafe rust: + /// + /// ``` + /// struct R<'a>(&'a i32); + /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { + /// std::mem::transmute::, R<'static>>(r) + /// } + /// + /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) + /// -> &'b mut R<'c> { + /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) + /// } + /// ``` + /// + /// # Alternatives + /// + /// However, many uses of `transmute` can be achieved through other means. + /// `transmute` can transform any type into any other, with just the caveat + /// that they're the same size, and often interesting results occur. Below + /// are common applications of `transmute` which can be replaced with safe + /// applications of `as`: + /// + /// Turning a pointer into a `usize`: + /// + /// ``` + /// let ptr = &0; + /// let ptr_num_transmute = unsafe { + /// std::mem::transmute::<&i32, usize>(ptr) + /// }; + /// // Use an `as` cast instead + /// let ptr_num_cast = ptr as *const i32 as usize; + /// ``` + /// + /// Turning a `*mut T` into an `&mut T`: + /// + /// ``` + /// let ptr: *mut i32 = &mut 0; + /// let ref_transmuted = unsafe { + /// std::mem::transmute::<*mut i32, &mut i32>(ptr) + /// }; + /// // Use a reborrow instead + /// let ref_casted = unsafe { &mut *ptr }; + /// ``` + /// + /// Turning an `&mut T` into an `&mut U`: + /// + /// ``` + /// let ptr = &mut 0; + /// let val_transmuted = unsafe { + /// std::mem::transmute::<&mut i32, &mut u32>(ptr) + /// }; + /// // Now, put together `as` and reborrowing - note the chaining of `as` + /// // `as` is not transitive + /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; + /// ``` + /// + /// Turning an `&str` into an `&[u8]`: + /// + /// ``` + /// // this is not a good way to do this. + /// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") }; + /// assert_eq!(slice, &[82, 117, 115, 116]); + /// // You could use `str::as_bytes` + /// let slice = "Rust".as_bytes(); + /// assert_eq!(slice, &[82, 117, 115, 116]); + /// // Or, just use a byte string, if you have control over the string + /// // literal + /// assert_eq!(b"Rust", &[82, 117, 115, 116]); + /// ``` + /// + /// Turning a `Vec<&T>` into a `Vec>`: + /// + /// ``` + /// let store = [0, 1, 2, 3]; + /// let mut v_orig = store.iter().collect::>(); + /// // Using transmute: this is Undefined Behavior, and a bad idea. + /// // However, it is no-copy. + /// let v_transmuted = unsafe { + /// std::mem::transmute::, Vec>>( + /// v_orig.clone()) + /// }; + /// // This is the suggested, safe way. + /// // It does copy the entire Vector, though, into a new array. + /// let v_collected = v_orig.clone() + /// .into_iter() + /// .map(|r| Some(r)) + /// .collect::>>(); + /// // The no-copy, unsafe way, still using transmute, but not UB. + /// // This is equivalent to the original, but safer, and reuses the + /// // same Vec internals. Therefore the new inner type must have the + /// // exact same size, and the same or lesser alignment, as the old + /// // type. The same caveats exist for this method as transmute, for + /// // the original inner type (`&i32`) to the converted inner type + /// // (`Option<&i32>`), so read the nomicon pages linked above. + /// let v_from_raw = unsafe { + /// Vec::from_raw_parts(v_orig.as_mut_ptr(), + /// v_orig.len(), + /// v_orig.capacity()) + /// }; + /// std::mem::forget(v_orig); + /// ``` + /// + /// Implementing `split_at_mut`: + /// + /// ``` + /// use std::{slice, mem}; + /// // There are multiple ways to do this; and there are multiple problems + /// // with the following, transmute, way. + /// fn split_at_mut_transmute(slice: &mut [T], mid: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(mid <= len); + /// unsafe { + /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); + /// // first: transmute is not typesafe; all it checks is that T and + /// // U are of the same size. Second, right here, you have two + /// // mutable references pointing to the same memory. + /// (&mut slice[0..mid], &mut slice2[mid..len]) + /// } + /// } + /// // This gets rid of the typesafety problems; `&mut *` will *only* give + /// // you an `&mut T` from an `&mut T` or `*mut T`. + /// fn split_at_mut_casts(slice: &mut [T], mid: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(mid <= len); + /// unsafe { + /// let slice2 = &mut *(slice as *mut [T]); + /// // however, you still have two mutable references pointing to + /// // the same memory. + /// (&mut slice[0..mid], &mut slice2[mid..len]) + /// } + /// } + /// // This is how the standard library does it. This is the best method, if + /// // you need to do something like this + /// fn split_at_stdlib(slice: &mut [T], mid: usize) + /// -> (&mut [T], &mut [T]) { + /// let len = slice.len(); + /// assert!(mid <= len); + /// unsafe { + /// let ptr = slice.as_mut_ptr(); + /// // This now has three mutable references pointing at the same + /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. + /// // `slice` is never used after `let ptr = ...`, and so one can + /// // treat it as "dead", and therefore, you only have two real + /// // mutable slices. + /// (slice::from_raw_parts_mut(ptr, mid), + /// slice::from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) + /// } + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn transmute(e: T) -> U; diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 896d1c6f30bf..292d72dd362a 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -386,10 +386,11 @@ pub trait Extend { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait DoubleEndedIterator: Iterator { - /// An iterator able to yield elements from both ends. + /// Removes and returns an element from the end of the iterator. /// - /// As this is the only method for this trait, the [trait-level] docs - /// contain more details. + /// Returns `None` when there are no more elements. + /// + /// The [trait-level] docs contain more details. /// /// [trait-level]: trait.DoubleEndedIterator.html /// diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 0ad1f671f155..fabb3900ec64 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -103,17 +103,17 @@ mod int_macros; #[macro_use] mod uint_macros; -#[path = "num/isize.rs"] pub mod isize; -#[path = "num/i8.rs"] pub mod i8; -#[path = "num/i16.rs"] pub mod i16; -#[path = "num/i32.rs"] pub mod i32; -#[path = "num/i64.rs"] pub mod i64; +#[path = "num/isize.rs"] pub mod isize; +#[path = "num/i8.rs"] pub mod i8; +#[path = "num/i16.rs"] pub mod i16; +#[path = "num/i32.rs"] pub mod i32; +#[path = "num/i64.rs"] pub mod i64; #[path = "num/usize.rs"] pub mod usize; -#[path = "num/u8.rs"] pub mod u8; -#[path = "num/u16.rs"] pub mod u16; -#[path = "num/u32.rs"] pub mod u32; -#[path = "num/u64.rs"] pub mod u64; +#[path = "num/u8.rs"] pub mod u8; +#[path = "num/u16.rs"] pub mod u16; +#[path = "num/u32.rs"] pub mod u32; +#[path = "num/u64.rs"] pub mod u64; #[path = "num/f32.rs"] pub mod f32; #[path = "num/f64.rs"] pub mod f64; @@ -161,5 +161,6 @@ pub mod hash; pub mod fmt; // note: does not need to be public +mod char_private; mod iter_private; mod tuple; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 43868d124a22..b0c79a3a8854 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -35,6 +35,17 @@ macro_rules! panic { /// This will invoke the `panic!` macro if the provided expression cannot be /// evaluated to `true` at runtime. /// +/// Assertions are always checked in both debug and release builds, and cannot +/// be disabled. See `debug_assert!` for assertions that are not enabled in +/// release builds by default. +/// +/// Unsafe code relies on `assert!` to enforce run-time invariants that, if +/// violated could lead to unsafety. +/// +/// Other use-cases of `assert!` include +/// [testing](https://doc.rust-lang.org/book/testing.html) and enforcing +/// run-time invariants in safe code (whose violation cannot result in unsafety). +/// /// This macro has a second version, where a custom panic message can be provided. /// /// # Examples @@ -123,6 +134,13 @@ macro_rules! assert_eq { /// expensive to be present in a release build but may be helpful during /// development. /// +/// An unchecked assertion allows a program in an inconsistent state to keep +/// running, which might have unexpected consequences but does not introduce +/// unsafety as long as this only happens in safe code. The performance cost +/// of assertions, is however, not measurable in general. Replacing `assert!` +/// with `debug_assert!` is thus only encouraged after thorough profiling, and +/// more importantly, only in safe code! +/// /// # Examples /// /// ``` diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index c18d230be31a..894982abaa93 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -144,6 +144,12 @@ pub trait Unsize { /// Generalizing the latter case, any type implementing `Drop` can't be `Copy`, because it's /// managing some resource besides its own `size_of::()` bytes. /// +/// ## What if I derive `Copy` on a type that can't? +/// +/// If you try to derive `Copy` on a struct or enum, you will get a compile-time error. +/// Specifically, with structs you'll get [E0204](https://doc.rust-lang.org/error-index.html#E0204) +/// and with enums you'll get [E0205](https://doc.rust-lang.org/error-index.html#E0205). +/// /// ## When should my type be `Copy`? /// /// Generally speaking, if your type _can_ implement `Copy`, it should. There's one important thing diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 97648cc34699..4636811aa46d 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -611,6 +611,31 @@ macro_rules! int_impl { if b {None} else {Some(a)} } + /// Checked absolute value. Computes `self.abs()`, returning `None` if + /// `self == MIN`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(no_panic_abs)] + /// + /// use std::i32; + /// + /// assert_eq!((-5i32).checked_abs(), Some(5)); + /// assert_eq!(i32::MIN.checked_abs(), None); + /// ``` + #[unstable(feature = "no_panic_abs", issue = "35057")] + #[inline] + pub fn checked_abs(self) -> Option { + if self.is_negative() { + self.checked_neg() + } else { + Some(self) + } + } + /// Saturating integer addition. Computes `self + other`, saturating at /// the numeric bounds instead of overflowing. /// @@ -863,6 +888,36 @@ macro_rules! int_impl { self.overflowing_shr(rhs).0 } + /// Wrapping (modular) absolute value. Computes `self.abs()`, + /// wrapping around at the boundary of the type. + /// + /// The only case where such wrapping can occur is when one takes + /// the absolute value of the negative minimal value for the type + /// this is a positive value that is too large to represent in the + /// type. In such a case, this function returns `MIN` itself. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(no_panic_abs)] + /// + /// assert_eq!(100i8.wrapping_abs(), 100); + /// assert_eq!((-100i8).wrapping_abs(), 100); + /// assert_eq!((-128i8).wrapping_abs(), -128); + /// assert_eq!((-128i8).wrapping_abs() as u8, 128); + /// ``` + #[unstable(feature = "no_panic_abs", issue = "35057")] + #[inline(always)] + pub fn wrapping_abs(self) -> Self { + if self.is_negative() { + self.wrapping_neg() + } else { + self + } + } + /// Calculates `self` + `rhs` /// /// Returns a tuple of the addition along with a boolean indicating @@ -1071,6 +1126,35 @@ macro_rules! int_impl { (self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1))) } + /// Computes the absolute value of `self`. + /// + /// Returns a tuple of the absolute version of self along with a + /// boolean indicating whether an overflow happened. If self is the + /// minimum value (e.g. i32::MIN for values of type i32), then the + /// minimum value will be returned again and true will be returned for + /// an overflow happening. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(no_panic_abs)] + /// + /// assert_eq!(10i8.overflowing_abs(), (10,false)); + /// assert_eq!((-10i8).overflowing_abs(), (10,false)); + /// assert_eq!((-128i8).overflowing_abs(), (-128,true)); + /// ``` + #[unstable(feature = "no_panic_abs", issue = "35057")] + #[inline] + pub fn overflowing_abs(self) -> (Self, bool) { + if self.is_negative() { + self.overflowing_neg() + } else { + (self, false) + } + } + /// Raises self to the power of `exp`, using exponentiation by squaring. /// /// # Examples diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 045c1f9feafc..fe508adb7138 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -142,6 +142,7 @@ use self::Option::*; use clone::Clone; +use convert::From; use default::Default; use iter::ExactSizeIterator; use iter::{Iterator, DoubleEndedIterator, FromIterator, IntoIterator}; @@ -754,6 +755,13 @@ impl<'a, T> IntoIterator for &'a mut Option { } } +#[stable(since = "1.12.0", feature = "option_from")] +impl From for Option { + fn from(val: T) -> Option { + Some(val) + } +} + ///////////////////////////////////////////////////////////////////////////// // The Option Iterators ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 4f11cac4eb2b..d8a11581c3b6 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -902,6 +902,8 @@ macro_rules! make_mut_slice { /// Immutable slice iterator /// +/// This struct is created by the [`iter`] method on [slices]. +/// /// # Examples /// /// Basic usage: @@ -915,6 +917,9 @@ macro_rules! make_mut_slice { /// println!("{}", element); /// } /// ``` +/// +/// [`iter`]: ../../std/primitive.slice.html#method.iter +/// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { ptr: *const T, @@ -993,6 +998,8 @@ impl<'a, T> Clone for Iter<'a, T> { /// Mutable slice iterator. /// +/// This struct is created by the [`iter_mut`] method on [slices]. +/// /// # Examples /// /// Basic usage: @@ -1010,6 +1017,9 @@ impl<'a, T> Clone for Iter<'a, T> { /// // We now have "[2, 3, 4]": /// println!("{:?}", slice); /// ``` +/// +/// [`iter_mut`]: ../../std/primitive.slice.html#method.iter_mut +/// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { ptr: *mut T, diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index a32c9da9815f..fdcadd43a0fb 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -459,6 +459,19 @@ impl<'a> Chars<'a> { /// /// This has the same lifetime as the original slice, and so the /// iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// let mut chars = "abc".chars(); + /// + /// assert_eq!(chars.as_str(), "abc"); + /// chars.next(); + /// assert_eq!(chars.as_str(), "bc"); + /// chars.next(); + /// chars.next(); + /// assert_eq!(chars.as_str(), ""); + /// ``` #[stable(feature = "iter_to_slice", since = "1.4.0")] #[inline] pub fn as_str(&self) -> &'a str { diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 47d9deb62ff6..2a7a0b623293 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -74,6 +74,8 @@ //! ``` #![stable(feature = "rust1", since = "1.0.0")] +#![cfg_attr(not(target_has_atomic = "8"), allow(dead_code))] +#![cfg_attr(not(target_has_atomic = "8"), allow(unused_imports))] use self::Ordering::*; diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index c8906fed3d2f..4632419336d7 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -123,6 +123,49 @@ fn test_is_digit() { assert!(!'Q'.is_numeric()); } +#[test] +fn test_escape_debug() { + fn string(c: char) -> String { + c.escape_debug().collect() + } + let s = string('\n'); + assert_eq!(s, "\\n"); + let s = string('\r'); + assert_eq!(s, "\\r"); + let s = string('\''); + assert_eq!(s, "\\'"); + let s = string('"'); + assert_eq!(s, "\\\""); + let s = string(' '); + assert_eq!(s, " "); + let s = string('a'); + assert_eq!(s, "a"); + let s = string('~'); + assert_eq!(s, "~"); + let s = string('é'); + assert_eq!(s, "é"); + let s = string('\x00'); + assert_eq!(s, "\\u{0}"); + let s = string('\x1f'); + assert_eq!(s, "\\u{1f}"); + let s = string('\x7f'); + assert_eq!(s, "\\u{7f}"); + let s = string('\u{80}'); + assert_eq!(s, "\\u{80}"); + let s = string('\u{ff}'); + assert_eq!(s, "\u{ff}"); + let s = string('\u{11b}'); + assert_eq!(s, "\u{11b}"); + let s = string('\u{1d4b6}'); + assert_eq!(s, "\u{1d4b6}"); + let s = string('\u{200b}'); // zero width space + assert_eq!(s, "\\u{200b}"); + let s = string('\u{e000}'); // private use 1 + assert_eq!(s, "\\u{e000}"); + let s = string('\u{100000}'); // private use 2 + assert_eq!(s, "\\u{100000}"); +} + #[test] fn test_escape_default() { fn string(c: char) -> String { @@ -142,18 +185,28 @@ fn test_escape_default() { assert_eq!(s, "a"); let s = string('~'); assert_eq!(s, "~"); + let s = string('é'); + assert_eq!(s, "\\u{e9}"); let s = string('\x00'); assert_eq!(s, "\\u{0}"); let s = string('\x1f'); assert_eq!(s, "\\u{1f}"); let s = string('\x7f'); assert_eq!(s, "\\u{7f}"); + let s = string('\u{80}'); + assert_eq!(s, "\\u{80}"); let s = string('\u{ff}'); assert_eq!(s, "\\u{ff}"); let s = string('\u{11b}'); assert_eq!(s, "\\u{11b}"); let s = string('\u{1d4b6}'); assert_eq!(s, "\\u{1d4b6}"); + let s = string('\u{200b}'); // zero width space + assert_eq!(s, "\\u{200b}"); + let s = string('\u{e000}'); // private use 1 + assert_eq!(s, "\\u{e000}"); + let s = string('\u{100000}'); // private use 2 + assert_eq!(s, "\\u{100000}"); } #[test] diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 1ef2b58351fe..9428b4096bfe 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -14,6 +14,7 @@ #![feature(borrow_state)] #![feature(box_syntax)] #![feature(cell_extras)] +#![feature(char_escape_debug)] #![feature(const_fn)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] @@ -29,10 +30,9 @@ #![feature(slice_patterns)] #![feature(step_by)] #![feature(test)] -#![feature(unboxed_closures)] +#![feature(try_from)] #![feature(unicode)] #![feature(unique)] -#![feature(try_from)] extern crate core; extern crate test; diff --git a/src/libflate/Cargo.toml b/src/libflate/Cargo.toml index 52aa6bb86ef9..5423da9c81c0 100644 --- a/src/libflate/Cargo.toml +++ b/src/libflate/Cargo.toml @@ -11,4 +11,4 @@ crate-type = ["dylib"] [build-dependencies] build_helper = { path = "../build_helper" } -gcc = "0.3" +gcc = "0.3.27" diff --git a/src/liblibc b/src/liblibc index b0d62534d48b..5066b7dcab7e 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit b0d62534d48b711c8978d1bbe8cca0558ae7b1cb +Subproject commit 5066b7dcab7e700844b0e2ba71b8af9dc627a59b diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs index 0ad6a74d1013..2284a9bbb73e 100644 --- a/src/libpanic_unwind/dwarf/eh.rs +++ b/src/libpanic_unwind/dwarf/eh.rs @@ -45,16 +45,25 @@ pub const DW_EH_PE_aligned: u8 = 0x50; pub const DW_EH_PE_indirect: u8 = 0x80; #[derive(Copy, Clone)] -pub struct EHContext { +pub struct EHContext<'a> { pub ip: usize, // Current instruction pointer pub func_start: usize, // Address of the current function - pub text_start: usize, // Address of the code section - pub data_start: usize, // Address of the data section + pub get_text_start: &'a Fn() -> usize, // Get address of the code section + pub get_data_start: &'a Fn() -> usize, // Get address of the data section } -pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) -> Option { +pub enum EHAction { + None, + Cleanup(usize), + Catch(usize), + Terminate, +} + +pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm")); + +pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction { if lsda.is_null() { - return None; + return EHAction::None; } let func_start = context.func_start; @@ -77,32 +86,61 @@ pub unsafe fn find_landing_pad(lsda: *const u8, context: &EHContext) -> Option(); let call_site_table_length = reader.read_uleb128(); let action_table = reader.ptr.offset(call_site_table_length as isize); - // Return addresses point 1 byte past the call instruction, which could - // be in the next IP range. - let ip = context.ip - 1; + let ip = context.ip; - while reader.ptr < action_table { - let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_action = reader.read_uleb128(); - // Callsite table is sorted by cs_start, so if we've passed the ip, we - // may stop searching. - if ip < func_start + cs_start { - break; + if !USING_SJLJ_EXCEPTIONS { + while reader.ptr < action_table { + let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding); + let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding); + let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding); + let cs_action = reader.read_uleb128(); + // Callsite table is sorted by cs_start, so if we've passed the ip, we + // may stop searching. + if ip < func_start + cs_start { + break; + } + if ip < func_start + cs_start + cs_len { + if cs_lpad == 0 { + return EHAction::None; + } else { + let lpad = lpad_base + cs_lpad; + return interpret_cs_action(cs_action, lpad); + } + } } - if ip < func_start + cs_start + cs_len { - if cs_lpad != 0 { - return Some(lpad_base + cs_lpad); - } else { - return None; + // Ip is not present in the table. This should not happen... but it does: issue #35011. + // So rather than returning EHAction::Terminate, we do this. + EHAction::None + } else { + // SjLj version: + // The "IP" is an index into the call-site table, with two exceptions: + // -1 means 'no-action', and 0 means 'terminate'. + match ip as isize { + -1 => return EHAction::None, + 0 => return EHAction::Terminate, + _ => (), + } + let mut idx = ip; + loop { + let cs_lpad = reader.read_uleb128(); + let cs_action = reader.read_uleb128(); + idx -= 1; + if idx == 0 { + // Can never have null landing pad for sjlj -- that would have + // been indicated by a -1 call site index. + let lpad = (cs_lpad + 1) as usize; + return interpret_cs_action(cs_action, lpad); } } } - // IP range not found: gcc's C++ personality calls terminate() here, - // however the rest of the languages treat this the same as cs_lpad == 0. - // We follow this suit. - None +} + +fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction { + if cs_action == 0 { + EHAction::Cleanup(lpad) + } else { + EHAction::Catch(lpad) + } } #[inline] @@ -140,18 +178,16 @@ unsafe fn read_encoded_pointer(reader: &mut DwarfReader, DW_EH_PE_absptr => 0, // relative to address of the encoded value, despite the name DW_EH_PE_pcrel => reader.ptr as usize, - DW_EH_PE_textrel => { - assert!(context.text_start != 0); - context.text_start - } - DW_EH_PE_datarel => { - assert!(context.data_start != 0); - context.data_start - } DW_EH_PE_funcrel => { assert!(context.func_start != 0); context.func_start } + DW_EH_PE_textrel => { + (*context.get_text_start)() + } + DW_EH_PE_datarel => { + (*context.get_data_start)() + } _ => panic!(), }; diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index 3c46072e17e1..fdae8f69a9c0 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -61,6 +61,8 @@ use core::ptr; use alloc::boxed::Box; use unwind as uw; +use libc::{c_int, uintptr_t}; +use dwarf::eh::{self, EHContext, EHAction}; #[repr(C)] struct Exception { @@ -106,160 +108,184 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class { 0x4d4f5a_00_52555354 } -// We could implement our personality routine in Rust, however exception -// info decoding is tedious. More importantly, personality routines have to -// handle various platform quirks, which are not fun to maintain. For this -// reason, we attempt to reuse personality routine of the C language: -// __gcc_personality_v0. -// -// Since C does not support exception catching, __gcc_personality_v0 simply -// always returns _URC_CONTINUE_UNWIND in search phase, and always returns -// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase. -// -// This is pretty close to Rust's exception handling approach, except that Rust -// does have a single "catch-all" handler at the bottom of each thread's stack. -// So we have two versions of the personality routine: -// - rust_eh_personality, used by all cleanup landing pads, which never catches, -// so the behavior of __gcc_personality_v0 is perfectly adequate there, and -// - rust_eh_personality_catch, used only by rust_try(), which always catches. -// -// See also: rustc_trans::trans::intrinsic::trans_gnu_try -#[cfg(all(not(target_arch = "arm"), - not(all(windows, target_arch = "x86_64"))))] -pub mod eabi { - use unwind as uw; - use libc::c_int; +// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister() +// and TargetLowering::getExceptionSelectorRegister() for each architecture, +// then mapped to DWARF register numbers via register definition tables +// (typically RegisterInfo.td, search for "DwarfRegNum"). +// See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register. - extern "C" { - fn __gcc_personality_v0(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code; +#[cfg(target_arch = "x86")] +const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX + +#[cfg(target_arch = "x86_64")] +const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX + +#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] +const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1 + +#[cfg(any(target_arch = "mips", target_arch = "mipsel"))] +const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 + +#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] +const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4 + +// The following code is based on GCC's C and C++ personality routines. For reference, see: +// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc +// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c + +// The personality routine for most of our targets, except ARM, which has a slightly different ABI +// (however, iOS goes here as it uses SjLj unwinding). Also, the 64-bit Windows implementation +// lives in seh64_gnu.rs +#[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))] +#[lang = "eh_personality"] +#[no_mangle] +#[allow(unused)] +unsafe extern "C" fn rust_eh_personality(version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code { + if version != 1 { + return uw::_URC_FATAL_PHASE1_ERROR; } - - #[lang = "eh_personality"] - #[no_mangle] - extern "C" fn rust_eh_personality(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) } - } - - #[lang = "eh_personality_catch"] - #[no_mangle] - pub extern "C" fn rust_eh_personality_catch(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - - if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { - // search phase - uw::_URC_HANDLER_FOUND // catch! - } else { - // cleanup phase - unsafe { __gcc_personality_v0(version, actions, exception_class, ue_header, context) } + let eh_action = find_eh_action(context); + if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 { + match eh_action { + EHAction::None | EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND, + EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND, + EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR, + } + } else { + match eh_action { + EHAction::None => return uw::_URC_CONTINUE_UNWIND, + EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => { + uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t); + uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0); + uw::_Unwind_SetIP(context, lpad); + return uw::_URC_INSTALL_CONTEXT; + } + EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR, } } } -// iOS on armv7 is using SjLj exceptions and therefore requires to use -// a specialized personality routine: __gcc_personality_sj0 - -#[cfg(all(target_os = "ios", target_arch = "arm"))] -pub mod eabi { - use unwind as uw; - use libc::c_int; - - extern "C" { - fn __gcc_personality_sj0(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code; - } - - #[lang = "eh_personality"] - #[no_mangle] - pub extern "C" fn rust_eh_personality(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) } - } - - #[lang = "eh_personality_catch"] - #[no_mangle] - pub extern "C" fn rust_eh_personality_catch(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { - // search phase - uw::_URC_HANDLER_FOUND // catch! - } else { - // cleanup phase - unsafe { __gcc_personality_sj0(version, actions, exception_class, ue_header, context) } - } - } -} - - -// ARM EHABI uses a slightly different personality routine signature, -// but otherwise works the same. +// ARM EHABI personality routine. +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf #[cfg(all(target_arch = "arm", not(target_os = "ios")))] -pub mod eabi { - use unwind as uw; - use libc::c_int; - - extern "C" { - fn __gcc_personality_v0(state: uw::_Unwind_State, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code; - } - - #[lang = "eh_personality"] - #[no_mangle] - extern "C" fn rust_eh_personality(state: uw::_Unwind_State, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - unsafe { __gcc_personality_v0(state, ue_header, context) } - } - - #[lang = "eh_personality_catch"] - #[no_mangle] - pub extern "C" fn rust_eh_personality_catch(state: uw::_Unwind_State, - ue_header: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { +#[lang = "eh_personality"] +#[no_mangle] +unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, + exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code { + let state = state as c_int; + let action = state & uw::_US_ACTION_MASK as c_int; + let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // Backtraces on ARM will call the personality routine with // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases // we want to continue unwinding the stack, otherwise all our backtraces - // would end at __rust_try. - if (state as c_int & uw::_US_ACTION_MASK as c_int) == - uw::_US_VIRTUAL_UNWIND_FRAME as c_int && - (state as c_int & uw::_US_FORCE_UNWIND as c_int) == 0 { - // search phase - uw::_URC_HANDLER_FOUND // catch! - } else { - // cleanup phase - unsafe { __gcc_personality_v0(state, ue_header, context) } + // would end at __rust_try + if state & uw::_US_FORCE_UNWIND as c_int != 0 { + return continue_unwind(exception_object, context) + } + true + } else if action == uw::_US_UNWIND_FRAME_STARTING as c_int { + false + } else if action == uw::_US_UNWIND_FRAME_RESUME as c_int { + return continue_unwind(exception_object, context); + } else { + return uw::_URC_FAILURE; + }; + + // The DWARF unwinder assumes that _Unwind_Context holds things like the function + // and LSDA pointers, however ARM EHABI places them into the exception object. + // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which + // take only the context pointer, GCC personality routines stash a pointer to exception_object + // in the context, using location reserved for ARM's "scratch register" (r12). + uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr); + // ...A more principled approach would be to provide the full definition of ARM's + // _Unwind_Context in our libunwind bindings and fetch the required data from there directly, + // bypassing DWARF compatibility functions. + + let eh_action = find_eh_action(context); + if search_phase { + match eh_action { + EHAction::None | + EHAction::Cleanup(_) => return continue_unwind(exception_object, context), + EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND, + EHAction::Terminate => return uw::_URC_FAILURE, + } + } else { + match eh_action { + EHAction::None => return continue_unwind(exception_object, context), + EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => { + uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t); + uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0); + uw::_Unwind_SetIP(context, lpad); + return uw::_URC_INSTALL_CONTEXT; + } + EHAction::Terminate => return uw::_URC_FAILURE, } } + + // On ARM EHABI the personality routine is responsible for actually + // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1). + unsafe fn continue_unwind(exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code { + if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON { + uw::_URC_CONTINUE_UNWIND + } else { + uw::_URC_FAILURE + } + } + // defined in libgcc + extern "C" { + fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code; + } +} + +unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> EHAction { + let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8; + let mut ip_before_instr: c_int = 0; + let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr); + let eh_context = EHContext { + // The return address points 1 byte past the call instruction, + // which could be in the next IP range in LSDA range table. + ip: if ip_before_instr != 0 { ip } else { ip - 1 }, + func_start: uw::_Unwind_GetRegionStart(context), + get_text_start: &|| uw::_Unwind_GetTextRelBase(context), + get_data_start: &|| uw::_Unwind_GetDataRelBase(context), + }; + eh::find_eh_action(lsda, &eh_context) +} + +// *** Delete after a new snapshot *** +#[cfg(all(stage0, any(target_os = "ios", not(target_arch = "arm"))))] +#[lang = "eh_personality_catch"] +#[no_mangle] +pub unsafe extern "C" fn rust_eh_personality_catch(version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + ue_header: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code { + rust_eh_personality(version, actions, exception_class, ue_header, context) +} + +// *** Delete after a new snapshot *** +#[cfg(all(stage0, target_arch = "arm", not(target_os = "ios")))] +#[lang = "eh_personality_catch"] +#[no_mangle] +pub unsafe extern "C" fn rust_eh_personality_catch(state: uw::_Unwind_State, + ue_header: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code { + rust_eh_personality(state, ue_header, context) } // See docs in the `unwind` module. diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index b765ee6f81cf..11dd9befe0a8 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -101,6 +101,7 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), // Entry point for raising an exception, just delegates to the platform-specific // implementation. #[no_mangle] +#[unwind] pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 { imp::panic(mem::transmute(raw::TraitObject { data: data as *mut (), diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index 56801e8cb6bc..3642e2488958 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -19,7 +19,7 @@ use alloc::boxed::Box; use core::any::Any; use core::intrinsics; use core::ptr; -use dwarf::eh; +use dwarf::eh::{EHContext, EHAction, find_eh_action}; use windows as c; // Define our exception codes: @@ -81,6 +81,8 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box { // This is considered acceptable, because the behavior of throwing exceptions // through a C ABI boundary is undefined. +// *** Delete after a new snapshot *** +#[cfg(stage0)] #[lang = "eh_personality_catch"] #[cfg(not(test))] unsafe extern "C" fn rust_eh_personality_catch(exceptionRecord: *mut c::EXCEPTION_RECORD, @@ -132,11 +134,17 @@ unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! { } unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option { - let eh_ctx = eh::EHContext { - ip: dc.ControlPc as usize, + let eh_ctx = EHContext { + // The return address points 1 byte past the call instruction, + // which could be in the next IP range in LSDA range table. + ip: dc.ControlPc as usize - 1, func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize, - text_start: dc.ImageBase as usize, - data_start: 0, + get_text_start: &|| dc.ImageBase as usize, + get_data_start: &|| unimplemented!(), }; - eh::find_landing_pad(dc.HandlerData, &eh_ctx) + match find_eh_action(dc.HandlerData, &eh_ctx) { + EHAction::None => None, + EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => Some(lpad), + EHAction::Terminate => intrinsics::abort(), + } } diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 73b96651b05e..c9247539990a 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -9,6 +9,7 @@ // except according to those terms. use std::fmt::Debug; +use std::sync::Arc; macro_rules! try_opt { ($e:expr) => ( @@ -45,6 +46,10 @@ pub enum DepNode { // in an extern crate. MetaData(D), + // Represents some artifact that we save to disk. Note that these + // do not have a def-id as part of their identifier. + WorkProduct(Arc), + // Represents different phases in the compiler. CrateReader, CollectLanguageItems, @@ -189,6 +194,11 @@ impl DepNode { TransCrate => Some(TransCrate), TransWriteMetadata => Some(TransWriteMetadata), LinkBinary => Some(LinkBinary), + + // work product names do not need to be mapped, because + // they are always absolute. + WorkProduct(ref id) => Some(WorkProduct(id.clone())), + Hir(ref d) => op(d).map(Hir), MetaData(ref d) => op(d).map(MetaData), CollectItem(ref d) => op(d).map(CollectItem), @@ -229,3 +239,12 @@ impl DepNode { } } } + +/// A "work product" corresponds to a `.o` (or other) file that we +/// save in between runs. These ids do not have a DefId but rather +/// some independent path or string that persists between runs without +/// the need to be mapped or unmapped. (This ensures we can serialize +/// them even in the absence of a tcx.) +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct WorkProductId(pub String); + diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 741ad65c29fd..bb027b11b45a 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -9,22 +9,45 @@ // except according to those terms. use hir::def_id::DefId; +use rustc_data_structures::fnv::FnvHashMap; +use session::config::OutputType; +use std::cell::{Ref, RefCell}; use std::rc::Rc; +use std::sync::Arc; -use super::dep_node::DepNode; +use super::dep_node::{DepNode, WorkProductId}; use super::query::DepGraphQuery; use super::raii; use super::thread::{DepGraphThreadData, DepMessage}; #[derive(Clone)] pub struct DepGraph { - data: Rc + data: Rc +} + +struct DepGraphData { + /// We send messages to the thread to let it build up the dep-graph + /// from the current run. + thread: DepGraphThreadData, + + /// When we load, there may be `.o` files, cached mir, or other such + /// things available to us. If we find that they are not dirty, we + /// load the path to the file storing those work-products here into + /// this map. We can later look for and extract that data. + previous_work_products: RefCell, WorkProduct>>, + + /// Work-products that we generate in this run. + work_products: RefCell, WorkProduct>>, } impl DepGraph { pub fn new(enabled: bool) -> DepGraph { DepGraph { - data: Rc::new(DepGraphThreadData::new(enabled)) + data: Rc::new(DepGraphData { + thread: DepGraphThreadData::new(enabled), + previous_work_products: RefCell::new(FnvHashMap()), + work_products: RefCell::new(FnvHashMap()) + }) } } @@ -32,19 +55,19 @@ impl DepGraph { /// then the other methods on this `DepGraph` will have no net effect. #[inline] pub fn enabled(&self) -> bool { - self.data.enabled() + self.data.thread.enabled() } pub fn query(&self) -> DepGraphQuery { - self.data.query() + self.data.thread.query() } pub fn in_ignore<'graph>(&'graph self) -> raii::IgnoreTask<'graph> { - raii::IgnoreTask::new(&self.data) + raii::IgnoreTask::new(&self.data.thread) } pub fn in_task<'graph>(&'graph self, key: DepNode) -> raii::DepTask<'graph> { - raii::DepTask::new(&self.data, key) + raii::DepTask::new(&self.data.thread, key) } pub fn with_ignore(&self, op: OP) -> R @@ -62,10 +85,84 @@ impl DepGraph { } pub fn read(&self, v: DepNode) { - self.data.enqueue(DepMessage::Read(v)); + self.data.thread.enqueue(DepMessage::Read(v)); } pub fn write(&self, v: DepNode) { - self.data.enqueue(DepMessage::Write(v)); + self.data.thread.enqueue(DepMessage::Write(v)); + } + + /// Indicates that a previous work product exists for `v`. This is + /// invoked during initial start-up based on what nodes are clean + /// (and what files exist in the incr. directory). + pub fn insert_previous_work_product(&self, v: &Arc, data: WorkProduct) { + debug!("insert_previous_work_product({:?}, {:?})", v, data); + self.data.previous_work_products.borrow_mut() + .insert(v.clone(), data); + } + + /// Indicates that we created the given work-product in this run + /// for `v`. This record will be preserved and loaded in the next + /// run. + pub fn insert_work_product(&self, v: &Arc, data: WorkProduct) { + debug!("insert_work_product({:?}, {:?})", v, data); + self.data.work_products.borrow_mut() + .insert(v.clone(), data); + } + + /// Check whether a previous work product exists for `v` and, if + /// so, return the path that leads to it. Used to skip doing work. + pub fn previous_work_product(&self, v: &Arc) -> Option { + self.data.previous_work_products.borrow() + .get(v) + .cloned() + } + + /// Access the map of work-products created during this run. Only + /// used during saving of the dep-graph. + pub fn work_products(&self) -> Ref, WorkProduct>> { + self.data.work_products.borrow() } } + +/// A "work product" is an intermediate result that we save into the +/// incremental directory for later re-use. The primary example are +/// the object files that we save for each partition at code +/// generation time. +/// +/// Each work product is associated with a dep-node, representing the +/// process that produced the work-product. If that dep-node is found +/// to be dirty when we load up, then we will delete the work-product +/// at load time. If the work-product is found to be clean, then we +/// will keep a record in the `previous_work_products` list. +/// +/// In addition, work products have an associated hash. This hash is +/// an extra hash that can be used to decide if the work-product from +/// a previous compilation can be re-used (in addition to the dirty +/// edges check). +/// +/// As the primary example, consider the object files we generate for +/// each partition. In the first run, we create partitions based on +/// the symbols that need to be compiled. For each partition P, we +/// hash the symbols in P and create a `WorkProduct` record associated +/// with `DepNode::TransPartition(P)`; the hash is the set of symbols +/// in P. +/// +/// The next time we compile, if the `DepNode::TransPartition(P)` is +/// judged to be clean (which means none of the things we read to +/// generate the partition were found to be dirty), it will be loaded +/// into previous work products. We will then regenerate the set of +/// symbols in the partition P and hash them (note that new symbols +/// may be added -- for example, new monomorphizations -- even if +/// nothing in P changed!). We will compare that hash against the +/// previous hash. If it matches up, we can reuse the object file. +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +pub struct WorkProduct { + /// Extra hash used to decide if work-product is still suitable; + /// note that this is *not* a hash of the work-product itself. + /// See documentation on `WorkProduct` type for an example. + pub input_hash: u64, + + /// Saved files associated with this CGU + pub saved_files: Vec<(OutputType, String)>, +} diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index e65f6bbcf7aa..a499cb10f232 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -20,7 +20,9 @@ mod visit; pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig}; pub use self::dep_node::DepNode; +pub use self::dep_node::WorkProductId; pub use self::graph::DepGraph; +pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; pub use self::visit::visit_all_items_in_krate; pub use self::raii::DepTask; diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 9040e4bf8db5..74e2c90503cd 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -23,7 +23,7 @@ code example: #[deny(const_err)] const X: i32 = 42 / 0; -// error: attempted to divide by zero in a constant expression +// error: attempt to divide by zero in a constant expression ``` "##, diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 442c85af22a2..aded220c0cdf 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -94,11 +94,14 @@ pub trait Visitor<'v> : Sized { /////////////////////////////////////////////////////////////////////////// + fn visit_id(&mut self, _node_id: NodeId) { + // Nothing to do. + } fn visit_name(&mut self, _span: Span, _name: Name) { // Nothing to do. } - fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { - walk_mod(self, m) + fn visit_mod(&mut self, m: &'v Mod, _s: Span, n: NodeId) { + walk_mod(self, m, n) } fn visit_foreign_item(&mut self, i: &'v ForeignItem) { walk_foreign_item(self, i) @@ -135,8 +138,8 @@ pub trait Visitor<'v> : Sized { fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) { walk_where_predicate(self, predicate) } - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) { - walk_fn(self, fk, fd, b, s) + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, id: NodeId) { + walk_fn(self, fk, fd, b, s, id) } fn visit_trait_item(&mut self, ti: &'v TraitItem) { walk_trait_item(self, ti) @@ -157,7 +160,7 @@ pub trait Visitor<'v> : Sized { s: &'v VariantData, _: Name, _: &'v Generics, - _: NodeId, + _parent_id: NodeId, _: Span) { walk_struct_def(self, s) } @@ -225,24 +228,28 @@ pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { } pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) { + visitor.visit_id(macro_def.id); visitor.visit_name(macro_def.span, macro_def.name); walk_opt_name(visitor, macro_def.span, macro_def.imported_from); walk_list!(visitor, visit_attribute, ¯o_def.attrs); } -pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) { +pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod, mod_node_id: NodeId) { + visitor.visit_id(mod_node_id); for &item_id in &module.item_ids { visitor.visit_nested_item(item_id); } } pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { + visitor.visit_id(local.id); visitor.visit_pat(&local.pat); walk_list!(visitor, visit_ty, &local.ty); walk_list!(visitor, visit_expr, &local.init); } pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) { + visitor.visit_id(lifetime.id); visitor.visit_name(lifetime.span, lifetime.name); } @@ -263,6 +270,7 @@ pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef) where V: Visitor<'v> { + visitor.visit_id(trait_ref.ref_id); visitor.visit_path(&trait_ref.path, trait_ref.ref_id) } @@ -271,9 +279,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_name(item.span, item.name); match item.node { ItemExternCrate(opt_name) => { + visitor.visit_id(item.id); walk_opt_name(visitor, item.span, opt_name) } ItemUse(ref vp) => { + visitor.visit_id(item.id); match vp.node { ViewPathSimple(name, ref path) => { visitor.visit_name(vp.span, name); @@ -292,6 +302,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { } ItemStatic(ref typ, _, ref expr) | ItemConst(ref typ, ref expr) => { + visitor.visit_id(item.id); visitor.visit_ty(typ); visitor.visit_expr(expr); } @@ -309,23 +320,29 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { item.id) } ItemMod(ref module) => { + // visit_mod() takes care of visiting the Item's NodeId visitor.visit_mod(module, item.span, item.id) } ItemForeignMod(ref foreign_module) => { + visitor.visit_id(item.id); walk_list!(visitor, visit_foreign_item, &foreign_module.items); } ItemTy(ref typ, ref type_parameters) => { + visitor.visit_id(item.id); visitor.visit_ty(typ); visitor.visit_generics(type_parameters) } ItemEnum(ref enum_definition, ref type_parameters) => { visitor.visit_generics(type_parameters); + // visit_enum_def() takes care of visiting the Item's NodeId visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span) } ItemDefaultImpl(_, ref trait_ref) => { + visitor.visit_id(item.id); visitor.visit_trait_ref(trait_ref) } ItemImpl(_, _, ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => { + visitor.visit_id(item.id); visitor.visit_generics(type_parameters); walk_list!(visitor, visit_trait_ref, opt_trait_reference); visitor.visit_ty(typ); @@ -333,9 +350,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { } ItemStruct(ref struct_definition, ref generics) => { visitor.visit_generics(generics); + visitor.visit_id(item.id); visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span); } ItemTrait(_, ref generics, ref bounds, ref methods) => { + visitor.visit_id(item.id); visitor.visit_generics(generics); walk_list!(visitor, visit_ty_param_bound, bounds); walk_list!(visitor, visit_trait_item, methods); @@ -348,6 +367,7 @@ pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V, enum_definition: &'v EnumDef, generics: &'v Generics, item_id: NodeId) { + visitor.visit_id(item_id); walk_list!(visitor, visit_variant, &enum_definition.variants, @@ -358,18 +378,20 @@ pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant, generics: &'v Generics, - item_id: NodeId) { + parent_item_id: NodeId) { visitor.visit_name(variant.span, variant.node.name); visitor.visit_variant_data(&variant.node.data, variant.node.name, generics, - item_id, + parent_item_id, variant.span); walk_list!(visitor, visit_expr, &variant.node.disr_expr); walk_list!(visitor, visit_attribute, &variant.node.attrs); } pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { + visitor.visit_id(typ.id); + match typ.node { TyVec(ref ty) => { visitor.visit_ty(ty) @@ -421,6 +443,7 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, _prefix: &'v Path, item: &'v PathListItem) { + visitor.visit_id(item.node.id()); walk_opt_name(visitor, item.span, item.node.name()); walk_opt_name(visitor, item.span, item.node.rename()); } @@ -450,11 +473,13 @@ pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, type_binding: &'v TypeBinding) { + visitor.visit_id(type_binding.id); visitor.visit_name(type_binding.span, type_binding.name); visitor.visit_ty(&type_binding.ty); } pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { + visitor.visit_id(pattern.id); match pattern.node { PatKind::TupleStruct(ref path, ref children, _) => { visitor.visit_path(path, pattern.id); @@ -499,6 +524,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { } pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem) { + visitor.visit_id(foreign_item.id); visitor.visit_vis(&foreign_item.vis); visitor.visit_name(foreign_item.span, foreign_item.name); @@ -526,11 +552,13 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyPar pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { for param in &generics.ty_params { + visitor.visit_id(param.id); visitor.visit_name(param.span, param.name); walk_list!(visitor, visit_ty_param_bound, ¶m.bounds); walk_list!(visitor, visit_ty, ¶m.default); } walk_list!(visitor, visit_lifetime_def, &generics.lifetimes); + visitor.visit_id(generics.where_clause.id); walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates); } @@ -557,6 +585,7 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>( ref path, ref ty, ..}) => { + visitor.visit_id(id); visitor.visit_path(path, id); visitor.visit_ty(ty); } @@ -571,6 +600,7 @@ pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionR pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { for argument in &function_declaration.inputs { + visitor.visit_id(argument.id); visitor.visit_pat(&argument.pat); visitor.visit_ty(&argument.ty) } @@ -579,6 +609,7 @@ pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: & pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) { for argument in &function_declaration.inputs { + visitor.visit_id(argument.id); visitor.visit_ty(&argument.ty) } walk_fn_ret_ty(visitor, &function_declaration.output) @@ -600,7 +631,9 @@ pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>, function_declaration: &'v FnDecl, function_body: &'v Block, - _span: Span) { + _span: Span, + id: NodeId) { + visitor.visit_id(id); walk_fn_decl(visitor, function_declaration); walk_fn_kind(visitor, function_kind); visitor.visit_block(function_body) @@ -611,10 +644,12 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai walk_list!(visitor, visit_attribute, &trait_item.attrs); match trait_item.node { ConstTraitItem(ref ty, ref default) => { + visitor.visit_id(trait_item.id); visitor.visit_ty(ty); walk_list!(visitor, visit_expr, default); } MethodTraitItem(ref sig, None) => { + visitor.visit_id(trait_item.id); visitor.visit_generics(&sig.generics); walk_fn_decl(visitor, &sig.decl); } @@ -629,6 +664,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai trait_item.id); } TypeTraitItem(ref bounds, ref default) => { + visitor.visit_id(trait_item.id); walk_list!(visitor, visit_ty_param_bound, bounds); walk_list!(visitor, visit_ty, default); } @@ -641,6 +677,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt walk_list!(visitor, visit_attribute, &impl_item.attrs); match impl_item.node { ImplItemKind::Const(ref ty, ref expr) => { + visitor.visit_id(impl_item.id); visitor.visit_ty(ty); visitor.visit_expr(expr); } @@ -655,16 +692,19 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt impl_item.id); } ImplItemKind::Type(ref ty) => { + visitor.visit_id(impl_item.id); visitor.visit_ty(ty); } } } pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) { + visitor.visit_id(struct_definition.id()); walk_list!(visitor, visit_struct_field, struct_definition.fields()); } pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) { + visitor.visit_id(struct_field.id); visitor.visit_vis(&struct_field.vis); visitor.visit_name(struct_field.span, struct_field.name); visitor.visit_ty(&struct_field.ty); @@ -672,14 +712,20 @@ pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v } pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) { + visitor.visit_id(block.id); walk_list!(visitor, visit_stmt, &block.stmts); walk_list!(visitor, visit_expr, &block.expr); } pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { match statement.node { - StmtDecl(ref declaration, _) => visitor.visit_decl(declaration), - StmtExpr(ref expression, _) | StmtSemi(ref expression, _) => { + StmtDecl(ref declaration, id) => { + visitor.visit_id(id); + visitor.visit_decl(declaration) + } + StmtExpr(ref expression, id) | + StmtSemi(ref expression, id) => { + visitor.visit_id(id); visitor.visit_expr(expression) } } @@ -693,6 +739,7 @@ pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) { } pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { + visitor.visit_id(expression.id); match expression.node { ExprBox(ref subexpression) => { visitor.visit_expr(subexpression) @@ -815,11 +862,12 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) { pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) { if let Visibility::Restricted { ref path, id } = *vis { + visitor.visit_id(id); visitor.visit_path(path, id) } } -#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq)] pub struct IdRange { pub min: NodeId, pub max: NodeId, @@ -837,15 +885,17 @@ impl IdRange { self.min >= self.max } + pub fn contains(&self, id: NodeId) -> bool { + id >= self.min && id < self.max + } + pub fn add(&mut self, id: NodeId) { self.min = cmp::min(self.min, id); self.max = cmp::max(self.max, id + 1); } + } -pub trait IdVisitingOperation { - fn visit_id(&mut self, node_id: NodeId); -} pub struct IdRangeComputingVisitor { pub result: IdRange, @@ -861,181 +911,12 @@ impl IdRangeComputingVisitor { } } -impl IdVisitingOperation for IdRangeComputingVisitor { +impl<'v> Visitor<'v> for IdRangeComputingVisitor { fn visit_id(&mut self, id: NodeId) { self.result.add(id); } } -pub struct IdVisitor<'a, O: 'a> { - operation: &'a mut O, - - // In general, the id visitor visits the contents of an item, but - // not including nested trait/impl items, nor other nested items. - // The base visitor itself always skips nested items, but not - // trait/impl items. This means in particular that if you start by - // visiting a trait or an impl, you should not visit the - // trait/impl items respectively. This is handled by setting - // `skip_members` to true when `visit_item` is on the stack. This - // way, if the user begins by calling `visit_trait_item`, we will - // visit the trait item, but if they begin with `visit_item`, we - // won't visit the (nested) trait items. - skip_members: bool, -} - -impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> { - pub fn new(operation: &'a mut O) -> IdVisitor<'a, O> { - IdVisitor { operation: operation, skip_members: false } - } - - fn visit_generics_helper(&mut self, generics: &Generics) { - for type_parameter in generics.ty_params.iter() { - self.operation.visit_id(type_parameter.id) - } - for lifetime in &generics.lifetimes { - self.operation.visit_id(lifetime.lifetime.id) - } - } -} - -impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { - fn visit_mod(&mut self, module: &Mod, _: Span, node_id: NodeId) { - self.operation.visit_id(node_id); - walk_mod(self, module) - } - - fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { - self.operation.visit_id(foreign_item.id); - walk_foreign_item(self, foreign_item) - } - - fn visit_item(&mut self, item: &Item) { - assert!(!self.skip_members); - self.skip_members = true; - - self.operation.visit_id(item.id); - match item.node { - ItemUse(ref view_path) => { - match view_path.node { - ViewPathSimple(_, _) | - ViewPathGlob(_) => {} - ViewPathList(_, ref paths) => { - for path in paths { - self.operation.visit_id(path.node.id()) - } - } - } - } - _ => {} - } - walk_item(self, item); - - self.skip_members = false; - } - - fn visit_local(&mut self, local: &Local) { - self.operation.visit_id(local.id); - walk_local(self, local) - } - - fn visit_block(&mut self, block: &Block) { - self.operation.visit_id(block.id); - walk_block(self, block) - } - - fn visit_stmt(&mut self, statement: &Stmt) { - self.operation.visit_id(statement.node.id()); - walk_stmt(self, statement) - } - - fn visit_pat(&mut self, pattern: &Pat) { - self.operation.visit_id(pattern.id); - walk_pat(self, pattern) - } - - fn visit_expr(&mut self, expression: &Expr) { - self.operation.visit_id(expression.id); - walk_expr(self, expression) - } - - fn visit_ty(&mut self, typ: &Ty) { - self.operation.visit_id(typ.id); - walk_ty(self, typ) - } - - fn visit_generics(&mut self, generics: &Generics) { - self.visit_generics_helper(generics); - walk_generics(self, generics) - } - - fn visit_fn(&mut self, - function_kind: FnKind<'v>, - function_declaration: &'v FnDecl, - block: &'v Block, - span: Span, - node_id: NodeId) { - self.operation.visit_id(node_id); - - match function_kind { - FnKind::ItemFn(_, generics, _, _, _, _, _) => { - self.visit_generics_helper(generics) - } - FnKind::Method(_, sig, _, _) => { - self.visit_generics_helper(&sig.generics) - } - FnKind::Closure(_) => {} - } - - for argument in &function_declaration.inputs { - self.operation.visit_id(argument.id) - } - - walk_fn(self, function_kind, function_declaration, block, span); - } - - fn visit_struct_field(&mut self, struct_field: &StructField) { - self.operation.visit_id(struct_field.id); - walk_struct_field(self, struct_field) - } - - fn visit_variant_data(&mut self, - struct_def: &VariantData, - _: Name, - _: &Generics, - _: NodeId, - _: Span) { - self.operation.visit_id(struct_def.id()); - walk_struct_def(self, struct_def); - } - - fn visit_trait_item(&mut self, ti: &TraitItem) { - if !self.skip_members { - self.operation.visit_id(ti.id); - walk_trait_item(self, ti); - } - } - - fn visit_impl_item(&mut self, ii: &ImplItem) { - if !self.skip_members { - self.operation.visit_id(ii.id); - walk_impl_item(self, ii); - } - } - - fn visit_lifetime(&mut self, lifetime: &Lifetime) { - self.operation.visit_id(lifetime.id); - } - - fn visit_lifetime_def(&mut self, def: &LifetimeDef) { - self.visit_lifetime(&def.lifetime); - } - - fn visit_trait_ref(&mut self, trait_ref: &TraitRef) { - self.operation.visit_id(trait_ref.ref_id); - walk_trait_ref(self, trait_ref); - } -} - /// Computes the id range for a single fn body, ignoring nested items. pub fn compute_id_range_for_fn_body(fk: FnKind, decl: &FnDecl, @@ -1043,8 +924,7 @@ pub fn compute_id_range_for_fn_body(fk: FnKind, sp: Span, id: NodeId) -> IdRange { - let mut visitor = IdRangeComputingVisitor { result: IdRange::max() }; - let mut id_visitor = IdVisitor::new(&mut visitor); - id_visitor.visit_fn(fk, decl, body, sp, id); - id_visitor.operation.result + let mut visitor = IdRangeComputingVisitor::new(); + visitor.visit_fn(fk, decl, body, sp, id); + visitor.result() } diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 693d7a2edfca..b3f222b22e89 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -197,7 +197,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl, b: &'ast Block, s: Span, id: NodeId) { assert_eq!(self.parent_node, id); - intravisit::walk_fn(self, fk, fd, b, s); + intravisit::walk_fn(self, fk, fd, b, s, id); } fn visit_block(&mut self, block: &'ast Block) { diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 960e32ae99fa..aed3613f44ed 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -32,6 +32,7 @@ use hir::print as pprust; use arena::TypedArena; use std::cell::RefCell; +use std::cmp; use std::io; use std::mem; @@ -127,7 +128,10 @@ impl<'ast> MapEntry<'ast> { EntryStructCtor(id, _) => id, EntryLifetime(id, _) => id, EntryTyParam(id, _) => id, - _ => return None + + NotPresent | + RootCrate | + RootInlinedParent(_) => return None, }) } @@ -196,6 +200,10 @@ pub struct Map<'ast> { map: RefCell>>, definitions: RefCell, + + /// All NodeIds that are numerically greater or equal to this value come + /// from inlined items. + local_node_id_watermark: NodeId, } impl<'ast> Map<'ast> { @@ -550,6 +558,13 @@ impl<'ast> Map<'ast> { } } + pub fn expect_inlined_item(&self, id: NodeId) -> &'ast InlinedItem { + match self.find_entry(id) { + Some(RootInlinedParent(inlined_item)) => inlined_item, + _ => bug!("expected inlined item, found {}", self.node_to_string(id)), + } + } + /// Returns the name associated with the given NodeId's AST. pub fn name(&self, id: NodeId) -> Name { match self.get(id) { @@ -649,6 +664,10 @@ impl<'ast> Map<'ast> { pub fn node_to_user_string(&self, id: NodeId) -> String { node_id_to_string(self, id, false) } + + pub fn is_inlined(&self, id: NodeId) -> bool { + id >= self.local_node_id_watermark + } } pub struct NodesMatchingSuffix<'a, 'ast:'a> { @@ -765,13 +784,37 @@ pub trait FoldOps { } /// A Folder that updates IDs and Span's according to fold_ops. -struct IdAndSpanUpdater { - fold_ops: F +pub struct IdAndSpanUpdater { + fold_ops: F, + min_id_assigned: NodeId, + max_id_assigned: NodeId, +} + +impl IdAndSpanUpdater { + pub fn new(fold_ops: F) -> IdAndSpanUpdater { + IdAndSpanUpdater { + fold_ops: fold_ops, + min_id_assigned: ::std::u32::MAX, + max_id_assigned: ::std::u32::MIN, + } + } + + pub fn id_range(&self) -> intravisit::IdRange { + intravisit::IdRange { + min: self.min_id_assigned, + max: self.max_id_assigned + 1, + } + } } impl Folder for IdAndSpanUpdater { fn new_id(&mut self, id: NodeId) -> NodeId { - self.fold_ops.new_id(id) + let id = self.fold_ops.new_id(id); + + self.min_id_assigned = cmp::min(self.min_id_assigned, id); + self.max_id_assigned = cmp::max(self.max_id_assigned, id); + + id } fn new_span(&mut self, span: Span) -> Span { @@ -802,11 +845,14 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest, entries, vector_length, (entries as f64 / vector_length as f64) * 100.); } + let local_node_id_watermark = map.len() as NodeId; + Map { forest: forest, dep_graph: forest.dep_graph.clone(), map: RefCell::new(map), definitions: RefCell::new(definitions), + local_node_id_watermark: local_node_id_watermark } } @@ -818,7 +864,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, ii: InlinedItem, fold_ops: F) -> &'ast InlinedItem { - let mut fld = IdAndSpanUpdater { fold_ops: fold_ops }; + let mut fld = IdAndSpanUpdater::new(fold_ops); let ii = match ii { II::Item(i) => II::Item(i.map(|i| fld.fold_item(i))), II::TraitItem(d, ti) => { @@ -835,6 +881,12 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, let ii = map.forest.inlined_items.alloc(ii); let ii_parent_id = fld.new_id(DUMMY_NODE_ID); + // Assert that the ii_parent_id is the last NodeId in our reserved range + assert!(ii_parent_id == fld.max_id_assigned); + // Assert that we did not violate the invariant that all inlined HIR items + // have NodeIds greater than or equal to `local_node_id_watermark` + assert!(fld.min_id_assigned >= map.local_node_id_watermark); + let defs = &mut *map.definitions.borrow_mut(); let mut def_collector = DefCollector::extend(ii_parent_id, parent_def_path.clone(), diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 655f80ec0723..9212fda65025 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -36,7 +36,7 @@ use hir::def::Def; use hir::def_id::DefId; use util::nodemap::{NodeMap, FnvHashSet}; -use syntax_pos::{mk_sp, Span, ExpnId}; +use syntax_pos::{BytePos, mk_sp, Span, ExpnId}; use syntax::codemap::{self, respan, Spanned}; use syntax::abi::Abi; use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect}; @@ -326,6 +326,38 @@ impl Generics { pub fn is_parameterized(&self) -> bool { self.is_lt_parameterized() || self.is_type_parameterized() } + + // Does return a span which includes lifetimes and type parameters, + // not where clause. + pub fn span(&self) -> Option { + if !self.is_parameterized() { + None + } else { + let mut span: Option = None; + for lifetime in self.lifetimes.iter() { + if let Some(ref mut span) = span { + let life_span = lifetime.lifetime.span; + span.hi = if span.hi > life_span.hi { span.hi } else { life_span.hi }; + span.lo = if span.lo < life_span.lo { span.lo } else { life_span.lo }; + } else { + span = Some(lifetime.lifetime.span.clone()); + } + } + for ty_param in self.ty_params.iter() { + if let Some(ref mut span) = span { + span.lo = if span.lo < ty_param.span.lo { span.lo } else { ty_param.span.lo }; + span.hi = if span.hi > ty_param.span.hi { span.hi } else { ty_param.span.hi }; + } else { + span = Some(ty_param.span.clone()); + } + } + if let Some(ref mut span) = span { + span.lo = span.lo - BytePos(1); + span.hi = span.hi + BytePos(1); + } + span + } + } } /// A `where` clause in a definition @@ -1362,9 +1394,9 @@ pub enum ViewPath_ { /// TraitRef's appear in impls. /// /// resolve maps each TraitRef's ref_id to its defining trait; that's all -/// that the ref_id is for. The impl_id maps to the "self type" of this impl. -/// If this impl is an ItemImpl, the impl_id is redundant (it could be the -/// same as the impl's node id). +/// that the ref_id is for. Note that ref_id's value is not the NodeId of the +/// trait being referred to but just a unique NodeId that serves as a key +/// within the DefMap. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct TraitRef { pub path: Path, diff --git a/src/librustc/infer/bivariate.rs b/src/librustc/infer/bivariate.rs index 96b14a6c321c..125f815feda6 100644 --- a/src/librustc/infer/bivariate.rs +++ b/src/librustc/infer/bivariate.rs @@ -32,22 +32,27 @@ use ty::{self, Ty, TyCtxt}; use ty::TyVar; use ty::relate::{Relate, RelateResult, TypeRelation}; -pub struct Bivariate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fields: CombineFields<'a, 'gcx, 'tcx> +pub struct Bivariate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, + a_is_expected: bool, } -impl<'a, 'gcx, 'tcx> Bivariate<'a, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Bivariate<'a, 'gcx, 'tcx> { - Bivariate { fields: fields } +impl<'combine, 'infcx, 'gcx, 'tcx> Bivariate<'combine, 'infcx, 'gcx, 'tcx> { + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) + -> Bivariate<'combine, 'infcx, 'gcx, 'tcx> + { + Bivariate { fields: fields, a_is_expected: a_is_expected } } } -impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Bivariate<'a, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> + for Bivariate<'combine, 'infcx, 'gcx, 'tcx> +{ fn tag(&self) -> &'static str { "Bivariate" } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() } + fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn a_is_expected(&self) -> bool { self.a_is_expected } fn relate_with_variance>(&mut self, variance: ty::Variance, @@ -86,12 +91,12 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Bivariate<'a, 'gcx, 'tcx> } (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, BiTo, a_id)?; + self.fields.instantiate(b, BiTo, a_id, self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, BiTo, b_id)?; + self.fields.instantiate(a, BiTo, b_id, self.a_is_expected)?; Ok(a) } diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index c9235d063cba..b4818f963b3b 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -52,21 +52,20 @@ use syntax::ast; use syntax_pos::Span; #[derive(Clone)] -pub struct CombineFields<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - pub a_is_expected: bool, +pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + pub infcx: &'infcx InferCtxt<'infcx, 'gcx, 'tcx>, pub trace: TypeTrace<'tcx>, pub cause: Option, pub obligations: PredicateObligations<'tcx>, } -impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { pub fn super_combine_tys(&self, relation: &mut R, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> - where R: TypeRelation<'a, 'gcx, 'tcx> + where R: TypeRelation<'infcx, 'gcx, 'tcx> { let a_is_expected = relation.a_is_expected(); @@ -150,42 +149,36 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { - pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { +impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { + pub fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.infcx.tcx } - pub fn switch_expected(&self) -> CombineFields<'a, 'gcx, 'tcx> { - CombineFields { - a_is_expected: !self.a_is_expected, - ..(*self).clone() - } + pub fn equate<'a>(&'a mut self, a_is_expected: bool) -> Equate<'a, 'infcx, 'gcx, 'tcx> { + Equate::new(self, a_is_expected) } - pub fn equate(&self) -> Equate<'a, 'gcx, 'tcx> { - Equate::new(self.clone()) + pub fn bivariate<'a>(&'a mut self, a_is_expected: bool) -> Bivariate<'a, 'infcx, 'gcx, 'tcx> { + Bivariate::new(self, a_is_expected) } - pub fn bivariate(&self) -> Bivariate<'a, 'gcx, 'tcx> { - Bivariate::new(self.clone()) + pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'gcx, 'tcx> { + Sub::new(self, a_is_expected) } - pub fn sub(&self) -> Sub<'a, 'gcx, 'tcx> { - Sub::new(self.clone()) + pub fn lub<'a>(&'a mut self, a_is_expected: bool) -> Lub<'a, 'infcx, 'gcx, 'tcx> { + Lub::new(self, a_is_expected) } - pub fn lub(&self) -> Lub<'a, 'gcx, 'tcx> { - Lub::new(self.clone()) + pub fn glb<'a>(&'a mut self, a_is_expected: bool) -> Glb<'a, 'infcx, 'gcx, 'tcx> { + Glb::new(self, a_is_expected) } - pub fn glb(&self) -> Glb<'a, 'gcx, 'tcx> { - Glb::new(self.clone()) - } - - pub fn instantiate(&self, + pub fn instantiate(&mut self, a_ty: Ty<'tcx>, dir: RelationDir, - b_vid: ty::TyVid) + b_vid: ty::TyVid, + a_is_expected: bool) -> RelateResult<'tcx, ()> { let mut stack = Vec::new(); @@ -255,10 +248,11 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // to associate causes/spans with each of the relations in // the stack to get this right. match dir { - BiTo => self.bivariate().relate(&a_ty, &b_ty), - EqTo => self.equate().relate(&a_ty, &b_ty), - SubtypeOf => self.sub().relate(&a_ty, &b_ty), - SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty), + BiTo => self.bivariate(a_is_expected).relate(&a_ty, &b_ty), + EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), + SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), + SupertypeOf => self.sub(a_is_expected).relate_with_variance( + ty::Contravariant, &a_ty, &b_ty), }?; } diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index 408f22cf15c7..e06f7303acb2 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -15,29 +15,29 @@ use super::type_variable::{EqTo}; use ty::{self, Ty, TyCtxt}; use ty::TyVar; use ty::relate::{Relate, RelateResult, TypeRelation}; -use traits::PredicateObligations; /// Ensures `a` is made equal to `b`. Returns `a` on success. -pub struct Equate<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fields: CombineFields<'a, 'gcx, 'tcx> +pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, + a_is_expected: bool, } -impl<'a, 'gcx, 'tcx> Equate<'a, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Equate<'a, 'gcx, 'tcx> { - Equate { fields: fields } - } - - pub fn obligations(self) -> PredicateObligations<'tcx> { - self.fields.obligations +impl<'combine, 'infcx, 'gcx, 'tcx> Equate<'combine, 'infcx, 'gcx, 'tcx> { + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) + -> Equate<'combine, 'infcx, 'gcx, 'tcx> + { + Equate { fields: fields, a_is_expected: a_is_expected } } } -impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Equate<'a, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> + for Equate<'combine, 'infcx, 'gcx, 'tcx> +{ fn tag(&self) -> &'static str { "Equate" } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() } + fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn a_is_expected(&self) -> bool { self.a_is_expected } fn relate_with_variance>(&mut self, _: ty::Variance, @@ -63,12 +63,12 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Equate<'a, 'gcx, 'tcx> { } (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, EqTo, a_id)?; + self.fields.instantiate(b, EqTo, a_id, self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, EqTo, b_id)?; + self.fields.instantiate(a, EqTo, b_id, self.a_is_expected)?; Ok(a) } @@ -93,7 +93,7 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Equate<'a, 'gcx, 'tcx> { -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> { - self.fields.higher_ranked_sub(a, b)?; - self.fields.higher_ranked_sub(b, a) + self.fields.higher_ranked_sub(a, b, self.a_is_expected)?; + self.fields.higher_ranked_sub(b, a, self.a_is_expected) } } diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 96ecad629f54..511cc32d2e1e 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -83,7 +83,7 @@ use hir::def_id::DefId; use infer::{self, TypeOrigin}; use middle::region; use ty::subst; -use ty::{self, Ty, TyCtxt, TypeFoldable}; +use ty::{self, TyCtxt, TypeFoldable}; use ty::{Region, ReFree}; use ty::error::TypeError; @@ -462,52 +462,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - fn report_type_error(&self, - trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>) - -> DiagnosticBuilder<'tcx> { - let (expected, found) = match self.values_str(&trace.values) { - Some(v) => v, - None => { - return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */ - } - }; - - let is_simple_error = if let &TypeError::Sorts(ref values) = terr { - values.expected.is_primitive() && values.found.is_primitive() - } else { - false - }; - - let mut err = struct_span_err!(self.tcx.sess, - trace.origin.span(), - E0308, - "{}", - trace.origin); - - if !is_simple_error || check_old_school() { - err.note_expected_found(&"type", &expected, &found); - } - - err.span_label(trace.origin.span(), &terr); - - self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span()); - - match trace.origin { - TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source { - hir::MatchSource::IfLetDesugar{..} => { - err.span_note(arm_span, "`if let` arm with an incompatible type"); - } - _ => { - err.span_note(arm_span, "match arm with an incompatible type"); - } - }, - _ => () - } - - err - } - /// Adds a note if the types come from similarly named crates fn check_and_note_conflicting_crates(&self, err: &mut DiagnosticBuilder, @@ -550,42 +504,102 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + fn note_error_origin(&self, + err: &mut DiagnosticBuilder<'tcx>, + origin: &TypeOrigin) + { + match origin { + &TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source { + hir::MatchSource::IfLetDesugar {..} => { + err.span_note(arm_span, "`if let` arm with an incompatible type"); + } + _ => { + err.span_note(arm_span, "match arm with an incompatible type"); + } + }, + _ => () + } + } + + pub fn note_type_err(&self, + diag: &mut DiagnosticBuilder<'tcx>, + origin: TypeOrigin, + values: Option>, + terr: &TypeError<'tcx>) + { + let expected_found = match values { + None => None, + Some(values) => match self.values_str(&values) { + Some((expected, found)) => Some((expected, found)), + None => { + // Derived error. Cancel the emitter. + self.tcx.sess.diagnostic().cancel(diag); + return + } + } + }; + + let span = origin.span(); + + let mut is_simple_error = false; + + if let Some((expected, found)) = expected_found { + is_simple_error = if let &TypeError::Sorts(ref values) = terr { + values.expected.is_primitive() && values.found.is_primitive() + } else { + false + }; + + if !is_simple_error || check_old_school() { + diag.note_expected_found(&"type", &expected, &found); + } + } + + if !is_simple_error && check_old_school() { + diag.span_note(span, &format!("{}", terr)); + } else { + diag.span_label(span, &terr); + } + + self.note_error_origin(diag, &origin); + self.check_and_note_conflicting_crates(diag, terr, span); + self.tcx.note_and_explain_type_err(diag, terr, span); + } + pub fn report_and_explain_type_error(&self, trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>) - -> DiagnosticBuilder<'tcx> { - let span = trace.origin.span(); - let mut err = self.report_type_error(trace, terr); - self.tcx.note_and_explain_type_err(&mut err, terr, span); - err + -> DiagnosticBuilder<'tcx> + { + // FIXME: do we want to use a different error code for each origin? + let mut diag = struct_span_err!( + self.tcx.sess, trace.origin.span(), E0308, + "{}", trace.origin.as_failure_str() + ); + self.note_type_err(&mut diag, trace.origin, Some(trace.values), terr); + diag } - /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived - /// error. + /// Returns a string of the form "expected `{}`, found `{}`". fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> { match *values { infer::Types(ref exp_found) => self.expected_found_str(exp_found), infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), - infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found) + infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found), } } - fn expected_found_str + TypeFoldable<'tcx>>( + fn expected_found_str>( &self, exp_found: &ty::error::ExpectedFound) -> Option<(String, String)> { - let expected = exp_found.expected.resolve(self); - if expected.references_error() { + let exp_found = self.resolve_type_vars_if_possible(exp_found); + if exp_found.references_error() { return None; } - let found = exp_found.found.resolve(self); - if found.references_error() { - return None; - } - - Some((format!("{}", expected), format!("{}", found))) + Some((format!("{}", exp_found.expected), format!("{}", exp_found.found))) } fn report_generic_bound_failure(&self, @@ -1608,59 +1622,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) { match *origin { infer::Subtype(ref trace) => { - let desc = match trace.origin { - TypeOrigin::Misc(_) => { - "types are compatible" - } - TypeOrigin::MethodCompatCheck(_) => { - "method type is compatible with trait" - } - TypeOrigin::ExprAssignable(_) => { - "expression is assignable" - } - TypeOrigin::RelateTraitRefs(_) => { - "traits are compatible" - } - TypeOrigin::RelateSelfType(_) => { - "self type matches impl self type" - } - TypeOrigin::RelateOutputImplTypes(_) => { - "trait type parameters matches those \ - specified on the impl" - } - TypeOrigin::MatchExpressionArm(_, _, _) => { - "match arms have compatible types" - } - TypeOrigin::IfExpression(_) => { - "if and else have compatible types" - } - TypeOrigin::IfExpressionWithNoElse(_) => { - "if may be missing an else clause" - } - TypeOrigin::RangeExpression(_) => { - "start and end of range have compatible types" - } - TypeOrigin::EquatePredicate(_) => { - "equality where clause is satisfied" - } - }; + if let Some((expected, found)) = self.values_str(&trace.values) { + // FIXME: do we want a "the" here? + err.span_note( + trace.origin.span(), + &format!("...so that {} (expected {}, found {})", + trace.origin.as_requirement_str(), expected, found)); + } else { + // FIXME: this really should be handled at some earlier stage. Our + // handling of region checking when type errors are present is + // *terrible*. - match self.values_str(&trace.values) { - Some((expected, found)) => { - err.span_note( - trace.origin.span(), - &format!("...so that {} (expected {}, found {})", - desc, expected, found)); - } - None => { - // Really should avoid printing this error at - // all, since it is derived, but that would - // require more refactoring than I feel like - // doing right now. - nmatsakis - err.span_note( - trace.origin.span(), - &format!("...so that {}", desc)); - } + err.span_note( + trace.origin.span(), + &format!("...so that {}", + trace.origin.as_requirement_str())); } } infer::Reborrow(span) => { @@ -1803,32 +1779,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -pub trait Resolvable<'tcx> { - fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self; -} - -impl<'tcx> Resolvable<'tcx> for Ty<'tcx> { - fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { - infcx.resolve_type_vars_if_possible(self) - } -} - -impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> { - fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> ty::TraitRef<'tcx> { - infcx.resolve_type_vars_if_possible(self) - } -} - -impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> { - fn resolve<'a, 'gcx>(&self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> ty::PolyTraitRef<'tcx> - { - infcx.resolve_type_vars_if_possible(self) - } -} - fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, scope_id: ast::NodeId) -> Vec { diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index b7085f0829f8..5dd85a31a9a2 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -15,29 +15,29 @@ use super::Subtype; use ty::{self, Ty, TyCtxt}; use ty::relate::{Relate, RelateResult, TypeRelation}; -use traits::PredicateObligations; /// "Greatest lower bound" (common subtype) -pub struct Glb<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fields: CombineFields<'a, 'gcx, 'tcx> +pub struct Glb<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, + a_is_expected: bool, } -impl<'a, 'gcx, 'tcx> Glb<'a, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Glb<'a, 'gcx, 'tcx> { - Glb { fields: fields } - } - - pub fn obligations(self) -> PredicateObligations<'tcx> { - self.fields.obligations +impl<'combine, 'infcx, 'gcx, 'tcx> Glb<'combine, 'infcx, 'gcx, 'tcx> { + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) + -> Glb<'combine, 'infcx, 'gcx, 'tcx> + { + Glb { fields: fields, a_is_expected: a_is_expected } } } -impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> + for Glb<'combine, 'infcx, 'gcx, 'tcx> +{ fn tag(&self) -> &'static str { "Glb" } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() } + fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn a_is_expected(&self) -> bool { self.a_is_expected } fn relate_with_variance>(&mut self, variance: ty::Variance, @@ -46,10 +46,10 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> { -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate().relate(a, b), + ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate().relate(a, b), - ty::Contravariant => self.fields.lub().relate(a, b), + ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b), } } @@ -71,17 +71,19 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> { -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> { - self.fields.higher_ranked_glb(a, b) + self.fields.higher_ranked_glb(a, b, self.a_is_expected) } } -impl<'a, 'gcx, 'tcx> LatticeDir<'a, 'gcx, 'tcx> for Glb<'a, 'gcx, 'tcx> { - fn infcx(&self) -> &'a InferCtxt<'a, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> + for Glb<'combine, 'infcx, 'gcx, 'tcx> +{ + fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx } - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(); + fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + let mut sub = self.fields.sub(self.a_is_expected); sub.relate(&v, &a)?; sub.relate(&v, &b)?; Ok(()) diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 03a09917c534..743d6135fbb5 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -40,7 +40,7 @@ pub struct HrMatchResult { } impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { - pub fn higher_ranked_sub(&self, a: &Binder, b: &Binder) + pub fn higher_ranked_sub(&mut self, a: &Binder, b: &Binder, a_is_expected: bool) -> RelateResult<'tcx, Binder> where T: Relate<'tcx> { @@ -77,11 +77,11 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { debug!("b_prime={:?}", b_prime); // Compare types now that bound regions have been replaced. - let result = self.sub().relate(&a_prime, &b_prime)?; + let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?; // Presuming type comparison succeeds, we need to check // that the skolemized regions do not "leak". - self.infcx.leak_check(!self.a_is_expected, span, &skol_map, snapshot)?; + self.infcx.leak_check(!a_is_expected, span, &skol_map, snapshot)?; // We are finished with the skolemized regions now so pop // them off. @@ -106,10 +106,11 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { /// NB. It should not happen that there are LBR appearing in `U` /// that do not appear in `T`. If that happens, those regions are /// unconstrained, and this routine replaces them with `'static`. - pub fn higher_ranked_match(&self, + pub fn higher_ranked_match(&mut self, span: Span, a_pair: &Binder<(T, U)>, - b_match: &T) + b_match: &T, + a_is_expected: bool) -> RelateResult<'tcx, HrMatchResult> where T: Relate<'tcx>, U: TypeFoldable<'tcx> @@ -129,7 +130,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { debug!("higher_ranked_match: skol_map={:?}", skol_map); // Equate types now that bound regions have been replaced. - try!(self.equate().relate(&a_match, &b_match)); + try!(self.equate(a_is_expected).relate(&a_match, &b_match)); // Map each skolemized region to a vector of other regions that it // must be equated with. (Note that this vector may include other @@ -221,7 +222,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { }); } - pub fn higher_ranked_lub(&self, a: &Binder, b: &Binder) + pub fn higher_ranked_lub(&mut self, a: &Binder, b: &Binder, a_is_expected: bool) -> RelateResult<'tcx, Binder> where T: Relate<'tcx> { @@ -239,7 +240,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Collect constraints. let result0 = - self.lub().relate(&a_with_fresh, &b_with_fresh)?; + self.lub(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?; let result0 = self.infcx.resolve_type_vars_if_possible(&result0); debug!("lub result0 = {:?}", result0); @@ -311,7 +312,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { } } - pub fn higher_ranked_glb(&self, a: &Binder, b: &Binder) + pub fn higher_ranked_glb(&mut self, a: &Binder, b: &Binder, a_is_expected: bool) -> RelateResult<'tcx, Binder> where T: Relate<'tcx> { @@ -333,7 +334,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Collect constraints. let result0 = - self.glb().relate(&a_with_fresh, &b_with_fresh)?; + self.glb(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?; let result0 = self.infcx.resolve_type_vars_if_possible(&result0); debug!("glb result0 = {:?}", result0); diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs index 1a2bc4b5cf2e..eda78428e61a 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc/infer/lattice.rs @@ -40,7 +40,7 @@ pub trait LatticeDir<'f, 'gcx: 'f+'tcx, 'tcx: 'f> : TypeRelation<'f, 'gcx, 'tcx> // Relates the type `v` to `a` and `b` such that `v` represents // the LUB/GLB of `a` and `b` as appropriate. - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; + fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; } pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L, diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index bd46f3a26a2d..ad1b32ffaeb3 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -15,29 +15,29 @@ use super::Subtype; use ty::{self, Ty, TyCtxt}; use ty::relate::{Relate, RelateResult, TypeRelation}; -use traits::PredicateObligations; /// "Least upper bound" (common supertype) -pub struct Lub<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fields: CombineFields<'a, 'gcx, 'tcx> +pub struct Lub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, + a_is_expected: bool, } -impl<'a, 'gcx, 'tcx> Lub<'a, 'gcx, 'tcx> { - pub fn new(fields: CombineFields<'a, 'gcx, 'tcx>) -> Lub<'a, 'gcx, 'tcx> { - Lub { fields: fields } - } - - pub fn obligations(self) -> PredicateObligations<'tcx> { - self.fields.obligations +impl<'combine, 'infcx, 'gcx, 'tcx> Lub<'combine, 'infcx, 'gcx, 'tcx> { + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) + -> Lub<'combine, 'infcx, 'gcx, 'tcx> + { + Lub { fields: fields, a_is_expected: a_is_expected } } } -impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> + for Lub<'combine, 'infcx, 'gcx, 'tcx> +{ fn tag(&self) -> &'static str { "Lub" } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.tcx() } + fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn a_is_expected(&self) -> bool { self.a_is_expected } fn relate_with_variance>(&mut self, variance: ty::Variance, @@ -46,10 +46,10 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> { -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate().relate(a, b), + ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate().relate(a, b), - ty::Contravariant => self.fields.glb().relate(a, b), + ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b), } } @@ -71,17 +71,19 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> { -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> { - self.fields.higher_ranked_lub(a, b) + self.fields.higher_ranked_lub(a, b, self.a_is_expected) } } -impl<'a, 'gcx, 'tcx> LatticeDir<'a, 'gcx, 'tcx> for Lub<'a, 'gcx, 'tcx> { - fn infcx(&self) -> &'a InferCtxt<'a, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> + for Lub<'combine, 'infcx, 'gcx, 'tcx> +{ + fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx } - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(); + fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + let mut sub = self.fields.sub(self.a_is_expected); sub.relate(&a, &v)?; sub.relate(&b, &v)?; Ok(()) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 2ea2978b2940..be9adf7085cd 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -32,7 +32,7 @@ use ty::adjustment; use ty::{TyVid, IntVid, FloatVid}; use ty::{self, Ty, TyCtxt}; use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; -use ty::fold::TypeFoldable; +use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::relate::{Relate, RelateResult, TypeRelation}; use traits::{self, PredicateObligations, ProjectionMode}; use rustc_data_structures::unify::{self, UnificationTable}; @@ -48,18 +48,18 @@ use self::higher_ranked::HrMatchResult; use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::unify_key::ToType; -pub mod bivariate; -pub mod combine; -pub mod equate; +mod bivariate; +mod combine; +mod equate; pub mod error_reporting; -pub mod glb; +mod glb; mod higher_ranked; pub mod lattice; -pub mod lub; +mod lub; pub mod region_inference; pub mod resolve; mod freshen; -pub mod sub; +mod sub; pub mod type_variable; pub mod unify_key; @@ -196,12 +196,6 @@ pub enum TypeOrigin { // FIXME(eddyb) #11161 is the original Expr required? ExprAssignable(Span), - // Relating trait refs when resolving vtables - RelateTraitRefs(Span), - - // Relating self types when resolving vtables - RelateSelfType(Span), - // Relating trait type parameters to those found in impl etc RelateOutputImplTypes(Span), @@ -219,16 +213,26 @@ pub enum TypeOrigin { // `where a == b` EquatePredicate(Span), + + // `main` has wrong type + MainFunctionType(Span), + + // `start` has wrong type + StartFunctionType(Span), + + // intrinsic has wrong type + IntrinsicType(Span), + + // method receiver + MethodReceiver(Span), } impl TypeOrigin { - fn as_str(&self) -> &'static str { + fn as_failure_str(&self) -> &'static str { match self { &TypeOrigin::Misc(_) | - &TypeOrigin::RelateSelfType(_) | &TypeOrigin::RelateOutputImplTypes(_) | &TypeOrigin::ExprAssignable(_) => "mismatched types", - &TypeOrigin::RelateTraitRefs(_) => "mismatched traits", &TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait", &TypeOrigin::MatchExpressionArm(_, _, source) => match source { hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types", @@ -238,13 +242,31 @@ impl TypeOrigin { &TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause", &TypeOrigin::RangeExpression(_) => "start and end of range have incompatible types", &TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied", + &TypeOrigin::MainFunctionType(_) => "main function has wrong type", + &TypeOrigin::StartFunctionType(_) => "start function has wrong type", + &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type", + &TypeOrigin::MethodReceiver(_) => "mismatched method receiver", } } -} -impl fmt::Display for TypeOrigin { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> { - fmt::Display::fmt(self.as_str(), f) + fn as_requirement_str(&self) -> &'static str { + match self { + &TypeOrigin::Misc(_) => "types are compatible", + &TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait", + &TypeOrigin::ExprAssignable(_) => "expression is assignable", + &TypeOrigin::RelateOutputImplTypes(_) => { + "trait type parameters matches those specified on the impl" + } + &TypeOrigin::MatchExpressionArm(_, _, _) => "match arms have compatible types", + &TypeOrigin::IfExpression(_) => "if and else have compatible types", + &TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()", + &TypeOrigin::RangeExpression(_) => "start and end of range have compatible types", + &TypeOrigin::EquatePredicate(_) => "equality where clause is satisfied", + &TypeOrigin::MainFunctionType(_) => "`main` function has the correct type", + &TypeOrigin::StartFunctionType(_) => "`start` function has the correct type", + &TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type", + &TypeOrigin::MethodReceiver(_) => "method receiver has the correct type", + } } } @@ -799,11 +821,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return variables; } - fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + fn combine_fields(&'a self, trace: TypeTrace<'tcx>) -> CombineFields<'a, 'gcx, 'tcx> { CombineFields { infcx: self, - a_is_expected: a_is_expected, trace: trace, cause: None, obligations: PredicateObligations::new(), @@ -814,36 +835,36 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut equate = self.combine_fields(a_is_expected, trace).equate(); - let result = equate.relate(a, b); - result.map(|t| InferOk { value: t, obligations: equate.obligations() }) + let mut fields = self.combine_fields(trace); + let result = fields.equate(a_is_expected).relate(a, b); + result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } pub fn sub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T) -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut sub = self.combine_fields(a_is_expected, trace).sub(); - let result = sub.relate(a, b); - result.map(|t| InferOk { value: t, obligations: sub.obligations() }) + let mut fields = self.combine_fields(trace); + let result = fields.sub(a_is_expected).relate(a, b); + result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } pub fn lub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T) -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut lub = self.combine_fields(a_is_expected, trace).lub(); - let result = lub.relate(a, b); - result.map(|t| InferOk { value: t, obligations: lub.obligations() }) + let mut fields = self.combine_fields(trace); + let result = fields.lub(a_is_expected).relate(a, b); + result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } pub fn glb(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T) -> InferResult<'tcx, T> where T: Relate<'tcx> { - let mut glb = self.combine_fields(a_is_expected, trace).glb(); - let result = glb.relate(a, b); - result.map(|t| InferOk { value: t, obligations: glb.obligations() }) + let mut fields = self.combine_fields(trace); + let result = fields.glb(a_is_expected).relate(a, b); + result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } fn start_snapshot(&self) -> CombinedSnapshot { @@ -1468,104 +1489,50 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // error type, meaning that an error occurred when typechecking this expression), // this is a derived error. The error cascaded from another error (that was already // reported), so it's not useful to display it to the user. - // The following four methods -- type_error_message_str, type_error_message_str_with_expected, - // type_error_message, and report_mismatched_types -- implement this logic. + // The following methods implement this logic. // They check if either the actual or expected type is TyError, and don't print the error // in this case. The typechecker should only ever report type errors involving mismatched - // types using one of these four methods, and should not call span_err directly for such + // types using one of these methods, and should not call span_err directly for such // errors. - pub fn type_error_message_str(&self, - sp: Span, - mk_msg: M, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - where M: FnOnce(Option, String) -> String, - { - self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err) - } - - pub fn type_error_struct_str(&self, - sp: Span, - mk_msg: M, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - -> DiagnosticBuilder<'tcx> - where M: FnOnce(Option, String) -> String, - { - self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err) - } - - pub fn type_error_message_str_with_expected(&self, - sp: Span, - mk_msg: M, - expected_ty: Option>, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - where M: FnOnce(Option, String) -> String, - { - self.type_error_struct_str_with_expected(sp, mk_msg, expected_ty, actual_ty, err) - .emit(); - } - - pub fn type_error_struct_str_with_expected(&self, - sp: Span, - mk_msg: M, - expected_ty: Option>, - actual_ty: String, - err: Option<&TypeError<'tcx>>) - -> DiagnosticBuilder<'tcx> - where M: FnOnce(Option, String) -> String, - { - debug!("hi! expected_ty = {:?}, actual_ty = {}", expected_ty, actual_ty); - - let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty)); - - if !resolved_expected.references_error() { - let error_str = err.map_or("".to_string(), |t_err| { - format!(" ({})", t_err) - }); - - let mut db = self.tcx.sess.struct_span_err(sp, &format!("{}{}", - mk_msg(resolved_expected.map(|t| self.ty_to_string(t)), actual_ty), - error_str)); - - if let Some(err) = err { - self.tcx.note_and_explain_type_err(&mut db, err, sp); - } - db - } else { - self.tcx.sess.diagnostic().struct_dummy() - } - } pub fn type_error_message(&self, sp: Span, mk_msg: M, - actual_ty: Ty<'tcx>, - err: Option<&TypeError<'tcx>>) + actual_ty: Ty<'tcx>) where M: FnOnce(String) -> String, { - self.type_error_struct(sp, mk_msg, actual_ty, err).emit(); + self.type_error_struct(sp, mk_msg, actual_ty).emit(); } + // FIXME: this results in errors without an error code. Deprecate? pub fn type_error_struct(&self, sp: Span, mk_msg: M, - actual_ty: Ty<'tcx>, - err: Option<&TypeError<'tcx>>) + actual_ty: Ty<'tcx>) -> DiagnosticBuilder<'tcx> where M: FnOnce(String) -> String, + { + self.type_error_struct_with_diag(sp, |actual_ty| { + self.tcx.sess.struct_span_err(sp, &mk_msg(actual_ty)) + }, actual_ty) + } + + pub fn type_error_struct_with_diag(&self, + sp: Span, + mk_diag: M, + actual_ty: Ty<'tcx>) + -> DiagnosticBuilder<'tcx> + where M: FnOnce(String) -> DiagnosticBuilder<'tcx>, { let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); + debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); // Don't report an error if actual type is TyError. if actual_ty.references_error() { return self.tcx.sess.diagnostic().struct_dummy(); } - self.type_error_struct_str(sp, - move |_e, a| { mk_msg(a) }, - self.ty_to_string(actual_ty), err) + mk_diag(self.ty_to_string(actual_ty)) } pub fn report_mismatched_types(&self, @@ -1646,8 +1613,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }; let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty)); - let combine = self.combine_fields(true, trace); - let result = combine.higher_ranked_match(span, &match_pair, &match_b)?; + let mut combine = self.combine_fields(trace); + let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?; Ok(InferOk { value: result, obligations: combine.obligations }) } @@ -1833,14 +1800,16 @@ impl TypeOrigin { TypeOrigin::MethodCompatCheck(span) => span, TypeOrigin::ExprAssignable(span) => span, TypeOrigin::Misc(span) => span, - TypeOrigin::RelateTraitRefs(span) => span, - TypeOrigin::RelateSelfType(span) => span, TypeOrigin::RelateOutputImplTypes(span) => span, TypeOrigin::MatchExpressionArm(match_span, _, _) => match_span, TypeOrigin::IfExpression(span) => span, TypeOrigin::IfExpressionWithNoElse(span) => span, TypeOrigin::RangeExpression(span) => span, TypeOrigin::EquatePredicate(span) => span, + TypeOrigin::MainFunctionType(span) => span, + TypeOrigin::StartFunctionType(span) => span, + TypeOrigin::IntrinsicType(span) => span, + TypeOrigin::MethodReceiver(span) => span, } } } @@ -1891,3 +1860,50 @@ impl RegionVariableOrigin { } } } + +impl<'tcx> TypeFoldable<'tcx> for TypeOrigin { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self { + self.clone() + } + + fn super_visit_with>(&self, _visitor: &mut V) -> bool { + false + } +} + +impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match *self { + ValuePairs::Types(ref ef) => { + ValuePairs::Types(ef.fold_with(folder)) + } + ValuePairs::TraitRefs(ref ef) => { + ValuePairs::TraitRefs(ef.fold_with(folder)) + } + ValuePairs::PolyTraitRefs(ref ef) => { + ValuePairs::PolyTraitRefs(ef.fold_with(folder)) + } + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + ValuePairs::Types(ref ef) => ef.visit_with(visitor), + ValuePairs::TraitRefs(ref ef) => ef.visit_with(visitor), + ValuePairs::PolyTraitRefs(ref ef) => ef.visit_with(visitor), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + TypeTrace { + origin: self.origin.fold_with(folder), + values: self.values.fold_with(folder) + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.origin.visit_with(visitor) || self.values.visit_with(visitor) + } +} diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 680dd0d63556..2f7f5254727d 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -15,28 +15,35 @@ use super::type_variable::{SubtypeOf, SupertypeOf}; use ty::{self, Ty, TyCtxt}; use ty::TyVar; use ty::relate::{Cause, Relate, RelateResult, TypeRelation}; -use traits::PredicateObligations; use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. -pub struct Sub<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fields: CombineFields<'a, 'gcx, 'tcx>, +pub struct Sub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { + fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, + a_is_expected: bool, } -impl<'a, 'gcx, 'tcx> Sub<'a, 'gcx, 'tcx> { - pub fn new(f: CombineFields<'a, 'gcx, 'tcx>) -> Sub<'a, 'gcx, 'tcx> { - Sub { fields: f } +impl<'combine, 'infcx, 'gcx, 'tcx> Sub<'combine, 'infcx, 'gcx, 'tcx> { + pub fn new(f: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) + -> Sub<'combine, 'infcx, 'gcx, 'tcx> + { + Sub { fields: f, a_is_expected: a_is_expected } } - pub fn obligations(self) -> PredicateObligations<'tcx> { - self.fields.obligations + fn with_expected_switched R>(&mut self, f: F) -> R { + self.a_is_expected = !self.a_is_expected; + let result = f(self); + self.a_is_expected = !self.a_is_expected; + result } } -impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Sub<'a, 'gcx, 'tcx> { +impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> + for Sub<'combine, 'infcx, 'gcx, 'tcx> +{ fn tag(&self) -> &'static str { "Sub" } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.fields.infcx.tcx } - fn a_is_expected(&self) -> bool { self.fields.a_is_expected } + fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx } + fn a_is_expected(&self) -> bool { self.a_is_expected } fn with_cause(&mut self, cause: Cause, f: F) -> R where F: FnOnce(&mut Self) -> R @@ -56,10 +63,10 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Sub<'a, 'gcx, 'tcx> { -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate().relate(a, b), + ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate().relate(a, b), - ty::Contravariant => self.fields.switch_expected().sub().relate(b, a), + ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }), } } @@ -80,12 +87,11 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Sub<'a, 'gcx, 'tcx> { } (&ty::TyInfer(TyVar(a_id)), _) => { self.fields - .switch_expected() - .instantiate(b, SupertypeOf, a_id)?; + .instantiate(b, SupertypeOf, a_id, !self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, SubtypeOf, b_id)?; + self.fields.instantiate(a, SubtypeOf, b_id, self.a_is_expected)?; Ok(a) } @@ -116,6 +122,6 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Sub<'a, 'gcx, 'tcx> { -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx> { - self.fields.higher_ranked_sub(a, b) + self.fields.higher_ranked_sub(a, b, self.a_is_expected) } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index ce3d72de9ae9..daac315e14de 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -29,7 +29,7 @@ use dep_graph::DepNode; use middle::privacy::AccessLevels; use ty::TyCtxt; use session::{config, early_error, Session}; -use lint::{Level, LevelSource, Lint, LintId, LintPass}; +use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource}; use lint::{EarlyLintPassObject, LateLintPassObject}; use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid}; use lint::builtin; @@ -45,7 +45,6 @@ use syntax_pos::Span; use errors::DiagnosticBuilder; use hir; use hir::intravisit as hir_visit; -use hir::intravisit::{IdVisitor, IdVisitingOperation}; use syntax::visit as ast_visit; /// Information about the registered lints. @@ -366,18 +365,18 @@ pub fn gather_attr(attr: &ast::Attribute) attr::mark_used(attr); let meta = &attr.node.value; - let metas = match meta.node { - ast::MetaItemKind::List(_, ref metas) => metas, - _ => { - out.push(Err(meta.span)); - return out; - } + let metas = if let Some(metas) = meta.meta_item_list() { + metas + } else { + out.push(Err(meta.span)); + return out; }; for meta in metas { - out.push(match meta.node { - ast::MetaItemKind::Word(ref lint_name) => Ok((lint_name.clone(), level, meta.span)), - _ => Err(meta.span), + out.push(if meta.is_word() { + Ok((meta.name().clone(), level, meta.span)) + } else { + Err(meta.span) }); } @@ -600,13 +599,23 @@ pub trait LintContext: Sized { }; for (lint_id, level, span) in v { - let now = self.lints().get_level_source(lint_id).0; + let (now, now_source) = self.lints().get_level_source(lint_id); if now == Forbid && level != Forbid { let lint_name = lint_id.as_str(); - span_err!(self.sess(), span, E0453, - "{}({}) overruled by outer forbid({})", - level.as_str(), lint_name, - lint_name); + let mut diag_builder = struct_span_err!(self.sess(), span, E0453, + "{}({}) overruled by outer forbid({})", + level.as_str(), lint_name, + lint_name); + match now_source { + LintSource::Default => &mut diag_builder, + LintSource::Node(forbid_source_span) => { + diag_builder.span_note(forbid_source_span, + "`forbid` lint level set here") + }, + LintSource::CommandLine => { + diag_builder.note("`forbid` lint level was set on command line") + } + }.emit() } else if now != level { let src = self.lints().get_level_source(lint_id).1; self.level_stack().push((lint_id, (now, src))); @@ -663,9 +672,11 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { } fn visit_ids(&mut self, f: F) - where F: FnOnce(&mut IdVisitor) + where F: FnOnce(&mut IdVisitor) { - let mut v = IdVisitor::new(self); + let mut v = IdVisitor { + cx: self + }; f(&mut v); } } @@ -779,7 +790,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl, body: &'v hir::Block, span: Span, id: ast::NodeId) { run_lints!(self, check_fn, late_passes, fk, decl, body, span, id); - hir_visit::walk_fn(self, fk, decl, body, span); + hir_visit::walk_fn(self, fk, decl, body, span, id); run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id); } @@ -820,7 +831,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) { run_lints!(self, check_mod, late_passes, m, s, n); - hir_visit::walk_mod(self, m); + hir_visit::walk_mod(self, m, n); run_lints!(self, check_mod_post, late_passes, m, s, n); } @@ -859,7 +870,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { self.with_lint_attrs(&trait_item.attrs, |cx| { run_lints!(cx, check_trait_item, late_passes, trait_item); - cx.visit_ids(|v| v.visit_trait_item(trait_item)); + cx.visit_ids(|v| hir_visit::walk_trait_item(v, trait_item)); hir_visit::walk_trait_item(cx, trait_item); run_lints!(cx, check_trait_item_post, late_passes, trait_item); }); @@ -868,7 +879,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { self.with_lint_attrs(&impl_item.attrs, |cx| { run_lints!(cx, check_impl_item, late_passes, impl_item); - cx.visit_ids(|v| v.visit_impl_item(impl_item)); + cx.visit_ids(|v| hir_visit::walk_impl_item(v, impl_item)); hir_visit::walk_impl_item(cx, impl_item); run_lints!(cx, check_impl_item_post, late_passes, impl_item); }); @@ -1046,16 +1057,30 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> { } } +struct IdVisitor<'a, 'b: 'a, 'tcx: 'a+'b> { + cx: &'a mut LateContext<'b, 'tcx> +} + // Output any lints that were previously added to the session. -impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> { +impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> { + fn visit_id(&mut self, id: ast::NodeId) { - if let Some(lints) = self.sess().lints.borrow_mut().remove(&id) { + if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) { debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints); for (lint_id, span, msg) in lints { - self.span_lint(lint_id.lint, span, &msg[..]) + self.cx.span_lint(lint_id.lint, span, &msg[..]) } } } + + fn visit_trait_item(&mut self, _ti: &hir::TraitItem) { + // Do not recurse into trait or impl items automatically. These are + // processed separately by calling hir_visit::walk_trait_item() + } + + fn visit_impl_item(&mut self, _ii: &hir::ImplItem) { + // See visit_trait_item() + } } enum CheckLintNameResult { @@ -1172,7 +1197,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Visit the whole crate. cx.with_lint_attrs(&krate.attrs, |cx| { - cx.visit_id(ast::CRATE_NODE_ID); cx.visit_ids(|v| { hir_visit::walk_crate(v, krate); }); diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index e856eb84ff2c..0a5f6884af9b 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -24,13 +24,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn prohibit_type_params(self, segments: &[ast::PathSegment]) { for segment in segments { for typ in segment.parameters.types() { - span_err!(self.sess, typ.span, E0109, - "type parameters are not allowed on this type"); + struct_span_err!(self.sess, typ.span, E0109, + "type parameters are not allowed on this type") + .span_label(typ.span, &format!("type parameter not allowed")) + .emit(); break; } for lifetime in segment.parameters.lifetimes() { - span_err!(self.sess, lifetime.span, E0110, - "lifetime parameters are not allowed on this type"); + struct_span_err!(self.sess, lifetime.span, E0110, + "lifetime parameters are not allowed on this type") + .span_label(lifetime.span, + &format!("lifetime parameter not allowed on this type")) + .emit(); break; } for binding in segment.parameters.bindings() { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index fd9463b13c05..32344a7b9c8d 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -44,7 +44,7 @@ use syntax::parse::token::InternedString; use syntax_pos::Span; use rustc_back::target::Target; use hir; -use hir::intravisit::{IdVisitor, IdVisitingOperation, Visitor}; +use hir::intravisit::Visitor; pub use self::DefLike::{DlDef, DlField, DlImpl}; pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown}; @@ -120,12 +120,6 @@ pub struct ChildItem { pub vis: ty::Visibility, } -pub enum FoundAst<'ast> { - Found(&'ast InlinedItem), - FoundParent(DefId, &'ast hir::Item), - NotFound, -} - #[derive(Copy, Clone, Debug)] pub struct ExternCrate { /// def_id of an `extern crate` in the current crate that caused @@ -250,7 +244,10 @@ pub trait CrateStore<'tcx> { // misc. metadata fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> FoundAst<'tcx>; + -> Option<(&'tcx InlinedItem, ast::NodeId)>; + fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option; + fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option; + fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option>; fn is_item_mir_available(&self, def: DefId) -> bool; @@ -292,11 +289,6 @@ impl InlinedItem { InlinedItem::ImplItem(_, ref ii) => visitor.visit_impl_item(ii), } } - - pub fn visit_ids(&self, operation: &mut O) { - let mut id_visitor = IdVisitor::new(operation); - self.visit(&mut id_visitor); - } } // FIXME: find a better place for this? @@ -452,7 +444,16 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // misc. metadata fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> FoundAst<'tcx> { bug!("maybe_get_item_ast") } + -> Option<(&'tcx InlinedItem, ast::NodeId)> { + bug!("maybe_get_item_ast") + } + fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option { + bug!("local_node_for_inlined_defid") + } + fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option { + bug!("defid_for_inlined_node") + } + fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { bug!("maybe_get_item_mir") } fn is_item_mir_available(&self, def: DefId) -> bool { diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 6fe98119c706..446767ecbcab 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -79,7 +79,7 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { fn visit_fn(&mut self, fn_kind: FnKind<'v>, fn_decl: &'v hir::FnDecl, - block: &'v hir::Block, span: Span, _: ast::NodeId) { + block: &'v hir::Block, span: Span, id: ast::NodeId) { let (is_item_fn, is_unsafe_fn) = match fn_kind { FnKind::ItemFn(_, _, unsafety, _, _, _, _) => @@ -96,7 +96,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { self.unsafe_context = UnsafeContext::new(SafeContext) } - intravisit::walk_fn(self, fn_kind, fn_decl, block, span); + intravisit::walk_fn(self, fn_kind, fn_decl, block, span, id); self.unsafe_context = old_unsafe_context } diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index 23a261400ed0..0a363fddd531 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -121,8 +121,11 @@ fn find_item(item: &Item, ctxt: &mut EntryContext, at_root: bool) { if ctxt.attr_main_fn.is_none() { ctxt.attr_main_fn = Some((item.id, item.span)); } else { - span_err!(ctxt.session, item.span, E0137, - "multiple functions with a #[main] attribute"); + struct_span_err!(ctxt.session, item.span, E0137, + "multiple functions with a #[main] attribute") + .span_label(item.span, &format!("additional #[main] function")) + .span_label(ctxt.attr_main_fn.unwrap().1, &format!("first #[main] function")) + .emit(); } }, EntryPointType::Start => { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 6551e0129f88..18b80a9636b4 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -271,10 +271,19 @@ enum PassArgs { impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn new(delegate: &'a mut (Delegate<'tcx>+'a), - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) + -> Self + { + ExprUseVisitor::with_options(delegate, infcx, mc::MemCategorizationOptions::default()) + } + + pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a), + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + options: mc::MemCategorizationOptions) + -> Self { ExprUseVisitor { - mc: mc::MemCategorizationContext::new(infcx), + mc: mc::MemCategorizationContext::with_options(infcx, options), delegate: delegate } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 960305e10488..a209b1d1abd7 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -359,7 +359,6 @@ language_item_table! { StartFnLangItem, "start", start_fn; EhPersonalityLangItem, "eh_personality", eh_personality; - EhPersonalityCatchLangItem, "eh_personality_catch", eh_personality_catch; EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume; MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index ea3765c76f89..1222b5f42a19 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -390,7 +390,7 @@ fn visit_fn(ir: &mut IrMaps, // gather up the various local variables, significant expressions, // and so forth: - intravisit::walk_fn(&mut fn_maps, fk, decl, body, sp); + intravisit::walk_fn(&mut fn_maps, fk, decl, body, sp, id); // Special nodes and variables: // - exit_ln represents the end of the fn, either by return or panic diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 28bfb460a14f..0bc3c1ae899d 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -259,6 +259,18 @@ impl ast_node for hir::Pat { #[derive(Copy, Clone)] pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + options: MemCategorizationOptions, +} + +#[derive(Copy, Clone, Default)] +pub struct MemCategorizationOptions { + // If true, then when analyzing a closure upvar, if the closure + // has a missing kind, we treat it like a Fn closure. When false, + // we ICE if the closure has a missing kind. Should be false + // except during closure kind inference. It is used by the + // mem-categorization code to be able to have stricter assertions + // (which are always true except during upvar inference). + pub during_closure_kind_inference: bool, } pub type McResult = Result; @@ -362,7 +374,16 @@ impl MutabilityCategory { impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> MemCategorizationContext<'a, 'gcx, 'tcx> { - MemCategorizationContext { infcx: infcx } + MemCategorizationContext::with_options(infcx, MemCategorizationOptions::default()) + } + + pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + options: MemCategorizationOptions) + -> MemCategorizationContext<'a, 'gcx, 'tcx> { + MemCategorizationContext { + infcx: infcx, + options: options, + } } fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { @@ -584,10 +605,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { self.cat_upvar(id, span, var_id, fn_node_id, kind) } None => { - span_bug!( - span, - "No closure kind for {:?}", - closure_id); + if !self.options.during_closure_kind_inference { + span_bug!( + span, + "No closure kind for {:?}", + closure_id); + } + + // during closure kind inference, we + // don't know the closure kind yet, but + // it's ok because we detect that we are + // accessing an upvar and handle that + // case specially anyhow. Use Fn + // arbitrarily. + self.cat_upvar(id, span, var_id, fn_node_id, ty::ClosureKind::Fn) } } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 36268a9de960..cbbc2c4f98f5 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -19,7 +19,7 @@ use session::Session; use lint; use middle::cstore::LOCAL_CRATE; use hir::def::Def; -use hir::def_id::{CRATE_DEF_INDEX, DefId}; +use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; use ty::{self, TyCtxt}; use middle::privacy::AccessLevels; use syntax::parse::token::InternedString; @@ -61,12 +61,46 @@ enum AnnotationKind { Container, } +/// An entry in the `depr_map`. +#[derive(Clone)] +pub struct DeprecationEntry { + /// The metadata of the attribute associated with this entry. + pub attr: Deprecation, + /// The def id where the attr was originally attached. `None` for non-local + /// `DefId`'s. + origin: Option, +} + +impl DeprecationEntry { + fn local(attr: Deprecation, id: DefId) -> DeprecationEntry { + assert!(id.is_local()); + DeprecationEntry { + attr: attr, + origin: Some(id.index), + } + } + + fn external(attr: Deprecation) -> DeprecationEntry { + DeprecationEntry { + attr: attr, + origin: None, + } + } + + pub fn same_origin(&self, other: &DeprecationEntry) -> bool { + match (self.origin, other.origin) { + (Some(o1), Some(o2)) => o1 == o2, + _ => false + } + } +} + /// A stability index, giving the stability level for items and methods. pub struct Index<'tcx> { /// This is mostly a cache, except the stabilities of local items /// are filled by the annotator. stab_map: DefIdMap>, - depr_map: DefIdMap>, + depr_map: DefIdMap>, /// Maps for each crate whether it is part of the staged API. staged_api: FnvHashMap @@ -77,7 +111,7 @@ struct Annotator<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, index: &'a mut Index<'tcx>, parent_stab: Option<&'tcx Stability>, - parent_depr: Option, + parent_depr: Option, access_levels: &'a AccessLevels, in_trait_impl: bool, } @@ -184,14 +218,15 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { // `Deprecation` is just two pointers, no need to intern it let def_id = self.tcx.map.local_def_id(id); - self.index.depr_map.insert(def_id, Some(depr.clone())); + let depr_entry = Some(DeprecationEntry::local(depr, def_id)); + self.index.depr_map.insert(def_id, depr_entry.clone()); - let orig_parent_depr = replace(&mut self.parent_depr, Some(depr)); + let orig_parent_depr = replace(&mut self.parent_depr, depr_entry); visit_children(self); self.parent_depr = orig_parent_depr; - } else if let Some(depr) = self.parent_depr.clone() { + } else if let parent_depr @ Some(_) = self.parent_depr.clone() { let def_id = self.tcx.map.local_def_id(id); - self.index.depr_map.insert(def_id, Some(depr)); + self.index.depr_map.insert(def_id, parent_depr); visit_children(self); } else { visit_children(self); @@ -351,7 +386,7 @@ struct Checker<'a, 'tcx: 'a> { impl<'a, 'tcx> Checker<'a, 'tcx> { fn check(&mut self, id: DefId, span: Span, - stab: &Option<&Stability>, _depr: &Option) { + stab: &Option<&Stability>, _depr: &Option) { if !is_staged_api(self.tcx, id) { return; } @@ -476,7 +511,7 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, warn_about_defns: bool, cb: &mut FnMut(DefId, Span, &Option<&Stability>, - &Option)) { + &Option)) { match item.node { hir::ItemExternCrate(_) => { // compiler-generated `extern crate` items have a dummy span. @@ -515,7 +550,7 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, cb: &mut FnMut(DefId, Span, &Option<&Stability>, - &Option)) { + &Option)) { let span; let id = match e.node { hir::ExprMethodCall(i, _, _) => { @@ -579,7 +614,7 @@ pub fn check_path<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, path: &hir::Path, id: ast::NodeId, cb: &mut FnMut(DefId, Span, &Option<&Stability>, - &Option)) { + &Option)) { // Paths in import prefixes may have no resolution. match tcx.expect_def_or_none(id) { Some(Def::PrimTy(..)) => {} @@ -595,7 +630,7 @@ pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::PathListItem, cb: &mut FnMut(DefId, Span, &Option<&Stability>, - &Option)) { + &Option)) { match tcx.expect_def(item.node.id()) { Def::PrimTy(..) => {} def => { @@ -607,7 +642,7 @@ pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, cb: &mut FnMut(DefId, Span, &Option<&Stability>, - &Option)) { + &Option)) { debug!("check_pat(pat = {:?})", pat); if is_internal(tcx, pat.span) { return; } @@ -638,7 +673,7 @@ fn maybe_do_stability_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId, span: Span, cb: &mut FnMut(DefId, Span, &Option<&Stability>, - &Option)) { + &Option)) { if is_internal(tcx, span) { debug!("maybe_do_stability_check: \ skipping span={:?} since it is internal", span); @@ -647,7 +682,7 @@ fn maybe_do_stability_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (stability, deprecation) = if is_staged_api(tcx, id) { (tcx.lookup_stability(id), None) } else { - (None, tcx.lookup_deprecation(id)) + (None, tcx.lookup_deprecation_entry(id)) }; debug!("maybe_do_stability_check: \ inspecting id={:?} span={:?} of stability={:?}", id, span, stability); @@ -685,6 +720,10 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { } pub fn lookup_deprecation(self, id: DefId) -> Option { + self.lookup_deprecation_entry(id).map(|depr| depr.attr) + } + + pub fn lookup_deprecation_entry(self, id: DefId) -> Option { if let Some(depr) = self.stability.borrow().depr_map.get(&id) { return depr.clone(); } @@ -703,12 +742,12 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { } } - fn lookup_deprecation_uncached(self, id: DefId) -> Option { + fn lookup_deprecation_uncached(self, id: DefId) -> Option { debug!("lookup(id={:?})", id); if id.is_local() { None // The stability cache is filled partially lazily } else { - self.sess.cstore.deprecation(id) + self.sess.cstore.deprecation(id).map(DeprecationEntry::external) } } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index ed14c1e64172..f32db9207fc6 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -30,7 +30,7 @@ use syntax::parse; use syntax::parse::token::InternedString; use syntax::feature_gate::UnstableFeatures; -use errors::{ColorConfig, Handler}; +use errors::{ColorConfig, FatalError, Handler}; use getopts; use std::collections::HashMap; @@ -61,7 +61,7 @@ pub enum DebugInfoLevel { FullDebugInfo, } -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum OutputType { Bitcode, Assembly, @@ -105,6 +105,17 @@ impl OutputType { OutputType::DepInfo => "dep-info", } } + + pub fn extension(&self) -> &'static str { + match *self { + OutputType::Bitcode => "bc", + OutputType::Assembly => "s", + OutputType::LlvmAssembly => "ll", + OutputType::Object => "o", + OutputType::DepInfo => "d", + OutputType::Exe => "", + } + } } #[derive(Clone)] @@ -219,15 +230,7 @@ impl OutputFilenames { flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf { - let extension = match flavor { - OutputType::Bitcode => "bc", - OutputType::Assembly => "s", - OutputType::LlvmAssembly => "ll", - OutputType::Object => "o", - OutputType::DepInfo => "d", - OutputType::Exe => "", - }; - + let extension = flavor.extension(); self.temp_path_ext(extension, codegen_unit_name) } @@ -331,6 +334,11 @@ impl Options { self.debugging_opts.dump_dep_graph || self.debugging_opts.query_dep_graph } + + pub fn single_codegen_unit(&self) -> bool { + self.incremental.is_none() || + self.cg.codegen_units == 1 + } } // The type of entry function, so @@ -459,6 +467,8 @@ macro_rules! options { pub const parse_bool: Option<&'static str> = None; pub const parse_opt_bool: Option<&'static str> = Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`"); + pub const parse_all_bool: Option<&'static str> = + Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`"); pub const parse_string: Option<&'static str> = Some("a string"); pub const parse_opt_string: Option<&'static str> = Some("a string"); pub const parse_list: Option<&'static str> = Some("a space-separated list of strings"); @@ -508,6 +518,25 @@ macro_rules! options { } } + fn parse_all_bool(slot: &mut bool, v: Option<&str>) -> bool { + match v { + Some(s) => { + match s { + "n" | "no" | "off" => { + *slot = false; + } + "y" | "yes" | "on" => { + *slot = true; + } + _ => { return false; } + } + + true + }, + None => { *slot = true; true } + } + } + fn parse_opt_string(slot: &mut Option, v: Option<&str>) -> bool { match v { Some(s) => { *slot = Some(s.to_string()); true }, @@ -656,7 +685,6 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "panic strategy to compile crate with"), } - options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, build_debugging_options, "Z", "debugging", DB_OPTIONS, db_type_desc, dbsetters, @@ -751,7 +779,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "set the MIR optimization level (0-3)"), dump_mir: Option = (None, parse_opt_string, "dump MIR state at various points in translation"), - orbit: bool = (false, parse_bool, + dump_mir_dir: Option = (None, parse_opt_string, + "the directory the MIR is dumped into"), + orbit: bool = (true, parse_all_bool, "get MIR where it belongs - everywhere; most importantly, in orbit"), } @@ -835,7 +865,10 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config { let target = match Target::search(&opts.target_triple) { Ok(t) => t, Err(e) => { - panic!(sp.fatal(&format!("Error loading target specification: {}", e))); + sp.struct_fatal(&format!("Error loading target specification: {}", e)) + .help("Use `--print target-list` for a list of built-in targets") + .emit(); + panic!(FatalError); } }; @@ -1140,7 +1173,15 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { }) }); - let debugging_opts = build_debugging_options(matches, error_format); + let mut debugging_opts = build_debugging_options(matches, error_format); + + // Incremental compilation only works reliably when translation is done via + // MIR, so let's enable -Z orbit if necessary (see #34973). + if debugging_opts.incremental.is_some() && !debugging_opts.orbit { + early_warn(error_format, "Automatically enabling `-Z orbit` because \ + `-Z incremental` was specified"); + debugging_opts.orbit = true; + } let parse_only = debugging_opts.parse_only; let no_trans = debugging_opts.no_trans; diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index fa9bc7c83680..cee18232ec98 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -80,7 +80,7 @@ pub struct Session { // forms a unique global identifier for the crate. It is used to allow // multiple crates with the same name to coexist. See the // trans::back::symbol_names module for more information. - pub crate_disambiguator: Cell, + pub crate_disambiguator: RefCell, pub features: RefCell, /// The maximum recursion limit for potentially infinitely recursive @@ -106,6 +106,9 @@ pub struct Session { } impl Session { + pub fn local_crate_disambiguator(&self) -> token::InternedString { + self.crate_disambiguator.borrow().clone() + } pub fn struct_span_warn<'a, S: Into>(&'a self, sp: S, msg: &str) @@ -126,20 +129,14 @@ impl Session { sp: S, msg: &str) -> DiagnosticBuilder<'a> { - match split_msg_into_multilines(msg) { - Some(ref msg) => self.diagnostic().struct_span_err(sp, msg), - None => self.diagnostic().struct_span_err(sp, msg), - } + self.diagnostic().struct_span_err(sp, msg) } pub fn struct_span_err_with_code<'a, S: Into>(&'a self, sp: S, msg: &str, code: &str) -> DiagnosticBuilder<'a> { - match split_msg_into_multilines(msg) { - Some(ref msg) => self.diagnostic().struct_span_err_with_code(sp, msg, code), - None => self.diagnostic().struct_span_err_with_code(sp, msg, code), - } + self.diagnostic().struct_span_err_with_code(sp, msg, code) } pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { self.diagnostic().struct_err(msg) @@ -178,16 +175,10 @@ impl Session { } } pub fn span_err>(&self, sp: S, msg: &str) { - match split_msg_into_multilines(msg) { - Some(msg) => self.diagnostic().span_err(sp, &msg), - None => self.diagnostic().span_err(sp, msg) - } + self.diagnostic().span_err(sp, msg) } pub fn span_err_with_code>(&self, sp: S, msg: &str, code: &str) { - match split_msg_into_multilines(msg) { - Some(msg) => self.diagnostic().span_err_with_code(sp, &msg, code), - None => self.diagnostic().span_err_with_code(sp, msg, code) - } + self.diagnostic().span_err_with_code(sp, &msg, code) } pub fn err(&self, msg: &str) { self.diagnostic().err(msg) @@ -343,67 +334,6 @@ impl Session { } } -fn split_msg_into_multilines(msg: &str) -> Option { - // Conditions for enabling multi-line errors: - if !msg.contains("mismatched types") && - !msg.contains("type mismatch resolving") && - !msg.contains("if and else have incompatible types") && - !msg.contains("if may be missing an else clause") && - !msg.contains("match arms have incompatible types") && - !msg.contains("structure constructor specifies a structure of type") && - !msg.contains("has an incompatible type for trait") { - return None - } - let first = msg.match_indices("expected").filter(|s| { - let last = msg[..s.0].chars().rev().next(); - last == Some(' ') || last == Some('(') - }).map(|(a, b)| (a - 1, a + b.len())); - let second = msg.match_indices("found").filter(|s| { - msg[..s.0].chars().rev().next() == Some(' ') - }).map(|(a, b)| (a - 1, a + b.len())); - - let mut new_msg = String::new(); - let mut head = 0; - - // Insert `\n` before expected and found. - for (pos1, pos2) in first.zip(second) { - new_msg = new_msg + - // A `(` may be preceded by a space and it should be trimmed - msg[head..pos1.0].trim_right() + // prefix - "\n" + // insert before first - &msg[pos1.0..pos1.1] + // insert what first matched - &msg[pos1.1..pos2.0] + // between matches - "\n " + // insert before second - // 123 - // `expected` is 3 char longer than `found`. To align the types, - // `found` gets 3 spaces prepended. - &msg[pos2.0..pos2.1]; // insert what second matched - - head = pos2.1; - } - - let mut tail = &msg[head..]; - let third = tail.find("(values differ") - .or(tail.find("(lifetime")) - .or(tail.find("(cyclic type of infinite size")); - // Insert `\n` before any remaining messages which match. - if let Some(pos) = third { - // The end of the message may just be wrapped in `()` without - // `expected`/`found`. Push this also to a new line and add the - // final tail after. - new_msg = new_msg + - // `(` is usually preceded by a space and should be trimmed. - tail[..pos].trim_right() + // prefix - "\n" + // insert before paren - &tail[pos..]; // append the tail - - tail = ""; - } - - new_msg.push_str(tail); - return Some(new_msg); -} - pub fn build_session(sopts: config::Options, dep_graph: &DepGraph, local_crate_source_file: Option, @@ -511,7 +441,7 @@ pub fn build_session_(sopts: config::Options, plugin_attributes: RefCell::new(Vec::new()), crate_types: RefCell::new(Vec::new()), dependency_formats: RefCell::new(FnvHashMap()), - crate_disambiguator: Cell::new(token::intern("")), + crate_disambiguator: RefCell::new(token::intern("").as_str()), features: RefCell::new(feature_gate::Features::new()), recursion_limit: Cell::new(64), next_node_id: Cell::new(1), diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 3b9ecb882585..67ad887530eb 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -26,8 +26,9 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; -use infer::{InferCtxt}; +use infer::{self, InferCtxt, TypeOrigin}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; use ty::subst::{self, Subst, TypeSpace}; @@ -107,24 +108,63 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let predicate = self.resolve_type_vars_if_possible(&obligation.predicate); - if !predicate.references_error() { - if let Some(warning_node_id) = warning_node_id { - self.tcx.sess.add_lint( - ::lint::builtin::UNSIZED_IN_TUPLE, - warning_node_id, - obligation.cause.span, - format!("type mismatch resolving `{}`: {}", - predicate, - error.err)); - } else { - let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, - "type mismatch resolving `{}`: {}", - predicate, - error.err); - self.note_obligation_cause(&mut err, obligation); - err.emit(); - } + if predicate.references_error() { + return } + if let Some(warning_node_id) = warning_node_id { + self.tcx.sess.add_lint( + ::lint::builtin::UNSIZED_IN_TUPLE, + warning_node_id, + obligation.cause.span, + format!("type mismatch resolving `{}`: {}", + predicate, + error.err)); + return + } + self.probe(|_| { + let origin = TypeOrigin::Misc(obligation.cause.span); + let err_buf; + let mut err = &error.err; + let mut values = None; + + // try to find the mismatched types to report the error with. + // + // this can fail if the problem was higher-ranked, in which + // cause I have no idea for a good error message. + if let ty::Predicate::Projection(ref data) = predicate { + let mut selcx = SelectionContext::new(self); + let (data, _) = self.replace_late_bound_regions_with_fresh_var( + obligation.cause.span, + infer::LateBoundRegionConversionTime::HigherRankedType, + data); + let normalized = super::normalize_projection_type( + &mut selcx, + data.projection_ty, + obligation.cause.clone(), + 0 + ); + let origin = TypeOrigin::Misc(obligation.cause.span); + if let Err(error) = self.eq_types( + false, origin, + data.ty, normalized.value + ) { + values = Some(infer::ValuePairs::Types(ExpectedFound { + expected: normalized.value, + found: data.ty, + })); + err_buf = error; + err = &err_buf; + } + } + + let mut diag = struct_span_err!( + self.tcx.sess, origin.span(), E0271, + "type mismatch resolving `{}`", predicate + ); + self.note_type_err(&mut diag, origin, values, err); + self.note_obligation_cause(&mut diag, obligation); + diag.emit(); + }); } fn impl_substs(&self, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 56938a7a8385..5444dd947612 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -504,7 +504,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn crate_disambiguator(self, cnum: ast::CrateNum) -> token::InternedString { if cnum == LOCAL_CRATE { - self.sess.crate_disambiguator.get().as_str() + self.sess.local_crate_disambiguator() } else { self.sess.cstore.crate_disambiguator(cnum) } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 1e2920ca87ea..16a54c20925d 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -1018,3 +1018,16 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeScheme<'tcx> { self.generics.visit_with(visitor) || self.ty.visit_with(visitor) } } + +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::error::ExpectedFound { + expected: self.expected.fold_with(folder), + found: self.found.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.expected.visit_with(visitor) || self.found.visit_with(visitor) + } +} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 21c14e6fe4c3..fadf36471555 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -182,6 +182,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pat_util::arm_contains_ref_binding(arm) } + pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { + match ty.sty { + ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + for field in def.all_fields() { + let field_ty = field.ty(self, substs); + if let TyError = field_ty.sty { + return true; + } + } + } + _ => () + } + false + } + /// Returns the type of element at index `i` in tuple or tuple-like type `t`. /// For an enum `t`, `variant` is None only if `t` is a univariant enum. pub fn positional_element_ty(self, diff --git a/src/librustc/util/fs.rs b/src/librustc/util/fs.rs index 4936e049ef2e..f4e1c06090e5 100644 --- a/src/librustc/util/fs.rs +++ b/src/librustc/util/fs.rs @@ -10,6 +10,8 @@ use std::path::{self, Path, PathBuf}; use std::ffi::OsString; +use std::fs; +use std::io; // Unfortunately, on windows, it looks like msvcrt.dll is silently translating // verbatim paths under the hood to non-verbatim paths! This manifests itself as @@ -53,3 +55,15 @@ pub fn fix_windows_verbatim_for_gcc(p: &Path) -> PathBuf { _ => p.to_path_buf(), } } + +/// Copy `p` into `q`, preferring to use hard-linking if possible. If +/// `q` already exists, it is removed first. +pub fn link_or_copy, Q: AsRef>(p: P, q: Q) -> io::Result<()> { + let p = p.as_ref(); + let q = q.as_ref(); + if q.exists() { + try!(fs::remove_file(&q)); + } + fs::hard_link(p, q) + .or_else(|_| fs::copy(p, q).map(|_| ())) +} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 0bfb7c1ed553..60977a80946f 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -974,7 +974,9 @@ impl fmt::Display for ty::InferTy { ty::TyVar(ref vid) if print_var_ids => write!(f, "{:?}", vid), ty::IntVar(ref vid) if print_var_ids => write!(f, "{:?}", vid), ty::FloatVar(ref vid) if print_var_ids => write!(f, "{:?}", vid), - ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => write!(f, "_"), + ty::TyVar(_) => write!(f, "_"), + ty::IntVar(_) => write!(f, "{}", "{integer}"), + ty::FloatVar(_) => write!(f, "{}", "{float}"), ty::FreshTy(v) => write!(f, "FreshTy({})", v), ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v), ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v) diff --git a/src/librustc_back/target/aarch64_apple_ios.rs b/src/librustc_back/target/aarch64_apple_ios.rs index 481338d1cee5..6530ccb0630d 100644 --- a/src/librustc_back/target/aarch64_apple_ios.rs +++ b/src/librustc_back/target/aarch64_apple_ios.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + let base = try!(opts(Arch::Arm64)); + Ok(Target { llvm_target: "arm64-apple-ios".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -25,7 +26,7 @@ pub fn target() -> Target { features: "+neon,+fp-armv8,+cyclone".to_string(), eliminate_frame_pointer: false, max_atomic_width: 128, - .. opts(Arch::Arm64) + .. base }, - } + }) } diff --git a/src/librustc_back/target/aarch64_linux_android.rs b/src/librustc_back/target/aarch64_linux_android.rs index 81be546e0c89..7f54dab5b538 100644 --- a/src/librustc_back/target/aarch64_linux_android.rs +++ b/src/librustc_back/target/aarch64_linux_android.rs @@ -8,23 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::android_base::opts(); base.max_atomic_width = 128; // As documented in http://developer.android.com/ndk/guides/cpu-features.html // the neon (ASIMD) and FP must exist on all android aarch64 targets. base.features = "+neon,+fp-armv8".to_string(); - Target { + Ok(Target { llvm_target: "aarch64-linux-android".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), - data_layout: "e-m:e-i64:64-i128:128-n32:64-S128".to_string(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs index aec1bae60c81..cca965f9d4ff 100644 --- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs @@ -8,20 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.max_atomic_width = 128; - Target { + Ok(Target { llvm_target: "aarch64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), target_env: "gnu".to_string(), - data_layout: "e-m:e-i64:64-i128:128-n32:64-S128".to_string(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), target_os: "linux".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/apple_ios_base.rs b/src/librustc_back/target/apple_ios_base.rs index d182fd960564..8bd9feabdbeb 100644 --- a/src/librustc_back/target/apple_ios_base.rs +++ b/src/librustc_back/target/apple_ios_base.rs @@ -36,7 +36,7 @@ impl Arch { } } -pub fn get_sdk_root(sdk_name: &str) -> String { +pub fn get_sdk_root(sdk_name: &str) -> Result { let res = Command::new("xcrun") .arg("--show-sdk-path") .arg("-sdk") @@ -55,12 +55,12 @@ pub fn get_sdk_root(sdk_name: &str) -> String { }); match res { - Ok(output) => output.trim().to_string(), - Err(e) => panic!("failed to get {} SDK path: {}", sdk_name, e) + Ok(output) => Ok(output.trim().to_string()), + Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)) } } -fn pre_link_args(arch: Arch) -> Vec { +fn build_pre_link_args(arch: Arch) -> Result, String> { let sdk_name = match arch { Armv7 | Armv7s | Arm64 => "iphoneos", I386 | X86_64 => "iphonesimulator" @@ -68,8 +68,10 @@ fn pre_link_args(arch: Arch) -> Vec { let arch_name = arch.to_string(); - vec!["-arch".to_string(), arch_name.to_string(), - "-Wl,-syslibroot".to_string(), get_sdk_root(sdk_name)] + let sdk_root = try!(get_sdk_root(sdk_name)); + + Ok(vec!["-arch".to_string(), arch_name.to_string(), + "-Wl,-syslibroot".to_string(), sdk_root]) } fn target_cpu(arch: Arch) -> String { @@ -82,13 +84,14 @@ fn target_cpu(arch: Arch) -> String { }.to_string() } -pub fn opts(arch: Arch) -> TargetOptions { - TargetOptions { +pub fn opts(arch: Arch) -> Result { + let pre_link_args = try!(build_pre_link_args(arch)); + Ok(TargetOptions { cpu: target_cpu(arch), dynamic_linking: false, executables: true, - pre_link_args: pre_link_args(arch), + pre_link_args: pre_link_args, has_elf_tls: false, .. super::apple_base::opts() - } + }) } diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs index e1b170422c60..f3a18b13c678 100644 --- a/src/librustc_back/target/arm_linux_androideabi.rs +++ b/src/librustc_back/target/arm_linux_androideabi.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::android_base::opts(); base.features = "+v7,+vfp3,+d16".to_string(); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "arm-linux-androideabi".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -25,5 +25,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs index 60c4a7c3c90c..e666a8460e5e 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "arm-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -27,5 +27,5 @@ pub fn target() -> Target { features: "+v6".to_string(), .. base }, - } + }) } diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs index 72128e30641c..d65c89abc206 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "arm-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -27,5 +27,5 @@ pub fn target() -> Target { features: "+v6,+vfp2".to_string(), .. base } - } + }) } diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_back/target/arm_unknown_linux_musleabi.rs new file mode 100644 index 000000000000..028c91eadaeb --- /dev/null +++ b/src/librustc_back/target/arm_unknown_linux_musleabi.rs @@ -0,0 +1,34 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::linux_musl_base::opts(); + + // Most of these settings are copied from the arm_unknown_linux_gnueabi + // target. + base.features = "+v6".to_string(); + base.max_atomic_width = 64; + Ok(Target { + // It's important we use "gnueabi" and not "musleabi" here. LLVM uses it + // to determine the calling convention and float ABI, and it doesn't + // support the "musleabi" value. + llvm_target: "arm-unknown-linux-gnueabi".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "linux".to_string(), + target_env: "musl".to_string(), + target_vendor: "unknown".to_string(), + options: base, + }) +} diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs new file mode 100644 index 000000000000..c7dda186f425 --- /dev/null +++ b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs @@ -0,0 +1,34 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::linux_musl_base::opts(); + + // Most of these settings are copied from the arm_unknown_linux_gnueabihf + // target. + base.features = "+v6,+vfp2".to_string(); + base.max_atomic_width = 64; + Ok(Target { + // It's important we use "gnueabihf" and not "musleabihf" here. LLVM + // uses it to determine the calling convention and float ABI, and it + // doesn't support the "musleabihf" value. + llvm_target: "arm-unknown-linux-gnueabihf".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "linux".to_string(), + target_env: "musl".to_string(), + target_vendor: "unknown".to_string(), + options: base, + }) +} diff --git a/src/librustc_back/target/armv7_apple_ios.rs b/src/librustc_back/target/armv7_apple_ios.rs index a2486a1330a5..a806204d0a6b 100644 --- a/src/librustc_back/target/armv7_apple_ios.rs +++ b/src/librustc_back/target/armv7_apple_ios.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + let base = try!(opts(Arch::Armv7)); + Ok(Target { llvm_target: "armv7-apple-ios".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -24,7 +25,7 @@ pub fn target() -> Target { options: TargetOptions { features: "+v7,+vfp3,+neon".to_string(), max_atomic_width: 64, - .. opts(Arch::Armv7) + .. base } - } + }) } diff --git a/src/librustc_back/target/armv7_linux_androideabi.rs b/src/librustc_back/target/armv7_linux_androideabi.rs index fd8f35da16f6..1c59262e0419 100644 --- a/src/librustc_back/target/armv7_linux_androideabi.rs +++ b/src/librustc_back/target/armv7_linux_androideabi.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::android_base::opts(); base.features = "+v7,+thumb2,+vfp3,+d16".to_string(); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "armv7-none-linux-android".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -25,5 +25,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs index 7bcca3a3934b..52269f0cd4a0 100644 --- a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let base = super::linux_base::opts(); - Target { + Ok(Target { llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -28,6 +28,6 @@ pub fn target() -> Target { max_atomic_width: 64, .. base } - } + }) } diff --git a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs new file mode 100644 index 000000000000..e40704e5d499 --- /dev/null +++ b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs @@ -0,0 +1,35 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::linux_musl_base::opts(); + + // Most of these settings are copied from the armv7_unknown_linux_gnueabihf + // target. + base.features = "+v7,+vfp3,+neon".to_string(); + base.cpu = "cortex-a8".to_string(); + base.max_atomic_width = 64; + Ok(Target { + // It's important we use "gnueabihf" and not "musleabihf" here. LLVM + // uses it to determine the calling convention and float ABI, and LLVM + // doesn't support the "musleabihf" value. + llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + target_os: "linux".to_string(), + target_env: "musl".to_string(), + target_vendor: "unknown".to_string(), + options: base, + }) +} diff --git a/src/librustc_back/target/armv7s_apple_ios.rs b/src/librustc_back/target/armv7s_apple_ios.rs index e5379aa1b42c..aaa3570fa62e 100644 --- a/src/librustc_back/target/armv7s_apple_ios.rs +++ b/src/librustc_back/target/armv7s_apple_ios.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + let base = try!(opts(Arch::Armv7s)); + Ok(Target { llvm_target: "armv7s-apple-ios".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -24,7 +25,7 @@ pub fn target() -> Target { options: TargetOptions { features: "+v7,+vfp4,+neon".to_string(), max_atomic_width: 64, - .. opts(Arch::Armv7s) + .. base } - } + }) } diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs index e6200177944b..07eb191471c4 100644 --- a/src/librustc_back/target/asmjs_unknown_emscripten.rs +++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs @@ -10,7 +10,7 @@ use super::{Target, TargetOptions}; -pub fn target() -> Target { +pub fn target() -> Result { let opts = TargetOptions { linker: "emcc".to_string(), ar: "emar".to_string(), @@ -25,7 +25,7 @@ pub fn target() -> Target { max_atomic_width: 32, .. Default::default() }; - Target { + Ok(Target { llvm_target: "asmjs-unknown-emscripten".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -35,5 +35,5 @@ pub fn target() -> Target { data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(), arch: "asmjs".to_string(), options: opts, - } + }) } diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs index cf4020eeb587..f391d4118ea7 100644 --- a/src/librustc_back/target/i386_apple_ios.rs +++ b/src/librustc_back/target/i386_apple_ios.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + let base = try!(opts(Arch::I386)); + Ok(Target { llvm_target: "i386-apple-ios".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -23,7 +24,7 @@ pub fn target() -> Target { target_vendor: "apple".to_string(), options: TargetOptions { max_atomic_width: 64, - .. opts(Arch::I386) + .. base } - } + }) } diff --git a/src/librustc_back/target/i586_pc_windows_msvc.rs b/src/librustc_back/target/i586_pc_windows_msvc.rs index 12bed370eae9..445ee6c41228 100644 --- a/src/librustc_back/target/i586_pc_windows_msvc.rs +++ b/src/librustc_back/target/i586_pc_windows_msvc.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::TargetResult; -pub fn target() -> Target { - let mut base = super::i686_pc_windows_msvc::target(); +pub fn target() -> TargetResult { + let mut base = try!(super::i686_pc_windows_msvc::target()); base.options.cpu = "pentium".to_string(); base.llvm_target = "i586-pc-windows-msvc".to_string(); - return base + Ok(base) } diff --git a/src/librustc_back/target/i586_unknown_linux_gnu.rs b/src/librustc_back/target/i586_unknown_linux_gnu.rs index 6eb645563819..1ca8606149bf 100644 --- a/src/librustc_back/target/i586_unknown_linux_gnu.rs +++ b/src/librustc_back/target/i586_unknown_linux_gnu.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::TargetResult; -pub fn target() -> Target { - let mut base = super::i686_unknown_linux_gnu::target(); +pub fn target() -> TargetResult { + let mut base = try!(super::i686_unknown_linux_gnu::target()); base.options.cpu = "pentium".to_string(); base.llvm_target = "i586-unknown-linux-gnu".to_string(); - return base + Ok(base) } diff --git a/src/librustc_back/target/i686_apple_darwin.rs b/src/librustc_back/target/i686_apple_darwin.rs index 302691e9a592..4876a3489d47 100644 --- a/src/librustc_back/target/i686_apple_darwin.rs +++ b/src/librustc_back/target/i686_apple_darwin.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::apple_base::opts(); base.cpu = "yonah".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m32".to_string()); - Target { + Ok(Target { llvm_target: "i686-apple-darwin".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "apple".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/i686_linux_android.rs b/src/librustc_back/target/i686_linux_android.rs index 2376de123980..1de629238a13 100644 --- a/src/librustc_back/target/i686_linux_android.rs +++ b/src/librustc_back/target/i686_linux_android.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::android_base::opts(); base.max_atomic_width = 64; @@ -19,7 +19,7 @@ pub fn target() -> Target { base.cpu = "pentiumpro".to_string(); base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string(); - Target { + Ok(Target { llvm_target: "i686-linux-android".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -29,5 +29,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_back/target/i686_pc_windows_gnu.rs index c2cc624c9f9e..2c19b8109c36 100644 --- a/src/librustc_back/target/i686_pc_windows_gnu.rs +++ b/src/librustc_back/target/i686_pc_windows_gnu.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::windows_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = 64; @@ -19,7 +19,7 @@ pub fn target() -> Target { // space available to x86 Windows binaries on x86_64. base.pre_link_args.push("-Wl,--large-address-aware".to_string()); - Target { + Ok(Target { llvm_target: "i686-pc-windows-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -29,5 +29,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "pc".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/i686_pc_windows_msvc.rs b/src/librustc_back/target/i686_pc_windows_msvc.rs index 8c1bacc28076..cb02fcc308c2 100644 --- a/src/librustc_back/target/i686_pc_windows_msvc.rs +++ b/src/librustc_back/target/i686_pc_windows_msvc.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::windows_msvc_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = 64; @@ -24,7 +24,7 @@ pub fn target() -> Target { // https://msdn.microsoft.com/en-us/library/9a89h429.aspx base.pre_link_args.push("/SAFESEH".to_string()); - Target { + Ok(Target { llvm_target: "i686-pc-windows-msvc".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -34,5 +34,5 @@ pub fn target() -> Target { target_env: "msvc".to_string(), target_vendor: "pc".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/i686_unknown_dragonfly.rs b/src/librustc_back/target/i686_unknown_dragonfly.rs index 6446ac45f7d6..f96ec004b481 100644 --- a/src/librustc_back/target/i686_unknown_dragonfly.rs +++ b/src/librustc_back/target/i686_unknown_dragonfly.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m32".to_string()); - Target { + Ok(Target { llvm_target: "i686-unknown-dragonfly".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/i686_unknown_freebsd.rs b/src/librustc_back/target/i686_unknown_freebsd.rs index a7903d5db641..3489ecfe614d 100644 --- a/src/librustc_back/target/i686_unknown_freebsd.rs +++ b/src/librustc_back/target/i686_unknown_freebsd.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m32".to_string()); - Target { + Ok(Target { llvm_target: "i686-unknown-freebsd".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/i686_unknown_linux_gnu.rs b/src/librustc_back/target/i686_unknown_linux_gnu.rs index 7813d5570762..f2e865c015e3 100644 --- a/src/librustc_back/target/i686_unknown_linux_gnu.rs +++ b/src/librustc_back/target/i686_unknown_linux_gnu.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m32".to_string()); - Target { + Ok(Target { llvm_target: "i686-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/i686_unknown_linux_musl.rs b/src/librustc_back/target/i686_unknown_linux_musl.rs index 527442958374..a0a8de46e2f5 100644 --- a/src/librustc_back/target/i686_unknown_linux_musl.rs +++ b/src/librustc_back/target/i686_unknown_linux_musl.rs @@ -8,16 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m32".to_string()); base.pre_link_args.push("-Wl,-melf_i386".to_string()); - Target { + Ok(Target { llvm_target: "i686-unknown-linux-musl".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -27,5 +27,5 @@ pub fn target() -> Target { target_env: "musl".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/le32_unknown_nacl.rs b/src/librustc_back/target/le32_unknown_nacl.rs index f4f0262d476d..25132f8a044d 100644 --- a/src/librustc_back/target/le32_unknown_nacl.rs +++ b/src/librustc_back/target/le32_unknown_nacl.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{Target, TargetOptions}; +use super::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let opts = TargetOptions { linker: "pnacl-clang".to_string(), ar: "pnacl-ar".to_string(), @@ -28,7 +28,7 @@ pub fn target() -> Target { max_atomic_width: 32, .. Default::default() }; - Target { + Ok(Target { llvm_target: "le32-unknown-nacl".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -38,5 +38,5 @@ pub fn target() -> Target { data_layout: "e-i64:64:64-p:32:32:32-v128:32:32".to_string(), arch: "le32".to_string(), options: opts, - } + }) } diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs index 794e4d4996c9..ab967f6b40fb 100644 --- a/src/librustc_back/target/mips_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + Ok(Target { llvm_target: "mips-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), target_pointer_width: "32".to_string(), @@ -22,9 +22,9 @@ pub fn target() -> Target { target_vendor: "unknown".to_string(), options: TargetOptions { cpu: "mips32r2".to_string(), - features: "+mips32r2,+soft-float".to_string(), + features: "+mips32r2".to_string(), max_atomic_width: 32, ..super::linux_base::opts() }, - } + }) } diff --git a/src/librustc_back/target/mips_unknown_linux_musl.rs b/src/librustc_back/target/mips_unknown_linux_musl.rs index 35366659d581..4a69bce53bc9 100644 --- a/src/librustc_back/target/mips_unknown_linux_musl.rs +++ b/src/librustc_back/target/mips_unknown_linux_musl.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + Ok(Target { llvm_target: "mips-unknown-linux-musl".to_string(), target_endian: "big".to_string(), target_pointer_width: "32".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { max_atomic_width: 32, ..super::linux_base::opts() } - } + }) } diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs index ac1536b3d009..b66fb62cd591 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + Ok(Target { llvm_target: "mipsel-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -27,5 +27,5 @@ pub fn target() -> Target { max_atomic_width: 32, ..super::linux_base::opts() }, - } + }) } diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_back/target/mipsel_unknown_linux_musl.rs index a9ea52c42786..a0524e5e7638 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_musl.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + Ok(Target { llvm_target: "mipsel-unknown-linux-musl".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), @@ -22,9 +22,9 @@ pub fn target() -> Target { target_vendor: "unknown".to_string(), options: TargetOptions { cpu: "mips32".to_string(), - features: "+mips32".to_string(), + features: "+mips32,+soft-float".to_string(), max_atomic_width: 32, ..super::linux_base::opts() } - } + }) } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 2163a8a1689b..3d24fd8ab67e 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -44,7 +44,8 @@ //! the target's settings, though `target-feature` and `link-args` will *add* //! to the list specified by the target, rather than replace. -use serialize::json::Json; +use serialize::json::{Json, ToJson}; +use std::collections::BTreeMap; use std::default::Default; use std::io::prelude::*; use syntax::abi::Abi; @@ -63,27 +64,61 @@ mod solaris_base; mod windows_base; mod windows_msvc_base; +pub type TargetResult = Result; + macro_rules! supported_targets { ( $(($triple:expr, $module:ident)),+ ) => ( $(mod $module;)* /// List of supported targets - pub const TARGETS: &'static [&'static str] = &[$($triple),*]; + const TARGETS: &'static [&'static str] = &[$($triple),*]; + + fn load_specific(target: &str) -> TargetResult { + match target { + $( + $triple => { + let mut t = try!($module::target()); + t.options.is_builtin = true; + + // round-trip through the JSON parser to ensure at + // run-time that the parser works correctly + t = try!(Target::from_json(t.to_json())); + debug!("Got builtin target: {:?}", t); + Ok(t) + }, + )+ + _ => Err(format!("Unable to find target: {}", target)) + } + } + + pub fn get_targets() -> Box> { + Box::new(TARGETS.iter().filter_map(|t| -> Option { + load_specific(t) + .map(|t| t.llvm_target) + .ok() + })) + } + + #[cfg(test)] + mod test_json_encode_decode { + use serialize::json::ToJson; + use super::Target; + $(use super::$module;)* - // this would use a match if stringify! were allowed in pattern position - fn load_specific(target: &str) -> Option { - let target = target.replace("-", "_"); - if false { } $( - else if target == stringify!($module) { - let mut t = $module::target(); - t.options.is_builtin = true; - debug!("Got builtin target: {:?}", t); - return Some(t); + #[test] + fn $module() { + // Grab the TargetResult struct. If we successfully retrieved + // a Target, then the test JSON encoding/decoding can run for this + // Target on this testing platform (i.e., checking the iOS targets + // only on a Mac test platform). + let _ = $module::target().map(|original| { + let as_json = original.to_json(); + let parsed = Target::from_json(as_json).unwrap(); + assert_eq!(original, parsed); + }); } )* - - None } ) } @@ -99,7 +134,10 @@ supported_targets! { ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu), ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi), ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf), + ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi), + ("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf), ("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf), + ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf), ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu), ("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl), ("i686-unknown-linux-musl", i686_unknown_linux_musl), @@ -147,7 +185,7 @@ supported_targets! { /// Everything `rustc` knows about how to compile for a specific target. /// /// Every field here must be specified, and has no default value. -#[derive(Clone, Debug)] +#[derive(PartialEq, Clone, Debug)] pub struct Target { /// Target triple to pass to LLVM. pub llvm_target: String, @@ -174,7 +212,7 @@ pub struct Target { /// /// This has an implementation of `Default`, see each field for what the default is. In general, /// these try to take "minimal defaults" that don't assume anything about the runtime they run in. -#[derive(Clone, Debug)] +#[derive(PartialEq, Clone, Debug)] pub struct TargetOptions { /// Whether the target is built-in or loaded from a custom target specification. pub is_builtin: bool, @@ -254,6 +292,13 @@ pub struct TargetOptions { pub is_like_android: bool, /// Whether the linker support GNU-like arguments such as -O. Defaults to false. pub linker_is_gnu: bool, + /// The MinGW toolchain has a known issue that prevents it from correctly + /// handling COFF object files with more than 2^15 sections. Since each weak + /// symbol needs its own COMDAT section, weak linkage implies a large + /// number sections that easily exceeds the given limit for larger + /// codebases. Consequently we want a way to disallow weak linkage on some + /// platforms. + pub allows_weak_linkage: bool, /// Whether the linker support rpaths or not. Defaults to false. pub has_rpath: bool, /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM @@ -329,6 +374,7 @@ impl Default for TargetOptions { is_like_android: false, is_like_msvc: false, linker_is_gnu: false, + allows_weak_linkage: true, has_rpath: false, no_compiler_rt: false, no_default_libraries: true, @@ -365,16 +411,21 @@ impl Target { } /// Load a target descriptor from a JSON object. - pub fn from_json(obj: Json) -> Target { - // this is 1. ugly, 2. error prone. + pub fn from_json(obj: Json) -> TargetResult { + // While ugly, this code must remain this way to retain + // compatibility with existing JSON fields and the internal + // expected naming of the Target and TargetOptions structs. + // To ensure compatibility is retained, the built-in targets + // are round-tripped through this code to catch cases where + // the JSON parser is not updated to match the structs. let get_req_field = |name: &str| { match obj.find(name) .map(|s| s.as_string()) .and_then(|os| os.map(|s| s.to_string())) { - Some(val) => val, + Some(val) => Ok(val), None => { - panic!("Field {} in target specification is required", name) + return Err(format!("Field {} in target specification is required", name)) } } }; @@ -386,12 +437,12 @@ impl Target { }; let mut base = Target { - llvm_target: get_req_field("llvm-target"), - target_endian: get_req_field("target-endian"), - target_pointer_width: get_req_field("target-pointer-width"), - data_layout: get_req_field("data-layout"), - arch: get_req_field("arch"), - target_os: get_req_field("os"), + llvm_target: try!(get_req_field("llvm-target")), + target_endian: try!(get_req_field("target-endian")), + target_pointer_width: try!(get_req_field("target-pointer-width")), + data_layout: try!(get_req_field("data-layout")), + arch: try!(get_req_field("arch")), + target_os: try!(get_req_field("os")), target_env: get_opt_field("env", ""), target_vendor: get_opt_field("vendor", "unknown"), options: Default::default(), @@ -436,38 +487,51 @@ impl Target { } ); } - key!(cpu); - key!(ar); + key!(is_builtin, bool); key!(linker); + key!(ar); + key!(pre_link_args, list); + key!(pre_link_objects_exe, list); + key!(pre_link_objects_dll, list); + key!(late_link_args, list); + key!(post_link_objects, list); + key!(post_link_args, list); + key!(cpu); + key!(features); + key!(dynamic_linking, bool); + key!(executables, bool); key!(relocation_model); key!(code_model); + key!(disable_redzone, bool); + key!(eliminate_frame_pointer, bool); + key!(function_sections, bool); key!(dll_prefix); key!(dll_suffix); key!(exe_suffix); key!(staticlib_prefix); key!(staticlib_suffix); - key!(features); - key!(dynamic_linking, bool); - key!(executables, bool); - key!(disable_redzone, bool); - key!(eliminate_frame_pointer, bool); - key!(function_sections, bool); key!(target_family, optional); key!(is_like_osx, bool); + key!(is_like_solaris, bool); key!(is_like_windows, bool); key!(is_like_msvc, bool); + key!(is_like_android, bool); key!(linker_is_gnu, bool); + key!(allows_weak_linkage, bool); key!(has_rpath, bool); key!(no_compiler_rt, bool); key!(no_default_libraries, bool); - key!(pre_link_args, list); - key!(post_link_args, list); + key!(position_independent_executables, bool); key!(archive_format); key!(allow_asm, bool); key!(custom_unwind_resume, bool); + key!(lib_allocation_crate); + key!(exe_allocation_crate); + key!(has_elf_tls, bool); + key!(obj_is_bitcode, bool); key!(max_atomic_width, u64); - base + Ok(base) } /// Search RUST_TARGET_PATH for a JSON file specifying the given target @@ -490,10 +554,10 @@ impl Target { f.read_to_end(&mut contents).map_err(|e| e.to_string())?; let obj = json::from_reader(&mut &contents[..]) .map_err(|e| e.to_string())?; - Ok(Target::from_json(obj)) + Target::from_json(obj) } - if let Some(t) = load_specific(target) { + if let Ok(t) = load_specific(target) { return Ok(t) } @@ -525,6 +589,95 @@ impl Target { } } +impl ToJson for Target { + fn to_json(&self) -> Json { + let mut d = BTreeMap::new(); + let default: TargetOptions = Default::default(); + + macro_rules! target_val { + ($attr:ident) => ( { + let name = (stringify!($attr)).replace("_", "-"); + d.insert(name.to_string(), self.$attr.to_json()); + } ); + ($attr:ident, $key_name:expr) => ( { + let name = $key_name; + d.insert(name.to_string(), self.$attr.to_json()); + } ); + } + + macro_rules! target_option_val { + ($attr:ident) => ( { + let name = (stringify!($attr)).replace("_", "-"); + if default.$attr != self.options.$attr { + d.insert(name.to_string(), self.options.$attr.to_json()); + } + } ); + ($attr:ident, $key_name:expr) => ( { + let name = $key_name; + if default.$attr != self.options.$attr { + d.insert(name.to_string(), self.options.$attr.to_json()); + } + } ); + } + + target_val!(llvm_target); + target_val!(target_endian); + target_val!(target_pointer_width); + target_val!(arch); + target_val!(target_os, "os"); + target_val!(target_env, "env"); + target_val!(target_vendor, "vendor"); + target_val!(arch); + target_val!(data_layout); + + target_option_val!(is_builtin); + target_option_val!(linker); + target_option_val!(ar); + target_option_val!(pre_link_args); + target_option_val!(pre_link_objects_exe); + target_option_val!(pre_link_objects_dll); + target_option_val!(late_link_args); + target_option_val!(post_link_objects); + target_option_val!(post_link_args); + target_option_val!(cpu); + target_option_val!(features); + target_option_val!(dynamic_linking); + target_option_val!(executables); + target_option_val!(relocation_model); + target_option_val!(code_model); + target_option_val!(disable_redzone); + target_option_val!(eliminate_frame_pointer); + target_option_val!(function_sections); + target_option_val!(dll_prefix); + target_option_val!(dll_suffix); + target_option_val!(exe_suffix); + target_option_val!(staticlib_prefix); + target_option_val!(staticlib_suffix); + target_option_val!(target_family); + target_option_val!(is_like_osx); + target_option_val!(is_like_solaris); + target_option_val!(is_like_windows); + target_option_val!(is_like_msvc); + target_option_val!(is_like_android); + target_option_val!(linker_is_gnu); + target_option_val!(allows_weak_linkage); + target_option_val!(has_rpath); + target_option_val!(no_compiler_rt); + target_option_val!(no_default_libraries); + target_option_val!(position_independent_executables); + target_option_val!(archive_format); + target_option_val!(allow_asm); + target_option_val!(custom_unwind_resume); + target_option_val!(lib_allocation_crate); + target_option_val!(exe_allocation_crate); + target_option_val!(has_elf_tls); + target_option_val!(obj_is_bitcode); + target_option_val!(max_atomic_width); + + Json::Object(d) + } +} + fn maybe_jemalloc() -> String { if cfg!(feature = "jemalloc") { "alloc_jemalloc".to_string() diff --git a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs index be4be8e6fc96..1c04e763417c 100644 --- a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "ppc64".to_string(); base.pre_link_args.push("-m64".to_string()); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "powerpc64-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs index b0a81ce7ec50..906e28d2f20c 100644 --- a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "ppc64le".to_string(); base.pre_link_args.push("-m64".to_string()); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "powerpc64le-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs index aea57dc4b7f9..aebf9cd68717 100644 --- a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.pre_link_args.push("-m32".to_string()); base.max_atomic_width = 32; - Target { + Ok(Target { llvm_target: "powerpc-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), target_pointer_width: "32".to_string(), @@ -25,5 +25,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs index 1e46f45bdcf4..c398ee40f2f9 100644 --- a/src/librustc_back/target/windows_base.rs +++ b/src/librustc_back/target/windows_base.rs @@ -25,6 +25,7 @@ pub fn opts() -> TargetOptions { staticlib_suffix: ".lib".to_string(), no_default_libraries: true, is_like_windows: true, + allows_weak_linkage: false, pre_link_args: vec!( // And here, we see obscure linker flags #45. On windows, it has been // found to be necessary to have this flag to compile liblibc. diff --git a/src/librustc_back/target/x86_64_apple_darwin.rs b/src/librustc_back/target/x86_64_apple_darwin.rs index 5542c9120a40..65e4b1400fcf 100644 --- a/src/librustc_back/target/x86_64_apple_darwin.rs +++ b/src/librustc_back/target/x86_64_apple_darwin.rs @@ -8,16 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::apple_base::opts(); base.cpu = "core2".to_string(); base.max_atomic_width = 128; // core2 support cmpxchg16b base.eliminate_frame_pointer = false; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-apple-darwin".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -27,5 +27,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "apple".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/x86_64_apple_ios.rs b/src/librustc_back/target/x86_64_apple_ios.rs index 8638241f8610..4afc9bcb946c 100644 --- a/src/librustc_back/target/x86_64_apple_ios.rs +++ b/src/librustc_back/target/x86_64_apple_ios.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetOptions}; +use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; -pub fn target() -> Target { - Target { +pub fn target() -> TargetResult { + let base = try!(opts(Arch::X86_64)); + Ok(Target { llvm_target: "x86_64-apple-ios".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -23,7 +24,7 @@ pub fn target() -> Target { target_vendor: "apple".to_string(), options: TargetOptions { max_atomic_width: 64, - .. opts(Arch::X86_64) + .. base } - } + }) } diff --git a/src/librustc_back/target/x86_64_pc_windows_gnu.rs b/src/librustc_back/target/x86_64_pc_windows_gnu.rs index e243054d0230..086e0e6bf4fe 100644 --- a/src/librustc_back/target/x86_64_pc_windows_gnu.rs +++ b/src/librustc_back/target/x86_64_pc_windows_gnu.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::windows_base::opts(); base.cpu = "x86-64".to_string(); base.pre_link_args.push("-m64".to_string()); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "x86_64-pc-windows-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "pc".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/x86_64_pc_windows_msvc.rs b/src/librustc_back/target/x86_64_pc_windows_msvc.rs index a23a807a0257..064f06e9b31d 100644 --- a/src/librustc_back/target/x86_64_pc_windows_msvc.rs +++ b/src/librustc_back/target/x86_64_pc_windows_msvc.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::windows_msvc_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "x86_64-pc-windows-msvc".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -25,5 +25,5 @@ pub fn target() -> Target { target_env: "msvc".to_string(), target_vendor: "pc".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs index af5d21c4d93e..fd6578c2a2a0 100644 --- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs +++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); + base.cpu = "x86-64".to_string(); base.pre_link_args.push("-m64".to_string()); base.linker = "x86_64-rumprun-netbsd-gcc".to_string(); base.ar = "x86_64-rumprun-netbsd-ar".to_string(); @@ -24,7 +25,7 @@ pub fn target() -> Target { base.no_default_libraries = false; base.exe_allocation_crate = "alloc_system".to_string(); - Target { + Ok(Target { llvm_target: "x86_64-rumprun-netbsd".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -34,5 +35,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "rumprun".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/x86_64_sun_solaris.rs b/src/librustc_back/target/x86_64_sun_solaris.rs index 8f2c905cf2ee..2a1feb937f74 100644 --- a/src/librustc_back/target/x86_64_sun_solaris.rs +++ b/src/librustc_back/target/x86_64_sun_solaris.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::solaris_base::opts(); base.pre_link_args.push("-m64".to_string()); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; - Target { + Ok(Target { llvm_target: "x86_64-pc-solaris".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "sun".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/x86_64_unknown_bitrig.rs b/src/librustc_back/target/x86_64_unknown_bitrig.rs index 87753da540a3..382096558981 100644 --- a/src/librustc_back/target/x86_64_unknown_bitrig.rs +++ b/src/librustc_back/target/x86_64_unknown_bitrig.rs @@ -8,14 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::bitrig_base::opts(); + base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-bitrig".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -25,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/x86_64_unknown_dragonfly.rs b/src/librustc_back/target/x86_64_unknown_dragonfly.rs index 2535071f3089..7e40d49b870a 100644 --- a/src/librustc_back/target/x86_64_unknown_dragonfly.rs +++ b/src/librustc_back/target/x86_64_unknown_dragonfly.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-dragonfly".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/x86_64_unknown_freebsd.rs b/src/librustc_back/target/x86_64_unknown_freebsd.rs index d3ad0578aeb6..f38cdd4bec55 100644 --- a/src/librustc_back/target/x86_64_unknown_freebsd.rs +++ b/src/librustc_back/target/x86_64_unknown_freebsd.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-freebsd".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs index 7908e0d581ba..ef81d397a8f1 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/x86_64_unknown_linux_musl.rs b/src/librustc_back/target/x86_64_unknown_linux_musl.rs index 3301e0e0dc93..4bad7754b390 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_musl.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_musl.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-linux-musl".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "musl".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/x86_64_unknown_netbsd.rs b/src/librustc_back/target/x86_64_unknown_netbsd.rs index 7e6d1b78469e..2d0b1e2a9330 100644 --- a/src/librustc_back/target/x86_64_unknown_netbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_netbsd.rs @@ -8,14 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); + base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-netbsd".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -25,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_back/target/x86_64_unknown_openbsd.rs b/src/librustc_back/target/x86_64_unknown_openbsd.rs index 823b0994b0a0..339dbd591a02 100644 --- a/src/librustc_back/target/x86_64_unknown_openbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_openbsd.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::Target; +use target::{Target, TargetResult}; -pub fn target() -> Target { +pub fn target() -> TargetResult { let mut base = super::openbsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = 64; base.pre_link_args.push("-m64".to_string()); - Target { + Ok(Target { llvm_target: "x86_64-unknown-openbsd".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), @@ -26,5 +26,5 @@ pub fn target() -> Target { target_env: "".to_string(), target_vendor: "unknown".to_string(), options: base, - } + }) } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index e86120b73bf9..1fe47cd48538 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -197,7 +197,7 @@ fn borrowck_fn(this: &mut BorrowckCtxt, decl, body); - intravisit::walk_fn(this, fk, decl, body, sp); + intravisit::walk_fn(this, fk, decl, body, sp, id); } fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 01872bbe3c04..8967672548b1 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -14,6 +14,7 @@ serialize = { path = "../libserialize" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } +rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } graphviz = { path = "../libgraphviz" } syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 0de00d9d7f63..d148d2a0885e 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal; use ::{eval_const_expr, eval_const_expr_partial, compare_const_vals}; use ::{const_expr_to_pat, lookup_const_by_id}; use ::EvalHint::ExprTypeChecked; +use eval::report_const_eval_err; use rustc::hir::def::*; use rustc::hir::def_id::{DefId}; use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; @@ -33,7 +34,7 @@ use std::iter::{FromIterator, IntoIterator, repeat}; use rustc::hir; use rustc::hir::{Pat, PatKind}; -use rustc::hir::intravisit::{self, IdVisitor, IdVisitingOperation, Visitor, FnKind}; +use rustc::hir::intravisit::{self, Visitor, FnKind}; use rustc_back::slice; use syntax::ast::{self, DUMMY_NODE_ID, NodeId}; @@ -42,6 +43,7 @@ use syntax_pos::{Span, DUMMY_SP}; use rustc::hir::fold::{Folder, noop_fold_pat}; use rustc::hir::print::pat_to_string; use syntax::ptr::P; +use rustc::util::common::ErrorReported; use rustc::util::nodemap::FnvHashMap; pub const DUMMY_WILD_PAT: &'static Pat = &Pat { @@ -279,13 +281,7 @@ fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) { Ok(_) => {} Err(err) => { - let mut diag = struct_span_err!(cx.tcx.sess, err.span, E0471, - "constant evaluation error: {}", - err.description()); - if !p.span.contains(err.span) { - diag.span_note(p.span, "in pattern here"); - } - diag.emit(); + report_const_eval_err(cx.tcx, &err, p.span, "pattern").emit(); } } } @@ -339,6 +335,7 @@ fn check_arms(cx: &MatchCheckCtxt, hir::MatchSource::Normal => { let mut err = struct_span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern"); + err.span_label(pat.span, &format!("this is an unreachable pattern")); // if we had a catchall pattern, hint at that for row in &seen.0 { if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0].0) { @@ -478,7 +475,7 @@ struct RenamingRecorder<'map> { renaming_map: &'map mut FnvHashMap<(NodeId, Span), NodeId> } -impl<'map> IdVisitingOperation for RenamingRecorder<'map> { +impl<'v, 'map> Visitor<'v> for RenamingRecorder<'map> { fn visit_id(&mut self, node_id: NodeId) { let key = (node_id, self.origin_span); self.renaming_map.insert(key, self.substituted_node_id); @@ -533,9 +530,7 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { renaming_map: renaming_map, }; - let mut id_visitor = IdVisitor::new(&mut renaming_recorder); - - id_visitor.visit_expr(const_expr); + renaming_recorder.visit_expr(const_expr); } } } @@ -838,22 +833,19 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us } } -fn range_covered_by_constructor(ctor: &Constructor, - from: &ConstVal, to: &ConstVal) -> Option { +fn range_covered_by_constructor(tcx: TyCtxt, span: Span, + ctor: &Constructor, + from: &ConstVal, to: &ConstVal) + -> Result { let (c_from, c_to) = match *ctor { ConstantValue(ref value) => (value, value), ConstantRange(ref from, ref to) => (from, to), - Single => return Some(true), + Single => return Ok(true), _ => bug!() }; - let cmp_from = compare_const_vals(c_from, from); - let cmp_to = compare_const_vals(c_to, to); - match (cmp_from, cmp_to) { - (Some(cmp_from), Some(cmp_to)) => { - Some(cmp_from != Ordering::Less && cmp_to != Ordering::Greater) - } - _ => None - } + let cmp_from = compare_const_vals(tcx, span, c_from, from)?; + let cmp_to = compare_const_vals(tcx, span, c_to, to)?; + Ok(cmp_from != Ordering::Less && cmp_to != Ordering::Greater) } fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>, @@ -965,13 +957,12 @@ pub fn specialize<'a, 'b, 'tcx>( Some(vec![(pat, Some(mt.ty))]) } else { let expr_value = eval_const_expr(cx.tcx, &expr); - match range_covered_by_constructor(constructor, &expr_value, &expr_value) { - Some(true) => Some(vec![]), - Some(false) => None, - None => { - span_err!(cx.tcx.sess, pat_span, E0298, "mismatched types between arms"); - None - } + match range_covered_by_constructor( + cx.tcx, expr.span, constructor, &expr_value, &expr_value + ) { + Ok(true) => Some(vec![]), + Ok(false) => None, + Err(ErrorReported) => None, } } } @@ -979,13 +970,12 @@ pub fn specialize<'a, 'b, 'tcx>( PatKind::Range(ref from, ref to) => { let from_value = eval_const_expr(cx.tcx, &from); let to_value = eval_const_expr(cx.tcx, &to); - match range_covered_by_constructor(constructor, &from_value, &to_value) { - Some(true) => Some(vec![]), - Some(false) => None, - None => { - span_err!(cx.tcx.sess, pat_span, E0299, "mismatched types between arms"); - None - } + match range_covered_by_constructor( + cx.tcx, pat_span, constructor, &from_value, &to_value + ) { + Ok(true) => Some(vec![]), + Ok(false) => None, + Err(ErrorReported) => None, } } @@ -1058,7 +1048,7 @@ fn check_fn(cx: &mut MatchCheckCtxt, _ => cx.param_env = ParameterEnvironment::for_item(cx.tcx, fn_id), } - intravisit::walk_fn(cx, kind, decl, body, sp); + intravisit::walk_fn(cx, kind, decl, body, sp, fn_id); for input in &decl.inputs { check_irrefutable(cx, &input.pat, true); diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index f2abdf831a3b..45414c33c075 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -551,6 +551,26 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases. See also https://github.com/rust-lang/rust/issues/14587 "##, +E0080: r##" +This error indicates that the compiler was unable to sensibly evaluate an +constant expression that had to be evaluated. Attempting to divide by 0 +or causing integer overflow are two ways to induce this error. For example: + +```compile_fail +enum Enum { + X = (1 << 500), + Y = (1 / 0) +} +``` + +Ensure that the expressions given can be evaluated as the desired integer type. +See the FFI section of the Reference for more information about using a custom +integer type: + +https://doc.rust-lang.org/reference.html#ffi-attributes +"##, + + E0306: r##" In an array literal `[x; N]`, `N` is the number of elements in the array. This must be an unsigned integer. Erroneous code example: @@ -566,29 +586,11 @@ Working example: let x = [0i32; 2]; ``` "##, - -E0307: r##" -The length of an array is part of its type. For this reason, this length must -be a compile-time constant. Erroneous code example: - -```compile_fail - let len = 10; - let x = [0i32; len]; // error: expected constant integer for repeat count, - // found variable -``` - -Working example: - -``` -let x = [0i32; 10]; -``` -"##, - } register_diagnostics! { -E0298, // mismatched types between arms -E0299, // mismatched types between arms -E0471, // constant evaluation error: .. + E0298, // cannot compare constants +// E0299, // mismatched types between arms +// E0471, // constant evaluation error (in pattern) } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index a3c707e82a0f..d424b57c9384 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -17,7 +17,7 @@ use self::EvalHint::*; use rustc::hir::map as ast_map; use rustc::hir::map::blocks::FnLikeNode; -use rustc::middle::cstore::{self, InlinedItem}; +use rustc::middle::cstore::InlinedItem; use rustc::traits; use rustc::hir::def::{Def, PathResolution}; use rustc::hir::def_id::DefId; @@ -25,6 +25,7 @@ use rustc::hir::pat_util::def_to_path; use rustc::ty::{self, Ty, TyCtxt, subst}; use rustc::ty::util::IntTypeExt; use rustc::traits::ProjectionMode; +use rustc::util::common::ErrorReported; use rustc::util::nodemap::NodeMap; use rustc::lint; @@ -43,6 +44,7 @@ use std::cmp::Ordering; use std::collections::hash_map::Entry::Vacant; use rustc_const_math::*; +use rustc_errors::{DiagnosticBuilder, check_old_school}; macro_rules! math { ($e:expr, $op:expr) => { @@ -140,13 +142,13 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let mut used_substs = false; let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) { - cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node { + Some((&InlinedItem::Item(ref item), _)) => match item.node { hir::ItemConst(ref ty, ref const_expr) => { Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty))) }, _ => None }, - cstore::FoundAst::Found(&InlinedItem::TraitItem(trait_id, ref ti)) => match ti.node { + Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node { hir::ConstTraitItem(_, _) => { used_substs = true; if let Some(substs) = substs { @@ -161,7 +163,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } _ => None }, - cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref ii)) => match ii.node { + Some((&InlinedItem::ImplItem(_, ref ii), _)) => match ii.node { hir::ImplItemKind::Const(ref ty, ref expr) => { Some((&**expr, tcx.ast_ty_to_prim_ty(ty))) }, @@ -196,8 +198,8 @@ fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) { - cstore::FoundAst::Found(&InlinedItem::Item(ref item)) => Some(item.id), - cstore::FoundAst::Found(&InlinedItem::ImplItem(_, ref item)) => Some(item.id), + Some((&InlinedItem::Item(ref item), _)) => Some(item.id), + Some((&InlinedItem::ImplItem(_, ref item), _)) => Some(item.id), _ => None }; tcx.extern_const_fns.borrow_mut().insert(def_id, @@ -338,20 +340,71 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(P(hir::Pat { id: expr.id, node: pat, span: span })) } +pub fn report_const_eval_err<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + err: &ConstEvalErr, + primary_span: Span, + primary_kind: &str) + -> DiagnosticBuilder<'tcx> +{ + let mut err = err; + while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err { + err = i_err; + } + + let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error"); + note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag); + diag +} + +pub fn fatal_const_eval_err<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + err: &ConstEvalErr, + primary_span: Span, + primary_kind: &str) + -> ! +{ + report_const_eval_err(tcx, err, primary_span, primary_kind).emit(); + tcx.sess.abort_if_errors(); + unreachable!() +} + +pub fn note_const_eval_err<'a, 'tcx>( + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + err: &ConstEvalErr, + primary_span: Span, + primary_kind: &str, + diag: &mut DiagnosticBuilder) +{ + match err.description() { + ConstEvalErrDescription::Simple(message) => { + if check_old_school() { + diag.note(&message); + } else { + diag.span_label(err.span, &message); + } + } + } + + if !primary_span.contains(err.span) { + diag.span_note(primary_span, + &format!("for {} here", primary_kind)); + } +} + pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &Expr) -> ConstVal { match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) { Ok(r) => r, // non-const path still needs to be a fatal error, because enums are funky Err(s) => { + report_const_eval_err(tcx, &s, e.span, "expression").emit(); match s.kind { NonConstPath | - UnimplementedConstVal(_) => tcx.sess.span_fatal(s.span, &s.description()), - _ => { - tcx.sess.span_err(s.span, &s.description()); - Dummy - } + UnimplementedConstVal(_) => tcx.sess.abort_if_errors(), + _ => {} } + Dummy }, } } @@ -400,6 +453,7 @@ pub enum ErrKind { IntermediateUnsignedNegative, /// Expected, Got TypeMismatch(String, ConstInt), + BadType(ConstVal), ErroneousReferencedConstant(Box), CharCast(ConstInt), @@ -411,57 +465,79 @@ impl From for ErrKind { } } +#[derive(Clone, Debug)] +pub enum ConstEvalErrDescription<'a> { + Simple(Cow<'a, str>), +} + +impl<'a> ConstEvalErrDescription<'a> { + /// Return a one-line description of the error, for lints and such + pub fn into_oneline(self) -> Cow<'a, str> { + match self { + ConstEvalErrDescription::Simple(simple) => simple, + } + } +} + impl ConstEvalErr { - pub fn description(&self) -> Cow { + pub fn description(&self) -> ConstEvalErrDescription { use self::ErrKind::*; + use self::ConstEvalErrDescription::*; + + macro_rules! simple { + ($msg:expr) => ({ Simple($msg.into_cow()) }); + ($fmt:expr, $($arg:tt)+) => ({ + Simple(format!($fmt, $($arg)+).into_cow()) + }) + } match self.kind { - CannotCast => "can't cast this type".into_cow(), - CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(), - InvalidOpForInts(_) => "can't do this op on integrals".into_cow(), - InvalidOpForBools(_) => "can't do this op on bools".into_cow(), - InvalidOpForFloats(_) => "can't do this op on floats".into_cow(), - InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(), - InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(), - NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(), - NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(), - CallOn(ref const_val) => format!("call on {}", const_val.description()).into_cow(), + CannotCast => simple!("can't cast this type"), + CannotCastTo(s) => simple!("can't cast this type to {}", s), + InvalidOpForInts(_) => simple!("can't do this op on integrals"), + InvalidOpForBools(_) => simple!("can't do this op on bools"), + InvalidOpForFloats(_) => simple!("can't do this op on floats"), + InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"), + InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"), + NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), + NotOn(ref const_val) => simple!("not on {}", const_val.description()), + CallOn(ref const_val) => simple!("call on {}", const_val.description()), - MissingStructField => "nonexistent struct field".into_cow(), - NonConstPath => "non-constant path in constant expression".into_cow(), + MissingStructField => simple!("nonexistent struct field"), + NonConstPath => simple!("non-constant path in constant expression"), UnimplementedConstVal(what) => - format!("unimplemented constant expression: {}", what).into_cow(), - UnresolvedPath => "unresolved path in constant expression".into_cow(), - ExpectedConstTuple => "expected constant tuple".into_cow(), - ExpectedConstStruct => "expected constant struct".into_cow(), - TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(), - IndexedNonVec => "indexing is only supported for arrays".into_cow(), - IndexNegative => "indices must be non-negative integers".into_cow(), - IndexNotInt => "indices must be integers".into_cow(), + simple!("unimplemented constant expression: {}", what), + UnresolvedPath => simple!("unresolved path in constant expression"), + ExpectedConstTuple => simple!("expected constant tuple"), + ExpectedConstStruct => simple!("expected constant struct"), + TupleIndexOutOfBounds => simple!("tuple index out of bounds"), + IndexedNonVec => simple!("indexing is only supported for arrays"), + IndexNegative => simple!("indices must be non-negative integers"), + IndexNotInt => simple!("indices must be integers"), IndexOutOfBounds { len, index } => { - format!("index out of bounds: the len is {} but the index is {}", - len, index).into_cow() + simple!("index out of bounds: the len is {} but the index is {}", + len, index) } - RepeatCountNotNatural => "repeat count must be a natural number".into_cow(), - RepeatCountNotInt => "repeat count must be integers".into_cow(), + RepeatCountNotNatural => simple!("repeat count must be a natural number"), + RepeatCountNotInt => simple!("repeat count must be integers"), - MiscBinaryOp => "bad operands for binary".into_cow(), - MiscCatchAll => "unsupported constant expr".into_cow(), - IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(), - Math(ref err) => err.description().into_cow(), + MiscBinaryOp => simple!("bad operands for binary"), + MiscCatchAll => simple!("unsupported constant expr"), + IndexOpFeatureGated => simple!("the index operation on const values is unstable"), + Math(ref err) => Simple(err.description().into_cow()), - IntermediateUnsignedNegative => "during the computation of an unsigned a negative \ - number was encountered. This is most likely a bug in\ - the constant evaluator".into_cow(), + IntermediateUnsignedNegative => simple!( + "during the computation of an unsigned a negative \ + number was encountered. This is most likely a bug in\ + the constant evaluator"), TypeMismatch(ref expected, ref got) => { - format!("mismatched types: expected `{}`, found `{}`", - expected, got.description()).into_cow() + simple!("expected {}, found {}", expected, got.description()) }, - BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(), - ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(), + BadType(ref i) => simple!("value of wrong type: {:?}", i), + ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), CharCast(ref got) => { - format!("only `u8` can be cast as `char`, not `{}`", got.description()).into_cow() + simple!("only `u8` can be cast as `char`, not `{}`", got.description()) }, } } @@ -1105,11 +1181,25 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty) Float(f) => cast_const_float(tcx, f, ty), Char(c) => cast_const_int(tcx, Infer(c as u64), ty), Function(_) => Err(UnimplementedConstVal("casting fn pointers")), - ByteStr(_) => match ty.sty { + ByteStr(b) => match ty.sty { ty::TyRawPtr(_) => { Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr")) }, - ty::TyRef(..) => Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice")), + ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty { + ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)), + ty::TySlice(_) => { + Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice")) + }, + _ => Err(CannotCast), + }, + _ => Err(CannotCast), + }, + Str(s) => match ty.sty { + ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting a str to a raw ptr")), + ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty { + ty::TyStr => Ok(Str(s)), + _ => Err(CannotCast), + }, _ => Err(CannotCast), }, _ => Err(CannotCast), @@ -1185,8 +1275,10 @@ fn parse_float(num: &str, fty_hint: Option, span: Span) -> ConstFl }) } -pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option { - match (a, b) { +pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal) + -> Result +{ + let result = match (a, b) { (&Integral(a), &Integral(b)) => a.try_cmp(b).ok(), (&Float(a), &Float(b)) => a.try_cmp(b).ok(), (&Str(ref a), &Str(ref b)) => Some(a.cmp(b)), @@ -1194,62 +1286,82 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option { (&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)), (&Char(a), &Char(ref b)) => Some(a.cmp(b)), _ => None, + }; + + match result { + Some(result) => Ok(result), + None => { + // FIXME: can this ever be reached? + span_err!(tcx.sess, span, E0298, + "type mismatch comparing {} and {}", + a.description(), + b.description()); + Err(ErrorReported) + } } } pub fn compare_lit_exprs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + span: Span, a: &Expr, - b: &Expr) -> Option { + b: &Expr) -> Result { let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) { Ok(a) => a, Err(e) => { - tcx.sess.span_err(a.span, &e.description()); - return None; + report_const_eval_err(tcx, &e, a.span, "expression").emit(); + return Err(ErrorReported); } }; let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) { Ok(b) => b, Err(e) => { - tcx.sess.span_err(b.span, &e.description()); - return None; + report_const_eval_err(tcx, &e, b.span, "expression").emit(); + return Err(ErrorReported); } }; - compare_const_vals(&a, &b) + compare_const_vals(tcx, span, &a, &b) } -/// Returns the repeat count for a repeating vector expression. -pub fn eval_repeat_count<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - count_expr: &hir::Expr) -> usize { +/// Returns the value of the length-valued expression +pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + count_expr: &hir::Expr, + reason: &str) + -> Result +{ let hint = UncheckedExprHint(tcx.types.usize); match eval_const_expr_partial(tcx, count_expr, hint, None) { Ok(Integral(Usize(count))) => { let val = count.as_u64(tcx.sess.target.uint_type); assert_eq!(val as usize as u64, val); - val as usize + Ok(val as usize) }, Ok(const_val) => { span_err!(tcx.sess, count_expr.span, E0306, - "expected positive integer for repeat count, found {}", + "expected usize for {}, found {}", + reason, const_val.description()); - 0 + Err(ErrorReported) } Err(err) => { - let err_msg = match count_expr.node { + let mut diag = report_const_eval_err( + tcx, &err, count_expr.span, reason); + + match count_expr.node { hir::ExprPath(None, hir::Path { global: false, ref segments, .. - }) if segments.len() == 1 => - format!("found variable"), - _ => match err.kind { - MiscCatchAll => format!("but found {}", err.description()), - _ => format!("but {}", err.description()) + }) if segments.len() == 1 => { + if let Some(Def::Local(..)) = tcx.expect_def_or_none(count_expr.id) { + diag.note(&format!("`{}` is a variable", segments[0].name)); + } } - }; - span_err!(tcx.sess, count_expr.span, E0307, - "expected constant integer for repeat count, {}", err_msg); - 0 + _ => {} + } + + diag.emit(); + Err(ErrorReported) } } } diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 726ba4fc1924..a6714c178e7c 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -36,6 +36,7 @@ #[macro_use] extern crate rustc; extern crate rustc_back; extern crate rustc_const_math; +extern crate rustc_errors; extern crate graphviz; extern crate syntax_pos; extern crate serialize as rustc_serialize; // used by deriving diff --git a/src/librustc_const_math/err.rs b/src/librustc_const_math/err.rs index e4eb0f2c97eb..e2e30ef026c2 100644 --- a/src/librustc_const_math/err.rs +++ b/src/librustc_const_math/err.rs @@ -57,18 +57,18 @@ impl ConstMathErr { UnequalTypes(BitOr) => "tried to bitor two values of different types", UnequalTypes(BitXor) => "tried to xor two values of different types", UnequalTypes(_) => unreachable!(), - Overflow(Add) => "attempted to add with overflow", - Overflow(Sub) => "attempted to subtract with overflow", - Overflow(Mul) => "attempted to multiply with overflow", - Overflow(Div) => "attempted to divide with overflow", - Overflow(Rem) => "attempted to calculate the remainder with overflow", - Overflow(Neg) => "attempted to negate with overflow", - Overflow(Shr) => "attempted to shift right with overflow", - Overflow(Shl) => "attempted to shift left with overflow", + Overflow(Add) => "attempt to add with overflow", + Overflow(Sub) => "attempt to subtract with overflow", + Overflow(Mul) => "attempt to multiply with overflow", + Overflow(Div) => "attempt to divide with overflow", + Overflow(Rem) => "attempt to calculate the remainder with overflow", + Overflow(Neg) => "attempt to negate with overflow", + Overflow(Shr) => "attempt to shift right with overflow", + Overflow(Shl) => "attempt to shift left with overflow", Overflow(_) => unreachable!(), - ShiftNegative => "attempted to shift by a negative amount", - DivisionByZero => "attempted to divide by zero", - RemainderByZero => "attempted to calculate the remainder with a divisor of zero", + ShiftNegative => "attempt to shift by a negative amount", + DivisionByZero => "attempt to divide by zero", + RemainderByZero => "attempt to calculate the remainder with a divisor of zero", UnsignedNegation => "unary negation of unsigned integer", ULitOutOfRange(ast::UintTy::U8) => "literal out of range for u8", ULitOutOfRange(ast::UintTy::U16) => "literal out of range for u16", diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index ab3b20e08c80..f1f5e194da4d 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -88,7 +88,7 @@ pub fn compile_input(sess: &Session, // We need nested scopes here, because the intermediate results can keep // large chunks of memory alive and we want to free them as soon as // possible to keep the peak memory usage low - let (outputs, trans) = { + let (outputs, trans, crate_name) = { let krate = match phase_1_parse_input(sess, cfg, input) { Ok(krate) => krate, Err(mut parse_error) => { @@ -113,13 +113,13 @@ pub fn compile_input(sess: &Session, }; let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess); - let id = link::find_crate_name(Some(sess), &krate.attrs, input); + let crate_name = link::find_crate_name(Some(sess), &krate.attrs, input); let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = { phase_2_configure_and_expand( - sess, &cstore, krate, &id, addl_plugins, control.make_glob_map, + sess, &cstore, krate, &crate_name, addl_plugins, control.make_glob_map, |expanded_crate| { let mut state = CompileState::state_after_expand( - input, sess, outdir, output, &cstore, expanded_crate, &id, + input, sess, outdir, output, &cstore, expanded_crate, &crate_name, ); controller_entry_point!(after_expand, sess, state, Ok(())); Ok(()) @@ -127,7 +127,7 @@ pub fn compile_input(sess: &Session, )? }; - write_out_deps(sess, &outputs, &id); + write_out_deps(sess, &outputs, &crate_name); let arenas = ty::CtxtArenas::new(); @@ -151,7 +151,7 @@ pub fn compile_input(sess: &Session, &resolutions, &expanded_crate, &hir_map.krate(), - &id), + &crate_name), Ok(())); } @@ -171,7 +171,7 @@ pub fn compile_input(sess: &Session, analysis, resolutions, &arenas, - &id, + &crate_name, |tcx, mir_map, analysis, result| { { // Eventually, we will want to track plugins. @@ -186,7 +186,7 @@ pub fn compile_input(sess: &Session, &analysis, mir_map.as_ref(), tcx, - &id); + &crate_name); (control.after_analysis.callback)(&mut state); if control.after_analysis.stop == Compilation::Stop { @@ -212,11 +212,11 @@ pub fn compile_input(sess: &Session, // Discard interned strings as they are no longer required. token::clear_ident_interner(); - Ok((outputs, trans)) + Ok((outputs, trans, crate_name.clone())) })?? }; - let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs); + let phase5_result = phase_5_run_llvm_passes(sess, &crate_name, &trans, &outputs); controller_entry_point!(after_llvm, sess, @@ -478,10 +478,6 @@ pub fn phase_1_parse_input<'a>(sess: &'a Session, cfg: ast::CrateConfig, input: &Input) -> PResult<'a, ast::Crate> { - // These may be left in an incoherent state after a previous compile. - syntax::ext::hygiene::reset_hygiene_data(); - // `clear_ident_interner` can be used to free memory, but it does not restore the initial state. - token::reset_ident_interner(); let continue_after_error = sess.opts.continue_parse_after_error; sess.diagnostic().set_continue_after_error(continue_after_error); @@ -570,7 +566,8 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, }); *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs); - sess.crate_disambiguator.set(token::intern(&compute_crate_disambiguator(sess))); + *sess.crate_disambiguator.borrow_mut() = + token::intern(&compute_crate_disambiguator(sess)).as_str(); time(time_passes, "recursion limit", || { middle::recursion_limit::update_recursion_limit(sess, &krate); @@ -998,6 +995,8 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("elaborate-drops")); + passes.push_pass(box mir::transform::deaggregator::Deaggregator); + passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans")); @@ -1023,6 +1022,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// Run LLVM itself, producing a bitcode file, assembly file or object file /// as a side effect. pub fn phase_5_run_llvm_passes(sess: &Session, + crate_name: &str, trans: &trans::CrateTranslation, outputs: &OutputFilenames) -> CompileResult { if sess.opts.cg.no_integrated_as { @@ -1044,6 +1044,10 @@ pub fn phase_5_run_llvm_passes(sess: &Session, || write::run_passes(sess, trans, &sess.opts.output_types, outputs)); } + time(sess.time_passes(), + "serialize work products", + move || rustc_incremental::save_work_products(sess, crate_name)); + if sess.err_count() > 0 { Err(sess.err_count()) } else { @@ -1067,14 +1071,14 @@ fn escape_dep_filename(filename: &str) -> String { filename.replace(" ", "\\ ") } -fn write_out_deps(sess: &Session, outputs: &OutputFilenames, id: &str) { +fn write_out_deps(sess: &Session, outputs: &OutputFilenames, crate_name: &str) { let mut out_filenames = Vec::new(); for output_type in sess.opts.output_types.keys() { let file = outputs.path(*output_type); match *output_type { OutputType::Exe => { for output in sess.crate_types.borrow().iter() { - let p = link::filename_for_input(sess, *output, id, outputs); + let p = link::filename_for_input(sess, *output, crate_name, outputs); out_filenames.push(p); } } @@ -1298,3 +1302,11 @@ pub fn build_output_filenames(input: &Input, } } } + +// For use by the `rusti` project (https://github.com/murarth/rusti). +pub fn reset_thread_local_state() { + // These may be left in an incoherent state after a previous compile. + syntax::ext::hygiene::reset_hygiene_data(); + // `clear_ident_interner` can be used to free memory, but it does not restore the initial state. + token::reset_ident_interner(); +} diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index f50ea9af493e..d92ecfaec328 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -31,7 +31,6 @@ #![feature(set_stdio)] #![feature(staged_api)] #![feature(question_mark)] -#![feature(unboxed_closures)] extern crate arena; extern crate flate; @@ -96,6 +95,7 @@ use std::thread; use rustc::session::early_error; use syntax::{ast, json}; +use syntax::attr::AttrMetaMethods; use syntax::codemap::{CodeMap, FileLoader, RealFileLoader}; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult}; @@ -187,7 +187,7 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String], let sopts = config::build_session_options(&matches); if sopts.debugging_opts.debug_llvm { - unsafe { llvm::LLVMSetDebug(1); } + unsafe { llvm::LLVMRustSetDebug(1); } } let descriptions = diagnostics_registry(); @@ -393,15 +393,12 @@ fn check_cfg(sopts: &config::Options, let mut saw_invalid_predicate = false; for item in sopts.cfg.iter() { - match item.node { - ast::MetaItemKind::List(ref pred, _) => { - saw_invalid_predicate = true; - handler.emit(&MultiSpan::new(), - &format!("invalid predicate in --cfg command line argument: `{}`", - pred), - errors::Level::Fatal); - } - _ => {}, + if item.is_meta_item_list() { + saw_invalid_predicate = true; + handler.emit(&MultiSpan::new(), + &format!("invalid predicate in --cfg command line argument: `{}`", + item.name()), + errors::Level::Fatal); } } @@ -610,7 +607,7 @@ impl RustcDefaultCalls { for req in &sess.opts.prints { match *req { PrintRequest::TargetList => { - let mut targets = rustc_back::target::TARGETS.to_vec(); + let mut targets = rustc_back::target::get_targets().collect::>(); targets.sort(); println!("{}", targets.join("\n")); }, @@ -650,20 +647,17 @@ impl RustcDefaultCalls { if !allow_unstable_cfg && GatedCfg::gate(&*cfg).is_some() { continue; } - match cfg.node { - ast::MetaItemKind::Word(ref word) => println!("{}", word), - ast::MetaItemKind::NameValue(ref name, ref value) => { - println!("{}=\"{}\"", name, match value.node { - ast::LitKind::Str(ref s, _) => s, - _ => continue, - }); + if cfg.is_word() { + println!("{}", cfg.name()); + } else if cfg.is_value_str() { + if let Some(s) = cfg.value_str() { + println!("{}=\"{}\"", cfg.name(), s); } + } else if cfg.is_meta_item_list() { // Right now there are not and should not be any // MetaItemKind::List items in the configuration returned by // `build_configuration`. - ast::MetaItemKind::List(..) => { - panic!("MetaItemKind::List encountered in default cfg") - } + panic!("MetaItemKind::List encountered in default cfg") } } } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 6a48f65714cc..610e5647d6d1 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -531,10 +531,12 @@ impl Handler { DiagnosticBuilder::new(self, Level::Fatal, msg) } - pub fn cancel(&mut self, err: &mut DiagnosticBuilder) { + pub fn cancel(&self, err: &mut DiagnosticBuilder) { if err.level == Level::Error || err.level == Level::Fatal { - assert!(self.has_errors()); - self.err_count.set(self.err_count.get() + 1); + self.err_count.set( + self.err_count.get().checked_sub(1) + .expect("cancelled an error but err_count is 0") + ); } err.cancel(); } diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index d38f979e33c5..774c5ca6d6b2 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -110,13 +110,11 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { if attr.check_name(IF_THIS_CHANGED) { let mut id = None; for meta_item in attr.meta_item_list().unwrap_or_default() { - match meta_item.node { - ast::MetaItemKind::Word(ref s) if id.is_none() => id = Some(s.clone()), - _ => { - self.tcx.sess.span_err( - meta_item.span, - &format!("unexpected meta-item {:?}", meta_item.node)); - } + if meta_item.is_word() && id.is_none() { + id = Some(meta_item.name().clone()); + } else { + // FIXME better-encapsulate meta_item (don't directly access `node`) + span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node) } } let id = id.unwrap_or(InternedString::new(ID)); @@ -127,16 +125,13 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { let mut dep_node_interned = None; let mut id = None; for meta_item in attr.meta_item_list().unwrap_or_default() { - match meta_item.node { - ast::MetaItemKind::Word(ref s) if dep_node_interned.is_none() => - dep_node_interned = Some(s.clone()), - ast::MetaItemKind::Word(ref s) if id.is_none() => - id = Some(s.clone()), - _ => { - self.tcx.sess.span_err( - meta_item.span, - &format!("unexpected meta-item {:?}", meta_item.node)); - } + if meta_item.is_word() && dep_node_interned.is_none() { + dep_node_interned = Some(meta_item.name().clone()); + } else if meta_item.is_word() && id.is_none() { + id = Some(meta_item.name().clone()); + } else { + // FIXME better-encapsulate meta_item (don't directly access `node`) + span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node) } } let dep_node = match dep_node_interned { diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs index cbc246ac2a11..bea6b7e28344 100644 --- a/src/librustc_incremental/calculate_svh.rs +++ b/src/librustc_incremental/calculate_svh.rs @@ -11,6 +11,7 @@ //! Calculation of a Strict Version Hash for crates. For a length //! comment explaining the general idea, see `librustc/middle/svh.rs`. +use syntax::attr::AttributeMethods; use std::hash::{Hash, SipHasher, Hasher}; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::svh::Svh; @@ -36,7 +37,7 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> { // to ensure it is not incorporating implementation artifacts into // the hash that are not otherwise visible.) - let crate_disambiguator = self.sess.crate_disambiguator.get(); + let crate_disambiguator = self.sess.local_crate_disambiguator(); let krate = self.map.krate(); // FIXME: this should use SHA1, not SipHash. SipHash is not built to @@ -47,10 +48,10 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> { // FIXME(#32753) -- at (*) we `to_le` for endianness, but is // this enough, and does it matter anyway? "crate_disambiguator".hash(&mut state); - crate_disambiguator.as_str().len().to_le().hash(&mut state); // (*) - crate_disambiguator.as_str().hash(&mut state); + crate_disambiguator.len().to_le().hash(&mut state); // (*) + crate_disambiguator.hash(&mut state); - debug!("crate_disambiguator: {:?}", crate_disambiguator.as_str()); + debug!("crate_disambiguator: {:?}", crate_disambiguator); debug!("state: {:?}", state); { @@ -69,7 +70,7 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> { // to avoid hashing the AttrId for attr in &krate.attrs { debug!("krate attr {:?}", attr); - attr.node.value.hash(&mut state); + attr.meta().hash(&mut state); } Svh::new(state.finish()) @@ -119,6 +120,7 @@ mod svh_visitor { use rustc::ty::TyCtxt; use rustc::hir; use rustc::hir::*; + use rustc::hir::map::DefPath; use rustc::hir::intravisit as visit; use rustc::hir::intravisit::{Visitor, FnKind}; @@ -135,6 +137,15 @@ mod svh_visitor { -> Self { StrictVersionHashVisitor { st: st, tcx: tcx } } + + fn hash_def_path(&mut self, path: &DefPath) { + self.tcx.crate_name(path.krate).hash(self.st); + self.tcx.crate_disambiguator(path.krate).hash(self.st); + for data in &path.data { + data.data.as_interned_str().hash(self.st); + data.disambiguator.hash(self.st); + } + } } // To off-load the bulk of the hash-computation on #[derive(Hash)], @@ -289,19 +300,21 @@ mod svh_visitor { impl<'a, 'tcx> Visitor<'a> for StrictVersionHashVisitor<'a, 'tcx> { fn visit_nested_item(&mut self, item: ItemId) { - debug!("visit_nested_item: {:?} st={:?}", item, self.st); - let def_path = self.tcx.map.def_path_from_id(item.id); - def_path.hash(self.st); + let def_path = self.tcx.map.def_path_from_id(item.id).unwrap(); + debug!("visit_nested_item: def_path={:?} st={:?}", def_path, self.st); + self.hash_def_path(&def_path); } fn visit_variant_data(&mut self, s: &'a VariantData, name: Name, g: &'a Generics, _: NodeId, _: Span) { + debug!("visit_variant_data: st={:?}", self.st); SawStructDef(name.as_str()).hash(self.st); visit::walk_generics(self, g); visit::walk_struct_def(self, s) } fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) { + debug!("visit_variant: st={:?}", self.st); SawVariant.hash(self.st); // walk_variant does not call walk_generics, so do it here. visit::walk_generics(self, g); @@ -323,14 +336,17 @@ mod svh_visitor { // pattern, please move that method up above this comment.) fn visit_name(&mut self, _: Span, name: Name) { + debug!("visit_name: st={:?}", self.st); SawIdent(name.as_str()).hash(self.st); } fn visit_lifetime(&mut self, l: &'a Lifetime) { + debug!("visit_lifetime: st={:?}", self.st); SawLifetime(l.name.as_str()).hash(self.st); } fn visit_lifetime_def(&mut self, l: &'a LifetimeDef) { + debug!("visit_lifetime_def: st={:?}", self.st); SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st); } @@ -340,14 +356,18 @@ mod svh_visitor { // that a change to a crate body will require downstream // crates to be recompiled. fn visit_expr(&mut self, ex: &'a Expr) { + debug!("visit_expr: st={:?}", self.st); SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex) } fn visit_stmt(&mut self, s: &'a Stmt) { + debug!("visit_stmt: st={:?}", self.st); SawStmt(saw_stmt(&s.node)).hash(self.st); visit::walk_stmt(self, s) } fn visit_foreign_item(&mut self, i: &'a ForeignItem) { + debug!("visit_foreign_item: st={:?}", self.st); + // FIXME (#14132) ideally we would incorporate privacy (or // perhaps reachability) somewhere here, so foreign items // that do not leak into downstream crates would not be @@ -357,6 +377,7 @@ mod svh_visitor { fn visit_item(&mut self, i: &'a Item) { debug!("visit_item: {:?} st={:?}", i, self.st); + // FIXME (#14132) ideally would incorporate reachability // analysis somewhere here, so items that never leak into // downstream crates (e.g. via monomorphisation or @@ -364,56 +385,69 @@ mod svh_visitor { SawItem.hash(self.st); visit::walk_item(self, i) } - fn visit_mod(&mut self, m: &'a Mod, _s: Span, _n: NodeId) { - SawMod.hash(self.st); visit::walk_mod(self, m) + fn visit_mod(&mut self, m: &'a Mod, _s: Span, n: NodeId) { + debug!("visit_mod: st={:?}", self.st); + SawMod.hash(self.st); visit::walk_mod(self, m, n) } fn visit_decl(&mut self, d: &'a Decl) { + debug!("visit_decl: st={:?}", self.st); SawDecl.hash(self.st); visit::walk_decl(self, d) } fn visit_ty(&mut self, t: &'a Ty) { + debug!("visit_ty: st={:?}", self.st); SawTy.hash(self.st); visit::walk_ty(self, t) } fn visit_generics(&mut self, g: &'a Generics) { + debug!("visit_generics: st={:?}", self.st); SawGenerics.hash(self.st); visit::walk_generics(self, g) } fn visit_fn(&mut self, fk: FnKind<'a>, fd: &'a FnDecl, - b: &'a Block, s: Span, _: NodeId) { - SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s) + b: &'a Block, s: Span, n: NodeId) { + debug!("visit_fn: st={:?}", self.st); + SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s, n) } fn visit_trait_item(&mut self, ti: &'a TraitItem) { + debug!("visit_trait_item: st={:?}", self.st); SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti) } fn visit_impl_item(&mut self, ii: &'a ImplItem) { + debug!("visit_impl_item: st={:?}", self.st); SawImplItem.hash(self.st); visit::walk_impl_item(self, ii) } fn visit_struct_field(&mut self, s: &'a StructField) { + debug!("visit_struct_field: st={:?}", self.st); SawStructField.hash(self.st); visit::walk_struct_field(self, s) } fn visit_path(&mut self, path: &'a Path, _: ast::NodeId) { + debug!("visit_path: st={:?}", self.st); SawPath.hash(self.st); visit::walk_path(self, path) } fn visit_block(&mut self, b: &'a Block) { + debug!("visit_block: st={:?}", self.st); SawBlock.hash(self.st); visit::walk_block(self, b) } fn visit_pat(&mut self, p: &'a Pat) { + debug!("visit_pat: st={:?}", self.st); SawPat.hash(self.st); visit::walk_pat(self, p) } fn visit_local(&mut self, l: &'a Local) { + debug!("visit_local: st={:?}", self.st); SawLocal.hash(self.st); visit::walk_local(self, l) } fn visit_arm(&mut self, a: &'a Arm) { + debug!("visit_arm: st={:?}", self.st); SawArm.hash(self.st); visit::walk_arm(self, a) } } diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index ed31e0ba5105..0d11b0794fea 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -19,6 +19,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] +#![feature(question_mark)] #![feature(rustc_private)] #![feature(staged_api)] @@ -40,3 +41,6 @@ pub use assert_dep_graph::assert_dep_graph; pub use calculate_svh::SvhCalculate; pub use persist::load_dep_graph; pub use persist::save_dep_graph; +pub use persist::save_trans_partition; +pub use persist::save_work_products; +pub use persist::in_incr_comp_dir; diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index f57ab19a5256..95e9a16f29bb 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -10,8 +10,9 @@ //! The data that we will serialize and deserialize. -use rustc::dep_graph::DepNode; +use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId}; use rustc::hir::def_id::DefIndex; +use std::sync::Arc; use super::directory::DefPathIndex; @@ -55,6 +56,15 @@ pub struct SerializedHash { pub hash: u64, } +#[derive(Debug, RustcEncodable, RustcDecodable)] +pub struct SerializedWorkProduct { + /// node that produced the work-product + pub id: Arc, + + /// work-product data itself + pub work_product: WorkProduct, +} + /// Data for use when downstream crates get recompiled. #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedMetadataHashes { diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 0ac1018462ee..36b6c79c40f5 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -14,12 +14,13 @@ use rbml::Error; use rbml::opaque::Decoder; use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; +use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashSet; use rustc_serialize::Decodable as RustcDecodable; use std::io::Read; -use std::fs::File; -use std::path::Path; +use std::fs::{self, File}; +use std::path::{Path}; use super::data::*; use super::directory::*; @@ -38,18 +39,43 @@ type CleanEdges = Vec<(DepNode, DepNode)>; /// actually it doesn't matter all that much.) See `README.md` for /// more general overview. pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _ignore = tcx.dep_graph.in_ignore(); + if tcx.sess.opts.incremental.is_none() { + return; + } - if let Some(dep_graph) = dep_graph_path(tcx) { - // FIXME(#32754) lock file? - load_dep_graph_if_exists(tcx, &dep_graph); - dirty_clean::check_dirty_clean_annotations(tcx); + let _ignore = tcx.dep_graph.in_ignore(); + load_dep_graph_if_exists(tcx); + dirty_clean::check_dirty_clean_annotations(tcx); +} + +fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + let dep_graph_path = dep_graph_path(tcx).unwrap(); + let dep_graph_data = match load_data(tcx.sess, &dep_graph_path) { + Some(p) => p, + None => return // no file + }; + + let work_products_path = tcx_work_products_path(tcx).unwrap(); + let work_products_data = match load_data(tcx.sess, &work_products_path) { + Some(p) => p, + None => return // no file + }; + + match decode_dep_graph(tcx, &dep_graph_data, &work_products_data) { + Ok(()) => return, + Err(err) => { + tcx.sess.warn( + &format!("decoding error in dep-graph from `{}` and `{}`: {}", + dep_graph_path.display(), + work_products_path.display(), + err)); + } } } -pub fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, path: &Path) { +fn load_data(sess: &Session, path: &Path) -> Option> { if !path.exists() { - return; + return None; } let mut data = vec![]; @@ -57,31 +83,30 @@ pub fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, path: &Pa File::open(path) .and_then(|mut file| file.read_to_end(&mut data)) { - Ok(_) => { } + Ok(_) => { + Some(data) + } Err(err) => { - tcx.sess.err( + sess.err( &format!("could not load dep-graph from `{}`: {}", path.display(), err)); - return; + None } } - match decode_dep_graph(tcx, &data) { - Ok(dirty) => dirty, - Err(err) => { - bug!("decoding error in dep-graph from `{}`: {}", path.display(), err); - } - } } +/// Decode the dep graph and load the edges/nodes that are still clean +/// into `tcx.dep_graph`. pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - data: &[u8]) + dep_graph_data: &[u8], + work_products_data: &[u8]) -> Result<(), Error> { // Deserialize the directory and dep-graph. - let mut decoder = Decoder::new(data, 0); - let directory = try!(DefIdDirectory::decode(&mut decoder)); - let serialized_dep_graph = try!(SerializedDepGraph::decode(&mut decoder)); + let mut dep_graph_decoder = Decoder::new(dep_graph_data, 0); + let directory = try!(DefIdDirectory::decode(&mut dep_graph_decoder)); + let serialized_dep_graph = try!(SerializedDepGraph::decode(&mut dep_graph_decoder)); debug!("decode_dep_graph: directory = {:#?}", directory); debug!("decode_dep_graph: serialized_dep_graph = {:#?}", serialized_dep_graph); @@ -121,12 +146,18 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Add nodes and edges that are not dirty into our main graph. let dep_graph = tcx.dep_graph.clone(); for (source, target) in clean_edges.into_iter().chain(clean_nodes) { - let _task = dep_graph.in_task(target.clone()); - dep_graph.read(source.clone()); - debug!("decode_dep_graph: clean edge: {:?} -> {:?}", source, target); + + let _task = dep_graph.in_task(target); + dep_graph.read(source); } + // Add in work-products that are still clean, and delete those that are + // dirty. + let mut work_product_decoder = Decoder::new(work_products_data, 0); + let work_products = try!(>::decode(&mut work_product_decoder)); + reconcile_work_products(tcx, work_products, &dirty_nodes); + Ok(()) } @@ -141,9 +172,9 @@ fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match hash.node.map_def(|&i| retraced.def_id(i)) { Some(dep_node) => { let current_hash = hcx.hash(&dep_node).unwrap(); - debug!("initial_dirty_nodes: hash of {:?} is {:?}, was {:?}", - dep_node, current_hash, hash.hash); if current_hash != hash.hash { + debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}", + dep_node, current_hash, hash.hash); dirty_nodes.insert(dep_node); } } @@ -177,6 +208,8 @@ fn compute_clean_edges(serialized_edges: &[(SerializedEdge)], clean_edges.push((source, target)) } else { // source removed, target must be dirty + debug!("compute_clean_edges: {:?} dirty because {:?} no longer exists", + target, serialized_source); dirty_nodes.insert(target); } } else { @@ -213,3 +246,51 @@ fn compute_clean_edges(serialized_edges: &[(SerializedEdge)], clean_edges } + +/// Go through the list of work-products produced in the previous run. +/// Delete any whose nodes have been found to be dirty or which are +/// otherwise no longer applicable. +fn reconcile_work_products<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + work_products: Vec, + dirty_nodes: &DirtyNodes) { + debug!("reconcile_work_products({:?})", work_products); + for swp in work_products { + let dep_node = DepNode::WorkProduct(swp.id.clone()); + if dirty_nodes.contains(&dep_node) { + debug!("reconcile_work_products: dep-node for {:?} is dirty", swp); + delete_dirty_work_product(tcx, swp); + } else { + let all_files_exist = + swp.work_product + .saved_files + .iter() + .all(|&(_, ref file_name)| { + let path = in_incr_comp_dir(tcx.sess, &file_name).unwrap(); + path.exists() + }); + if all_files_exist { + debug!("reconcile_work_products: all files for {:?} exist", swp); + tcx.dep_graph.insert_previous_work_product(&swp.id, swp.work_product); + } else { + debug!("reconcile_work_products: some file for {:?} does not exist", swp); + delete_dirty_work_product(tcx, swp); + } + } + } +} + +fn delete_dirty_work_product(tcx: TyCtxt, + swp: SerializedWorkProduct) { + debug!("delete_dirty_work_product({:?})", swp); + for &(_, ref file_name) in &swp.work_product.saved_files { + let path = in_incr_comp_dir(tcx.sess, file_name).unwrap(); + match fs::remove_file(&path) { + Ok(()) => { } + Err(err) => { + tcx.sess.warn( + &format!("file-system error deleting outdated file `{}`: {}", + path.display(), err)); + } + } + } +} diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index 72ccc29c97b6..1157f494ce60 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -19,6 +19,10 @@ mod hash; mod load; mod save; mod util; +mod work_product; pub use self::load::load_dep_graph; pub use self::save::save_dep_graph; +pub use self::save::save_work_products; +pub use self::work_product::save_trans_partition; +pub use self::util::in_incr_comp_dir; diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 99f4d4f30729..305250d59623 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -11,6 +11,7 @@ use rbml::opaque::Encoder; use rustc::dep_graph::DepNode; use rustc::middle::cstore::LOCAL_CRATE; +use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_serialize::{Encodable as RustcEncodable}; use std::hash::{Hasher, SipHasher}; @@ -24,19 +25,26 @@ use super::hash::*; use super::util::*; pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + debug!("save_dep_graph()"); let _ignore = tcx.dep_graph.in_ignore(); + let sess = tcx.sess; let mut hcx = HashContext::new(tcx); - save_in(&mut hcx, dep_graph_path(tcx), encode_dep_graph); - save_in(&mut hcx, metadata_hash_path(tcx, LOCAL_CRATE), encode_metadata_hashes); + save_in(sess, dep_graph_path(tcx), |e| encode_dep_graph(&mut hcx, e)); + save_in(sess, metadata_hash_path(tcx, LOCAL_CRATE), |e| encode_metadata_hashes(&mut hcx, e)); } -fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>, - opt_path_buf: Option, - encode: F) - where F: FnOnce(&mut HashContext<'a, 'tcx>, &mut Encoder) -> io::Result<()> -{ - let tcx = hcx.tcx; +pub fn save_work_products(sess: &Session, local_crate_name: &str) { + debug!("save_work_products()"); + let _ignore = sess.dep_graph.in_ignore(); + let path = sess_work_products_path(sess, local_crate_name); + save_in(sess, path, |e| encode_work_products(sess, e)); +} +fn save_in(sess: &Session, + opt_path_buf: Option, + encode: F) + where F: FnOnce(&mut Encoder) -> io::Result<()> +{ let path_buf = match opt_path_buf { Some(p) => p, None => return @@ -49,7 +57,7 @@ fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>, match fs::remove_file(&path_buf) { Ok(()) => { } Err(err) => { - tcx.sess.err( + sess.err( &format!("unable to delete old dep-graph at `{}`: {}", path_buf.display(), err)); return; @@ -59,10 +67,10 @@ fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>, // generate the data in a memory buffer let mut wr = Cursor::new(Vec::new()); - match encode(hcx, &mut Encoder::new(&mut wr)) { + match encode(&mut Encoder::new(&mut wr)) { Ok(()) => { } Err(err) => { - tcx.sess.err( + sess.err( &format!("could not encode dep-graph to `{}`: {}", path_buf.display(), err)); return; @@ -77,7 +85,7 @@ fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>, { Ok(_) => { } Err(err) => { - tcx.sess.err( + sess.err( &format!("failed to write dep-graph to `{}`: {}", path_buf.display(), err)); return; @@ -192,3 +200,22 @@ pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>, Ok(()) } + +pub fn encode_work_products(sess: &Session, + encoder: &mut Encoder) + -> io::Result<()> +{ + let work_products: Vec<_> = + sess.dep_graph.work_products() + .iter() + .map(|(id, work_product)| { + SerializedWorkProduct { + id: id.clone(), + work_product: work_product.clone(), + } + }) + .collect(); + + work_products.encode(encoder) +} + diff --git a/src/librustc_incremental/persist/util.rs b/src/librustc_incremental/persist/util.rs index a77a9607e773..f1e81fdb266b 100644 --- a/src/librustc_incremental/persist/util.rs +++ b/src/librustc_incremental/persist/util.rs @@ -9,6 +9,7 @@ // except according to those terms. use rustc::middle::cstore::LOCAL_CRATE; +use rustc::session::Session; use rustc::ty::TyCtxt; use std::fs; @@ -17,33 +18,56 @@ use std::path::{Path, PathBuf}; use syntax::ast; pub fn dep_graph_path(tcx: TyCtxt) -> Option { - path(tcx, LOCAL_CRATE, "local") + tcx_path(tcx, LOCAL_CRATE, "local") } pub fn metadata_hash_path(tcx: TyCtxt, cnum: ast::CrateNum) -> Option { - path(tcx, cnum, "metadata") + tcx_path(tcx, cnum, "metadata") } -fn path(tcx: TyCtxt, cnum: ast::CrateNum, suffix: &str) -> Option { +pub fn tcx_work_products_path(tcx: TyCtxt) -> Option { + let crate_name = tcx.crate_name(LOCAL_CRATE); + sess_work_products_path(tcx.sess, &crate_name) +} + +pub fn sess_work_products_path(sess: &Session, + local_crate_name: &str) + -> Option { + let crate_disambiguator = sess.local_crate_disambiguator(); + path(sess, local_crate_name, &crate_disambiguator, "work-products") +} + +pub fn in_incr_comp_dir(sess: &Session, file_name: &str) -> Option { + sess.opts.incremental.as_ref().map(|incr_dir| incr_dir.join(file_name)) +} + +fn tcx_path(tcx: TyCtxt, + cnum: ast::CrateNum, + middle: &str) + -> Option { + path(tcx.sess, &tcx.crate_name(cnum), &tcx.crate_disambiguator(cnum), middle) +} + +fn path(sess: &Session, + crate_name: &str, + crate_disambiguator: &str, + middle: &str) + -> Option { // For now, just save/load dep-graph from // directory/dep_graph.rbml - tcx.sess.opts.incremental.as_ref().and_then(|incr_dir| { + sess.opts.incremental.as_ref().and_then(|incr_dir| { match create_dir_racy(&incr_dir) { Ok(()) => {} Err(err) => { - tcx.sess.err( + sess.err( &format!("could not create the directory `{}`: {}", incr_dir.display(), err)); return None; } } - let crate_name = tcx.crate_name(cnum); - let crate_disambiguator = tcx.crate_disambiguator(cnum); - let file_name = format!("{}-{}.{}.bin", - crate_name, - crate_disambiguator, - suffix); + let file_name = format!("{}-{}.{}.bin", crate_name, crate_disambiguator, middle); + Some(incr_dir.join(file_name)) }) } diff --git a/src/librustc_incremental/persist/work_product.rs b/src/librustc_incremental/persist/work_product.rs new file mode 100644 index 000000000000..c106ea8f2626 --- /dev/null +++ b/src/librustc_incremental/persist/work_product.rs @@ -0,0 +1,63 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains files for saving intermediate work-products. + +use persist::util::*; +use rustc::dep_graph::{WorkProduct, WorkProductId}; +use rustc::session::Session; +use rustc::session::config::OutputType; +use rustc::util::fs::link_or_copy; +use std::path::PathBuf; +use std::sync::Arc; + +pub fn save_trans_partition(sess: &Session, + cgu_name: &str, + partition_hash: u64, + files: &[(OutputType, PathBuf)]) { + debug!("save_trans_partition({:?},{},{:?})", + cgu_name, + partition_hash, + files); + if sess.opts.incremental.is_none() { + return; + } + let work_product_id = Arc::new(WorkProductId(cgu_name.to_string())); + + let saved_files: Option> = + files.iter() + .map(|&(kind, ref path)| { + let file_name = format!("cgu-{}.{}", cgu_name, kind.extension()); + let path_in_incr_dir = in_incr_comp_dir(sess, &file_name).unwrap(); + match link_or_copy(path, &path_in_incr_dir) { + Ok(_) => Some((kind, file_name)), + Err(err) => { + sess.warn(&format!("error copying object file `{}` \ + to incremental directory as `{}`: {}", + path.display(), + path_in_incr_dir.display(), + err)); + None + } + } + }) + .collect(); + let saved_files = match saved_files { + Some(v) => v, + None => return, + }; + + let work_product = WorkProduct { + input_hash: partition_hash, + saved_files: saved_files, + }; + + sess.dep_graph.insert_work_product(&work_product_id, work_product); +} diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 18f9733040e0..49dad2d0f6d9 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -44,7 +44,7 @@ use lint::{LintPass, LateLintPass}; use std::collections::HashSet; use syntax::{ast}; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr::{self, AttrMetaMethods, AttributeMethods}; use syntax_pos::{self, Span}; use rustc::hir::{self, PatKind}; @@ -298,12 +298,7 @@ impl MissingDoc { } } - let has_doc = attrs.iter().any(|a| { - match a.node.value.node { - ast::MetaItemKind::NameValue(ref name, _) if *name == "doc" => true, - _ => false - } - }); + let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc"); if !has_doc { cx.span_lint(MISSING_DOCS, sp, &format!("missing documentation for {}", desc)); @@ -572,18 +567,36 @@ declare_lint! { } /// Checks for use of items with `#[deprecated]` or `#[rustc_deprecated]` attributes -#[derive(Copy, Clone)] -pub struct Deprecated; +#[derive(Clone)] +pub struct Deprecated { + /// Tracks the `NodeId` of the current item. + /// + /// This is required since not all node ids are present in the hir map. + current_item: ast::NodeId, +} impl Deprecated { + pub fn new() -> Deprecated { + Deprecated { + current_item: ast::CRATE_NODE_ID, + } + } + fn lint(&self, cx: &LateContext, _id: DefId, span: Span, - stability: &Option<&attr::Stability>, deprecation: &Option) { + stability: &Option<&attr::Stability>, + deprecation: &Option) { // Deprecated attributes apply in-crate and cross-crate. if let Some(&attr::Stability{rustc_depr: Some(attr::RustcDeprecation{ref reason, ..}), ..}) = *stability { output(cx, DEPRECATED, span, Some(&reason)) - } else if let Some(attr::Deprecation{ref note, ..}) = *deprecation { - output(cx, DEPRECATED, span, note.as_ref().map(|x| &**x)) + } else if let Some(ref depr_entry) = *deprecation { + if let Some(parent_depr) = cx.tcx.lookup_deprecation_entry(self.parent_def(cx)) { + if parent_depr.same_origin(depr_entry) { + return; + } + } + + output(cx, DEPRECATED, span, depr_entry.attr.note.as_ref().map(|x| &**x)) } fn output(cx: &LateContext, lint: &'static Lint, span: Span, note: Option<&str>) { @@ -596,6 +609,19 @@ impl Deprecated { cx.span_lint(lint, span, &msg); } } + + fn push_item(&mut self, item_id: ast::NodeId) { + self.current_item = item_id; + } + + fn item_post(&mut self, cx: &LateContext, item_id: ast::NodeId) { + assert_eq!(self.current_item, item_id); + self.current_item = cx.tcx.map.get_parent(item_id); + } + + fn parent_def(&self, cx: &LateContext) -> DefId { + cx.tcx.map.local_def_id(self.current_item) + } } impl LintPass for Deprecated { @@ -606,11 +632,16 @@ impl LintPass for Deprecated { impl LateLintPass for Deprecated { fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { + self.push_item(item.id); stability::check_item(cx.tcx, item, false, &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } + fn check_item_post(&mut self, cx: &LateContext, item: &hir::Item) { + self.item_post(cx, item.id); + } + fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { stability::check_expr(cx.tcx, e, &mut |id, sp, stab, depr| @@ -634,6 +665,30 @@ impl LateLintPass for Deprecated { &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr)); } + + fn check_impl_item(&mut self, _: &LateContext, item: &hir::ImplItem) { + self.push_item(item.id); + } + + fn check_impl_item_post(&mut self, cx: &LateContext, item: &hir::ImplItem) { + self.item_post(cx, item.id); + } + + fn check_trait_item(&mut self, _: &LateContext, item: &hir::TraitItem) { + self.push_item(item.id); + } + + fn check_trait_item_post(&mut self, cx: &LateContext, item: &hir::TraitItem) { + self.item_post(cx, item.id); + } + + fn check_foreign_item(&mut self, _: &LateContext, item: &hir::ForeignItem) { + self.push_item(item.id); + } + + fn check_foreign_item_post(&mut self, cx: &LateContext, item: &hir::ForeignItem) { + self.item_post(cx, item.id); + } } declare_lint! { @@ -1094,10 +1149,10 @@ impl LintPass for UnstableFeatures { impl LateLintPass for UnstableFeatures { fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) { - if attr::contains_name(&[attr.node.value.clone()], "feature") { - if let Some(items) = attr.node.value.meta_item_list() { + if attr::contains_name(&[attr.meta().clone()], "feature") { + if let Some(items) = attr.meta().meta_item_list() { for item in items { - ctx.span_lint(UNSTABLE_FEATURES, item.span, "unstable feature"); + ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature"); } } } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 7b0ee91b69ed..43376dfd8c2a 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -124,7 +124,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UnusedAllocation, MissingCopyImplementations, UnstableFeatures, - Deprecated, UnconditionalRecursion, InvalidNoMangleItems, PluginAsLibrary, @@ -133,6 +132,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { ); add_builtin_with_new!(sess, + Deprecated, TypeLimits, MissingDoc, MissingDebugImplementations, diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml index 05d20911a5dc..f97daa22ff66 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/src/librustc_llvm/Cargo.toml @@ -17,4 +17,4 @@ rustc_bitflags = { path = "../librustc_bitflags" } [build-dependencies] build_helper = { path = "../build_helper" } -gcc = "0.3" +gcc = "0.3.27" diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 96b419d647ee..5f7a0f788ca1 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -13,7 +13,7 @@ extern crate build_helper; use std::process::Command; use std::env; -use std::path::PathBuf; +use std::path::{PathBuf, Path}; use build_helper::output; @@ -116,8 +116,7 @@ fn main() { cfg.flag("-DLLVM_RUSTLLVM"); } - cfg.file("../rustllvm/ExecutionEngineWrapper.cpp") - .file("../rustllvm/PassWrapper.cpp") + cfg.file("../rustllvm/PassWrapper.cpp") .file("../rustllvm/RustWrapper.cpp") .file("../rustllvm/ArchiveWrapper.cpp") .cpp(true) @@ -139,8 +138,17 @@ fn main() { &lib[2..] } else if lib.starts_with("-") { &lib[1..] + } else if Path::new(lib).exists() { + // On MSVC llvm-config will print the full name to libraries, but + // we're only interested in the name part + let name = Path::new(lib).file_name().unwrap().to_str().unwrap(); + name.trim_right_matches(".lib") + } else if lib.ends_with(".lib") { + // Some MSVC libraries just come up with `.lib` tacked on, so chop + // that off + lib.trim_right_matches(".lib") } else { - continue; + continue }; // Don't need or want this library, but LLVM's CMake build system @@ -149,7 +157,7 @@ fn main() { // library and it otherwise may just pull in extra dependencies on // libedit which we don't want if name == "LLVMLineEditor" { - continue; + continue } let kind = if name.starts_with("LLVM") { @@ -169,7 +177,9 @@ fn main() { let mut cmd = Command::new(&llvm_config); cmd.arg("--ldflags"); for lib in output(&mut cmd).split_whitespace() { - if is_crossed { + if lib.starts_with("-LIBPATH:") { + println!("cargo:rustc-link-search=native={}", &lib[9..]); + } else if is_crossed { if lib.starts_with("-L") { println!("cargo:rustc-link-search=native={}", lib[2..].replace(&host, &target)); diff --git a/src/librustc_llvm/diagnostic.rs b/src/librustc_llvm/diagnostic.rs index 44e015614640..8520ae1df60d 100644 --- a/src/librustc_llvm/diagnostic.rs +++ b/src/librustc_llvm/diagnostic.rs @@ -16,22 +16,29 @@ pub use self::Diagnostic::*; use libc::{c_char, c_uint}; use std::ptr; -use {DebugLocRef, DiagnosticInfoRef, TwineRef, ValueRef}; +use {DiagnosticInfoRef, TwineRef, ValueRef}; +use ffi::DebugLocRef; #[derive(Copy, Clone)] pub enum OptimizationDiagnosticKind { OptimizationRemark, OptimizationMissed, OptimizationAnalysis, + OptimizationAnalysisFPCommute, + OptimizationAnalysisAliasing, OptimizationFailure, + OptimizationRemarkOther, } impl OptimizationDiagnosticKind { pub fn describe(self) -> &'static str { match self { - OptimizationRemark => "remark", + OptimizationRemark | + OptimizationRemarkOther => "remark", OptimizationMissed => "missed", OptimizationAnalysis => "analysis", + OptimizationAnalysisFPCommute => "floating-point", + OptimizationAnalysisAliasing => "aliasing", OptimizationFailure => "failure", } } @@ -58,11 +65,11 @@ impl OptimizationDiagnostic { message: ptr::null_mut(), }; - super::LLVMUnpackOptimizationDiagnostic(di, - &mut opt.pass_name, - &mut opt.function, - &mut opt.debug_loc, - &mut opt.message); + super::LLVMRustUnpackOptimizationDiagnostic(di, + &mut opt.pass_name, + &mut opt.function, + &mut opt.debug_loc, + &mut opt.message); opt } @@ -84,10 +91,10 @@ impl InlineAsmDiagnostic { instruction: ptr::null_mut(), }; - super::LLVMUnpackInlineAsmDiagnostic(di, - &mut opt.cookie, - &mut opt.message, - &mut opt.instruction); + super::LLVMRustUnpackInlineAsmDiagnostic(di, + &mut opt.cookie, + &mut opt.message, + &mut opt.instruction); opt } @@ -103,24 +110,39 @@ pub enum Diagnostic { impl Diagnostic { pub unsafe fn unpack(di: DiagnosticInfoRef) -> Diagnostic { - let kind = super::LLVMGetDiagInfoKind(di); + use super::DiagnosticKind as Dk; + let kind = super::LLVMRustGetDiagInfoKind(di); match kind { - super::DK_InlineAsm => InlineAsm(InlineAsmDiagnostic::unpack(di)), + Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpack(di)), - super::DK_OptimizationRemark => { + Dk::OptimizationRemark => { Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di)) } - - super::DK_OptimizationRemarkMissed => { + Dk::OptimizationRemarkOther => { + Optimization(OptimizationDiagnostic::unpack(OptimizationRemarkOther, di)) + } + Dk::OptimizationRemarkMissed => { Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di)) } - super::DK_OptimizationRemarkAnalysis => { + Dk::OptimizationRemarkAnalysis => { Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di)) } - super::DK_OptimizationFailure => { + + Dk::OptimizationRemarkAnalysisFPCommute => { + Optimization(OptimizationDiagnostic::unpack( + OptimizationAnalysisFPCommute, di)) + } + + Dk::OptimizationRemarkAnalysisAliasing => { + Optimization(OptimizationDiagnostic::unpack( + OptimizationAnalysisAliasing, di)) + } + + + Dk::OptimizationFailure => { Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di)) } diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs new file mode 100644 index 000000000000..b2ffcac365ba --- /dev/null +++ b/src/librustc_llvm/ffi.rs @@ -0,0 +1,2071 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use debuginfo::{DIBuilderRef, DIDescriptor, + DIFile, DILexicalBlock, DISubprogram, DIType, + DIBasicType, DIDerivedType, DICompositeType, DIScope, + DIVariable, DIGlobalVariable, DIArray, DISubrange, + DITemplateTypeParameter, DIEnumerator, DINameSpace}; + +use libc::{c_uint, c_int, size_t, c_char}; +use libc::{c_longlong, c_ulonglong, c_void}; + +use RustStringRef; + +pub type Opcode = u32; +pub type Bool = c_uint; + +pub const True: Bool = 1 as Bool; +pub const False: Bool = 0 as Bool; + +#[derive(Copy, Clone, PartialEq)] +#[repr(C)] +pub enum LLVMRustResult { + Success, + Failure, +} +// Consts for the LLVM CallConv type, pre-cast to usize. + +/// LLVM CallingConv::ID. Should we wrap this? +#[derive(Copy, Clone, PartialEq)] +#[repr(C)] +pub enum CallConv { + CCallConv = 0, + FastCallConv = 8, + ColdCallConv = 9, + X86StdcallCallConv = 64, + X86FastcallCallConv = 65, + X86_64_Win64 = 79, + X86_VectorCall = 80 +} + +/// LLVMLinkage +/// +/// This enum omits the obsolete (and no-op) linkage types DLLImportLinkage, +/// DLLExportLinkage, GhostLinkage and LinkOnceODRAutoHideLinkage. +/// LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either; +/// they've been removed in upstream LLVM commit r203866. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[repr(C)] +pub enum Linkage { + ExternalLinkage = 0, + AvailableExternallyLinkage = 1, + LinkOnceAnyLinkage = 2, + LinkOnceODRLinkage = 3, + WeakAnyLinkage = 5, + WeakODRLinkage = 6, + AppendingLinkage = 7, + InternalLinkage = 8, + PrivateLinkage = 9, + ExternalWeakLinkage = 12, + CommonLinkage = 14, +} + +/// LLVMDiagnosticSeverity +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub enum DiagnosticSeverity { + Error = 0, + Warning = 1, + Remark = 2, + Note = 3, +} + +/// LLVMDLLStorageClass +#[derive(Copy, Clone)] +#[repr(C)] +pub enum DLLStorageClass { + Default = 0, + DllImport = 1, /* Function to be imported from DLL. */ + DllExport = 2, /* Function to be accessible from DLL. */ +} + +bitflags! { + #[derive(Default, Debug)] + flags Attribute : u64 { + const ZExt = 1 << 0, + const SExt = 1 << 1, + const NoReturn = 1 << 2, + const InReg = 1 << 3, + const StructRet = 1 << 4, + const NoUnwind = 1 << 5, + const NoAlias = 1 << 6, + const ByVal = 1 << 7, + const Nest = 1 << 8, + const ReadNone = 1 << 9, + const ReadOnly = 1 << 10, + const NoInline = 1 << 11, + const AlwaysInline = 1 << 12, + const OptimizeForSize = 1 << 13, + const StackProtect = 1 << 14, + const StackProtectReq = 1 << 15, + const NoCapture = 1 << 21, + const NoRedZone = 1 << 22, + const NoImplicitFloat = 1 << 23, + const Naked = 1 << 24, + const InlineHint = 1 << 25, + const ReturnsTwice = 1 << 29, + const UWTable = 1 << 30, + const NonLazyBind = 1 << 31, + + // Some of these are missing from the LLVM C API, the rest are + // present, but commented out, and preceded by the following warning: + // FIXME: These attributes are currently not included in the C API as + // a temporary measure until the API/ABI impact to the C API is understood + // and the path forward agreed upon. + const SanitizeAddress = 1 << 32, + const MinSize = 1 << 33, + const NoDuplicate = 1 << 34, + const StackProtectStrong = 1 << 35, + const SanitizeThread = 1 << 36, + const SanitizeMemory = 1 << 37, + const NoBuiltin = 1 << 38, + const Returned = 1 << 39, + const Cold = 1 << 40, + const Builtin = 1 << 41, + const OptimizeNone = 1 << 42, + const InAlloca = 1 << 43, + const NonNull = 1 << 44, + const JumpTable = 1 << 45, + const Convergent = 1 << 46, + const SafeStack = 1 << 47, + const NoRecurse = 1 << 48, + const InaccessibleMemOnly = 1 << 49, + const InaccessibleMemOrArgMemOnly = 1 << 50, + } +} + +/// LLVMIntPredicate +#[derive(Copy, Clone)] +#[repr(C)] +pub enum IntPredicate { + IntEQ = 32, + IntNE = 33, + IntUGT = 34, + IntUGE = 35, + IntULT = 36, + IntULE = 37, + IntSGT = 38, + IntSGE = 39, + IntSLT = 40, + IntSLE = 41, +} + +/// LLVMRealPredicate +#[derive(Copy, Clone)] +#[repr(C)] +pub enum RealPredicate { + RealPredicateFalse = 0, + RealOEQ = 1, + RealOGT = 2, + RealOGE = 3, + RealOLT = 4, + RealOLE = 5, + RealONE = 6, + RealORD = 7, + RealUNO = 8, + RealUEQ = 9, + RealUGT = 10, + RealUGE = 11, + RealULT = 12, + RealULE = 13, + RealUNE = 14, + RealPredicateTrue = 15, +} + +/// LLVMTypeKind +#[derive(Copy, Clone, PartialEq, Debug)] +#[repr(C)] +pub enum TypeKind { + Void = 0, + Half = 1, + Float = 2, + Double = 3, + X86_FP80 = 4, + FP128 = 5, + PPC_FP128 = 6, + Label = 7, + Integer = 8, + Function = 9, + Struct = 10, + Array = 11, + Pointer = 12, + Vector = 13, + Metadata = 14, + X86_MMX = 15, + Token = 16, +} + +/// LLVMAtomicRmwBinOp +#[derive(Copy, Clone)] +#[repr(C)] +pub enum AtomicRmwBinOp { + AtomicXchg = 0, + AtomicAdd = 1, + AtomicSub = 2, + AtomicAnd = 3, + AtomicNand = 4, + AtomicOr = 5, + AtomicXor = 6, + AtomicMax = 7, + AtomicMin = 8, + AtomicUMax = 9, + AtomicUMin = 10, +} + +/// LLVMAtomicOrdering +#[derive(Copy, Clone)] +#[repr(C)] +pub enum AtomicOrdering { + NotAtomic = 0, + Unordered = 1, + Monotonic = 2, + // Consume = 3, // Not specified yet. + Acquire = 4, + Release = 5, + AcquireRelease = 6, + SequentiallyConsistent = 7 +} + +/// LLVMRustSynchronizationScope +#[derive(Copy, Clone)] +#[repr(C)] +pub enum SynchronizationScope { + Other, + SingleThread, + CrossThread, +} + +/// LLVMRustFileType +#[derive(Copy, Clone)] +#[repr(C)] +pub enum FileType { + Other, + AssemblyFile, + ObjectFile, +} + +/// Enum pinned in LLVMContext, used in +/// LLVMSetMetadata so ABI-stable. +#[derive(Copy, Clone)] +#[repr(C)] +pub enum MetadataType { + MD_dbg = 0, + MD_tbaa = 1, + MD_prof = 2, + MD_fpmath = 3, + MD_range = 4, + MD_tbaa_struct = 5, + MD_invariant_load = 6, + MD_alias_scope = 7, + MD_noalias = 8, + MD_nontemporal = 9, + MD_mem_parallel_loop_access = 10, + MD_nonnull = 11, +} + +/// LLVMRustAsmDialect +#[derive(Copy, Clone)] +#[repr(C)] +pub enum AsmDialect { + Other, + Att, + Intel, +} + +/// LLVMRustCodeGenOptLevel +#[derive(Copy, Clone, PartialEq)] +#[repr(C)] +pub enum CodeGenOptLevel { + Other, + None, + Less, + Default, + Aggressive, +} + +/// LLVMRelocMode +#[derive(Copy, Clone, PartialEq)] +#[repr(C)] +pub enum RelocMode { + Default = 0, + Static = 1, + PIC = 2, + DynamicNoPic = 3, +} + +/// LLVMRustCodeModel +#[derive(Copy, Clone)] +#[repr(C)] +pub enum CodeModel { + Other, + Default, + JITDefault, + Small, + Kernel, + Medium, + Large, +} + +/// LLVMRustDiagnosticKind +#[derive(Copy, Clone)] +#[repr(C)] +pub enum DiagnosticKind { + Other, + InlineAsm, + StackSize, + DebugMetadataVersion, + SampleProfile, + OptimizationRemark, + OptimizationRemarkMissed, + OptimizationRemarkAnalysis, + OptimizationRemarkAnalysisFPCommute, + OptimizationRemarkAnalysisAliasing, + OptimizationRemarkOther, + OptimizationFailure, +} + +/// LLVMRustArchiveKind +#[derive(Copy, Clone)] +#[repr(C)] +pub enum ArchiveKind { + Other, + K_GNU, + K_MIPS64, + K_BSD, + K_COFF, +} + +/// LLVMRustPassKind +#[derive(Copy, Clone, PartialEq, Debug)] +#[repr(C)] +pub enum PassKind { + Other, + Function, + Module, +} + +// Opaque pointer types +#[allow(missing_copy_implementations)] +pub enum Module_opaque {} +pub type ModuleRef = *mut Module_opaque; +#[allow(missing_copy_implementations)] +pub enum Context_opaque {} +pub type ContextRef = *mut Context_opaque; +#[allow(missing_copy_implementations)] +pub enum Type_opaque {} +pub type TypeRef = *mut Type_opaque; +#[allow(missing_copy_implementations)] +pub enum Value_opaque {} +pub type ValueRef = *mut Value_opaque; +#[allow(missing_copy_implementations)] +pub enum Metadata_opaque {} +pub type MetadataRef = *mut Metadata_opaque; +#[allow(missing_copy_implementations)] +pub enum BasicBlock_opaque {} +pub type BasicBlockRef = *mut BasicBlock_opaque; +#[allow(missing_copy_implementations)] +pub enum Builder_opaque {} +pub type BuilderRef = *mut Builder_opaque; +#[allow(missing_copy_implementations)] +pub enum ExecutionEngine_opaque {} +pub type ExecutionEngineRef = *mut ExecutionEngine_opaque; +#[allow(missing_copy_implementations)] +pub enum MemoryBuffer_opaque {} +pub type MemoryBufferRef = *mut MemoryBuffer_opaque; +#[allow(missing_copy_implementations)] +pub enum PassManager_opaque {} +pub type PassManagerRef = *mut PassManager_opaque; +#[allow(missing_copy_implementations)] +pub enum PassManagerBuilder_opaque {} +pub type PassManagerBuilderRef = *mut PassManagerBuilder_opaque; +#[allow(missing_copy_implementations)] +pub enum Use_opaque {} +pub type UseRef = *mut Use_opaque; +#[allow(missing_copy_implementations)] +pub enum TargetData_opaque {} +pub type TargetDataRef = *mut TargetData_opaque; +#[allow(missing_copy_implementations)] +pub enum ObjectFile_opaque {} +pub type ObjectFileRef = *mut ObjectFile_opaque; +#[allow(missing_copy_implementations)] +pub enum SectionIterator_opaque {} +pub type SectionIteratorRef = *mut SectionIterator_opaque; +#[allow(missing_copy_implementations)] +pub enum Pass_opaque {} +pub type PassRef = *mut Pass_opaque; +#[allow(missing_copy_implementations)] +pub enum TargetMachine_opaque {} +pub type TargetMachineRef = *mut TargetMachine_opaque; +pub enum Archive_opaque {} +pub type ArchiveRef = *mut Archive_opaque; +pub enum ArchiveIterator_opaque {} +pub type ArchiveIteratorRef = *mut ArchiveIterator_opaque; +pub enum ArchiveChild_opaque {} +pub type ArchiveChildRef = *mut ArchiveChild_opaque; +#[allow(missing_copy_implementations)] +pub enum Twine_opaque {} +pub type TwineRef = *mut Twine_opaque; +#[allow(missing_copy_implementations)] +pub enum DiagnosticInfo_opaque {} +pub type DiagnosticInfoRef = *mut DiagnosticInfo_opaque; +#[allow(missing_copy_implementations)] +pub enum DebugLoc_opaque {} +pub type DebugLocRef = *mut DebugLoc_opaque; +#[allow(missing_copy_implementations)] +pub enum SMDiagnostic_opaque {} +pub type SMDiagnosticRef = *mut SMDiagnostic_opaque; +#[allow(missing_copy_implementations)] +pub enum RustArchiveMember_opaque {} +pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque; +#[allow(missing_copy_implementations)] +pub enum OperandBundleDef_opaque {} +pub type OperandBundleDefRef = *mut OperandBundleDef_opaque; + +pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void); +pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint); + +pub mod debuginfo { + pub use self::DIDescriptorFlags::*; + use super::{MetadataRef}; + + #[allow(missing_copy_implementations)] + pub enum DIBuilder_opaque {} + pub type DIBuilderRef = *mut DIBuilder_opaque; + + pub type DIDescriptor = MetadataRef; + pub type DIScope = DIDescriptor; + pub type DILocation = DIDescriptor; + pub type DIFile = DIScope; + pub type DILexicalBlock = DIScope; + pub type DISubprogram = DIScope; + pub type DINameSpace = DIScope; + pub type DIType = DIDescriptor; + pub type DIBasicType = DIType; + pub type DIDerivedType = DIType; + pub type DICompositeType = DIDerivedType; + pub type DIVariable = DIDescriptor; + pub type DIGlobalVariable = DIDescriptor; + pub type DIArray = DIDescriptor; + pub type DISubrange = DIDescriptor; + pub type DIEnumerator = DIDescriptor; + pub type DITemplateTypeParameter = DIDescriptor; + + #[derive(Copy, Clone)] + pub enum DIDescriptorFlags { + FlagPrivate = 1 << 0, + FlagProtected = 1 << 1, + FlagFwdDecl = 1 << 2, + FlagAppleBlock = 1 << 3, + FlagBlockByrefStruct = 1 << 4, + FlagVirtual = 1 << 5, + FlagArtificial = 1 << 6, + FlagExplicit = 1 << 7, + FlagPrototyped = 1 << 8, + FlagObjcClassComplete = 1 << 9, + FlagObjectPointer = 1 << 10, + FlagVector = 1 << 11, + FlagStaticMember = 1 << 12, + FlagIndirectVariable = 1 << 13, + FlagLValueReference = 1 << 14, + FlagRValueReference = 1 << 15 + } +} + + +// Link to our native llvm bindings (things that we need to use the C++ api +// for) and because llvm is written in C++ we need to link against libstdc++ +// +// You'll probably notice that there is an omission of all LLVM libraries +// from this location. This is because the set of LLVM libraries that we +// link to is mostly defined by LLVM, and the `llvm-config` tool is used to +// figure out the exact set of libraries. To do this, the build system +// generates an llvmdeps.rs file next to this one which will be +// automatically updated whenever LLVM is updated to include an up-to-date +// set of the libraries we need to link to LLVM for. +#[link(name = "rustllvm", kind = "static")] +#[cfg(not(cargobuild))] +extern {} + +#[linked_from = "rustllvm"] // not quite true but good enough +extern { + /* Create and destroy contexts. */ + pub fn LLVMContextCreate() -> ContextRef; + pub fn LLVMContextDispose(C: ContextRef); + pub fn LLVMGetMDKindIDInContext(C: ContextRef, + Name: *const c_char, + SLen: c_uint) + -> c_uint; + + /* Create and destroy modules. */ + pub fn LLVMModuleCreateWithNameInContext(ModuleID: *const c_char, + C: ContextRef) + -> ModuleRef; + pub fn LLVMGetModuleContext(M: ModuleRef) -> ContextRef; + pub fn LLVMCloneModule(M: ModuleRef) -> ModuleRef; + pub fn LLVMDisposeModule(M: ModuleRef); + + /// Data layout. See Module::getDataLayout. + pub fn LLVMGetDataLayout(M: ModuleRef) -> *const c_char; + pub fn LLVMSetDataLayout(M: ModuleRef, Triple: *const c_char); + + /// Target triple. See Module::getTargetTriple. + pub fn LLVMGetTarget(M: ModuleRef) -> *const c_char; + pub fn LLVMSetTarget(M: ModuleRef, Triple: *const c_char); + + /// See Module::dump. + pub fn LLVMDumpModule(M: ModuleRef); + + /// See Module::setModuleInlineAsm. + pub fn LLVMSetModuleInlineAsm(M: ModuleRef, Asm: *const c_char); + + /// See llvm::LLVMTypeKind::getTypeID. + pub fn LLVMRustGetTypeKind(Ty: TypeRef) -> TypeKind; + + /// See llvm::LLVMType::getContext. + pub fn LLVMGetTypeContext(Ty: TypeRef) -> ContextRef; + + /* Operations on integer types */ + pub fn LLVMInt1TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMInt8TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMInt16TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMInt32TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMInt64TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMIntTypeInContext(C: ContextRef, NumBits: c_uint) + -> TypeRef; + + pub fn LLVMGetIntTypeWidth(IntegerTy: TypeRef) -> c_uint; + + /* Operations on real types */ + pub fn LLVMFloatTypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMDoubleTypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMX86FP80TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMFP128TypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMPPCFP128TypeInContext(C: ContextRef) -> TypeRef; + + /* Operations on function types */ + pub fn LLVMFunctionType(ReturnType: TypeRef, + ParamTypes: *const TypeRef, + ParamCount: c_uint, + IsVarArg: Bool) + -> TypeRef; + pub fn LLVMIsFunctionVarArg(FunctionTy: TypeRef) -> Bool; + pub fn LLVMGetReturnType(FunctionTy: TypeRef) -> TypeRef; + pub fn LLVMCountParamTypes(FunctionTy: TypeRef) -> c_uint; + pub fn LLVMGetParamTypes(FunctionTy: TypeRef, Dest: *mut TypeRef); + + /* Operations on struct types */ + pub fn LLVMStructTypeInContext(C: ContextRef, + ElementTypes: *const TypeRef, + ElementCount: c_uint, + Packed: Bool) + -> TypeRef; + pub fn LLVMCountStructElementTypes(StructTy: TypeRef) -> c_uint; + pub fn LLVMGetStructElementTypes(StructTy: TypeRef, + Dest: *mut TypeRef); + pub fn LLVMIsPackedStruct(StructTy: TypeRef) -> Bool; + + /* Operations on array, pointer, and vector types (sequence types) */ + pub fn LLVMRustArrayType(ElementType: TypeRef, ElementCount: u64) -> TypeRef; + pub fn LLVMPointerType(ElementType: TypeRef, AddressSpace: c_uint) + -> TypeRef; + pub fn LLVMVectorType(ElementType: TypeRef, ElementCount: c_uint) + -> TypeRef; + + pub fn LLVMGetElementType(Ty: TypeRef) -> TypeRef; + pub fn LLVMGetArrayLength(ArrayTy: TypeRef) -> c_uint; + pub fn LLVMGetPointerAddressSpace(PointerTy: TypeRef) -> c_uint; + pub fn LLVMGetPointerToGlobal(EE: ExecutionEngineRef, V: ValueRef) + -> *const c_void; + pub fn LLVMGetVectorSize(VectorTy: TypeRef) -> c_uint; + + /* Operations on other types */ + pub fn LLVMVoidTypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMLabelTypeInContext(C: ContextRef) -> TypeRef; + pub fn LLVMRustMetadataTypeInContext(C: ContextRef) -> TypeRef; + + /* Operations on all values */ + pub fn LLVMTypeOf(Val: ValueRef) -> TypeRef; + pub fn LLVMGetValueName(Val: ValueRef) -> *const c_char; + pub fn LLVMSetValueName(Val: ValueRef, Name: *const c_char); + pub fn LLVMDumpValue(Val: ValueRef); + pub fn LLVMReplaceAllUsesWith(OldVal: ValueRef, NewVal: ValueRef); + pub fn LLVMSetMetadata(Val: ValueRef, KindID: c_uint, Node: ValueRef); + + /* Operations on Uses */ + pub fn LLVMGetFirstUse(Val: ValueRef) -> UseRef; + pub fn LLVMGetNextUse(U: UseRef) -> UseRef; + pub fn LLVMGetUser(U: UseRef) -> ValueRef; + pub fn LLVMGetUsedValue(U: UseRef) -> ValueRef; + + /* Operations on Users */ + pub fn LLVMGetNumOperands(Val: ValueRef) -> c_int; + pub fn LLVMGetOperand(Val: ValueRef, Index: c_uint) -> ValueRef; + pub fn LLVMSetOperand(Val: ValueRef, Index: c_uint, Op: ValueRef); + + /* Operations on constants of any type */ + pub fn LLVMConstNull(Ty: TypeRef) -> ValueRef; + /* all zeroes */ + pub fn LLVMConstAllOnes(Ty: TypeRef) -> ValueRef; + pub fn LLVMConstICmp(Pred: IntPredicate, V1: ValueRef, V2: ValueRef) + -> ValueRef; + pub fn LLVMConstFCmp(Pred: RealPredicate, V1: ValueRef, V2: ValueRef) + -> ValueRef; + /* only for isize/vector */ + pub fn LLVMGetUndef(Ty: TypeRef) -> ValueRef; + pub fn LLVMIsConstant(Val: ValueRef) -> Bool; + pub fn LLVMIsNull(Val: ValueRef) -> Bool; + pub fn LLVMIsUndef(Val: ValueRef) -> Bool; + pub fn LLVMConstPointerNull(Ty: TypeRef) -> ValueRef; + + /* Operations on metadata */ + pub fn LLVMMDStringInContext(C: ContextRef, + Str: *const c_char, + SLen: c_uint) + -> ValueRef; + pub fn LLVMMDNodeInContext(C: ContextRef, + Vals: *const ValueRef, + Count: c_uint) + -> ValueRef; + pub fn LLVMAddNamedMetadataOperand(M: ModuleRef, + Str: *const c_char, + Val: ValueRef); + + /* Operations on scalar constants */ + pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) + -> ValueRef; + pub fn LLVMConstIntOfString(IntTy: TypeRef, Text: *const c_char, Radix: u8) + -> ValueRef; + pub fn LLVMConstIntOfStringAndSize(IntTy: TypeRef, + Text: *const c_char, + SLen: c_uint, + Radix: u8) + -> ValueRef; + pub fn LLVMConstReal(RealTy: TypeRef, N: f64) -> ValueRef; + pub fn LLVMConstRealOfString(RealTy: TypeRef, Text: *const c_char) + -> ValueRef; + pub fn LLVMConstRealOfStringAndSize(RealTy: TypeRef, + Text: *const c_char, + SLen: c_uint) + -> ValueRef; + pub fn LLVMConstIntGetZExtValue(ConstantVal: ValueRef) -> c_ulonglong; + pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong; + + + /* Operations on composite constants */ + pub fn LLVMConstStringInContext(C: ContextRef, + Str: *const c_char, + Length: c_uint, + DontNullTerminate: Bool) + -> ValueRef; + pub fn LLVMConstStructInContext(C: ContextRef, + ConstantVals: *const ValueRef, + Count: c_uint, + Packed: Bool) + -> ValueRef; + + pub fn LLVMConstArray(ElementTy: TypeRef, + ConstantVals: *const ValueRef, + Length: c_uint) + -> ValueRef; + pub fn LLVMConstVector(ScalarConstantVals: *const ValueRef, Size: c_uint) + -> ValueRef; + + /* Constant expressions */ + pub fn LLVMAlignOf(Ty: TypeRef) -> ValueRef; + pub fn LLVMSizeOf(Ty: TypeRef) -> ValueRef; + pub fn LLVMConstNeg(ConstantVal: ValueRef) -> ValueRef; + pub fn LLVMConstNSWNeg(ConstantVal: ValueRef) -> ValueRef; + pub fn LLVMConstNUWNeg(ConstantVal: ValueRef) -> ValueRef; + pub fn LLVMConstFNeg(ConstantVal: ValueRef) -> ValueRef; + pub fn LLVMConstNot(ConstantVal: ValueRef) -> ValueRef; + pub fn LLVMConstAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstNSWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstNUWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstFAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstSub(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstNSWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstNUWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstFSub(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstMul(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstNSWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstNUWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstFMul(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstUDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstSDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstExactSDiv(LHSConstant: ValueRef, + RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstFDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstURem(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstSRem(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstFRem(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstAnd(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstOr(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstXor(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstShl(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstLShr(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstAShr(LHSConstant: ValueRef, RHSConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstGEP(ConstantVal: ValueRef, + ConstantIndices: *const ValueRef, + NumIndices: c_uint) + -> ValueRef; + pub fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, + ConstantIndices: *const ValueRef, + NumIndices: c_uint) + -> ValueRef; + pub fn LLVMConstTrunc(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstSExt(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstZExt(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstFPTrunc(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstFPExt(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstUIToFP(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstSIToFP(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstFPToUI(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstFPToSI(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstPtrToInt(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstIntToPtr(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstBitCast(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstZExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstSExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstTruncOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstPointerCast(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstIntCast(ConstantVal: ValueRef, + ToType: TypeRef, + isSigned: Bool) + -> ValueRef; + pub fn LLVMConstFPCast(ConstantVal: ValueRef, ToType: TypeRef) + -> ValueRef; + pub fn LLVMConstSelect(ConstantCondition: ValueRef, + ConstantIfTrue: ValueRef, + ConstantIfFalse: ValueRef) + -> ValueRef; + pub fn LLVMConstExtractElement(VectorConstant: ValueRef, + IndexConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstInsertElement(VectorConstant: ValueRef, + ElementValueConstant: ValueRef, + IndexConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstShuffleVector(VectorAConstant: ValueRef, + VectorBConstant: ValueRef, + MaskConstant: ValueRef) + -> ValueRef; + pub fn LLVMConstExtractValue(AggConstant: ValueRef, + IdxList: *const c_uint, + NumIdx: c_uint) + -> ValueRef; + pub fn LLVMConstInsertValue(AggConstant: ValueRef, + ElementValueConstant: ValueRef, + IdxList: *const c_uint, + NumIdx: c_uint) + -> ValueRef; + pub fn LLVMConstInlineAsm(Ty: TypeRef, + AsmString: *const c_char, + Constraints: *const c_char, + HasSideEffects: Bool, + IsAlignStack: Bool) + -> ValueRef; + pub fn LLVMBlockAddress(F: ValueRef, BB: BasicBlockRef) -> ValueRef; + + + + /* Operations on global variables, functions, and aliases (globals) */ + pub fn LLVMGetGlobalParent(Global: ValueRef) -> ModuleRef; + pub fn LLVMIsDeclaration(Global: ValueRef) -> Bool; + pub fn LLVMGetLinkage(Global: ValueRef) -> c_uint; + pub fn LLVMSetLinkage(Global: ValueRef, Link: Linkage); + pub fn LLVMGetSection(Global: ValueRef) -> *const c_char; + pub fn LLVMSetSection(Global: ValueRef, Section: *const c_char); + pub fn LLVMGetVisibility(Global: ValueRef) -> c_uint; + pub fn LLVMSetVisibility(Global: ValueRef, Viz: c_uint); + pub fn LLVMGetAlignment(Global: ValueRef) -> c_uint; + pub fn LLVMSetAlignment(Global: ValueRef, Bytes: c_uint); + pub fn LLVMSetDLLStorageClass(V: ValueRef, + C: DLLStorageClass); + + + /* Operations on global variables */ + pub fn LLVMIsAGlobalVariable(GlobalVar: ValueRef) -> ValueRef; + pub fn LLVMAddGlobal(M: ModuleRef, Ty: TypeRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMAddGlobalInAddressSpace(M: ModuleRef, + Ty: TypeRef, + Name: *const c_char, + AddressSpace: c_uint) + -> ValueRef; + pub fn LLVMGetNamedGlobal(M: ModuleRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMRustGetOrInsertGlobal(M: ModuleRef, + Name: *const c_char, + T: TypeRef) + -> ValueRef; + pub fn LLVMGetFirstGlobal(M: ModuleRef) -> ValueRef; + pub fn LLVMGetLastGlobal(M: ModuleRef) -> ValueRef; + pub fn LLVMGetNextGlobal(GlobalVar: ValueRef) -> ValueRef; + pub fn LLVMGetPreviousGlobal(GlobalVar: ValueRef) -> ValueRef; + pub fn LLVMDeleteGlobal(GlobalVar: ValueRef); + pub fn LLVMGetInitializer(GlobalVar: ValueRef) -> ValueRef; + pub fn LLVMSetInitializer(GlobalVar: ValueRef, + ConstantVal: ValueRef); + pub fn LLVMIsThreadLocal(GlobalVar: ValueRef) -> Bool; + pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool); + pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool; + pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool); + pub fn LLVMRustGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef; + + /* Operations on aliases */ + pub fn LLVMAddAlias(M: ModuleRef, + Ty: TypeRef, + Aliasee: ValueRef, + Name: *const c_char) + -> ValueRef; + + /* Operations on functions */ + pub fn LLVMAddFunction(M: ModuleRef, + Name: *const c_char, + FunctionTy: TypeRef) + -> ValueRef; + pub fn LLVMGetNamedFunction(M: ModuleRef, Name: *const c_char) -> ValueRef; + pub fn LLVMGetFirstFunction(M: ModuleRef) -> ValueRef; + pub fn LLVMGetLastFunction(M: ModuleRef) -> ValueRef; + pub fn LLVMGetNextFunction(Fn: ValueRef) -> ValueRef; + pub fn LLVMGetPreviousFunction(Fn: ValueRef) -> ValueRef; + pub fn LLVMDeleteFunction(Fn: ValueRef); + pub fn LLVMRustGetOrInsertFunction(M: ModuleRef, + Name: *const c_char, + FunctionTy: TypeRef) + -> ValueRef; + pub fn LLVMGetIntrinsicID(Fn: ValueRef) -> c_uint; + pub fn LLVMGetFunctionCallConv(Fn: ValueRef) -> c_uint; + pub fn LLVMSetFunctionCallConv(Fn: ValueRef, CC: c_uint); + pub fn LLVMGetGC(Fn: ValueRef) -> *const c_char; + pub fn LLVMSetGC(Fn: ValueRef, Name: *const c_char); + pub fn LLVMRustAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: u64); + pub fn LLVMRustAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: u64); + pub fn LLVMRustAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); + pub fn LLVMRustAddFunctionAttrStringValue(Fn: ValueRef, index: c_uint, + Name: *const c_char, + Value: *const c_char); + pub fn LLVMRustRemoveFunctionAttributes(Fn: ValueRef, + index: c_uint, + attr: u64); + pub fn LLVMRustRemoveFunctionAttrString(Fn: ValueRef, + index: c_uint, + Name: *const c_char); + pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_uint; + pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_uint); + + /* Operations on parameters */ + pub fn LLVMCountParams(Fn: ValueRef) -> c_uint; + pub fn LLVMGetParams(Fn: ValueRef, Params: *const ValueRef); + pub fn LLVMGetParam(Fn: ValueRef, Index: c_uint) -> ValueRef; + pub fn LLVMGetParamParent(Inst: ValueRef) -> ValueRef; + pub fn LLVMGetFirstParam(Fn: ValueRef) -> ValueRef; + pub fn LLVMGetLastParam(Fn: ValueRef) -> ValueRef; + pub fn LLVMGetNextParam(Arg: ValueRef) -> ValueRef; + pub fn LLVMGetPreviousParam(Arg: ValueRef) -> ValueRef; + pub fn LLVMAddAttribute(Arg: ValueRef, PA: c_uint); + pub fn LLVMRemoveAttribute(Arg: ValueRef, PA: c_uint); + pub fn LLVMGetAttribute(Arg: ValueRef) -> c_uint; + pub fn LLVMSetParamAlignment(Arg: ValueRef, align: c_uint); + + /* Operations on basic blocks */ + pub fn LLVMBasicBlockAsValue(BB: BasicBlockRef) -> ValueRef; + pub fn LLVMValueIsBasicBlock(Val: ValueRef) -> Bool; + pub fn LLVMValueAsBasicBlock(Val: ValueRef) -> BasicBlockRef; + pub fn LLVMGetBasicBlockParent(BB: BasicBlockRef) -> ValueRef; + pub fn LLVMCountBasicBlocks(Fn: ValueRef) -> c_uint; + pub fn LLVMGetBasicBlocks(Fn: ValueRef, BasicBlocks: *const ValueRef); + pub fn LLVMGetFirstBasicBlock(Fn: ValueRef) -> BasicBlockRef; + pub fn LLVMGetLastBasicBlock(Fn: ValueRef) -> BasicBlockRef; + pub fn LLVMGetNextBasicBlock(BB: BasicBlockRef) -> BasicBlockRef; + pub fn LLVMGetPreviousBasicBlock(BB: BasicBlockRef) -> BasicBlockRef; + pub fn LLVMGetEntryBasicBlock(Fn: ValueRef) -> BasicBlockRef; + + pub fn LLVMAppendBasicBlockInContext(C: ContextRef, + Fn: ValueRef, + Name: *const c_char) + -> BasicBlockRef; + pub fn LLVMInsertBasicBlockInContext(C: ContextRef, + BB: BasicBlockRef, + Name: *const c_char) + -> BasicBlockRef; + pub fn LLVMDeleteBasicBlock(BB: BasicBlockRef); + + pub fn LLVMMoveBasicBlockAfter(BB: BasicBlockRef, + MoveAfter: BasicBlockRef); + + pub fn LLVMMoveBasicBlockBefore(BB: BasicBlockRef, + MoveBefore: BasicBlockRef); + + /* Operations on instructions */ + pub fn LLVMGetInstructionParent(Inst: ValueRef) -> BasicBlockRef; + pub fn LLVMGetFirstInstruction(BB: BasicBlockRef) -> ValueRef; + pub fn LLVMGetLastInstruction(BB: BasicBlockRef) -> ValueRef; + pub fn LLVMGetNextInstruction(Inst: ValueRef) -> ValueRef; + pub fn LLVMGetPreviousInstruction(Inst: ValueRef) -> ValueRef; + pub fn LLVMInstructionEraseFromParent(Inst: ValueRef); + + /* Operations on call sites */ + pub fn LLVMSetInstructionCallConv(Instr: ValueRef, CC: c_uint); + pub fn LLVMGetInstructionCallConv(Instr: ValueRef) -> c_uint; + pub fn LLVMAddInstrAttribute(Instr: ValueRef, + index: c_uint, + IA: c_uint); + pub fn LLVMRemoveInstrAttribute(Instr: ValueRef, + index: c_uint, + IA: c_uint); + pub fn LLVMSetInstrParamAlignment(Instr: ValueRef, + index: c_uint, + align: c_uint); + pub fn LLVMRustAddCallSiteAttribute(Instr: ValueRef, + index: c_uint, + Val: u64); + pub fn LLVMRustAddDereferenceableCallSiteAttr(Instr: ValueRef, + index: c_uint, + bytes: u64); + + /* Operations on call instructions (only) */ + pub fn LLVMIsTailCall(CallInst: ValueRef) -> Bool; + pub fn LLVMSetTailCall(CallInst: ValueRef, IsTailCall: Bool); + + /* Operations on load/store instructions (only) */ + pub fn LLVMGetVolatile(MemoryAccessInst: ValueRef) -> Bool; + pub fn LLVMSetVolatile(MemoryAccessInst: ValueRef, volatile: Bool); + + /* Operations on phi nodes */ + pub fn LLVMAddIncoming(PhiNode: ValueRef, + IncomingValues: *const ValueRef, + IncomingBlocks: *const BasicBlockRef, + Count: c_uint); + pub fn LLVMCountIncoming(PhiNode: ValueRef) -> c_uint; + pub fn LLVMGetIncomingValue(PhiNode: ValueRef, Index: c_uint) + -> ValueRef; + pub fn LLVMGetIncomingBlock(PhiNode: ValueRef, Index: c_uint) + -> BasicBlockRef; + + /* Instruction builders */ + pub fn LLVMCreateBuilderInContext(C: ContextRef) -> BuilderRef; + pub fn LLVMPositionBuilder(Builder: BuilderRef, + Block: BasicBlockRef, + Instr: ValueRef); + pub fn LLVMPositionBuilderBefore(Builder: BuilderRef, + Instr: ValueRef); + pub fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, + Block: BasicBlockRef); + pub fn LLVMGetInsertBlock(Builder: BuilderRef) -> BasicBlockRef; + pub fn LLVMClearInsertionPosition(Builder: BuilderRef); + pub fn LLVMInsertIntoBuilder(Builder: BuilderRef, Instr: ValueRef); + pub fn LLVMInsertIntoBuilderWithName(Builder: BuilderRef, + Instr: ValueRef, + Name: *const c_char); + pub fn LLVMDisposeBuilder(Builder: BuilderRef); + + /* Metadata */ + pub fn LLVMSetCurrentDebugLocation(Builder: BuilderRef, L: ValueRef); + pub fn LLVMGetCurrentDebugLocation(Builder: BuilderRef) -> ValueRef; + pub fn LLVMSetInstDebugLocation(Builder: BuilderRef, Inst: ValueRef); + + /* Terminators */ + pub fn LLVMBuildRetVoid(B: BuilderRef) -> ValueRef; + pub fn LLVMBuildRet(B: BuilderRef, V: ValueRef) -> ValueRef; + pub fn LLVMBuildAggregateRet(B: BuilderRef, + RetVals: *const ValueRef, + N: c_uint) + -> ValueRef; + pub fn LLVMBuildBr(B: BuilderRef, Dest: BasicBlockRef) -> ValueRef; + pub fn LLVMBuildCondBr(B: BuilderRef, + If: ValueRef, + Then: BasicBlockRef, + Else: BasicBlockRef) + -> ValueRef; + pub fn LLVMBuildSwitch(B: BuilderRef, + V: ValueRef, + Else: BasicBlockRef, + NumCases: c_uint) + -> ValueRef; + pub fn LLVMBuildIndirectBr(B: BuilderRef, + Addr: ValueRef, + NumDests: c_uint) + -> ValueRef; + pub fn LLVMRustBuildInvoke(B: BuilderRef, + Fn: ValueRef, + Args: *const ValueRef, + NumArgs: c_uint, + Then: BasicBlockRef, + Catch: BasicBlockRef, + Bundle: OperandBundleDefRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMRustBuildLandingPad(B: BuilderRef, + Ty: TypeRef, + PersFn: ValueRef, + NumClauses: c_uint, + Name: *const c_char, + F: ValueRef) + -> ValueRef; + pub fn LLVMBuildResume(B: BuilderRef, Exn: ValueRef) -> ValueRef; + pub fn LLVMBuildUnreachable(B: BuilderRef) -> ValueRef; + + pub fn LLVMRustBuildCleanupPad(B: BuilderRef, + ParentPad: ValueRef, + ArgCnt: c_uint, + Args: *const ValueRef, + Name: *const c_char) -> ValueRef; + pub fn LLVMRustBuildCleanupRet(B: BuilderRef, + CleanupPad: ValueRef, + UnwindBB: BasicBlockRef) -> ValueRef; + pub fn LLVMRustBuildCatchPad(B: BuilderRef, + ParentPad: ValueRef, + ArgCnt: c_uint, + Args: *const ValueRef, + Name: *const c_char) -> ValueRef; + pub fn LLVMRustBuildCatchRet(B: BuilderRef, + Pad: ValueRef, + BB: BasicBlockRef) -> ValueRef; + pub fn LLVMRustBuildCatchSwitch(Builder: BuilderRef, + ParentPad: ValueRef, + BB: BasicBlockRef, + NumHandlers: c_uint, + Name: *const c_char) -> ValueRef; + pub fn LLVMRustAddHandler(CatchSwitch: ValueRef, + Handler: BasicBlockRef); + pub fn LLVMRustSetPersonalityFn(B: BuilderRef, Pers: ValueRef); + + /* Add a case to the switch instruction */ + pub fn LLVMAddCase(Switch: ValueRef, + OnVal: ValueRef, + Dest: BasicBlockRef); + + /* Add a destination to the indirectbr instruction */ + pub fn LLVMAddDestination(IndirectBr: ValueRef, Dest: BasicBlockRef); + + /* Add a clause to the landing pad instruction */ + pub fn LLVMAddClause(LandingPad: ValueRef, ClauseVal: ValueRef); + + /* Set the cleanup on a landing pad instruction */ + pub fn LLVMSetCleanup(LandingPad: ValueRef, Val: Bool); + + /* Arithmetic */ + pub fn LLVMBuildAdd(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNSWAdd(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNUWAdd(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFAdd(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSub(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNSWSub(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNUWSub(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFSub(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildMul(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNSWMul(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNUWMul(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFMul(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildUDiv(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSDiv(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildExactSDiv(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFDiv(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildURem(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSRem(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFRem(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildShl(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildLShr(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildAShr(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildAnd(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildOr(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildXor(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildBinOp(B: BuilderRef, + Op: Opcode, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNSWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNUWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildNot(B: BuilderRef, V: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMRustSetHasUnsafeAlgebra(Instr: ValueRef); + + /* Memory */ + pub fn LLVMBuildAlloca(B: BuilderRef, Ty: TypeRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFree(B: BuilderRef, PointerVal: ValueRef) -> ValueRef; + pub fn LLVMBuildLoad(B: BuilderRef, + PointerVal: ValueRef, + Name: *const c_char) + -> ValueRef; + + pub fn LLVMBuildStore(B: BuilderRef, Val: ValueRef, Ptr: ValueRef) + -> ValueRef; + + pub fn LLVMBuildGEP(B: BuilderRef, + Pointer: ValueRef, + Indices: *const ValueRef, + NumIndices: c_uint, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildInBoundsGEP(B: BuilderRef, + Pointer: ValueRef, + Indices: *const ValueRef, + NumIndices: c_uint, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildStructGEP(B: BuilderRef, + Pointer: ValueRef, + Idx: c_uint, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildGlobalString(B: BuilderRef, + Str: *const c_char, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildGlobalStringPtr(B: BuilderRef, + Str: *const c_char, + Name: *const c_char) + -> ValueRef; + + /* Casts */ + pub fn LLVMBuildTrunc(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildZExt(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSExt(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFPToUI(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFPToSI(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildUIToFP(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSIToFP(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFPTrunc(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFPExt(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildPtrToInt(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildIntToPtr(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildBitCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildZExtOrBitCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSExtOrBitCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildTruncOrBitCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildCast(B: BuilderRef, + Op: Opcode, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) -> ValueRef; + pub fn LLVMBuildPointerCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildIntCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFPCast(B: BuilderRef, + Val: ValueRef, + DestTy: TypeRef, + Name: *const c_char) + -> ValueRef; + + /* Comparisons */ + pub fn LLVMBuildICmp(B: BuilderRef, + Op: c_uint, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildFCmp(B: BuilderRef, + Op: c_uint, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + + /* Miscellaneous instructions */ + pub fn LLVMBuildPhi(B: BuilderRef, Ty: TypeRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMRustBuildCall(B: BuilderRef, + Fn: ValueRef, + Args: *const ValueRef, + NumArgs: c_uint, + Bundle: OperandBundleDefRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildSelect(B: BuilderRef, + If: ValueRef, + Then: ValueRef, + Else: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildVAArg(B: BuilderRef, + list: ValueRef, + Ty: TypeRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildExtractElement(B: BuilderRef, + VecVal: ValueRef, + Index: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildInsertElement(B: BuilderRef, + VecVal: ValueRef, + EltVal: ValueRef, + Index: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildShuffleVector(B: BuilderRef, + V1: ValueRef, + V2: ValueRef, + Mask: ValueRef, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildExtractValue(B: BuilderRef, + AggVal: ValueRef, + Index: c_uint, + Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildInsertValue(B: BuilderRef, + AggVal: ValueRef, + EltVal: ValueRef, + Index: c_uint, + Name: *const c_char) + -> ValueRef; + + pub fn LLVMBuildIsNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildIsNotNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) + -> ValueRef; + pub fn LLVMBuildPtrDiff(B: BuilderRef, + LHS: ValueRef, + RHS: ValueRef, + Name: *const c_char) + -> ValueRef; + + /* Atomic Operations */ + pub fn LLVMRustBuildAtomicLoad(B: BuilderRef, + PointerVal: ValueRef, + Name: *const c_char, + Order: AtomicOrdering, + Alignment: c_uint) + -> ValueRef; + + pub fn LLVMRustBuildAtomicStore(B: BuilderRef, + Val: ValueRef, + Ptr: ValueRef, + Order: AtomicOrdering, + Alignment: c_uint) + -> ValueRef; + + pub fn LLVMRustBuildAtomicCmpXchg(B: BuilderRef, + LHS: ValueRef, + CMP: ValueRef, + RHS: ValueRef, + Order: AtomicOrdering, + FailureOrder: AtomicOrdering, + Weak: Bool) + -> ValueRef; + + pub fn LLVMBuildAtomicRMW(B: BuilderRef, + Op: AtomicRmwBinOp, + LHS: ValueRef, + RHS: ValueRef, + Order: AtomicOrdering, + SingleThreaded: Bool) + -> ValueRef; + + pub fn LLVMRustBuildAtomicFence(B: BuilderRef, + Order: AtomicOrdering, + Scope: SynchronizationScope); + + + /* Selected entries from the downcasts. */ + pub fn LLVMIsATerminatorInst(Inst: ValueRef) -> ValueRef; + pub fn LLVMIsAStoreInst(Inst: ValueRef) -> ValueRef; + + /// Writes a module to the specified path. Returns 0 on success. + pub fn LLVMWriteBitcodeToFile(M: ModuleRef, Path: *const c_char) -> c_int; + + /// Creates target data from a target layout string. + pub fn LLVMCreateTargetData(StringRep: *const c_char) -> TargetDataRef; + /// Number of bytes clobbered when doing a Store to *T. + pub fn LLVMStoreSizeOfType(TD: TargetDataRef, Ty: TypeRef) + -> c_ulonglong; + + /// Number of bytes clobbered when doing a Store to *T. + pub fn LLVMSizeOfTypeInBits(TD: TargetDataRef, Ty: TypeRef) + -> c_ulonglong; + + /// Distance between successive elements in an array of T. Includes ABI padding. + pub fn LLVMABISizeOfType(TD: TargetDataRef, Ty: TypeRef) -> c_ulonglong; + + /// Returns the preferred alignment of a type. + pub fn LLVMPreferredAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) + -> c_uint; + /// Returns the minimum alignment of a type. + pub fn LLVMABIAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) + -> c_uint; + + /// Computes the byte offset of the indexed struct element for a + /// target. + pub fn LLVMOffsetOfElement(TD: TargetDataRef, + StructTy: TypeRef, + Element: c_uint) + -> c_ulonglong; + + /// Returns the minimum alignment of a type when part of a call frame. + pub fn LLVMCallFrameAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) + -> c_uint; + + /// Disposes target data. + pub fn LLVMDisposeTargetData(TD: TargetDataRef); + + /// Creates a pass manager. + pub fn LLVMCreatePassManager() -> PassManagerRef; + + /// Creates a function-by-function pass manager + pub fn LLVMCreateFunctionPassManagerForModule(M: ModuleRef) + -> PassManagerRef; + + /// Disposes a pass manager. + pub fn LLVMDisposePassManager(PM: PassManagerRef); + + /// Runs a pass manager on a module. + pub fn LLVMRunPassManager(PM: PassManagerRef, M: ModuleRef) -> Bool; + + /// Runs the function passes on the provided function. + pub fn LLVMRunFunctionPassManager(FPM: PassManagerRef, F: ValueRef) + -> Bool; + + /// Initializes all the function passes scheduled in the manager + pub fn LLVMInitializeFunctionPassManager(FPM: PassManagerRef) -> Bool; + + /// Finalizes all the function passes scheduled in the manager + pub fn LLVMFinalizeFunctionPassManager(FPM: PassManagerRef) -> Bool; + + pub fn LLVMInitializePasses(); + + /// Adds a verification pass. + pub fn LLVMAddVerifierPass(PM: PassManagerRef); + + pub fn LLVMAddGlobalOptimizerPass(PM: PassManagerRef); + pub fn LLVMAddIPSCCPPass(PM: PassManagerRef); + pub fn LLVMAddDeadArgEliminationPass(PM: PassManagerRef); + pub fn LLVMAddInstructionCombiningPass(PM: PassManagerRef); + pub fn LLVMAddCFGSimplificationPass(PM: PassManagerRef); + pub fn LLVMAddFunctionInliningPass(PM: PassManagerRef); + pub fn LLVMAddFunctionAttrsPass(PM: PassManagerRef); + pub fn LLVMAddScalarReplAggregatesPass(PM: PassManagerRef); + pub fn LLVMAddScalarReplAggregatesPassSSA(PM: PassManagerRef); + pub fn LLVMAddJumpThreadingPass(PM: PassManagerRef); + pub fn LLVMAddConstantPropagationPass(PM: PassManagerRef); + pub fn LLVMAddReassociatePass(PM: PassManagerRef); + pub fn LLVMAddLoopRotatePass(PM: PassManagerRef); + pub fn LLVMAddLICMPass(PM: PassManagerRef); + pub fn LLVMAddLoopUnswitchPass(PM: PassManagerRef); + pub fn LLVMAddLoopDeletionPass(PM: PassManagerRef); + pub fn LLVMAddLoopUnrollPass(PM: PassManagerRef); + pub fn LLVMAddGVNPass(PM: PassManagerRef); + pub fn LLVMAddMemCpyOptPass(PM: PassManagerRef); + pub fn LLVMAddSCCPPass(PM: PassManagerRef); + pub fn LLVMAddDeadStoreEliminationPass(PM: PassManagerRef); + pub fn LLVMAddStripDeadPrototypesPass(PM: PassManagerRef); + pub fn LLVMAddConstantMergePass(PM: PassManagerRef); + pub fn LLVMAddArgumentPromotionPass(PM: PassManagerRef); + pub fn LLVMAddTailCallEliminationPass(PM: PassManagerRef); + pub fn LLVMAddIndVarSimplifyPass(PM: PassManagerRef); + pub fn LLVMAddAggressiveDCEPass(PM: PassManagerRef); + pub fn LLVMAddGlobalDCEPass(PM: PassManagerRef); + pub fn LLVMAddCorrelatedValuePropagationPass(PM: PassManagerRef); + pub fn LLVMAddPruneEHPass(PM: PassManagerRef); + pub fn LLVMAddSimplifyLibCallsPass(PM: PassManagerRef); + pub fn LLVMAddLoopIdiomPass(PM: PassManagerRef); + pub fn LLVMAddEarlyCSEPass(PM: PassManagerRef); + pub fn LLVMAddTypeBasedAliasAnalysisPass(PM: PassManagerRef); + pub fn LLVMAddBasicAliasAnalysisPass(PM: PassManagerRef); + + pub fn LLVMPassManagerBuilderCreate() -> PassManagerBuilderRef; + pub fn LLVMPassManagerBuilderDispose(PMB: PassManagerBuilderRef); + pub fn LLVMPassManagerBuilderSetOptLevel(PMB: PassManagerBuilderRef, + OptimizationLevel: c_uint); + pub fn LLVMPassManagerBuilderSetSizeLevel(PMB: PassManagerBuilderRef, + Value: Bool); + pub fn LLVMPassManagerBuilderSetDisableUnitAtATime( + PMB: PassManagerBuilderRef, + Value: Bool); + pub fn LLVMPassManagerBuilderSetDisableUnrollLoops( + PMB: PassManagerBuilderRef, + Value: Bool); + pub fn LLVMPassManagerBuilderSetDisableSimplifyLibCalls( + PMB: PassManagerBuilderRef, + Value: Bool); + pub fn LLVMPassManagerBuilderUseInlinerWithThreshold( + PMB: PassManagerBuilderRef, + threshold: c_uint); + pub fn LLVMPassManagerBuilderPopulateModulePassManager( + PMB: PassManagerBuilderRef, + PM: PassManagerRef); + + pub fn LLVMPassManagerBuilderPopulateFunctionPassManager( + PMB: PassManagerBuilderRef, + PM: PassManagerRef); + pub fn LLVMPassManagerBuilderPopulateLTOPassManager( + PMB: PassManagerBuilderRef, + PM: PassManagerRef, + Internalize: Bool, + RunInliner: Bool); + + /// Destroys a memory buffer. + pub fn LLVMDisposeMemoryBuffer(MemBuf: MemoryBufferRef); + + + /* Stuff that's in rustllvm/ because it's not upstream yet. */ + + /// Opens an object file. + pub fn LLVMCreateObjectFile(MemBuf: MemoryBufferRef) -> ObjectFileRef; + /// Closes an object file. + pub fn LLVMDisposeObjectFile(ObjFile: ObjectFileRef); + + /// Enumerates the sections in an object file. + pub fn LLVMGetSections(ObjFile: ObjectFileRef) -> SectionIteratorRef; + /// Destroys a section iterator. + pub fn LLVMDisposeSectionIterator(SI: SectionIteratorRef); + /// Returns true if the section iterator is at the end of the section + /// list: + pub fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef, + SI: SectionIteratorRef) + -> Bool; + /// Moves the section iterator to point to the next section. + pub fn LLVMMoveToNextSection(SI: SectionIteratorRef); + /// Returns the current section size. + pub fn LLVMGetSectionSize(SI: SectionIteratorRef) -> c_ulonglong; + /// Returns the current section contents as a string buffer. + pub fn LLVMGetSectionContents(SI: SectionIteratorRef) -> *const c_char; + + /// Reads the given file and returns it as a memory buffer. Use + /// LLVMDisposeMemoryBuffer() to get rid of it. + pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: *const c_char) + -> MemoryBufferRef; + /// Borrows the contents of the memory buffer (doesn't copy it) + pub fn LLVMCreateMemoryBufferWithMemoryRange(InputData: *const c_char, + InputDataLength: size_t, + BufferName: *const c_char, + RequiresNull: Bool) + -> MemoryBufferRef; + pub fn LLVMCreateMemoryBufferWithMemoryRangeCopy(InputData: *const c_char, + InputDataLength: size_t, + BufferName: *const c_char) + -> MemoryBufferRef; + + pub fn LLVMIsMultithreaded() -> Bool; + pub fn LLVMStartMultithreaded() -> Bool; + + /// Returns a string describing the last error caused by an LLVMRust* call. + pub fn LLVMRustGetLastError() -> *const c_char; + + /// Print the pass timings since static dtors aren't picking them up. + pub fn LLVMRustPrintPassTimings(); + + pub fn LLVMStructCreateNamed(C: ContextRef, Name: *const c_char) -> TypeRef; + + pub fn LLVMStructSetBody(StructTy: TypeRef, + ElementTypes: *const TypeRef, + ElementCount: c_uint, + Packed: Bool); + + pub fn LLVMConstNamedStruct(S: TypeRef, + ConstantVals: *const ValueRef, + Count: c_uint) + -> ValueRef; + + /// Enables LLVM debug output. + pub fn LLVMRustSetDebug(Enabled: c_int); + + /// Prepares inline assembly. + pub fn LLVMRustInlineAsm(Ty: TypeRef, + AsmString: *const c_char, + Constraints: *const c_char, + SideEffects: Bool, + AlignStack: Bool, + Dialect: AsmDialect) + -> ValueRef; + + pub fn LLVMRustDebugMetadataVersion() -> u32; + pub fn LLVMRustVersionMajor() -> u32; + pub fn LLVMRustVersionMinor() -> u32; + + pub fn LLVMRustAddModuleFlag(M: ModuleRef, + name: *const c_char, + value: u32); + + pub fn LLVMRustDIBuilderCreate(M: ModuleRef) -> DIBuilderRef; + + pub fn LLVMRustDIBuilderDispose(Builder: DIBuilderRef); + + pub fn LLVMRustDIBuilderFinalize(Builder: DIBuilderRef); + + pub fn LLVMRustDIBuilderCreateCompileUnit(Builder: DIBuilderRef, + Lang: c_uint, + File: *const c_char, + Dir: *const c_char, + Producer: *const c_char, + isOptimized: bool, + Flags: *const c_char, + RuntimeVer: c_uint, + SplitName: *const c_char) + -> DIDescriptor; + + pub fn LLVMRustDIBuilderCreateFile(Builder: DIBuilderRef, + Filename: *const c_char, + Directory: *const c_char) + -> DIFile; + + pub fn LLVMRustDIBuilderCreateSubroutineType(Builder: DIBuilderRef, + File: DIFile, + ParameterTypes: DIArray) + -> DICompositeType; + + pub fn LLVMRustDIBuilderCreateFunction(Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *const c_char, + LinkageName: *const c_char, + File: DIFile, + LineNo: c_uint, + Ty: DIType, + isLocalToUnit: bool, + isDefinition: bool, + ScopeLine: c_uint, + Flags: c_uint, + isOptimized: bool, + Fn: ValueRef, + TParam: DIArray, + Decl: DIDescriptor) + -> DISubprogram; + + pub fn LLVMRustDIBuilderCreateBasicType(Builder: DIBuilderRef, + Name: *const c_char, + SizeInBits: u64, + AlignInBits: u64, + Encoding: c_uint) + -> DIBasicType; + + pub fn LLVMRustDIBuilderCreatePointerType(Builder: DIBuilderRef, + PointeeTy: DIType, + SizeInBits: u64, + AlignInBits: u64, + Name: *const c_char) + -> DIDerivedType; + + pub fn LLVMRustDIBuilderCreateStructType(Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *const c_char, + File: DIFile, + LineNumber: c_uint, + SizeInBits: u64, + AlignInBits: u64, + Flags: c_uint, + DerivedFrom: DIType, + Elements: DIArray, + RunTimeLang: c_uint, + VTableHolder: DIType, + UniqueId: *const c_char) + -> DICompositeType; + + pub fn LLVMRustDIBuilderCreateMemberType(Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *const c_char, + File: DIFile, + LineNo: c_uint, + SizeInBits: u64, + AlignInBits: u64, + OffsetInBits: u64, + Flags: c_uint, + Ty: DIType) + -> DIDerivedType; + + pub fn LLVMRustDIBuilderCreateLexicalBlock(Builder: DIBuilderRef, + Scope: DIScope, + File: DIFile, + Line: c_uint, + Col: c_uint) + -> DILexicalBlock; + + pub fn LLVMRustDIBuilderCreateStaticVariable(Builder: DIBuilderRef, + Context: DIScope, + Name: *const c_char, + LinkageName: *const c_char, + File: DIFile, + LineNo: c_uint, + Ty: DIType, + isLocalToUnit: bool, + Val: ValueRef, + Decl: DIDescriptor) + -> DIGlobalVariable; + + pub fn LLVMRustDIBuilderCreateVariable(Builder: DIBuilderRef, + Tag: c_uint, + Scope: DIDescriptor, + Name: *const c_char, + File: DIFile, + LineNo: c_uint, + Ty: DIType, + AlwaysPreserve: bool, + Flags: c_uint, + AddrOps: *const i64, + AddrOpsCount: c_uint, + ArgNo: c_uint) + -> DIVariable; + + pub fn LLVMRustDIBuilderCreateArrayType(Builder: DIBuilderRef, + Size: u64, + AlignInBits: u64, + Ty: DIType, + Subscripts: DIArray) + -> DIType; + + pub fn LLVMRustDIBuilderCreateVectorType(Builder: DIBuilderRef, + Size: u64, + AlignInBits: u64, + Ty: DIType, + Subscripts: DIArray) + -> DIType; + + pub fn LLVMRustDIBuilderGetOrCreateSubrange(Builder: DIBuilderRef, + Lo: i64, + Count: i64) + -> DISubrange; + + pub fn LLVMRustDIBuilderGetOrCreateArray(Builder: DIBuilderRef, + Ptr: *const DIDescriptor, + Count: c_uint) + -> DIArray; + + pub fn LLVMRustDIBuilderInsertDeclareAtEnd(Builder: DIBuilderRef, + Val: ValueRef, + VarInfo: DIVariable, + AddrOps: *const i64, + AddrOpsCount: c_uint, + DL: ValueRef, + InsertAtEnd: BasicBlockRef) + -> ValueRef; + + pub fn LLVMRustDIBuilderInsertDeclareBefore(Builder: DIBuilderRef, + Val: ValueRef, + VarInfo: DIVariable, + AddrOps: *const i64, + AddrOpsCount: c_uint, + DL: ValueRef, + InsertBefore: ValueRef) + -> ValueRef; + + pub fn LLVMRustDIBuilderCreateEnumerator(Builder: DIBuilderRef, + Name: *const c_char, + Val: u64) + -> DIEnumerator; + + pub fn LLVMRustDIBuilderCreateEnumerationType(Builder: DIBuilderRef, + Scope: DIScope, + Name: *const c_char, + File: DIFile, + LineNumber: c_uint, + SizeInBits: u64, + AlignInBits: u64, + Elements: DIArray, + ClassType: DIType) + -> DIType; + + pub fn LLVMRustDIBuilderCreateUnionType(Builder: DIBuilderRef, + Scope: DIScope, + Name: *const c_char, + File: DIFile, + LineNumber: c_uint, + SizeInBits: u64, + AlignInBits: u64, + Flags: c_uint, + Elements: DIArray, + RunTimeLang: c_uint, + UniqueId: *const c_char) + -> DIType; + + pub fn LLVMSetUnnamedAddr(GlobalVar: ValueRef, UnnamedAddr: Bool); + + pub fn LLVMRustDIBuilderCreateTemplateTypeParameter(Builder: DIBuilderRef, + Scope: DIScope, + Name: *const c_char, + Ty: DIType, + File: DIFile, + LineNo: c_uint, + ColumnNo: c_uint) + -> DITemplateTypeParameter; + + + pub fn LLVMRustDIBuilderCreateNameSpace(Builder: DIBuilderRef, + Scope: DIScope, + Name: *const c_char, + File: DIFile, + LineNo: c_uint) + -> DINameSpace; + pub fn LLVMRustDICompositeTypeSetTypeArray(Builder: DIBuilderRef, + CompositeType: DIType, + TypeArray: DIArray); + + + pub fn LLVMRustDIBuilderCreateDebugLocation(Context: ContextRef, + Line: c_uint, + Column: c_uint, + Scope: DIScope, + InlinedAt: MetadataRef) + -> ValueRef; + pub fn LLVMRustDIBuilderCreateOpDeref() -> i64; + pub fn LLVMRustDIBuilderCreateOpPlus() -> i64; + + pub fn LLVMRustWriteTypeToString(Type: TypeRef, s: RustStringRef); + pub fn LLVMRustWriteValueToString(value_ref: ValueRef, s: RustStringRef); + + pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef; + + pub fn LLVMIsAAllocaInst(value_ref: ValueRef) -> ValueRef; + pub fn LLVMIsAConstantInt(value_ref: ValueRef) -> ValueRef; + + pub fn LLVMRustPassKind(Pass: PassRef) -> PassKind; + pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> PassRef; + pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: PassRef); + + pub fn LLVMRustHasFeature(T: TargetMachineRef, + s: *const c_char) -> bool; + + pub fn LLVMRustPrintTargetCPUs(T: TargetMachineRef); + pub fn LLVMRustPrintTargetFeatures(T: TargetMachineRef); + + pub fn LLVMRustCreateTargetMachine(Triple: *const c_char, + CPU: *const c_char, + Features: *const c_char, + Model: CodeModel, + Reloc: RelocMode, + Level: CodeGenOptLevel, + UseSoftFP: bool, + PositionIndependentExecutable: bool, + FunctionSections: bool, + DataSections: bool) -> TargetMachineRef; + pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef); + pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef, + PM: PassManagerRef, + M: ModuleRef); + pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef, + M: ModuleRef, + DisableSimplifyLibCalls: bool); + pub fn LLVMRustConfigurePassManagerBuilder(PMB: PassManagerBuilderRef, + OptLevel: CodeGenOptLevel, + MergeFunctions: bool, + SLPVectorize: bool, + LoopVectorize: bool); + pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef, + DisableSimplifyLibCalls: bool); + pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef); + pub fn LLVMRustWriteOutputFile(T: TargetMachineRef, + PM: PassManagerRef, + M: ModuleRef, + Output: *const c_char, + FileType: FileType) + -> LLVMRustResult; + pub fn LLVMRustPrintModule(PM: PassManagerRef, + M: ModuleRef, + Output: *const c_char); + pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char); + pub fn LLVMRustPrintPasses(); + pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char); + pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef, + AddLifetimes: bool); + pub fn LLVMRustLinkInExternalBitcode(M: ModuleRef, + bc: *const c_char, + len: size_t) -> bool; + pub fn LLVMRustRunRestrictionPass(M: ModuleRef, + syms: *const *const c_char, + len: size_t); + pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef); + + pub fn LLVMRustOpenArchive(path: *const c_char) -> ArchiveRef; + pub fn LLVMRustArchiveIteratorNew(AR: ArchiveRef) -> ArchiveIteratorRef; + pub fn LLVMRustArchiveIteratorNext(AIR: ArchiveIteratorRef) -> ArchiveChildRef; + pub fn LLVMRustArchiveChildName(ACR: ArchiveChildRef, + size: *mut size_t) -> *const c_char; + pub fn LLVMRustArchiveChildData(ACR: ArchiveChildRef, + size: *mut size_t) -> *const c_char; + pub fn LLVMRustArchiveChildFree(ACR: ArchiveChildRef); + pub fn LLVMRustArchiveIteratorFree(AIR: ArchiveIteratorRef); + pub fn LLVMRustDestroyArchive(AR: ArchiveRef); + + pub fn LLVMRustGetSectionName(SI: SectionIteratorRef, + data: *mut *const c_char) -> size_t; + + pub fn LLVMRustWriteTwineToString(T: TwineRef, s: RustStringRef); + + pub fn LLVMContextSetDiagnosticHandler(C: ContextRef, + Handler: DiagnosticHandler, + DiagnosticContext: *mut c_void); + + pub fn LLVMRustUnpackOptimizationDiagnostic(DI: DiagnosticInfoRef, + pass_name_out: *mut *const c_char, + function_out: *mut ValueRef, + debugloc_out: *mut DebugLocRef, + message_out: *mut TwineRef); + pub fn LLVMRustUnpackInlineAsmDiagnostic(DI: DiagnosticInfoRef, + cookie_out: *mut c_uint, + message_out: *mut TwineRef, + instruction_out: *mut ValueRef); + + pub fn LLVMRustWriteDiagnosticInfoToString(DI: DiagnosticInfoRef, + s: RustStringRef); + pub fn LLVMGetDiagInfoSeverity(DI: DiagnosticInfoRef) -> DiagnosticSeverity; + pub fn LLVMRustGetDiagInfoKind(DI: DiagnosticInfoRef) -> DiagnosticKind; + + pub fn LLVMRustWriteDebugLocToString(C: ContextRef, + DL: DebugLocRef, + s: RustStringRef); + + pub fn LLVMRustSetInlineAsmDiagnosticHandler(C: ContextRef, + H: InlineAsmDiagHandler, + CX: *mut c_void); + + pub fn LLVMRustWriteSMDiagnosticToString(d: SMDiagnosticRef, s: RustStringRef); + + pub fn LLVMRustWriteArchive(Dst: *const c_char, + NumMembers: size_t, + Members: *const RustArchiveMemberRef, + WriteSymbtab: bool, + Kind: ArchiveKind) -> + LLVMRustResult; + pub fn LLVMRustArchiveMemberNew(Filename: *const c_char, + Name: *const c_char, + Child: ArchiveChildRef) -> RustArchiveMemberRef; + pub fn LLVMRustArchiveMemberFree(Member: RustArchiveMemberRef); + + pub fn LLVMRustSetDataLayoutFromTargetMachine(M: ModuleRef, + TM: TargetMachineRef); + pub fn LLVMRustGetModuleDataLayout(M: ModuleRef) -> TargetDataRef; + + pub fn LLVMRustBuildOperandBundleDef(Name: *const c_char, + Inputs: *const ValueRef, + NumInputs: c_uint) + -> OperandBundleDefRef; + pub fn LLVMRustFreeOperandBundleDef(Bundle: OperandBundleDefRef); + + pub fn LLVMRustPositionBuilderAtStart(B: BuilderRef, BB: BasicBlockRef); + + pub fn LLVMRustSetComdat(M: ModuleRef, V: ValueRef, Name: *const c_char); + pub fn LLVMRustUnsetComdat(V: ValueRef); + pub fn LLVMRustSetModulePIELevel(M: ModuleRef); +} + + +// LLVM requires symbols from this library, but apparently they're not printed +// during llvm-config? +#[cfg(windows)] +#[link(name = "ole32")] +extern {} diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 033342b81a4c..6c4e1a54ea72 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -33,157 +33,35 @@ extern crate libc; #[macro_use] #[no_link] extern crate rustc_bitflags; -pub use self::AttributeSet::*; pub use self::IntPredicate::*; pub use self::RealPredicate::*; pub use self::TypeKind::*; -pub use self::AtomicBinOp::*; -pub use self::AtomicOrdering::*; -pub use self::SynchronizationScope::*; -pub use self::FileType::*; +pub use self::AtomicRmwBinOp::*; pub use self::MetadataType::*; -pub use self::AsmDialect::*; -pub use self::CodeGenOptLevel::*; pub use self::CodeGenOptSize::*; -pub use self::RelocMode::*; -pub use self::CodeGenModel::*; pub use self::DiagnosticKind::*; pub use self::CallConv::*; -pub use self::Visibility::*; pub use self::DiagnosticSeverity::*; pub use self::Linkage::*; -pub use self::DLLStorageClassTypes::*; use std::str::FromStr; +use std::slice; use std::ffi::{CString, CStr}; use std::cell::RefCell; -use std::slice; -use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char}; -use libc::{c_longlong, c_ulonglong, c_void}; -use debuginfo::{DIBuilderRef, DIDescriptor, - DIFile, DILexicalBlock, DISubprogram, DIType, - DIBasicType, DIDerivedType, DICompositeType, DIScope, - DIVariable, DIGlobalVariable, DIArray, DISubrange, - DITemplateTypeParameter, DIEnumerator, DINameSpace}; +use libc::{c_uint, c_char, size_t}; pub mod archive_ro; pub mod diagnostic; +pub mod ffi; -pub type Opcode = u32; -pub type Bool = c_uint; +pub use ffi::*; -pub const True: Bool = 1 as Bool; -pub const False: Bool = 0 as Bool; - -// Consts for the LLVM CallConv type, pre-cast to usize. - -#[derive(Copy, Clone, PartialEq)] -pub enum CallConv { - CCallConv = 0, - FastCallConv = 8, - ColdCallConv = 9, - X86StdcallCallConv = 64, - X86FastcallCallConv = 65, - X86_64_Win64 = 79, - X86_VectorCall = 80 -} - -#[derive(Copy, Clone)] -pub enum Visibility { - LLVMDefaultVisibility = 0, - HiddenVisibility = 1, - ProtectedVisibility = 2, -} - -// This enum omits the obsolete (and no-op) linkage types DLLImportLinkage, -// DLLExportLinkage, GhostLinkage and LinkOnceODRAutoHideLinkage. -// LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either; -// they've been removed in upstream LLVM commit r203866. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum Linkage { - ExternalLinkage = 0, - AvailableExternallyLinkage = 1, - LinkOnceAnyLinkage = 2, - LinkOnceODRLinkage = 3, - WeakAnyLinkage = 5, - WeakODRLinkage = 6, - AppendingLinkage = 7, - InternalLinkage = 8, - PrivateLinkage = 9, - ExternalWeakLinkage = 12, - CommonLinkage = 14, -} - -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub enum DiagnosticSeverity { - Error, - Warning, - Remark, - Note, -} - - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum DLLStorageClassTypes { - DefaultStorageClass = 0, - DLLImportStorageClass = 1, - DLLExportStorageClass = 2, -} - -bitflags! { - #[derive(Default, Debug)] - flags Attribute : u64 { - const ZExt = 1 << 0, - const SExt = 1 << 1, - const NoReturn = 1 << 2, - const InReg = 1 << 3, - const StructRet = 1 << 4, - const NoUnwind = 1 << 5, - const NoAlias = 1 << 6, - const ByVal = 1 << 7, - const Nest = 1 << 8, - const ReadNone = 1 << 9, - const ReadOnly = 1 << 10, - const NoInline = 1 << 11, - const AlwaysInline = 1 << 12, - const OptimizeForSize = 1 << 13, - const StackProtect = 1 << 14, - const StackProtectReq = 1 << 15, - const NoCapture = 1 << 21, - const NoRedZone = 1 << 22, - const NoImplicitFloat = 1 << 23, - const Naked = 1 << 24, - const InlineHint = 1 << 25, - const ReturnsTwice = 1 << 29, - const UWTable = 1 << 30, - const NonLazyBind = 1 << 31, - - // Some of these are missing from the LLVM C API, the rest are - // present, but commented out, and preceded by the following warning: - // FIXME: These attributes are currently not included in the C API as - // a temporary measure until the API/ABI impact to the C API is understood - // and the path forward agreed upon. - const SanitizeAddress = 1 << 32, - const MinSize = 1 << 33, - const NoDuplicate = 1 << 34, - const StackProtectStrong = 1 << 35, - const SanitizeThread = 1 << 36, - const SanitizeMemory = 1 << 37, - const NoBuiltin = 1 << 38, - const Returned = 1 << 39, - const Cold = 1 << 40, - const Builtin = 1 << 41, - const OptimizeNone = 1 << 42, - const InAlloca = 1 << 43, - const NonNull = 1 << 44, - const JumpTable = 1 << 45, - const Convergent = 1 << 46, - const SafeStack = 1 << 47, - const NoRecurse = 1 << 48, - const InaccessibleMemOnly = 1 << 49, - const InaccessibleMemOrArgMemOnly = 1 << 50, +impl LLVMRustResult { + pub fn into_result(self) -> Result<(), ()> { + match self { + LLVMRustResult::Success => Ok(()), + LLVMRustResult::Failure => Err(()), + } } } @@ -214,167 +92,64 @@ impl Attributes { self } - pub fn apply_llfn(&self, idx: usize, llfn: ValueRef) { + pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { unsafe { - LLVMAddFunctionAttribute(llfn, idx as c_uint, self.regular.bits()); + self.regular.apply_llfn(idx, llfn); if self.dereferenceable_bytes != 0 { - LLVMAddDereferenceableAttr(llfn, idx as c_uint, - self.dereferenceable_bytes); + LLVMRustAddDereferenceableAttr( + llfn, + idx.as_uint(), + self.dereferenceable_bytes); } } } - pub fn apply_callsite(&self, idx: usize, callsite: ValueRef) { + pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { unsafe { - LLVMAddCallSiteAttribute(callsite, idx as c_uint, self.regular.bits()); + self.regular.apply_callsite(idx, callsite); if self.dereferenceable_bytes != 0 { - LLVMAddDereferenceableCallSiteAttr(callsite, idx as c_uint, - self.dereferenceable_bytes); + LLVMRustAddDereferenceableCallSiteAttr( + callsite, + idx.as_uint(), + self.dereferenceable_bytes); } } } } -#[repr(C)] -#[derive(Copy, Clone)] -pub enum AttributeSet { - ReturnIndex = 0, - FunctionIndex = !0 -} - -// enum for the LLVM IntPredicate type -#[derive(Copy, Clone)] -pub enum IntPredicate { - IntEQ = 32, - IntNE = 33, - IntUGT = 34, - IntUGE = 35, - IntULT = 36, - IntULE = 37, - IntSGT = 38, - IntSGE = 39, - IntSLT = 40, - IntSLE = 41, -} - -// enum for the LLVM RealPredicate type -#[derive(Copy, Clone)] -pub enum RealPredicate { - RealPredicateFalse = 0, - RealOEQ = 1, - RealOGT = 2, - RealOGE = 3, - RealOLT = 4, - RealOLE = 5, - RealONE = 6, - RealORD = 7, - RealUNO = 8, - RealUEQ = 9, - RealUGT = 10, - RealUGE = 11, - RealULT = 12, - RealULE = 13, - RealUNE = 14, - RealPredicateTrue = 15, -} - -// The LLVM TypeKind type - must stay in sync with the def of -// LLVMTypeKind in llvm/include/llvm-c/Core.h -#[derive(Copy, Clone, PartialEq, Debug)] -#[repr(C)] -pub enum TypeKind { - Void = 0, - Half = 1, - Float = 2, - Double = 3, - X86_FP80 = 4, - FP128 = 5, - PPC_FP128 = 6, - Label = 7, - Integer = 8, - Function = 9, - Struct = 10, - Array = 11, - Pointer = 12, - Vector = 13, - Metadata = 14, - X86_MMX = 15, +pub fn AddFunctionAttrStringValue( + llfn: ValueRef, + idx: AttributePlace, + attr: &'static str, + value: &'static str +) { + unsafe { + LLVMRustAddFunctionAttrStringValue( + llfn, + idx.as_uint(), + attr.as_ptr() as *const _, + value.as_ptr() as *const _) + } } #[repr(C)] #[derive(Copy, Clone)] -pub enum AtomicBinOp { - AtomicXchg = 0, - AtomicAdd = 1, - AtomicSub = 2, - AtomicAnd = 3, - AtomicNand = 4, - AtomicOr = 5, - AtomicXor = 6, - AtomicMax = 7, - AtomicMin = 8, - AtomicUMax = 9, - AtomicUMin = 10, +pub enum AttributePlace { + Argument(u32), + Function, } -#[repr(C)] -#[derive(Copy, Clone)] -pub enum AtomicOrdering { - NotAtomic = 0, - Unordered = 1, - Monotonic = 2, - // Consume = 3, // Not specified yet. - Acquire = 4, - Release = 5, - AcquireRelease = 6, - SequentiallyConsistent = 7 -} +impl AttributePlace { + pub fn ReturnValue() -> Self { + AttributePlace::Argument(0) + } -#[repr(C)] -#[derive(Copy, Clone)] -pub enum SynchronizationScope { - SingleThread = 0, - CrossThread = 1 -} - -// Consts for the LLVMCodeGenFileType type (in include/llvm/c/TargetMachine.h) -#[repr(C)] -#[derive(Copy, Clone)] -pub enum FileType { - AssemblyFileType = 0, - ObjectFileType = 1 -} - -#[derive(Copy, Clone)] -pub enum MetadataType { - MD_dbg = 0, - MD_tbaa = 1, - MD_prof = 2, - MD_fpmath = 3, - MD_range = 4, - MD_tbaa_struct = 5, - MD_invariant_load = 6, - MD_alias_scope = 7, - MD_noalias = 8, - MD_nontemporal = 9, - MD_mem_parallel_loop_access = 10, - MD_nonnull = 11, -} - -// Inline Asm Dialect -#[derive(Copy, Clone)] -pub enum AsmDialect { - AD_ATT = 0, - AD_Intel = 1 -} - -#[derive(Copy, Clone, PartialEq)] -#[repr(C)] -pub enum CodeGenOptLevel { - CodeGenLevelNone = 0, - CodeGenLevelLess = 1, - CodeGenLevelDefault = 2, - CodeGenLevelAggressive = 3, + fn as_uint(self) -> c_uint { + match self { + AttributePlace::Function => !0, + AttributePlace::Argument(i) => i, + } + } } #[derive(Copy, Clone, PartialEq)] @@ -385,48 +160,6 @@ pub enum CodeGenOptSize { CodeGenOptSizeAggressive = 2, } -#[derive(Copy, Clone, PartialEq)] -#[repr(C)] -pub enum RelocMode { - RelocDefault = 0, - RelocStatic = 1, - RelocPIC = 2, - RelocDynamicNoPic = 3, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum CodeGenModel { - CodeModelDefault = 0, - CodeModelJITDefault = 1, - CodeModelSmall = 2, - CodeModelKernel = 3, - CodeModelMedium = 4, - CodeModelLarge = 5, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum DiagnosticKind { - DK_InlineAsm = 0, - DK_StackSize, - DK_DebugMetadataVersion, - DK_SampleProfile, - DK_OptimizationRemark, - DK_OptimizationRemarkMissed, - DK_OptimizationRemarkAnalysis, - DK_OptimizationFailure, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub enum ArchiveKind { - K_GNU, - K_MIPS64, - K_BSD, - K_COFF, -} - impl FromStr for ArchiveKind { type Err = (); @@ -441,1731 +174,22 @@ impl FromStr for ArchiveKind { } } -/// Represents the different LLVM passes Rust supports -#[derive(Copy, Clone, PartialEq, Debug)] -#[repr(C)] -pub enum SupportedPassKind { - Function, - Module, - Unsupported, +#[allow(missing_copy_implementations)] +pub enum RustString_opaque {} +pub type RustStringRef = *mut RustString_opaque; +type RustStringRepr = *mut RefCell>; + +/// Appending to a Rust string -- used by raw_rust_string_ostream. +#[no_mangle] +pub unsafe extern "C" fn rust_llvm_string_write_impl(sr: RustStringRef, + ptr: *const c_char, + size: size_t) { + let slice = slice::from_raw_parts(ptr as *const u8, size as usize); + + let sr = sr as RustStringRepr; + (*sr).borrow_mut().extend_from_slice(slice); } -// Opaque pointer types -#[allow(missing_copy_implementations)] -pub enum Module_opaque {} -pub type ModuleRef = *mut Module_opaque; -#[allow(missing_copy_implementations)] -pub enum Context_opaque {} -pub type ContextRef = *mut Context_opaque; -#[allow(missing_copy_implementations)] -pub enum Type_opaque {} -pub type TypeRef = *mut Type_opaque; -#[allow(missing_copy_implementations)] -pub enum Value_opaque {} -pub type ValueRef = *mut Value_opaque; -#[allow(missing_copy_implementations)] -pub enum Metadata_opaque {} -pub type MetadataRef = *mut Metadata_opaque; -#[allow(missing_copy_implementations)] -pub enum BasicBlock_opaque {} -pub type BasicBlockRef = *mut BasicBlock_opaque; -#[allow(missing_copy_implementations)] -pub enum Builder_opaque {} -pub type BuilderRef = *mut Builder_opaque; -#[allow(missing_copy_implementations)] -pub enum ExecutionEngine_opaque {} -pub type ExecutionEngineRef = *mut ExecutionEngine_opaque; -#[allow(missing_copy_implementations)] -pub enum MemoryBuffer_opaque {} -pub type MemoryBufferRef = *mut MemoryBuffer_opaque; -#[allow(missing_copy_implementations)] -pub enum PassManager_opaque {} -pub type PassManagerRef = *mut PassManager_opaque; -#[allow(missing_copy_implementations)] -pub enum PassManagerBuilder_opaque {} -pub type PassManagerBuilderRef = *mut PassManagerBuilder_opaque; -#[allow(missing_copy_implementations)] -pub enum Use_opaque {} -pub type UseRef = *mut Use_opaque; -#[allow(missing_copy_implementations)] -pub enum TargetData_opaque {} -pub type TargetDataRef = *mut TargetData_opaque; -#[allow(missing_copy_implementations)] -pub enum ObjectFile_opaque {} -pub type ObjectFileRef = *mut ObjectFile_opaque; -#[allow(missing_copy_implementations)] -pub enum SectionIterator_opaque {} -pub type SectionIteratorRef = *mut SectionIterator_opaque; -#[allow(missing_copy_implementations)] -pub enum Pass_opaque {} -pub type PassRef = *mut Pass_opaque; -#[allow(missing_copy_implementations)] -pub enum TargetMachine_opaque {} -pub type TargetMachineRef = *mut TargetMachine_opaque; -pub enum Archive_opaque {} -pub type ArchiveRef = *mut Archive_opaque; -pub enum ArchiveIterator_opaque {} -pub type ArchiveIteratorRef = *mut ArchiveIterator_opaque; -pub enum ArchiveChild_opaque {} -pub type ArchiveChildRef = *mut ArchiveChild_opaque; -#[allow(missing_copy_implementations)] -pub enum Twine_opaque {} -pub type TwineRef = *mut Twine_opaque; -#[allow(missing_copy_implementations)] -pub enum DiagnosticInfo_opaque {} -pub type DiagnosticInfoRef = *mut DiagnosticInfo_opaque; -#[allow(missing_copy_implementations)] -pub enum DebugLoc_opaque {} -pub type DebugLocRef = *mut DebugLoc_opaque; -#[allow(missing_copy_implementations)] -pub enum SMDiagnostic_opaque {} -pub type SMDiagnosticRef = *mut SMDiagnostic_opaque; -#[allow(missing_copy_implementations)] -pub enum RustArchiveMember_opaque {} -pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque; -#[allow(missing_copy_implementations)] -pub enum OperandBundleDef_opaque {} -pub type OperandBundleDefRef = *mut OperandBundleDef_opaque; - -pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void); -pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint); - -pub mod debuginfo { - pub use self::DIDescriptorFlags::*; - use super::{MetadataRef}; - - #[allow(missing_copy_implementations)] - pub enum DIBuilder_opaque {} - pub type DIBuilderRef = *mut DIBuilder_opaque; - - pub type DIDescriptor = MetadataRef; - pub type DIScope = DIDescriptor; - pub type DILocation = DIDescriptor; - pub type DIFile = DIScope; - pub type DILexicalBlock = DIScope; - pub type DISubprogram = DIScope; - pub type DINameSpace = DIScope; - pub type DIType = DIDescriptor; - pub type DIBasicType = DIType; - pub type DIDerivedType = DIType; - pub type DICompositeType = DIDerivedType; - pub type DIVariable = DIDescriptor; - pub type DIGlobalVariable = DIDescriptor; - pub type DIArray = DIDescriptor; - pub type DISubrange = DIDescriptor; - pub type DIEnumerator = DIDescriptor; - pub type DITemplateTypeParameter = DIDescriptor; - - #[derive(Copy, Clone)] - pub enum DIDescriptorFlags { - FlagPrivate = 1 << 0, - FlagProtected = 1 << 1, - FlagFwdDecl = 1 << 2, - FlagAppleBlock = 1 << 3, - FlagBlockByrefStruct = 1 << 4, - FlagVirtual = 1 << 5, - FlagArtificial = 1 << 6, - FlagExplicit = 1 << 7, - FlagPrototyped = 1 << 8, - FlagObjcClassComplete = 1 << 9, - FlagObjectPointer = 1 << 10, - FlagVector = 1 << 11, - FlagStaticMember = 1 << 12, - FlagIndirectVariable = 1 << 13, - FlagLValueReference = 1 << 14, - FlagRValueReference = 1 << 15 - } -} - - -// Link to our native llvm bindings (things that we need to use the C++ api -// for) and because llvm is written in C++ we need to link against libstdc++ -// -// You'll probably notice that there is an omission of all LLVM libraries -// from this location. This is because the set of LLVM libraries that we -// link to is mostly defined by LLVM, and the `llvm-config` tool is used to -// figure out the exact set of libraries. To do this, the build system -// generates an llvmdeps.rs file next to this one which will be -// automatically updated whenever LLVM is updated to include an up-to-date -// set of the libraries we need to link to LLVM for. -#[link(name = "rustllvm", kind = "static")] -#[cfg(not(cargobuild))] -extern {} - -#[linked_from = "rustllvm"] // not quite true but good enough -extern { - /* Create and destroy contexts. */ - pub fn LLVMContextCreate() -> ContextRef; - pub fn LLVMContextDispose(C: ContextRef); - pub fn LLVMGetMDKindIDInContext(C: ContextRef, - Name: *const c_char, - SLen: c_uint) - -> c_uint; - - /* Create and destroy modules. */ - pub fn LLVMModuleCreateWithNameInContext(ModuleID: *const c_char, - C: ContextRef) - -> ModuleRef; - pub fn LLVMGetModuleContext(M: ModuleRef) -> ContextRef; - pub fn LLVMCloneModule(M: ModuleRef) -> ModuleRef; - pub fn LLVMDisposeModule(M: ModuleRef); - - /// Data layout. See Module::getDataLayout. - pub fn LLVMGetDataLayout(M: ModuleRef) -> *const c_char; - pub fn LLVMSetDataLayout(M: ModuleRef, Triple: *const c_char); - - /// Target triple. See Module::getTargetTriple. - pub fn LLVMGetTarget(M: ModuleRef) -> *const c_char; - pub fn LLVMSetTarget(M: ModuleRef, Triple: *const c_char); - - /// See Module::dump. - pub fn LLVMDumpModule(M: ModuleRef); - - /// See Module::setModuleInlineAsm. - pub fn LLVMSetModuleInlineAsm(M: ModuleRef, Asm: *const c_char); - - /// See llvm::LLVMTypeKind::getTypeID. - pub fn LLVMGetTypeKind(Ty: TypeRef) -> TypeKind; - - /// See llvm::LLVMType::getContext. - pub fn LLVMGetTypeContext(Ty: TypeRef) -> ContextRef; - - /* Operations on integer types */ - pub fn LLVMInt1TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMInt8TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMInt16TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMInt32TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMInt64TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMIntTypeInContext(C: ContextRef, NumBits: c_uint) - -> TypeRef; - - pub fn LLVMGetIntTypeWidth(IntegerTy: TypeRef) -> c_uint; - - /* Operations on real types */ - pub fn LLVMFloatTypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMDoubleTypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMX86FP80TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMFP128TypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMPPCFP128TypeInContext(C: ContextRef) -> TypeRef; - - /* Operations on function types */ - pub fn LLVMFunctionType(ReturnType: TypeRef, - ParamTypes: *const TypeRef, - ParamCount: c_uint, - IsVarArg: Bool) - -> TypeRef; - pub fn LLVMIsFunctionVarArg(FunctionTy: TypeRef) -> Bool; - pub fn LLVMGetReturnType(FunctionTy: TypeRef) -> TypeRef; - pub fn LLVMCountParamTypes(FunctionTy: TypeRef) -> c_uint; - pub fn LLVMGetParamTypes(FunctionTy: TypeRef, Dest: *mut TypeRef); - - /* Operations on struct types */ - pub fn LLVMStructTypeInContext(C: ContextRef, - ElementTypes: *const TypeRef, - ElementCount: c_uint, - Packed: Bool) - -> TypeRef; - pub fn LLVMCountStructElementTypes(StructTy: TypeRef) -> c_uint; - pub fn LLVMGetStructElementTypes(StructTy: TypeRef, - Dest: *mut TypeRef); - pub fn LLVMIsPackedStruct(StructTy: TypeRef) -> Bool; - - /* Operations on array, pointer, and vector types (sequence types) */ - pub fn LLVMRustArrayType(ElementType: TypeRef, ElementCount: u64) -> TypeRef; - pub fn LLVMPointerType(ElementType: TypeRef, AddressSpace: c_uint) - -> TypeRef; - pub fn LLVMVectorType(ElementType: TypeRef, ElementCount: c_uint) - -> TypeRef; - - pub fn LLVMGetElementType(Ty: TypeRef) -> TypeRef; - pub fn LLVMGetArrayLength(ArrayTy: TypeRef) -> c_uint; - pub fn LLVMGetPointerAddressSpace(PointerTy: TypeRef) -> c_uint; - pub fn LLVMGetPointerToGlobal(EE: ExecutionEngineRef, V: ValueRef) - -> *const c_void; - pub fn LLVMGetVectorSize(VectorTy: TypeRef) -> c_uint; - - /* Operations on other types */ - pub fn LLVMVoidTypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMLabelTypeInContext(C: ContextRef) -> TypeRef; - pub fn LLVMMetadataTypeInContext(C: ContextRef) -> TypeRef; - - /* Operations on all values */ - pub fn LLVMTypeOf(Val: ValueRef) -> TypeRef; - pub fn LLVMGetValueName(Val: ValueRef) -> *const c_char; - pub fn LLVMSetValueName(Val: ValueRef, Name: *const c_char); - pub fn LLVMDumpValue(Val: ValueRef); - pub fn LLVMReplaceAllUsesWith(OldVal: ValueRef, NewVal: ValueRef); - pub fn LLVMHasMetadata(Val: ValueRef) -> c_int; - pub fn LLVMGetMetadata(Val: ValueRef, KindID: c_uint) -> ValueRef; - pub fn LLVMSetMetadata(Val: ValueRef, KindID: c_uint, Node: ValueRef); - - /* Operations on Uses */ - pub fn LLVMGetFirstUse(Val: ValueRef) -> UseRef; - pub fn LLVMGetNextUse(U: UseRef) -> UseRef; - pub fn LLVMGetUser(U: UseRef) -> ValueRef; - pub fn LLVMGetUsedValue(U: UseRef) -> ValueRef; - - /* Operations on Users */ - pub fn LLVMGetNumOperands(Val: ValueRef) -> c_int; - pub fn LLVMGetOperand(Val: ValueRef, Index: c_uint) -> ValueRef; - pub fn LLVMSetOperand(Val: ValueRef, Index: c_uint, Op: ValueRef); - - /* Operations on constants of any type */ - pub fn LLVMConstNull(Ty: TypeRef) -> ValueRef; - /* all zeroes */ - pub fn LLVMConstAllOnes(Ty: TypeRef) -> ValueRef; - pub fn LLVMConstICmp(Pred: c_ushort, V1: ValueRef, V2: ValueRef) - -> ValueRef; - pub fn LLVMConstFCmp(Pred: c_ushort, V1: ValueRef, V2: ValueRef) - -> ValueRef; - /* only for isize/vector */ - pub fn LLVMGetUndef(Ty: TypeRef) -> ValueRef; - pub fn LLVMIsConstant(Val: ValueRef) -> Bool; - pub fn LLVMIsNull(Val: ValueRef) -> Bool; - pub fn LLVMIsUndef(Val: ValueRef) -> Bool; - pub fn LLVMConstPointerNull(Ty: TypeRef) -> ValueRef; - - /* Operations on metadata */ - pub fn LLVMMDStringInContext(C: ContextRef, - Str: *const c_char, - SLen: c_uint) - -> ValueRef; - pub fn LLVMMDNodeInContext(C: ContextRef, - Vals: *const ValueRef, - Count: c_uint) - -> ValueRef; - pub fn LLVMAddNamedMetadataOperand(M: ModuleRef, - Str: *const c_char, - Val: ValueRef); - - /* Operations on scalar constants */ - pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) - -> ValueRef; - pub fn LLVMConstIntOfString(IntTy: TypeRef, Text: *const c_char, Radix: u8) - -> ValueRef; - pub fn LLVMConstIntOfStringAndSize(IntTy: TypeRef, - Text: *const c_char, - SLen: c_uint, - Radix: u8) - -> ValueRef; - pub fn LLVMConstReal(RealTy: TypeRef, N: f64) -> ValueRef; - pub fn LLVMConstRealOfString(RealTy: TypeRef, Text: *const c_char) - -> ValueRef; - pub fn LLVMConstRealOfStringAndSize(RealTy: TypeRef, - Text: *const c_char, - SLen: c_uint) - -> ValueRef; - pub fn LLVMConstIntGetZExtValue(ConstantVal: ValueRef) -> c_ulonglong; - pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong; - - - /* Operations on composite constants */ - pub fn LLVMConstStringInContext(C: ContextRef, - Str: *const c_char, - Length: c_uint, - DontNullTerminate: Bool) - -> ValueRef; - pub fn LLVMConstStructInContext(C: ContextRef, - ConstantVals: *const ValueRef, - Count: c_uint, - Packed: Bool) - -> ValueRef; - - pub fn LLVMConstArray(ElementTy: TypeRef, - ConstantVals: *const ValueRef, - Length: c_uint) - -> ValueRef; - pub fn LLVMConstVector(ScalarConstantVals: *const ValueRef, Size: c_uint) - -> ValueRef; - - /* Constant expressions */ - pub fn LLVMAlignOf(Ty: TypeRef) -> ValueRef; - pub fn LLVMSizeOf(Ty: TypeRef) -> ValueRef; - pub fn LLVMConstNeg(ConstantVal: ValueRef) -> ValueRef; - pub fn LLVMConstNSWNeg(ConstantVal: ValueRef) -> ValueRef; - pub fn LLVMConstNUWNeg(ConstantVal: ValueRef) -> ValueRef; - pub fn LLVMConstFNeg(ConstantVal: ValueRef) -> ValueRef; - pub fn LLVMConstNot(ConstantVal: ValueRef) -> ValueRef; - pub fn LLVMConstAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNSWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNUWAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFAdd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstSub(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNSWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNUWSub(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFSub(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstMul(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNSWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstNUWMul(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFMul(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstUDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstSDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstExactSDiv(LHSConstant: ValueRef, - RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFDiv(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstURem(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstSRem(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstFRem(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstAnd(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstOr(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstXor(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstShl(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstLShr(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstAShr(LHSConstant: ValueRef, RHSConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstGEP(ConstantVal: ValueRef, - ConstantIndices: *const ValueRef, - NumIndices: c_uint) - -> ValueRef; - pub fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, - ConstantIndices: *const ValueRef, - NumIndices: c_uint) - -> ValueRef; - pub fn LLVMConstTrunc(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstSExt(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstZExt(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstFPTrunc(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstFPExt(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstUIToFP(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstSIToFP(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstFPToUI(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstFPToSI(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstPtrToInt(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstIntToPtr(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstBitCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstZExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstSExtOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstTruncOrBitCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstPointerCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstIntCast(ConstantVal: ValueRef, - ToType: TypeRef, - isSigned: Bool) - -> ValueRef; - pub fn LLVMConstFPCast(ConstantVal: ValueRef, ToType: TypeRef) - -> ValueRef; - pub fn LLVMConstSelect(ConstantCondition: ValueRef, - ConstantIfTrue: ValueRef, - ConstantIfFalse: ValueRef) - -> ValueRef; - pub fn LLVMConstExtractElement(VectorConstant: ValueRef, - IndexConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstInsertElement(VectorConstant: ValueRef, - ElementValueConstant: ValueRef, - IndexConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstShuffleVector(VectorAConstant: ValueRef, - VectorBConstant: ValueRef, - MaskConstant: ValueRef) - -> ValueRef; - pub fn LLVMConstExtractValue(AggConstant: ValueRef, - IdxList: *const c_uint, - NumIdx: c_uint) - -> ValueRef; - pub fn LLVMConstInsertValue(AggConstant: ValueRef, - ElementValueConstant: ValueRef, - IdxList: *const c_uint, - NumIdx: c_uint) - -> ValueRef; - pub fn LLVMConstInlineAsm(Ty: TypeRef, - AsmString: *const c_char, - Constraints: *const c_char, - HasSideEffects: Bool, - IsAlignStack: Bool) - -> ValueRef; - pub fn LLVMBlockAddress(F: ValueRef, BB: BasicBlockRef) -> ValueRef; - - - - /* Operations on global variables, functions, and aliases (globals) */ - pub fn LLVMGetGlobalParent(Global: ValueRef) -> ModuleRef; - pub fn LLVMIsDeclaration(Global: ValueRef) -> Bool; - pub fn LLVMGetLinkage(Global: ValueRef) -> c_uint; - pub fn LLVMSetLinkage(Global: ValueRef, Link: c_uint); - pub fn LLVMGetSection(Global: ValueRef) -> *const c_char; - pub fn LLVMSetSection(Global: ValueRef, Section: *const c_char); - pub fn LLVMGetVisibility(Global: ValueRef) -> c_uint; - pub fn LLVMSetVisibility(Global: ValueRef, Viz: c_uint); - pub fn LLVMGetAlignment(Global: ValueRef) -> c_uint; - pub fn LLVMSetAlignment(Global: ValueRef, Bytes: c_uint); - - - /* Operations on global variables */ - pub fn LLVMIsAGlobalVariable(GlobalVar: ValueRef) -> ValueRef; - pub fn LLVMAddGlobal(M: ModuleRef, Ty: TypeRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMAddGlobalInAddressSpace(M: ModuleRef, - Ty: TypeRef, - Name: *const c_char, - AddressSpace: c_uint) - -> ValueRef; - pub fn LLVMGetNamedGlobal(M: ModuleRef, Name: *const c_char) -> ValueRef; - pub fn LLVMGetOrInsertGlobal(M: ModuleRef, Name: *const c_char, T: TypeRef) -> ValueRef; - pub fn LLVMGetFirstGlobal(M: ModuleRef) -> ValueRef; - pub fn LLVMGetLastGlobal(M: ModuleRef) -> ValueRef; - pub fn LLVMGetNextGlobal(GlobalVar: ValueRef) -> ValueRef; - pub fn LLVMGetPreviousGlobal(GlobalVar: ValueRef) -> ValueRef; - pub fn LLVMDeleteGlobal(GlobalVar: ValueRef); - pub fn LLVMGetInitializer(GlobalVar: ValueRef) -> ValueRef; - pub fn LLVMSetInitializer(GlobalVar: ValueRef, - ConstantVal: ValueRef); - pub fn LLVMIsThreadLocal(GlobalVar: ValueRef) -> Bool; - pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool); - pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool; - pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool); - pub fn LLVMGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef; - - /* Operations on aliases */ - pub fn LLVMAddAlias(M: ModuleRef, - Ty: TypeRef, - Aliasee: ValueRef, - Name: *const c_char) - -> ValueRef; - - /* Operations on functions */ - pub fn LLVMAddFunction(M: ModuleRef, - Name: *const c_char, - FunctionTy: TypeRef) - -> ValueRef; - pub fn LLVMGetNamedFunction(M: ModuleRef, Name: *const c_char) -> ValueRef; - pub fn LLVMGetFirstFunction(M: ModuleRef) -> ValueRef; - pub fn LLVMGetLastFunction(M: ModuleRef) -> ValueRef; - pub fn LLVMGetNextFunction(Fn: ValueRef) -> ValueRef; - pub fn LLVMGetPreviousFunction(Fn: ValueRef) -> ValueRef; - pub fn LLVMDeleteFunction(Fn: ValueRef); - pub fn LLVMGetOrInsertFunction(M: ModuleRef, - Name: *const c_char, - FunctionTy: TypeRef) - -> ValueRef; - pub fn LLVMGetIntrinsicID(Fn: ValueRef) -> c_uint; - pub fn LLVMGetFunctionCallConv(Fn: ValueRef) -> c_uint; - pub fn LLVMSetFunctionCallConv(Fn: ValueRef, CC: c_uint); - pub fn LLVMGetGC(Fn: ValueRef) -> *const c_char; - pub fn LLVMSetGC(Fn: ValueRef, Name: *const c_char); - pub fn LLVMAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: uint64_t); - pub fn LLVMAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: uint64_t); - pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); - pub fn LLVMAddFunctionAttrStringValue(Fn: ValueRef, index: c_uint, - Name: *const c_char, - Value: *const c_char); - pub fn LLVMRemoveFunctionAttributes(Fn: ValueRef, index: c_uint, attr: uint64_t); - pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); - pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_uint; - pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_uint); - - /* Operations on parameters */ - pub fn LLVMCountParams(Fn: ValueRef) -> c_uint; - pub fn LLVMGetParams(Fn: ValueRef, Params: *const ValueRef); - pub fn LLVMGetParam(Fn: ValueRef, Index: c_uint) -> ValueRef; - pub fn LLVMGetParamParent(Inst: ValueRef) -> ValueRef; - pub fn LLVMGetFirstParam(Fn: ValueRef) -> ValueRef; - pub fn LLVMGetLastParam(Fn: ValueRef) -> ValueRef; - pub fn LLVMGetNextParam(Arg: ValueRef) -> ValueRef; - pub fn LLVMGetPreviousParam(Arg: ValueRef) -> ValueRef; - pub fn LLVMAddAttribute(Arg: ValueRef, PA: c_uint); - pub fn LLVMRemoveAttribute(Arg: ValueRef, PA: c_uint); - pub fn LLVMGetAttribute(Arg: ValueRef) -> c_uint; - pub fn LLVMSetParamAlignment(Arg: ValueRef, align: c_uint); - - /* Operations on basic blocks */ - pub fn LLVMBasicBlockAsValue(BB: BasicBlockRef) -> ValueRef; - pub fn LLVMValueIsBasicBlock(Val: ValueRef) -> Bool; - pub fn LLVMValueAsBasicBlock(Val: ValueRef) -> BasicBlockRef; - pub fn LLVMGetBasicBlockParent(BB: BasicBlockRef) -> ValueRef; - pub fn LLVMCountBasicBlocks(Fn: ValueRef) -> c_uint; - pub fn LLVMGetBasicBlocks(Fn: ValueRef, BasicBlocks: *const ValueRef); - pub fn LLVMGetFirstBasicBlock(Fn: ValueRef) -> BasicBlockRef; - pub fn LLVMGetLastBasicBlock(Fn: ValueRef) -> BasicBlockRef; - pub fn LLVMGetNextBasicBlock(BB: BasicBlockRef) -> BasicBlockRef; - pub fn LLVMGetPreviousBasicBlock(BB: BasicBlockRef) -> BasicBlockRef; - pub fn LLVMGetEntryBasicBlock(Fn: ValueRef) -> BasicBlockRef; - - pub fn LLVMAppendBasicBlockInContext(C: ContextRef, - Fn: ValueRef, - Name: *const c_char) - -> BasicBlockRef; - pub fn LLVMInsertBasicBlockInContext(C: ContextRef, - BB: BasicBlockRef, - Name: *const c_char) - -> BasicBlockRef; - pub fn LLVMDeleteBasicBlock(BB: BasicBlockRef); - - pub fn LLVMMoveBasicBlockAfter(BB: BasicBlockRef, - MoveAfter: BasicBlockRef); - - pub fn LLVMMoveBasicBlockBefore(BB: BasicBlockRef, - MoveBefore: BasicBlockRef); - - /* Operations on instructions */ - pub fn LLVMGetInstructionParent(Inst: ValueRef) -> BasicBlockRef; - pub fn LLVMGetFirstInstruction(BB: BasicBlockRef) -> ValueRef; - pub fn LLVMGetLastInstruction(BB: BasicBlockRef) -> ValueRef; - pub fn LLVMGetNextInstruction(Inst: ValueRef) -> ValueRef; - pub fn LLVMGetPreviousInstruction(Inst: ValueRef) -> ValueRef; - pub fn LLVMInstructionEraseFromParent(Inst: ValueRef); - - /* Operations on call sites */ - pub fn LLVMSetInstructionCallConv(Instr: ValueRef, CC: c_uint); - pub fn LLVMGetInstructionCallConv(Instr: ValueRef) -> c_uint; - pub fn LLVMAddInstrAttribute(Instr: ValueRef, - index: c_uint, - IA: c_uint); - pub fn LLVMRemoveInstrAttribute(Instr: ValueRef, - index: c_uint, - IA: c_uint); - pub fn LLVMSetInstrParamAlignment(Instr: ValueRef, - index: c_uint, - align: c_uint); - pub fn LLVMAddCallSiteAttribute(Instr: ValueRef, - index: c_uint, - Val: uint64_t); - pub fn LLVMAddDereferenceableCallSiteAttr(Instr: ValueRef, - index: c_uint, - bytes: uint64_t); - - /* Operations on call instructions (only) */ - pub fn LLVMIsTailCall(CallInst: ValueRef) -> Bool; - pub fn LLVMSetTailCall(CallInst: ValueRef, IsTailCall: Bool); - - /* Operations on load/store instructions (only) */ - pub fn LLVMGetVolatile(MemoryAccessInst: ValueRef) -> Bool; - pub fn LLVMSetVolatile(MemoryAccessInst: ValueRef, volatile: Bool); - - /* Operations on phi nodes */ - pub fn LLVMAddIncoming(PhiNode: ValueRef, - IncomingValues: *const ValueRef, - IncomingBlocks: *const BasicBlockRef, - Count: c_uint); - pub fn LLVMCountIncoming(PhiNode: ValueRef) -> c_uint; - pub fn LLVMGetIncomingValue(PhiNode: ValueRef, Index: c_uint) - -> ValueRef; - pub fn LLVMGetIncomingBlock(PhiNode: ValueRef, Index: c_uint) - -> BasicBlockRef; - - /* Instruction builders */ - pub fn LLVMCreateBuilderInContext(C: ContextRef) -> BuilderRef; - pub fn LLVMPositionBuilder(Builder: BuilderRef, - Block: BasicBlockRef, - Instr: ValueRef); - pub fn LLVMPositionBuilderBefore(Builder: BuilderRef, - Instr: ValueRef); - pub fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, - Block: BasicBlockRef); - pub fn LLVMGetInsertBlock(Builder: BuilderRef) -> BasicBlockRef; - pub fn LLVMClearInsertionPosition(Builder: BuilderRef); - pub fn LLVMInsertIntoBuilder(Builder: BuilderRef, Instr: ValueRef); - pub fn LLVMInsertIntoBuilderWithName(Builder: BuilderRef, - Instr: ValueRef, - Name: *const c_char); - pub fn LLVMDisposeBuilder(Builder: BuilderRef); - - /* Execution engine */ - pub fn LLVMBuildExecutionEngine(Mod: ModuleRef) -> ExecutionEngineRef; - pub fn LLVMDisposeExecutionEngine(EE: ExecutionEngineRef); - pub fn LLVMExecutionEngineFinalizeObject(EE: ExecutionEngineRef); - pub fn LLVMRustLoadDynamicLibrary(path: *const c_char) -> Bool; - pub fn LLVMExecutionEngineAddModule(EE: ExecutionEngineRef, M: ModuleRef); - pub fn LLVMExecutionEngineRemoveModule(EE: ExecutionEngineRef, M: ModuleRef) - -> Bool; - - /* Metadata */ - pub fn LLVMSetCurrentDebugLocation(Builder: BuilderRef, L: ValueRef); - pub fn LLVMGetCurrentDebugLocation(Builder: BuilderRef) -> ValueRef; - pub fn LLVMSetInstDebugLocation(Builder: BuilderRef, Inst: ValueRef); - - /* Terminators */ - pub fn LLVMBuildRetVoid(B: BuilderRef) -> ValueRef; - pub fn LLVMBuildRet(B: BuilderRef, V: ValueRef) -> ValueRef; - pub fn LLVMBuildAggregateRet(B: BuilderRef, - RetVals: *const ValueRef, - N: c_uint) - -> ValueRef; - pub fn LLVMBuildBr(B: BuilderRef, Dest: BasicBlockRef) -> ValueRef; - pub fn LLVMBuildCondBr(B: BuilderRef, - If: ValueRef, - Then: BasicBlockRef, - Else: BasicBlockRef) - -> ValueRef; - pub fn LLVMBuildSwitch(B: BuilderRef, - V: ValueRef, - Else: BasicBlockRef, - NumCases: c_uint) - -> ValueRef; - pub fn LLVMBuildIndirectBr(B: BuilderRef, - Addr: ValueRef, - NumDests: c_uint) - -> ValueRef; - pub fn LLVMRustBuildInvoke(B: BuilderRef, - Fn: ValueRef, - Args: *const ValueRef, - NumArgs: c_uint, - Then: BasicBlockRef, - Catch: BasicBlockRef, - Bundle: OperandBundleDefRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMRustBuildLandingPad(B: BuilderRef, - Ty: TypeRef, - PersFn: ValueRef, - NumClauses: c_uint, - Name: *const c_char, - F: ValueRef) - -> ValueRef; - pub fn LLVMBuildResume(B: BuilderRef, Exn: ValueRef) -> ValueRef; - pub fn LLVMBuildUnreachable(B: BuilderRef) -> ValueRef; - - pub fn LLVMRustBuildCleanupPad(B: BuilderRef, - ParentPad: ValueRef, - ArgCnt: c_uint, - Args: *const ValueRef, - Name: *const c_char) -> ValueRef; - pub fn LLVMRustBuildCleanupRet(B: BuilderRef, - CleanupPad: ValueRef, - UnwindBB: BasicBlockRef) -> ValueRef; - pub fn LLVMRustBuildCatchPad(B: BuilderRef, - ParentPad: ValueRef, - ArgCnt: c_uint, - Args: *const ValueRef, - Name: *const c_char) -> ValueRef; - pub fn LLVMRustBuildCatchRet(B: BuilderRef, - Pad: ValueRef, - BB: BasicBlockRef) -> ValueRef; - pub fn LLVMRustBuildCatchSwitch(Builder: BuilderRef, - ParentPad: ValueRef, - BB: BasicBlockRef, - NumHandlers: c_uint, - Name: *const c_char) -> ValueRef; - pub fn LLVMRustAddHandler(CatchSwitch: ValueRef, - Handler: BasicBlockRef); - pub fn LLVMRustSetPersonalityFn(B: BuilderRef, Pers: ValueRef); - - /* Add a case to the switch instruction */ - pub fn LLVMAddCase(Switch: ValueRef, - OnVal: ValueRef, - Dest: BasicBlockRef); - - /* Add a destination to the indirectbr instruction */ - pub fn LLVMAddDestination(IndirectBr: ValueRef, Dest: BasicBlockRef); - - /* Add a clause to the landing pad instruction */ - pub fn LLVMAddClause(LandingPad: ValueRef, ClauseVal: ValueRef); - - /* Set the cleanup on a landing pad instruction */ - pub fn LLVMSetCleanup(LandingPad: ValueRef, Val: Bool); - - /* Arithmetic */ - pub fn LLVMBuildAdd(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNSWAdd(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNUWAdd(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFAdd(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSub(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNSWSub(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNUWSub(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFSub(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildMul(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNSWMul(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNUWMul(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFMul(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildUDiv(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSDiv(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildExactSDiv(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFDiv(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildURem(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSRem(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFRem(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildShl(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildLShr(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildAShr(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildAnd(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildOr(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildXor(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildBinOp(B: BuilderRef, - Op: Opcode, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNSWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNUWNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFNeg(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildNot(B: BuilderRef, V: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMRustSetHasUnsafeAlgebra(Instr: ValueRef); - - /* Memory */ - pub fn LLVMBuildAlloca(B: BuilderRef, Ty: TypeRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFree(B: BuilderRef, PointerVal: ValueRef) -> ValueRef; - pub fn LLVMBuildLoad(B: BuilderRef, - PointerVal: ValueRef, - Name: *const c_char) - -> ValueRef; - - pub fn LLVMBuildStore(B: BuilderRef, Val: ValueRef, Ptr: ValueRef) - -> ValueRef; - - pub fn LLVMBuildGEP(B: BuilderRef, - Pointer: ValueRef, - Indices: *const ValueRef, - NumIndices: c_uint, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildInBoundsGEP(B: BuilderRef, - Pointer: ValueRef, - Indices: *const ValueRef, - NumIndices: c_uint, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildStructGEP(B: BuilderRef, - Pointer: ValueRef, - Idx: c_uint, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildGlobalString(B: BuilderRef, - Str: *const c_char, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildGlobalStringPtr(B: BuilderRef, - Str: *const c_char, - Name: *const c_char) - -> ValueRef; - - /* Casts */ - pub fn LLVMBuildTrunc(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildZExt(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSExt(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFPToUI(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFPToSI(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildUIToFP(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSIToFP(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFPTrunc(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFPExt(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildPtrToInt(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildIntToPtr(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildBitCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildZExtOrBitCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSExtOrBitCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildTruncOrBitCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildCast(B: BuilderRef, - Op: Opcode, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) -> ValueRef; - pub fn LLVMBuildPointerCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildIntCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFPCast(B: BuilderRef, - Val: ValueRef, - DestTy: TypeRef, - Name: *const c_char) - -> ValueRef; - - /* Comparisons */ - pub fn LLVMBuildICmp(B: BuilderRef, - Op: c_uint, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildFCmp(B: BuilderRef, - Op: c_uint, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - - /* Miscellaneous instructions */ - pub fn LLVMBuildPhi(B: BuilderRef, Ty: TypeRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMRustBuildCall(B: BuilderRef, - Fn: ValueRef, - Args: *const ValueRef, - NumArgs: c_uint, - Bundle: OperandBundleDefRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildSelect(B: BuilderRef, - If: ValueRef, - Then: ValueRef, - Else: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildVAArg(B: BuilderRef, - list: ValueRef, - Ty: TypeRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildExtractElement(B: BuilderRef, - VecVal: ValueRef, - Index: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildInsertElement(B: BuilderRef, - VecVal: ValueRef, - EltVal: ValueRef, - Index: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildShuffleVector(B: BuilderRef, - V1: ValueRef, - V2: ValueRef, - Mask: ValueRef, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildExtractValue(B: BuilderRef, - AggVal: ValueRef, - Index: c_uint, - Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildInsertValue(B: BuilderRef, - AggVal: ValueRef, - EltVal: ValueRef, - Index: c_uint, - Name: *const c_char) - -> ValueRef; - - pub fn LLVMBuildIsNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildIsNotNull(B: BuilderRef, Val: ValueRef, Name: *const c_char) - -> ValueRef; - pub fn LLVMBuildPtrDiff(B: BuilderRef, - LHS: ValueRef, - RHS: ValueRef, - Name: *const c_char) - -> ValueRef; - - /* Atomic Operations */ - pub fn LLVMBuildAtomicLoad(B: BuilderRef, - PointerVal: ValueRef, - Name: *const c_char, - Order: AtomicOrdering, - Alignment: c_uint) - -> ValueRef; - - pub fn LLVMBuildAtomicStore(B: BuilderRef, - Val: ValueRef, - Ptr: ValueRef, - Order: AtomicOrdering, - Alignment: c_uint) - -> ValueRef; - - pub fn LLVMBuildAtomicCmpXchg(B: BuilderRef, - LHS: ValueRef, - CMP: ValueRef, - RHS: ValueRef, - Order: AtomicOrdering, - FailureOrder: AtomicOrdering, - Weak: Bool) - -> ValueRef; - pub fn LLVMBuildAtomicRMW(B: BuilderRef, - Op: AtomicBinOp, - LHS: ValueRef, - RHS: ValueRef, - Order: AtomicOrdering, - SingleThreaded: Bool) - -> ValueRef; - - pub fn LLVMBuildAtomicFence(B: BuilderRef, - Order: AtomicOrdering, - Scope: SynchronizationScope); - - - /* Selected entries from the downcasts. */ - pub fn LLVMIsATerminatorInst(Inst: ValueRef) -> ValueRef; - pub fn LLVMIsAStoreInst(Inst: ValueRef) -> ValueRef; - - /// Writes a module to the specified path. Returns 0 on success. - pub fn LLVMWriteBitcodeToFile(M: ModuleRef, Path: *const c_char) -> c_int; - - /// Creates target data from a target layout string. - pub fn LLVMCreateTargetData(StringRep: *const c_char) -> TargetDataRef; - /// Adds the target data to the given pass manager. The pass manager - /// references the target data only weakly. - pub fn LLVMAddTargetData(TD: TargetDataRef, PM: PassManagerRef); - /// Number of bytes clobbered when doing a Store to *T. - pub fn LLVMStoreSizeOfType(TD: TargetDataRef, Ty: TypeRef) - -> c_ulonglong; - - /// Number of bytes clobbered when doing a Store to *T. - pub fn LLVMSizeOfTypeInBits(TD: TargetDataRef, Ty: TypeRef) - -> c_ulonglong; - - /// Distance between successive elements in an array of T. Includes ABI padding. - pub fn LLVMABISizeOfType(TD: TargetDataRef, Ty: TypeRef) -> c_ulonglong; - - /// Returns the preferred alignment of a type. - pub fn LLVMPreferredAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) - -> c_uint; - /// Returns the minimum alignment of a type. - pub fn LLVMABIAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) - -> c_uint; - - /// Computes the byte offset of the indexed struct element for a - /// target. - pub fn LLVMOffsetOfElement(TD: TargetDataRef, - StructTy: TypeRef, - Element: c_uint) - -> c_ulonglong; - - /// Returns the minimum alignment of a type when part of a call frame. - pub fn LLVMCallFrameAlignmentOfType(TD: TargetDataRef, Ty: TypeRef) - -> c_uint; - - /// Disposes target data. - pub fn LLVMDisposeTargetData(TD: TargetDataRef); - - /// Creates a pass manager. - pub fn LLVMCreatePassManager() -> PassManagerRef; - - /// Creates a function-by-function pass manager - pub fn LLVMCreateFunctionPassManagerForModule(M: ModuleRef) - -> PassManagerRef; - - /// Disposes a pass manager. - pub fn LLVMDisposePassManager(PM: PassManagerRef); - - /// Runs a pass manager on a module. - pub fn LLVMRunPassManager(PM: PassManagerRef, M: ModuleRef) -> Bool; - - /// Runs the function passes on the provided function. - pub fn LLVMRunFunctionPassManager(FPM: PassManagerRef, F: ValueRef) - -> Bool; - - /// Initializes all the function passes scheduled in the manager - pub fn LLVMInitializeFunctionPassManager(FPM: PassManagerRef) -> Bool; - - /// Finalizes all the function passes scheduled in the manager - pub fn LLVMFinalizeFunctionPassManager(FPM: PassManagerRef) -> Bool; - - pub fn LLVMInitializePasses(); - - /// Adds a verification pass. - pub fn LLVMAddVerifierPass(PM: PassManagerRef); - - pub fn LLVMAddGlobalOptimizerPass(PM: PassManagerRef); - pub fn LLVMAddIPSCCPPass(PM: PassManagerRef); - pub fn LLVMAddDeadArgEliminationPass(PM: PassManagerRef); - pub fn LLVMAddInstructionCombiningPass(PM: PassManagerRef); - pub fn LLVMAddCFGSimplificationPass(PM: PassManagerRef); - pub fn LLVMAddFunctionInliningPass(PM: PassManagerRef); - pub fn LLVMAddFunctionAttrsPass(PM: PassManagerRef); - pub fn LLVMAddScalarReplAggregatesPass(PM: PassManagerRef); - pub fn LLVMAddScalarReplAggregatesPassSSA(PM: PassManagerRef); - pub fn LLVMAddJumpThreadingPass(PM: PassManagerRef); - pub fn LLVMAddConstantPropagationPass(PM: PassManagerRef); - pub fn LLVMAddReassociatePass(PM: PassManagerRef); - pub fn LLVMAddLoopRotatePass(PM: PassManagerRef); - pub fn LLVMAddLICMPass(PM: PassManagerRef); - pub fn LLVMAddLoopUnswitchPass(PM: PassManagerRef); - pub fn LLVMAddLoopDeletionPass(PM: PassManagerRef); - pub fn LLVMAddLoopUnrollPass(PM: PassManagerRef); - pub fn LLVMAddGVNPass(PM: PassManagerRef); - pub fn LLVMAddMemCpyOptPass(PM: PassManagerRef); - pub fn LLVMAddSCCPPass(PM: PassManagerRef); - pub fn LLVMAddDeadStoreEliminationPass(PM: PassManagerRef); - pub fn LLVMAddStripDeadPrototypesPass(PM: PassManagerRef); - pub fn LLVMAddConstantMergePass(PM: PassManagerRef); - pub fn LLVMAddArgumentPromotionPass(PM: PassManagerRef); - pub fn LLVMAddTailCallEliminationPass(PM: PassManagerRef); - pub fn LLVMAddIndVarSimplifyPass(PM: PassManagerRef); - pub fn LLVMAddAggressiveDCEPass(PM: PassManagerRef); - pub fn LLVMAddGlobalDCEPass(PM: PassManagerRef); - pub fn LLVMAddCorrelatedValuePropagationPass(PM: PassManagerRef); - pub fn LLVMAddPruneEHPass(PM: PassManagerRef); - pub fn LLVMAddSimplifyLibCallsPass(PM: PassManagerRef); - pub fn LLVMAddLoopIdiomPass(PM: PassManagerRef); - pub fn LLVMAddEarlyCSEPass(PM: PassManagerRef); - pub fn LLVMAddTypeBasedAliasAnalysisPass(PM: PassManagerRef); - pub fn LLVMAddBasicAliasAnalysisPass(PM: PassManagerRef); - - pub fn LLVMPassManagerBuilderCreate() -> PassManagerBuilderRef; - pub fn LLVMPassManagerBuilderDispose(PMB: PassManagerBuilderRef); - pub fn LLVMPassManagerBuilderSetOptLevel(PMB: PassManagerBuilderRef, - OptimizationLevel: c_uint); - pub fn LLVMPassManagerBuilderSetSizeLevel(PMB: PassManagerBuilderRef, - Value: Bool); - pub fn LLVMPassManagerBuilderSetDisableUnitAtATime( - PMB: PassManagerBuilderRef, - Value: Bool); - pub fn LLVMPassManagerBuilderSetDisableUnrollLoops( - PMB: PassManagerBuilderRef, - Value: Bool); - pub fn LLVMPassManagerBuilderSetDisableSimplifyLibCalls( - PMB: PassManagerBuilderRef, - Value: Bool); - pub fn LLVMPassManagerBuilderUseInlinerWithThreshold( - PMB: PassManagerBuilderRef, - threshold: c_uint); - pub fn LLVMPassManagerBuilderPopulateModulePassManager( - PMB: PassManagerBuilderRef, - PM: PassManagerRef); - - pub fn LLVMPassManagerBuilderPopulateFunctionPassManager( - PMB: PassManagerBuilderRef, - PM: PassManagerRef); - pub fn LLVMPassManagerBuilderPopulateLTOPassManager( - PMB: PassManagerBuilderRef, - PM: PassManagerRef, - Internalize: Bool, - RunInliner: Bool); - - /// Destroys a memory buffer. - pub fn LLVMDisposeMemoryBuffer(MemBuf: MemoryBufferRef); - - - /* Stuff that's in rustllvm/ because it's not upstream yet. */ - - /// Opens an object file. - pub fn LLVMCreateObjectFile(MemBuf: MemoryBufferRef) -> ObjectFileRef; - /// Closes an object file. - pub fn LLVMDisposeObjectFile(ObjFile: ObjectFileRef); - - /// Enumerates the sections in an object file. - pub fn LLVMGetSections(ObjFile: ObjectFileRef) -> SectionIteratorRef; - /// Destroys a section iterator. - pub fn LLVMDisposeSectionIterator(SI: SectionIteratorRef); - /// Returns true if the section iterator is at the end of the section - /// list: - pub fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef, - SI: SectionIteratorRef) - -> Bool; - /// Moves the section iterator to point to the next section. - pub fn LLVMMoveToNextSection(SI: SectionIteratorRef); - /// Returns the current section size. - pub fn LLVMGetSectionSize(SI: SectionIteratorRef) -> c_ulonglong; - /// Returns the current section contents as a string buffer. - pub fn LLVMGetSectionContents(SI: SectionIteratorRef) -> *const c_char; - - /// Reads the given file and returns it as a memory buffer. Use - /// LLVMDisposeMemoryBuffer() to get rid of it. - pub fn LLVMRustCreateMemoryBufferWithContentsOfFile(Path: *const c_char) - -> MemoryBufferRef; - /// Borrows the contents of the memory buffer (doesn't copy it) - pub fn LLVMCreateMemoryBufferWithMemoryRange(InputData: *const c_char, - InputDataLength: size_t, - BufferName: *const c_char, - RequiresNull: Bool) - -> MemoryBufferRef; - pub fn LLVMCreateMemoryBufferWithMemoryRangeCopy(InputData: *const c_char, - InputDataLength: size_t, - BufferName: *const c_char) - -> MemoryBufferRef; - - pub fn LLVMIsMultithreaded() -> Bool; - pub fn LLVMStartMultithreaded() -> Bool; - - /// Returns a string describing the last error caused by an LLVMRust* call. - pub fn LLVMRustGetLastError() -> *const c_char; - - /// Print the pass timings since static dtors aren't picking them up. - pub fn LLVMRustPrintPassTimings(); - - pub fn LLVMStructCreateNamed(C: ContextRef, Name: *const c_char) -> TypeRef; - - pub fn LLVMStructSetBody(StructTy: TypeRef, - ElementTypes: *const TypeRef, - ElementCount: c_uint, - Packed: Bool); - - pub fn LLVMConstNamedStruct(S: TypeRef, - ConstantVals: *const ValueRef, - Count: c_uint) - -> ValueRef; - - /// Enables LLVM debug output. - pub fn LLVMSetDebug(Enabled: c_int); - - /// Prepares inline assembly. - pub fn LLVMInlineAsm(Ty: TypeRef, - AsmString: *const c_char, - Constraints: *const c_char, - SideEffects: Bool, - AlignStack: Bool, - Dialect: c_uint) - -> ValueRef; - - pub fn LLVMRustDebugMetadataVersion() -> u32; - pub fn LLVMVersionMajor() -> u32; - pub fn LLVMVersionMinor() -> u32; - - pub fn LLVMRustAddModuleFlag(M: ModuleRef, - name: *const c_char, - value: u32); - - pub fn LLVMDIBuilderCreate(M: ModuleRef) -> DIBuilderRef; - - pub fn LLVMDIBuilderDispose(Builder: DIBuilderRef); - - pub fn LLVMDIBuilderFinalize(Builder: DIBuilderRef); - - pub fn LLVMDIBuilderCreateCompileUnit(Builder: DIBuilderRef, - Lang: c_uint, - File: *const c_char, - Dir: *const c_char, - Producer: *const c_char, - isOptimized: bool, - Flags: *const c_char, - RuntimeVer: c_uint, - SplitName: *const c_char) - -> DIDescriptor; - - pub fn LLVMDIBuilderCreateFile(Builder: DIBuilderRef, - Filename: *const c_char, - Directory: *const c_char) - -> DIFile; - - pub fn LLVMDIBuilderCreateSubroutineType(Builder: DIBuilderRef, - File: DIFile, - ParameterTypes: DIArray) - -> DICompositeType; - - pub fn LLVMDIBuilderCreateFunction(Builder: DIBuilderRef, - Scope: DIDescriptor, - Name: *const c_char, - LinkageName: *const c_char, - File: DIFile, - LineNo: c_uint, - Ty: DIType, - isLocalToUnit: bool, - isDefinition: bool, - ScopeLine: c_uint, - Flags: c_uint, - isOptimized: bool, - Fn: ValueRef, - TParam: DIArray, - Decl: DIDescriptor) - -> DISubprogram; - - pub fn LLVMDIBuilderCreateBasicType(Builder: DIBuilderRef, - Name: *const c_char, - SizeInBits: c_ulonglong, - AlignInBits: c_ulonglong, - Encoding: c_uint) - -> DIBasicType; - - pub fn LLVMDIBuilderCreatePointerType(Builder: DIBuilderRef, - PointeeTy: DIType, - SizeInBits: c_ulonglong, - AlignInBits: c_ulonglong, - Name: *const c_char) - -> DIDerivedType; - - pub fn LLVMDIBuilderCreateStructType(Builder: DIBuilderRef, - Scope: DIDescriptor, - Name: *const c_char, - File: DIFile, - LineNumber: c_uint, - SizeInBits: c_ulonglong, - AlignInBits: c_ulonglong, - Flags: c_uint, - DerivedFrom: DIType, - Elements: DIArray, - RunTimeLang: c_uint, - VTableHolder: DIType, - UniqueId: *const c_char) - -> DICompositeType; - - pub fn LLVMDIBuilderCreateMemberType(Builder: DIBuilderRef, - Scope: DIDescriptor, - Name: *const c_char, - File: DIFile, - LineNo: c_uint, - SizeInBits: c_ulonglong, - AlignInBits: c_ulonglong, - OffsetInBits: c_ulonglong, - Flags: c_uint, - Ty: DIType) - -> DIDerivedType; - - pub fn LLVMDIBuilderCreateLexicalBlock(Builder: DIBuilderRef, - Scope: DIScope, - File: DIFile, - Line: c_uint, - Col: c_uint) - -> DILexicalBlock; - - pub fn LLVMDIBuilderCreateStaticVariable(Builder: DIBuilderRef, - Context: DIScope, - Name: *const c_char, - LinkageName: *const c_char, - File: DIFile, - LineNo: c_uint, - Ty: DIType, - isLocalToUnit: bool, - Val: ValueRef, - Decl: DIDescriptor) - -> DIGlobalVariable; - - pub fn LLVMDIBuilderCreateVariable(Builder: DIBuilderRef, - Tag: c_uint, - Scope: DIDescriptor, - Name: *const c_char, - File: DIFile, - LineNo: c_uint, - Ty: DIType, - AlwaysPreserve: bool, - Flags: c_uint, - AddrOps: *const i64, - AddrOpsCount: c_uint, - ArgNo: c_uint) - -> DIVariable; - - pub fn LLVMDIBuilderCreateArrayType(Builder: DIBuilderRef, - Size: c_ulonglong, - AlignInBits: c_ulonglong, - Ty: DIType, - Subscripts: DIArray) - -> DIType; - - pub fn LLVMDIBuilderCreateVectorType(Builder: DIBuilderRef, - Size: c_ulonglong, - AlignInBits: c_ulonglong, - Ty: DIType, - Subscripts: DIArray) - -> DIType; - - pub fn LLVMDIBuilderGetOrCreateSubrange(Builder: DIBuilderRef, - Lo: c_longlong, - Count: c_longlong) - -> DISubrange; - - pub fn LLVMDIBuilderGetOrCreateArray(Builder: DIBuilderRef, - Ptr: *const DIDescriptor, - Count: c_uint) - -> DIArray; - - pub fn LLVMDIBuilderInsertDeclareAtEnd(Builder: DIBuilderRef, - Val: ValueRef, - VarInfo: DIVariable, - AddrOps: *const i64, - AddrOpsCount: c_uint, - DL: ValueRef, - InsertAtEnd: BasicBlockRef) - -> ValueRef; - - pub fn LLVMDIBuilderInsertDeclareBefore(Builder: DIBuilderRef, - Val: ValueRef, - VarInfo: DIVariable, - AddrOps: *const i64, - AddrOpsCount: c_uint, - DL: ValueRef, - InsertBefore: ValueRef) - -> ValueRef; - - pub fn LLVMDIBuilderCreateEnumerator(Builder: DIBuilderRef, - Name: *const c_char, - Val: c_ulonglong) - -> DIEnumerator; - - pub fn LLVMDIBuilderCreateEnumerationType(Builder: DIBuilderRef, - Scope: DIScope, - Name: *const c_char, - File: DIFile, - LineNumber: c_uint, - SizeInBits: c_ulonglong, - AlignInBits: c_ulonglong, - Elements: DIArray, - ClassType: DIType) - -> DIType; - - pub fn LLVMDIBuilderCreateUnionType(Builder: DIBuilderRef, - Scope: DIScope, - Name: *const c_char, - File: DIFile, - LineNumber: c_uint, - SizeInBits: c_ulonglong, - AlignInBits: c_ulonglong, - Flags: c_uint, - Elements: DIArray, - RunTimeLang: c_uint, - UniqueId: *const c_char) - -> DIType; - - pub fn LLVMSetUnnamedAddr(GlobalVar: ValueRef, UnnamedAddr: Bool); - - pub fn LLVMDIBuilderCreateTemplateTypeParameter(Builder: DIBuilderRef, - Scope: DIScope, - Name: *const c_char, - Ty: DIType, - File: DIFile, - LineNo: c_uint, - ColumnNo: c_uint) - -> DITemplateTypeParameter; - - pub fn LLVMDIBuilderCreateOpDeref() -> i64; - - pub fn LLVMDIBuilderCreateOpPlus() -> i64; - - pub fn LLVMDIBuilderCreateNameSpace(Builder: DIBuilderRef, - Scope: DIScope, - Name: *const c_char, - File: DIFile, - LineNo: c_uint) - -> DINameSpace; - - pub fn LLVMDIBuilderCreateDebugLocation(Context: ContextRef, - Line: c_uint, - Column: c_uint, - Scope: DIScope, - InlinedAt: MetadataRef) - -> ValueRef; - - pub fn LLVMDICompositeTypeSetTypeArray(Builder: DIBuilderRef, - CompositeType: DIType, - TypeArray: DIArray); - pub fn LLVMWriteTypeToString(Type: TypeRef, s: RustStringRef); - pub fn LLVMWriteValueToString(value_ref: ValueRef, s: RustStringRef); - - pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef; - - pub fn LLVMIsAAllocaInst(value_ref: ValueRef) -> ValueRef; - pub fn LLVMIsAConstantInt(value_ref: ValueRef) -> ValueRef; - - pub fn LLVMRustPassKind(Pass: PassRef) -> SupportedPassKind; - pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> PassRef; - pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: PassRef); - - pub fn LLVMRustHasFeature(T: TargetMachineRef, - s: *const c_char) -> bool; - - pub fn LLVMRustPrintTargetCPUs(T: TargetMachineRef); - pub fn LLVMRustPrintTargetFeatures(T: TargetMachineRef); - - pub fn LLVMRustCreateTargetMachine(Triple: *const c_char, - CPU: *const c_char, - Features: *const c_char, - Model: CodeGenModel, - Reloc: RelocMode, - Level: CodeGenOptLevel, - UseSoftFP: bool, - PositionIndependentExecutable: bool, - FunctionSections: bool, - DataSections: bool) -> TargetMachineRef; - pub fn LLVMRustDisposeTargetMachine(T: TargetMachineRef); - pub fn LLVMRustAddAnalysisPasses(T: TargetMachineRef, - PM: PassManagerRef, - M: ModuleRef); - pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef, - M: ModuleRef, - DisableSimplifyLibCalls: bool); - pub fn LLVMRustConfigurePassManagerBuilder(PMB: PassManagerBuilderRef, - OptLevel: CodeGenOptLevel, - MergeFunctions: bool, - SLPVectorize: bool, - LoopVectorize: bool); - pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef, - DisableSimplifyLibCalls: bool); - pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef); - pub fn LLVMRustWriteOutputFile(T: TargetMachineRef, - PM: PassManagerRef, - M: ModuleRef, - Output: *const c_char, - FileType: FileType) -> bool; - pub fn LLVMRustPrintModule(PM: PassManagerRef, - M: ModuleRef, - Output: *const c_char); - pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char); - pub fn LLVMRustPrintPasses(); - pub fn LLVMRustSetNormalizedTarget(M: ModuleRef, triple: *const c_char); - pub fn LLVMRustAddAlwaysInlinePass(P: PassManagerBuilderRef, - AddLifetimes: bool); - pub fn LLVMRustLinkInExternalBitcode(M: ModuleRef, - bc: *const c_char, - len: size_t) -> bool; - pub fn LLVMRustRunRestrictionPass(M: ModuleRef, - syms: *const *const c_char, - len: size_t); - pub fn LLVMRustMarkAllFunctionsNounwind(M: ModuleRef); - - pub fn LLVMRustOpenArchive(path: *const c_char) -> ArchiveRef; - pub fn LLVMRustArchiveIteratorNew(AR: ArchiveRef) -> ArchiveIteratorRef; - pub fn LLVMRustArchiveIteratorNext(AIR: ArchiveIteratorRef) -> ArchiveChildRef; - pub fn LLVMRustArchiveChildName(ACR: ArchiveChildRef, - size: *mut size_t) -> *const c_char; - pub fn LLVMRustArchiveChildData(ACR: ArchiveChildRef, - size: *mut size_t) -> *const c_char; - pub fn LLVMRustArchiveChildFree(ACR: ArchiveChildRef); - pub fn LLVMRustArchiveIteratorFree(AIR: ArchiveIteratorRef); - pub fn LLVMRustDestroyArchive(AR: ArchiveRef); - - pub fn LLVMRustSetDLLStorageClass(V: ValueRef, - C: DLLStorageClassTypes); - - pub fn LLVMRustGetSectionName(SI: SectionIteratorRef, - data: *mut *const c_char) -> c_int; - - pub fn LLVMWriteTwineToString(T: TwineRef, s: RustStringRef); - - pub fn LLVMContextSetDiagnosticHandler(C: ContextRef, - Handler: DiagnosticHandler, - DiagnosticContext: *mut c_void); - - pub fn LLVMUnpackOptimizationDiagnostic(DI: DiagnosticInfoRef, - pass_name_out: *mut *const c_char, - function_out: *mut ValueRef, - debugloc_out: *mut DebugLocRef, - message_out: *mut TwineRef); - pub fn LLVMUnpackInlineAsmDiagnostic(DI: DiagnosticInfoRef, - cookie_out: *mut c_uint, - message_out: *mut TwineRef, - instruction_out: *mut ValueRef); - - pub fn LLVMWriteDiagnosticInfoToString(DI: DiagnosticInfoRef, s: RustStringRef); - pub fn LLVMGetDiagInfoSeverity(DI: DiagnosticInfoRef) -> DiagnosticSeverity; - pub fn LLVMGetDiagInfoKind(DI: DiagnosticInfoRef) -> DiagnosticKind; - - pub fn LLVMWriteDebugLocToString(C: ContextRef, DL: DebugLocRef, s: RustStringRef); - - pub fn LLVMSetInlineAsmDiagnosticHandler(C: ContextRef, - H: InlineAsmDiagHandler, - CX: *mut c_void); - - pub fn LLVMWriteSMDiagnosticToString(d: SMDiagnosticRef, s: RustStringRef); - - pub fn LLVMRustWriteArchive(Dst: *const c_char, - NumMembers: size_t, - Members: *const RustArchiveMemberRef, - WriteSymbtab: bool, - Kind: ArchiveKind) -> c_int; - pub fn LLVMRustArchiveMemberNew(Filename: *const c_char, - Name: *const c_char, - Child: ArchiveChildRef) -> RustArchiveMemberRef; - pub fn LLVMRustArchiveMemberFree(Member: RustArchiveMemberRef); - - pub fn LLVMRustSetDataLayoutFromTargetMachine(M: ModuleRef, - TM: TargetMachineRef); - pub fn LLVMRustGetModuleDataLayout(M: ModuleRef) -> TargetDataRef; - - pub fn LLVMRustBuildOperandBundleDef(Name: *const c_char, - Inputs: *const ValueRef, - NumInputs: c_uint) - -> OperandBundleDefRef; - pub fn LLVMRustFreeOperandBundleDef(Bundle: OperandBundleDefRef); - - pub fn LLVMRustPositionBuilderAtStart(B: BuilderRef, BB: BasicBlockRef); - - pub fn LLVMRustSetComdat(M: ModuleRef, V: ValueRef, Name: *const c_char); - pub fn LLVMRustUnsetComdat(V: ValueRef); -} - -// LLVM requires symbols from this library, but apparently they're not printed -// during llvm-config? -#[cfg(windows)] -#[link(name = "ole32")] -extern {} - pub fn SetInstructionCallConv(instr: ValueRef, cc: CallConv) { unsafe { LLVMSetInstructionCallConv(instr, cc as c_uint); @@ -2176,11 +200,6 @@ pub fn SetFunctionCallConv(fn_: ValueRef, cc: CallConv) { LLVMSetFunctionCallConv(fn_, cc as c_uint); } } -pub fn SetLinkage(global: ValueRef, link: Linkage) { - unsafe { - LLVMSetLinkage(global, link as c_uint); - } -} // Externally visible symbols that might appear in multiple translation units need to appear in // their own comdat section so that the duplicates can be discarded at link time. This can for @@ -2200,12 +219,6 @@ pub fn UnsetComdat(val: ValueRef) { } } -pub fn SetDLLStorageClass(global: ValueRef, class: DLLStorageClassTypes) { - unsafe { - LLVMRustSetDLLStorageClass(global, class); - } -} - pub fn SetUnnamedAddr(global: ValueRef, unnamed: bool) { unsafe { LLVMSetUnnamedAddr(global, unnamed as Bool); @@ -2218,29 +231,40 @@ pub fn set_thread_local(global: ValueRef, is_thread_local: bool) { } } -pub fn ConstICmp(pred: IntPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef { - unsafe { - LLVMConstICmp(pred as c_ushort, v1, v2) +impl Attribute { + pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { + unsafe { + LLVMRustAddFunctionAttribute( + llfn, idx.as_uint(), self.bits()) + } } -} -pub fn ConstFCmp(pred: RealPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef { - unsafe { - LLVMConstFCmp(pred as c_ushort, v1, v2) - } -} -pub fn SetFunctionAttribute(fn_: ValueRef, attr: Attribute) { - unsafe { - LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint, - attr.bits() as uint64_t) + pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { + unsafe { + LLVMRustAddCallSiteAttribute( + callsite, idx.as_uint(), self.bits()) + } } -} -pub fn RemoveFunctionAttributes(fn_: ValueRef, attr: Attribute) { - unsafe { - LLVMRemoveFunctionAttributes(fn_, FunctionIndex as c_uint, - attr.bits() as uint64_t) + pub fn unapply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { + unsafe { + LLVMRustRemoveFunctionAttributes( + llfn, idx.as_uint(), self.bits()) + } } + + pub fn toggle_llfn(&self, + idx: AttributePlace, + llfn: ValueRef, + set: bool) + { + if set { + self.apply_llfn(idx, llfn); + } else { + self.unapply_llfn(idx, llfn); + } + } + } /* Memory-managed interface to target data. */ @@ -2337,22 +361,6 @@ pub fn get_params(llfn: ValueRef) -> Vec { } } -#[allow(missing_copy_implementations)] -pub enum RustString_opaque {} -pub type RustStringRef = *mut RustString_opaque; -type RustStringRepr = *mut RefCell>; - -/// Appending to a Rust string -- used by raw_rust_string_ostream. -#[no_mangle] -pub unsafe extern "C" fn rust_llvm_string_write_impl(sr: RustStringRef, - ptr: *const c_char, - size: size_t) { - let slice = slice::from_raw_parts(ptr as *const u8, size as usize); - - let sr = sr as RustStringRepr; - (*sr).borrow_mut().extend_from_slice(slice); -} - pub fn build_string(f: F) -> Option where F: FnOnce(RustStringRef){ let mut buf = RefCell::new(Vec::new()); f(&mut buf as RustStringRepr as RustStringRef); @@ -2360,12 +368,12 @@ pub fn build_string(f: F) -> Option where F: FnOnce(RustStringRef){ } pub unsafe fn twine_to_string(tr: TwineRef) -> String { - build_string(|s| LLVMWriteTwineToString(tr, s)) + build_string(|s| LLVMRustWriteTwineToString(tr, s)) .expect("got a non-UTF8 Twine from LLVM") } pub unsafe fn debug_loc_to_string(c: ContextRef, tr: DebugLocRef) -> String { - build_string(|s| LLVMWriteDebugLocToString(c, tr, s)) + build_string(|s| LLVMRustWriteDebugLocToString(c, tr, s)) .expect("got a non-UTF8 DebugLoc from LLVM") } diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 2e8c5a7c2341..c39ad414492e 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -18,7 +18,7 @@ use rustc::session::Session; use rustc::hir; use rustc::hir::fold; use rustc::hir::fold::Folder; -use rustc::hir::intravisit::{IdRange, IdRangeComputingVisitor, IdVisitingOperation}; +use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange}; use common as c; use cstore; @@ -88,8 +88,9 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext, rbml_w.writer.seek(SeekFrom::Current(0))); // Folding could be avoided with a smarter encoder. - let ii = simplify_ast(ii); + let (ii, expected_id_range) = simplify_ast(ii); let id_range = inlined_item_id_range(&ii); + assert_eq!(expected_id_range, id_range); rbml_w.start_tag(c::tag_ast as usize); id_range.encode(rbml_w); @@ -186,6 +187,10 @@ impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> { pub fn tr_id(&self, id: ast::NodeId) -> ast::NodeId { // from_id_range should be non-empty assert!(!self.from_id_range.empty()); + // Make sure that translating the NodeId will actually yield a + // meaningful result + assert!(self.from_id_range.contains(id)); + // Use wrapping arithmetic because otherwise it introduces control flow. // Maybe we should just have the control flow? -- aatch (id.wrapping_sub(self.from_id_range.min).wrapping_add(self.to_id_range.min)) @@ -279,9 +284,23 @@ fn encode_ast(rbml_w: &mut Encoder, item: &InlinedItem) { rbml_w.end_tag(); } -struct NestedItemsDropper; +struct NestedItemsDropper { + id_range: IdRange +} impl Folder for NestedItemsDropper { + + // The unit tests below run on HIR with NodeIds not properly assigned. That + // causes an integer overflow. So we just don't track the id_range when + // building the unit tests. + #[cfg(not(test))] + fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId { + // Record the range of NodeIds we are visiting, so we can do a sanity + // check later + self.id_range.add(id); + id + } + fn fold_block(&mut self, blk: P) -> P { blk.and_then(|hir::Block {id, stmts, expr, rules, span, ..}| { let stmts_sans_items = stmts.into_iter().filter_map(|stmt| { @@ -322,10 +341,12 @@ impl Folder for NestedItemsDropper { // As it happens, trans relies on the fact that we do not export // nested items, as otherwise it would get confused when translating // inlined items. -fn simplify_ast(ii: InlinedItemRef) -> InlinedItem { - let mut fld = NestedItemsDropper; +fn simplify_ast(ii: InlinedItemRef) -> (InlinedItem, IdRange) { + let mut fld = NestedItemsDropper { + id_range: IdRange::max() + }; - match ii { + let ii = match ii { // HACK we're not dropping items. InlinedItemRef::Item(i) => { InlinedItem::Item(P(fold::noop_fold_item(i.clone(), &mut fld))) @@ -339,7 +360,9 @@ fn simplify_ast(ii: InlinedItemRef) -> InlinedItem { InlinedItemRef::Foreign(i) => { InlinedItem::Foreign(P(fold::noop_fold_foreign_item(i.clone(), &mut fld))) } - } + }; + + (ii, fld.id_range) } fn decode_ast(item_doc: rbml::Doc) -> InlinedItem { @@ -361,8 +384,18 @@ impl tr for Def { match *self { Def::Fn(did) => Def::Fn(did.tr(dcx)), Def::Method(did) => Def::Method(did.tr(dcx)), - Def::SelfTy(opt_did, impl_id) => { Def::SelfTy(opt_did.map(|did| did.tr(dcx)), - impl_id.map(|id| dcx.tr_id(id))) } + Def::SelfTy(opt_did, impl_id) => { + // Since the impl_id will never lie within the reserved range of + // imported NodeIds, it does not make sense to translate it. + // The result would not make any sense within the importing crate. + // We also don't allow for impl items to be inlined (just their + // members), so even if we had a DefId here, we wouldn't be able + // to do much with it. + // So, we set the id to DUMMY_NODE_ID. That way we make it + // explicit that this is no usable NodeId. + Def::SelfTy(opt_did.map(|did| did.tr(dcx)), + impl_id.map(|_| ast::DUMMY_NODE_ID)) + } Def::Mod(did) => { Def::Mod(did.tr(dcx)) } Def::ForeignMod(did) => { Def::ForeignMod(did.tr(dcx)) } Def::Static(did, m) => { Def::Static(did.tr(dcx), m) } @@ -693,7 +726,7 @@ struct SideTableEncodingIdVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { rbml_w: &'a mut Encoder<'b>, } -impl<'a, 'b, 'c, 'tcx> IdVisitingOperation for +impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'c, 'tcx> { fn visit_id(&mut self, id: ast::NodeId) { encode_side_tables_for_id(self.ecx, self.rbml_w, id) @@ -704,7 +737,7 @@ fn encode_side_tables_for_ii(ecx: &e::EncodeContext, rbml_w: &mut Encoder, ii: &InlinedItem) { rbml_w.start_tag(c::tag_table as usize); - ii.visit_ids(&mut SideTableEncodingIdVisitor { + ii.visit(&mut SideTableEncodingIdVisitor { ecx: ecx, rbml_w: rbml_w }); @@ -1242,9 +1275,9 @@ fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem, orig_did: DefId) { } } -fn inlined_item_id_range(v: &InlinedItem) -> IdRange { +fn inlined_item_id_range(ii: &InlinedItem) -> IdRange { let mut visitor = IdRangeComputingVisitor::new(); - v.visit_ids(&mut visitor); + ii.visit(&mut visitor); visitor.result() } @@ -1361,7 +1394,7 @@ fn test_simplification() { with_testing_context(|lcx| { let hir_item = lcx.lower_item(&item); let item_in = InlinedItemRef::Item(&hir_item); - let item_out = simplify_ast(item_in); + let (item_out, _) = simplify_ast(item_in); let item_exp = InlinedItem::Item(P(lcx.lower_item("e_item!(&cx, fn new_int_alist() -> alist { return alist {eq_fn: eq_int, data: Vec::new()}; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index d4443c6d09d7..0b60fc386a7b 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -243,7 +243,7 @@ impl<'a> CrateReader<'a> { // Check for (potential) conflicts with the local crate if self.local_crate_name == crate_name && - self.sess.crate_disambiguator.get().as_str() == disambiguator { + self.sess.local_crate_disambiguator() == disambiguator { span_fatal!(self.sess, span, E0519, "the current crate is indistinguishable from one of its \ dependencies: it has the same crate-name `{}` and was \ diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 850d6c91f66e..862245b9b786 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -14,7 +14,7 @@ use decoder; use encoder; use loader; -use middle::cstore::{CrateStore, CrateSource, ChildItem, ExternCrate, FoundAst, DefLike}; +use middle::cstore::{InlinedItem, CrateStore, CrateSource, ChildItem, ExternCrate, DefLike}; use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; use rustc::hir::def; use middle::lang_items; @@ -482,12 +482,146 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } - fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> FoundAst<'tcx> + fn maybe_get_item_ast<'a>(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> Option<(&'tcx InlinedItem, ast::NodeId)> { - self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::maybe_get_item_ast(&cdata, tcx, def.index) + self.dep_graph.read(DepNode::MetaData(def_id)); + + match self.inlined_item_cache.borrow().get(&def_id) { + Some(&None) => { + return None; // Not inlinable + } + Some(&Some(ref cached_inlined_item)) => { + // Already inline + debug!("maybe_get_item_ast({}): already inline as node id {}", + tcx.item_path_str(def_id), cached_inlined_item.item_id); + return Some((tcx.map.expect_inlined_item(cached_inlined_item.inlined_root), + cached_inlined_item.item_id)); + } + None => { + // Not seen yet + } + } + + debug!("maybe_get_item_ast({}): inlining item", tcx.item_path_str(def_id)); + + let cdata = self.get_crate_data(def_id.krate); + let inlined = decoder::maybe_get_item_ast(&cdata, tcx, def_id.index); + + let cache_inlined_item = |original_def_id, inlined_item_id, inlined_root_node_id| { + let cache_entry = cstore::CachedInlinedItem { + inlined_root: inlined_root_node_id, + item_id: inlined_item_id, + }; + self.inlined_item_cache + .borrow_mut() + .insert(original_def_id, Some(cache_entry)); + self.defid_for_inlined_node + .borrow_mut() + .insert(inlined_item_id, original_def_id); + }; + + let find_inlined_item_root = |inlined_item_id| { + let mut node = inlined_item_id; + let mut path = Vec::with_capacity(10); + + // If we can't find the inline root after a thousand hops, we can + // be pretty sure there's something wrong with the HIR map. + for _ in 0 .. 1000 { + path.push(node); + let parent_node = tcx.map.get_parent_node(node); + if parent_node == node { + return node; + } + node = parent_node; + } + bug!("cycle in HIR map parent chain") + }; + + match inlined { + decoder::FoundAst::NotFound => { + self.inlined_item_cache + .borrow_mut() + .insert(def_id, None); + } + decoder::FoundAst::Found(&InlinedItem::Item(ref item)) => { + let inlined_root_node_id = find_inlined_item_root(item.id); + cache_inlined_item(def_id, item.id, inlined_root_node_id); + } + decoder::FoundAst::Found(&InlinedItem::Foreign(ref item)) => { + let inlined_root_node_id = find_inlined_item_root(item.id); + cache_inlined_item(def_id, item.id, inlined_root_node_id); + } + decoder::FoundAst::FoundParent(parent_did, item) => { + let inlined_root_node_id = find_inlined_item_root(item.id); + cache_inlined_item(parent_did, item.id, inlined_root_node_id); + + match item.node { + hir::ItemEnum(ref ast_def, _) => { + let ast_vs = &ast_def.variants; + let ty_vs = &tcx.lookup_adt_def(parent_did).variants; + assert_eq!(ast_vs.len(), ty_vs.len()); + for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) { + cache_inlined_item(ty_v.did, + ast_v.node.data.id(), + inlined_root_node_id); + } + } + hir::ItemStruct(ref struct_def, _) => { + if struct_def.is_struct() { + bug!("instantiate_inline: called on a non-tuple struct") + } else { + cache_inlined_item(def_id, + struct_def.id(), + inlined_root_node_id); + } + } + _ => bug!("instantiate_inline: item has a \ + non-enum, non-struct parent") + } + } + decoder::FoundAst::Found(&InlinedItem::TraitItem(_, ref trait_item)) => { + let inlined_root_node_id = find_inlined_item_root(trait_item.id); + cache_inlined_item(def_id, trait_item.id, inlined_root_node_id); + + // Associated consts already have to be evaluated in `typeck`, so + // the logic to do that already exists in `middle`. In order to + // reuse that code, it needs to be able to look up the traits for + // inlined items. + let ty_trait_item = tcx.impl_or_trait_item(def_id).clone(); + let trait_item_def_id = tcx.map.local_def_id(trait_item.id); + tcx.impl_or_trait_items.borrow_mut() + .insert(trait_item_def_id, ty_trait_item); + } + decoder::FoundAst::Found(&InlinedItem::ImplItem(_, ref impl_item)) => { + let inlined_root_node_id = find_inlined_item_root(impl_item.id); + cache_inlined_item(def_id, impl_item.id, inlined_root_node_id); + } + } + + // We can be sure to hit the cache now + return self.maybe_get_item_ast(tcx, def_id); + } + + fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option { + assert!(!def_id.is_local()); + match self.inlined_item_cache.borrow().get(&def_id) { + Some(&Some(ref cached_inlined_item)) => { + Some(cached_inlined_item.item_id) + } + Some(&None) => { + None + } + _ => { + bug!("Trying to lookup inlined NodeId for unexpected item"); + } + } + } + + fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option { + self.defid_for_inlined_node.borrow().get(&node_id).map(|x| *x) } fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) @@ -634,3 +768,4 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { visible_parent_map } } + diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 6baa0ac23f3f..d786cc5ba0eb 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -25,7 +25,7 @@ use rustc::dep_graph::DepGraph; use rustc::hir::def_id::{DefIndex, DefId}; use rustc::hir::map::DefKey; use rustc::hir::svh::Svh; -use rustc::middle::cstore::{ExternCrate}; +use rustc::middle::cstore::ExternCrate; use rustc::session::config::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; @@ -96,6 +96,13 @@ pub struct CrateMetadata { pub explicitly_linked: Cell, } +pub struct CachedInlinedItem { + /// The NodeId of the RootInlinedParent HIR map entry + pub inlined_root: ast::NodeId, + /// The local NodeId of the inlined entity + pub item_id: ast::NodeId, +} + pub struct CStore { pub dep_graph: DepGraph, metas: RefCell>>, @@ -105,6 +112,8 @@ pub struct CStore { used_libraries: RefCell>, used_link_args: RefCell>, statically_included_foreign_items: RefCell, + pub inlined_item_cache: RefCell>>, + pub defid_for_inlined_node: RefCell>, pub visible_parent_map: RefCell>, } @@ -119,6 +128,8 @@ impl CStore { used_link_args: RefCell::new(Vec::new()), statically_included_foreign_items: RefCell::new(NodeSet()), visible_parent_map: RefCell::new(FnvHashMap()), + inlined_item_cache: RefCell::new(FnvHashMap()), + defid_for_inlined_node: RefCell::new(FnvHashMap()), } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 409cec282bce..d8fd25d62774 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -30,7 +30,7 @@ use rustc::util::nodemap::FnvHashMap; use rustc::hir; use rustc::session::config::PanicStrategy; -use middle::cstore::{FoundAst, InlinedItem, LinkagePreference}; +use middle::cstore::{InlinedItem, LinkagePreference}; use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls}; use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex}; @@ -55,7 +55,6 @@ use rustc_serialize::Decodable; use syntax::attr; use syntax::parse::token; use syntax::ast; -use syntax::abi::Abi; use syntax::codemap; use syntax::print::pprust; use syntax::ptr::P; @@ -756,6 +755,12 @@ pub fn maybe_get_item_name(cdata: Cmd, id: DefIndex) -> Option { maybe_item_name(cdata.lookup_item(id)) } +pub enum FoundAst<'ast> { + Found(&'ast InlinedItem), + FoundParent(DefId, &'ast hir::Item), + NotFound, +} + pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) -> FoundAst<'tcx> { debug!("Looking up item: {:?}", id); @@ -1160,15 +1165,7 @@ fn get_attributes(md: rbml::Doc) -> Vec { // an attribute assert_eq!(meta_items.len(), 1); let meta_item = meta_items.into_iter().nth(0).unwrap(); - codemap::Spanned { - node: ast::Attribute_ { - id: attr::mk_attr_id(), - style: ast::AttrStyle::Outer, - value: meta_item, - is_sugared_doc: is_sugared_doc, - }, - span: syntax_pos::DUMMY_SP - } + attr::mk_doc_attr_outer(attr::mk_attr_id(), meta_item, is_sugared_doc) }).collect() }, None => vec![], @@ -1542,13 +1539,9 @@ pub fn is_extern_item<'a, 'tcx>(cdata: Cmd, let applicable = match item_family(item_doc) { ImmStatic | MutStatic => true, Fn => { - let ty::TypeScheme { generics, ty } = get_type(cdata, id, tcx); + let ty::TypeScheme { generics, .. } = get_type(cdata, id, tcx); let no_generics = generics.types.is_empty(); - match ty.sty { - ty::TyFnDef(_, _, fn_ty) | ty::TyFnPtr(fn_ty) - if fn_ty.abi != Abi::Rust => return no_generics, - _ => no_generics, - } + no_generics }, _ => false, }; diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 731425942359..732c256a1910 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -44,7 +44,7 @@ use std::rc::Rc; use std::u32; use syntax::abi::Abi; use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum}; -use syntax::attr; +use syntax::attr::{self,AttrMetaMethods,AttributeMethods}; use errors::Handler; use syntax; use syntax_pos::BytePos; @@ -1431,31 +1431,28 @@ fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) { } fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) { - match mi.node { - ast::MetaItemKind::Word(ref name) => { + if mi.is_word() { + let name = mi.name(); rbml_w.start_tag(tag_meta_item_word); - rbml_w.wr_tagged_str(tag_meta_item_name, name); + rbml_w.wr_tagged_str(tag_meta_item_name, &name); rbml_w.end_tag(); - } - ast::MetaItemKind::NameValue(ref name, ref value) => { - match value.node { - ast::LitKind::Str(ref value, _) => { - rbml_w.start_tag(tag_meta_item_name_value); - rbml_w.wr_tagged_str(tag_meta_item_name, name); - rbml_w.wr_tagged_str(tag_meta_item_value, value); - rbml_w.end_tag(); - } - _ => {/* FIXME (#623): encode other variants */ } - } - } - ast::MetaItemKind::List(ref name, ref items) => { + } else if mi.is_value_str() { + let name = mi.name(); + /* FIXME (#623): support other literal kinds */ + let value = mi.value_str().unwrap(); + rbml_w.start_tag(tag_meta_item_name_value); + rbml_w.wr_tagged_str(tag_meta_item_name, &name); + rbml_w.wr_tagged_str(tag_meta_item_value, &value); + rbml_w.end_tag(); + } else { // it must be a list + let name = mi.name(); + let items = mi.meta_item_list().unwrap(); rbml_w.start_tag(tag_meta_item_list); - rbml_w.wr_tagged_str(tag_meta_item_name, name); + rbml_w.wr_tagged_str(tag_meta_item_name, &name); for inner_item in items { encode_meta_item(rbml_w, &inner_item); } rbml_w.end_tag(); - } } } @@ -1464,7 +1461,7 @@ fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) { for attr in attrs { rbml_w.start_tag(tag_attribute); rbml_w.wr_tagged_u8(tag_attribute_is_sugared_doc, attr.node.is_sugared_doc as u8); - encode_meta_item(rbml_w, &attr.node.value); + encode_meta_item(rbml_w, attr.meta()); rbml_w.end_tag(); } rbml_w.end_tag(); @@ -1893,7 +1890,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, encode_crate_name(rbml_w, &ecx.link_meta.crate_name); encode_crate_triple(rbml_w, &ecx.tcx.sess.opts.target_triple); encode_hash(rbml_w, &ecx.link_meta.crate_hash); - encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.crate_disambiguator.get().as_str()); + encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.local_crate_disambiguator()); encode_dylib_dependency_formats(rbml_w, &ecx); encode_panic_strategy(rbml_w, &ecx); diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index 7dadf8d108a7..4be044c1df30 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -60,10 +60,10 @@ impl<'a> ext::base::MacroLoader for MacroLoader<'a> { } if let (Some(sel), Some(names)) = (import.as_mut(), names) { for attr in names { - if let ast::MetaItemKind::Word(ref name) = attr.node { - sel.insert(name.clone(), attr.span); + if attr.is_word() { + sel.insert(attr.name().clone(), attr.span()); } else { - span_err!(self.sess, attr.span, E0466, "bad macro import"); + span_err!(self.sess, attr.span(), E0466, "bad macro import"); } } } @@ -78,10 +78,10 @@ impl<'a> ext::base::MacroLoader for MacroLoader<'a> { }; for attr in names { - if let ast::MetaItemKind::Word(ref name) = attr.node { - reexport.insert(name.clone(), attr.span); + if attr.is_word() { + reexport.insert(attr.name().clone(), attr.span()); } else { - call_bad_macro_reexport(self.sess, attr.span); + call_bad_macro_reexport(self.sess, attr.span()); } } } diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index b7c5f35892b0..11d6b0779275 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -250,7 +250,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { build::construct_fn(cx, id, arguments, fn_sig.output, body) }); - intravisit::walk_fn(self, fk, decl, body, span); + intravisit::walk_fn(self, fk, decl, body, span, id); } } diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index 515620d42538..d1b88ddda0c6 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -19,6 +19,7 @@ use std::fmt::Display; use std::fs; use std::io::{self, Write}; use syntax::ast::NodeId; +use std::path::{PathBuf, Path}; const INDENT: &'static str = " "; /// Alignment for lining up comments following MIR statements @@ -66,9 +67,15 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => String::new() }; + let mut file_path = PathBuf::new(); + if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir { + let p = Path::new(file_dir); + file_path.push(p); + }; let file_name = format!("rustc.node{}{}.{}.{}.mir", node_id, promotion_id, pass_name, disambiguator); - let _ = fs::File::create(&file_name).and_then(|mut file| { + file_path.push(&file_name); + let _ = fs::File::create(&file_path).and_then(|mut file| { try!(writeln!(file, "// MIR for `{}`", node_path)); try!(writeln!(file, "// node_id = {}", node_id)); try!(writeln!(file, "// pass_name = {}", pass_name)); @@ -195,7 +202,7 @@ fn write_basic_block(tcx: TyCtxt, ALIGN, comment(tcx, data.terminator().source_info))?; - writeln!(w, "{}}}\n", INDENT) + writeln!(w, "{}}}", INDENT) } fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String { diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs new file mode 100644 index 000000000000..fccd4a607fdc --- /dev/null +++ b/src/librustc_mir/transform/deaggregator.rs @@ -0,0 +1,116 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::ty::TyCtxt; +use rustc::mir::repr::*; +use rustc::mir::transform::{MirPass, MirSource, Pass}; +use rustc_data_structures::indexed_vec::Idx; +use rustc::ty::VariantKind; + +pub struct Deaggregator; + +impl Pass for Deaggregator {} + +impl<'tcx> MirPass<'tcx> for Deaggregator { + fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + source: MirSource, mir: &mut Mir<'tcx>) { + let node_id = source.item_id(); + let node_path = tcx.item_path_str(tcx.map.local_def_id(node_id)); + debug!("running on: {:?}", node_path); + // we only run when mir_opt_level > 1 + match tcx.sess.opts.debugging_opts.mir_opt_level { + Some(0) | + Some(1) | + None => { return; }, + _ => {} + }; + + // Do not trigger on constants. Could be revised in future + if let MirSource::Fn(_) = source {} else { return; } + // In fact, we might not want to trigger in other cases. + // Ex: when we could use SROA. See issue #35259 + + let mut curr: usize = 0; + for bb in mir.basic_blocks_mut() { + let idx = match get_aggregate_statement(curr, &bb.statements) { + Some(idx) => idx, + None => continue, + }; + // do the replacement + debug!("removing statement {:?}", idx); + let src_info = bb.statements[idx].source_info; + let suffix_stmts = bb.statements.split_off(idx+1); + let orig_stmt = bb.statements.pop().unwrap(); + let StatementKind::Assign(ref lhs, ref rhs) = orig_stmt.kind; + let (agg_kind, operands) = match rhs { + &Rvalue::Aggregate(ref agg_kind, ref operands) => (agg_kind, operands), + _ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs), + }; + let (adt_def, variant, substs) = match agg_kind { + &AggregateKind::Adt(adt_def, variant, substs) => (adt_def, variant, substs), + _ => span_bug!(src_info.span, "expected struct, not {:?}", rhs), + }; + let n = bb.statements.len(); + bb.statements.reserve(n + operands.len() + suffix_stmts.len()); + for (i, op) in operands.iter().enumerate() { + let ref variant_def = adt_def.variants[variant]; + let ty = variant_def.fields[i].ty(tcx, substs); + let rhs = Rvalue::Use(op.clone()); + + // since we don't handle enums, we don't need a cast + let lhs_cast = lhs.clone(); + + // FIXME we cannot deaggregate enums issue: #35186 + + let lhs_proj = Lvalue::Projection(Box::new(LvalueProjection { + base: lhs_cast, + elem: ProjectionElem::Field(Field::new(i), ty), + })); + let new_statement = Statement { + source_info: src_info, + kind: StatementKind::Assign(lhs_proj, rhs), + }; + debug!("inserting: {:?} @ {:?}", new_statement, idx + i); + bb.statements.push(new_statement); + } + curr = bb.statements.len(); + bb.statements.extend(suffix_stmts); + } + } +} + +fn get_aggregate_statement<'a, 'tcx, 'b>(curr: usize, + statements: &Vec>) + -> Option { + for i in curr..statements.len() { + let ref statement = statements[i]; + let StatementKind::Assign(_, ref rhs) = statement.kind; + let (kind, operands) = match rhs { + &Rvalue::Aggregate(ref kind, ref operands) => (kind, operands), + _ => continue, + }; + let (adt_def, variant) = match kind { + &AggregateKind::Adt(adt_def, variant, _) => (adt_def, variant), + _ => continue, + }; + if operands.len() == 0 || adt_def.variants.len() > 1 { + // don't deaggregate () + // don't deaggregate enums ... for now + continue; + } + debug!("getting variant {:?}", variant); + debug!("for adt_def {:?}", adt_def); + let variant_def = &adt_def.variants[variant]; + if variant_def.kind == VariantKind::Struct { + return Some(i); + } + }; + None +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 7b707b4adb69..c3485b8256da 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -17,3 +17,4 @@ pub mod add_call_guards; pub mod promote_consts; pub mod qualify_consts; pub mod dump_mir; +pub mod deaggregator; diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index a90b563515ea..d2cf48eddeba 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -55,6 +55,17 @@ impl<'a> AstValidator<'a> { err.emit(); } } + + fn check_decl_no_pat(&self, decl: &FnDecl, report_err: ReportFn) { + for arg in &decl.inputs { + match arg.pat.node { + PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), _, None) | + PatKind::Wild => {} + PatKind::Ident(..) => report_err(arg.pat.span, true), + _ => report_err(arg.pat.span, false), + } + } + } } impl<'a> Visitor for AstValidator<'a> { @@ -82,6 +93,23 @@ impl<'a> Visitor for AstValidator<'a> { visit::walk_expr(self, expr) } + fn visit_ty(&mut self, ty: &Ty) { + match ty.node { + TyKind::BareFn(ref bfty) => { + self.check_decl_no_pat(&bfty.decl, |span, _| { + let mut err = struct_span_err!(self.session, span, E0561, + "patterns aren't allowed in function pointer types"); + err.span_note(span, "this is a recent error, see \ + issue #35203 for more details"); + err.emit(); + }); + } + _ => {} + } + + visit::walk_ty(self, ty) + } + fn visit_path(&mut self, path: &Path, id: NodeId) { if path.global && path.segments.len() > 0 { let ident = path.segments[0].identifier; @@ -135,6 +163,25 @@ impl<'a> Visitor for AstValidator<'a> { visit::walk_item(self, item) } + fn visit_foreign_item(&mut self, fi: &ForeignItem) { + match fi.node { + ForeignItemKind::Fn(ref decl, _) => { + self.check_decl_no_pat(decl, |span, is_recent| { + let mut err = struct_span_err!(self.session, span, E0130, + "patterns aren't allowed in foreign function declarations"); + if is_recent { + err.span_note(span, "this is a recent error, see \ + issue #35203 for more details"); + } + err.emit(); + }); + } + ForeignItemKind::Static(..) => {} + } + + visit::walk_foreign_item(self, fi) + } + fn visit_variant_data(&mut self, vdata: &VariantData, _: Ident, _: &Generics, _: NodeId, span: Span) { if vdata.fields().is_empty() { diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 27ce03b2d939..1030a4b0116d 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -40,6 +40,7 @@ use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::ty::{self, Ty, TyCtxt}; use rustc::traits::ProjectionMode; +use rustc::util::common::ErrorReported; use rustc::util::nodemap::NodeMap; use rustc::middle::const_qualif::ConstQualif; use rustc::lint::builtin::CONST_ERR; @@ -116,7 +117,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { _ => self.tcx.sess.add_lint(CONST_ERR, expr.id, expr.span, format!("constant evaluation error: {}. This will \ become a HARD ERROR in the future", - err.description())), + err.description().into_oneline())), } } self.with_mode(mode, |this| { @@ -157,7 +158,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { let qualif = self.with_mode(mode, |this| { this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b)); - intravisit::walk_fn(this, fk, fd, b, s); + intravisit::walk_fn(this, fk, fd, b, s, fn_id); this.qualif }); @@ -211,15 +212,6 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { } } } - - fn msg(&self) -> &'static str { - match self.mode { - Mode::Const => "constant", - Mode::ConstFn => "constant function", - Mode::StaticMut | Mode::Static => "static", - Mode::Var => bug!(), - } - } } impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { @@ -289,18 +281,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { self.global_expr(Mode::Const, &start); self.global_expr(Mode::Const, &end); - match compare_lit_exprs(self.tcx, start, end) { - Some(Ordering::Less) | - Some(Ordering::Equal) => {} - Some(Ordering::Greater) => { + match compare_lit_exprs(self.tcx, p.span, start, end) { + Ok(Ordering::Less) | + Ok(Ordering::Equal) => {} + Ok(Ordering::Greater) => { span_err!(self.tcx.sess, start.span, E0030, "lower range bound must be less than or equal to upper"); } - None => { - span_err!(self.tcx.sess, p.span, E0014, - "paths in {}s may only refer to constants", - self.msg()); - } + Err(ErrorReported) => {} } } _ => intravisit::walk_pat(self, p) @@ -429,7 +417,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { Err(msg) => { self.tcx.sess.add_lint(CONST_ERR, ex.id, msg.span, - msg.description().into_owned()) + msg.description().into_oneline().into_owned()) } } } diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 918e17d21ea9..3e2dd477bccf 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -11,7 +11,7 @@ #![allow(non_snake_case)] register_long_diagnostics! { - +/* E0014: r##" Constants can only be initialized by a constant value or, in a future version of Rust, a call to a const function. This error indicates the use @@ -30,7 +30,7 @@ const FOO: i32 = { const X : i32 = 0; X }; const FOO2: i32 = { 0 }; // but brackets are useless here ``` "##, - +*/ E0030: r##" When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to @@ -49,6 +49,39 @@ match 5u32 { ``` "##, +E0130: r##" +You declared a pattern as an argument in a foreign function declaration. +Erroneous code example: + +```compile_fail +extern { + fn foo((a, b): (u32, u32)); // error: patterns aren't allowed in foreign + // function declarations +} +``` + +Please replace the pattern argument with a regular one. Example: + +``` +struct SomeStruct { + a: u32, + b: u32, +} + +extern { + fn foo(s: SomeStruct); // ok! +} +``` + +Or: + +``` +extern { + fn foo(a: (u32, u32)); // ok! +} +``` +"##, + E0161: r##" A value was moved. However, its size was not known at compile time, and only values of a known size can be moved. @@ -187,4 +220,5 @@ pub impl Foo for Bar { register_diagnostics! { E0472, // asm! is unsupported on this target + E0561, // patterns aren't allowed in function pointer types } diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs index 4684683f0250..2a5dc50cae92 100644 --- a/src/librustc_passes/rvalues.rs +++ b/src/librustc_passes/rvalues.rs @@ -49,7 +49,7 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> { let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx); euv.walk_fn(fd, b); }); - intravisit::walk_fn(self, fk, fd, b, s) + intravisit::walk_fn(self, fk, fd, b, s, fn_id) } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index acaf9b9b2fae..793e52d37920 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -291,7 +291,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { } } - intravisit::walk_mod(self, m); + intravisit::walk_mod(self, m, id); } fn visit_macro_def(&mut self, md: &'v hir::MacroDef) { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index aa8c706ea1e2..b26e3b3819ce 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -219,7 +219,13 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, name) } ResolutionError::IsNotATrait(name) => { - struct_span_err!(resolver.session, span, E0404, "`{}` is not a trait", name) + let mut err = struct_span_err!(resolver.session, + span, + E0404, + "`{}` is not a trait", + name); + err.span_label(span, &format!("not a trait")); + err } ResolutionError::UndeclaredTraitName(name, candidates) => { let mut err = struct_span_err!(resolver.session, @@ -825,8 +831,6 @@ enum NameBindingKind<'a> { Import { binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>, - // Some(error) if using this imported name causes the import to be a privacy error - privacy_error: Option>>, }, } @@ -1206,16 +1210,11 @@ impl<'a> Resolver<'a> { self.used_crates.insert(krate); } - let (directive, privacy_error) = match binding.kind { - NameBindingKind::Import { directive, ref privacy_error, .. } => - (directive, privacy_error), + let directive = match binding.kind { + NameBindingKind::Import { directive, .. } => directive, _ => return, }; - if let Some(error) = privacy_error.as_ref() { - self.privacy_errors.push((**error).clone()); - } - if !self.make_glob_map { return; } @@ -1814,39 +1813,25 @@ impl<'a> Resolver<'a> { path_depth: usize) -> Result { self.resolve_path(id, trait_path, path_depth, TypeNS).and_then(|path_res| { - if let Def::Trait(_) = path_res.base_def { - debug!("(resolving trait) found trait def: {:?}", path_res); - Ok(path_res) - } else { - let mut err = - resolve_struct_error(self, - trait_path.span, - ResolutionError::IsNotATrait(&path_names_to_string(trait_path, - path_depth))); - - // If it's a typedef, give a note - if let Def::TyAlias(..) = path_res.base_def { - let trait_name = trait_path.segments.last().unwrap().identifier.name; - err.span_label(trait_path.span, - &format!("`{}` is not a trait", trait_name)); - - let definition_site = { - let segments = &trait_path.segments; - if trait_path.global { - self.resolve_crate_relative_path(trait_path.span, segments, TypeNS) - } else { - self.resolve_module_relative_path(trait_path.span, segments, TypeNS) - }.map(|binding| binding.span).unwrap_or(syntax_pos::DUMMY_SP) - }; - - if definition_site != syntax_pos::DUMMY_SP { - err.span_label(definition_site, - &format!("type aliases cannot be used for traits")); - } + match path_res.base_def { + Def::Trait(_) => { + debug!("(resolving trait) found trait def: {:?}", path_res); + return Ok(path_res); } - err.emit(); - Err(true) + Def::Err => return Err(true), + _ => {} } + + let mut err = resolve_struct_error(self, trait_path.span, { + ResolutionError::IsNotATrait(&path_names_to_string(trait_path, path_depth)) + }); + + // If it's a typedef, give a note + if let Def::TyAlias(..) = path_res.base_def { + err.note(&format!("type aliases cannot be used for traits")); + } + err.emit(); + Err(true) }).map_err(|error_reported| { if error_reported { return } @@ -2274,7 +2259,7 @@ impl<'a> Resolver<'a> { let resolution = if let Some(resolution) = self.resolve_possibly_assoc_item(pat_id, qself, path, namespace) { if resolution.depth == 0 { - if expected_fn(resolution.base_def) { + if expected_fn(resolution.base_def) || resolution.base_def == Def::Err { resolution } else { resolve_error( @@ -2345,7 +2330,7 @@ impl<'a> Resolver<'a> { ); None } - Def::Local(..) | Def::Upvar(..) | Def::Fn(..) => { + Def::Local(..) | Def::Upvar(..) | Def::Fn(..) | Def::Err => { // These entities are explicitly allowed // to be shadowed by fresh bindings. None diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 681d9ec735b4..fc5e2a48e876 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -73,13 +73,11 @@ pub struct ImportDirective<'a> { impl<'a> ImportDirective<'a> { // Given the binding to which this directive resolves in a particular namespace, // this returns the binding for the name this directive defines in that namespace. - fn import(&'a self, binding: &'a NameBinding<'a>, privacy_error: Option>>) - -> NameBinding<'a> { + fn import(&'a self, binding: &'a NameBinding<'a>) -> NameBinding<'a> { NameBinding { kind: NameBindingKind::Import { binding: binding, directive: self, - privacy_error: privacy_error, }, span: self.span, vis: self.vis, @@ -328,7 +326,7 @@ impl<'a> ::ModuleS<'a> { fn define_in_glob_importers(&self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) { if !binding.is_importable() || !binding.is_pseudo_public() { return } for &(importer, directive) in self.glob_importers.borrow_mut().iter() { - let _ = importer.try_define_child(name, ns, directive.import(binding, None)); + let _ = importer.try_define_child(name, ns, directive.import(binding)); } } } @@ -409,7 +407,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { span: DUMMY_SP, vis: ty::Visibility::Public, }); - let dummy_binding = directive.import(dummy_binding, None); + let dummy_binding = directive.import(dummy_binding); let _ = source_module.try_define_child(target, ValueNS, dummy_binding.clone()); let _ = source_module.try_define_child(target, TypeNS, dummy_binding); @@ -494,14 +492,17 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.resolver.resolve_name_in_module(target_module, source, TypeNS, false, true); let module_ = self.resolver.current_module; + let mut privacy_error = true; for &(ns, result, determined) in &[(ValueNS, &value_result, value_determined), (TypeNS, &type_result, type_determined)] { - if determined.get() { continue } - if let Indeterminate = *result { continue } - - determined.set(true); - if let Success(binding) = *result { - if !binding.is_importable() { + match *result { + Failed(..) if !determined.get() => { + determined.set(true); + module_.update_resolution(target, ns, |resolution| { + resolution.single_imports.directive_failed() + }); + } + Success(binding) if !binding.is_importable() => { let msg = format!("`{}` is not directly importable", target); span_err!(self.resolver.session, directive.span, E0253, "{}", &msg); // Do not import this illegal binding. Import a dummy binding and pretend @@ -509,23 +510,19 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.import_dummy_binding(module_, directive); return Success(()); } - - let privacy_error = if !self.resolver.is_accessible(binding.vis) { - Some(Box::new(PrivacyError(directive.span, source, binding))) - } else { - None - }; - - let imported_binding = directive.import(binding, privacy_error); - let conflict = module_.try_define_child(target, ns, imported_binding); - if let Err(old_binding) = conflict { - let binding = &directive.import(binding, None); - self.resolver.report_conflict(module_, target, ns, binding, old_binding); + Success(binding) if !self.resolver.is_accessible(binding.vis) => {} + Success(binding) if !determined.get() => { + determined.set(true); + let imported_binding = directive.import(binding); + let conflict = module_.try_define_child(target, ns, imported_binding); + if let Err(old_binding) = conflict { + let binding = &directive.import(binding); + self.resolver.report_conflict(module_, target, ns, binding, old_binding); + } + privacy_error = false; } - } else { - module_.update_resolution(target, ns, |resolution| { - resolution.single_imports.directive_failed(); - }); + Success(_) => privacy_error = false, + _ => {} } } @@ -556,6 +553,14 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { _ => (), } + if privacy_error { + for &(ns, result) in &[(ValueNS, &value_result), (TypeNS, &type_result)] { + let binding = match *result { Success(binding) => binding, _ => continue }; + self.resolver.privacy_errors.push(PrivacyError(directive.span, source, binding)); + let _ = module_.try_define_child(target, ns, directive.import(binding)); + } + } + match (&value_result, &type_result) { (&Success(binding), _) if !binding.pseudo_vis() .is_at_least(directive.vis, self.resolver) && @@ -592,19 +597,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { _ => {} } - // Report a privacy error here if all successful namespaces are privacy errors. - let mut privacy_error = None; - for &ns in &[ValueNS, TypeNS] { - privacy_error = match module_.resolve_name(target, ns, true) { - Success(&NameBinding { - kind: NameBindingKind::Import { ref privacy_error, .. }, .. - }) => privacy_error.as_ref().map(|error| (**error).clone()), - _ => continue, - }; - if privacy_error.is_none() { break } - } - privacy_error.map(|error| self.resolver.privacy_errors.push(error)); - // Record what this import resolves to for later uses in documentation, // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. @@ -652,7 +644,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }).collect::>(); for ((name, ns), binding) in bindings { if binding.is_importable() && binding.is_pseudo_public() { - let _ = module_.try_define_child(name, ns, directive.import(binding, None)); + let _ = module_.try_define_child(name, ns, directive.import(binding)); } } diff --git a/src/librustc_save_analysis/csv_dumper.rs b/src/librustc_save_analysis/csv_dumper.rs index e7cc534c5b55..0fd95500422f 100644 --- a/src/librustc_save_analysis/csv_dumper.rs +++ b/src/librustc_save_analysis/csv_dumper.rs @@ -427,7 +427,7 @@ fn make_values_str(pairs: &[(&'static str, &str)]) -> String { } fn span_extent_str(span: SpanData) -> String { - format!("file_name,\"{}\",file_line,{},file_col,{},byte_start,{}\ + format!("file_name,\"{}\",file_line,{},file_col,{},byte_start,{},\ file_line_end,{},file_col_end,{},byte_end,{}", span.file_name, span.line_start, span.column_start, span.byte_start, span.line_end, span.column_end, span.byte_end) diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index 08e894ffbcfd..f7fd970f37f2 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -190,7 +190,7 @@ use self::FailureHandler::*; use llvm::{ValueRef, BasicBlockRef}; use rustc_const_eval::check_match::{self, Constructor, StaticInliner}; -use rustc_const_eval::{compare_lit_exprs, eval_const_expr}; +use rustc_const_eval::{compare_lit_exprs, eval_const_expr, fatal_const_eval_err}; use rustc::hir::def::{Def, DefMap}; use rustc::hir::def_id::DefId; use middle::expr_use_visitor as euv; @@ -239,9 +239,9 @@ struct ConstantExpr<'a>(&'a hir::Expr); impl<'a> ConstantExpr<'a> { fn eq<'b, 'tcx>(self, other: ConstantExpr<'a>, tcx: TyCtxt<'b, 'tcx, 'tcx>) -> bool { - match compare_lit_exprs(tcx, self.0, other.0) { - Some(result) => result == Ordering::Equal, - None => bug!("compare_list_exprs: type mismatch"), + match compare_lit_exprs(tcx, self.0.span, self.0, other.0) { + Ok(result) => result == Ordering::Equal, + Err(_) => bug!("compare_list_exprs: type mismatch"), } } } @@ -288,7 +288,9 @@ impl<'a, 'b, 'tcx> Opt<'a, 'tcx> { let expr = consts::const_expr(ccx, &lit_expr, bcx.fcx.param_substs, None, Yes); let llval = match expr { Ok((llval, _)) => llval, - Err(err) => bcx.ccx().sess().span_fatal(lit_expr.span, &err.description()), + Err(err) => { + fatal_const_eval_err(bcx.tcx(), err.as_inner(), lit_expr.span, "pattern"); + } }; let lit_datum = immediate_rvalue(llval, lit_ty); let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx)); @@ -297,11 +299,11 @@ impl<'a, 'b, 'tcx> Opt<'a, 'tcx> { ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => { let l1 = match consts::const_expr(ccx, &l1, bcx.fcx.param_substs, None, Yes) { Ok((l1, _)) => l1, - Err(err) => bcx.ccx().sess().span_fatal(l1.span, &err.description()), + Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l1.span, "pattern"), }; let l2 = match consts::const_expr(ccx, &l2, bcx.fcx.param_substs, None, Yes) { Ok((l2, _)) => l2, - Err(err) => bcx.ccx().sess().span_fatal(l2.span, &err.description()), + Err(err) => fatal_const_eval_err(bcx.tcx(), err.as_inner(), l2.span, "pattern"), }; RangeResult(Result::new(bcx, l1), Result::new(bcx, l2)) } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 6c2a09f8060c..587c03af3abb 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -552,13 +552,13 @@ impl FnType { pub fn apply_attrs_llfn(&self, llfn: ValueRef) { let mut i = if self.ret.is_indirect() { 1 } else { 0 }; if !self.ret.is_ignore() { - self.ret.attrs.apply_llfn(i, llfn); + self.ret.attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn); } i += 1; for arg in &self.args { if !arg.is_ignore() { if arg.pad.is_some() { i += 1; } - arg.attrs.apply_llfn(i, llfn); + arg.attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn); i += 1; } } @@ -567,13 +567,13 @@ impl FnType { pub fn apply_attrs_callsite(&self, callsite: ValueRef) { let mut i = if self.ret.is_indirect() { 1 } else { 0 }; if !self.ret.is_ignore() { - self.ret.attrs.apply_callsite(i, callsite); + self.ret.attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite); } i += 1; for arg in &self.args { if !arg.is_ignore() { if arg.pad.is_some() { i += 1; } - arg.attrs.apply_callsite(i, callsite); + arg.attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite); i += 1; } } diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index e27bec683757..5514fb0f4efc 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -83,8 +83,8 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; let dialect = match ia.dialect { - AsmDialect::Att => llvm::AD_ATT, - AsmDialect::Intel => llvm::AD_Intel + AsmDialect::Att => llvm::AsmDialect::Att, + AsmDialect::Intel => llvm::AsmDialect::Intel, }; let asm = CString::new(ia.asm.as_bytes()).unwrap(); diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs new file mode 100644 index 000000000000..e0532e7476f5 --- /dev/null +++ b/src/librustc_trans/assert_module_sources.rs @@ -0,0 +1,149 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This pass is only used for UNIT TESTS related to incremental +//! compilation. It tests whether a particular `.o` file will be re-used +//! from a previous compilation or whether it must be regenerated. +//! +//! The user adds annotations to the crate of the following form: +//! +//! ``` +//! #![rustc_partition_reused(module="spike", cfg="rpass2")] +//! #![rustc_partition_translated(module="spike-x", cfg="rpass2")] +//! ``` +//! +//! The first indicates (in the cfg `rpass2`) that `spike.o` will be +//! reused, the second that `spike-x.o` will be recreated. If these +//! annotations are inaccurate, errors are reported. +//! +//! The reason that we use `cfg=...` and not `#[cfg_attr]` is so that +//! the HIR doesn't change as a result of the annotations, which might +//! perturb the reuse results. + +use rustc::ty::TyCtxt; +use syntax::ast; +use syntax::attr::AttrMetaMethods; +use syntax::parse::token::InternedString; + +use {ModuleSource, ModuleTranslation}; + +const PARTITION_REUSED: &'static str = "rustc_partition_reused"; +const PARTITION_TRANSLATED: &'static str = "rustc_partition_translated"; + +const MODULE: &'static str = "module"; +const CFG: &'static str = "cfg"; + +#[derive(Debug, PartialEq)] +enum Disposition { Reused, Translated } + +pub fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + modules: &[ModuleTranslation]) { + let _ignore = tcx.dep_graph.in_ignore(); + + if tcx.sess.opts.incremental.is_none() { + return; + } + + let ams = AssertModuleSource { tcx: tcx, modules: modules }; + for attr in &tcx.map.krate().attrs { + ams.check_attr(attr); + } +} + +struct AssertModuleSource<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + modules: &'a [ModuleTranslation], +} + +impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { + fn check_attr(&self, attr: &ast::Attribute) { + let disposition = if attr.check_name(PARTITION_REUSED) { + Disposition::Reused + } else if attr.check_name(PARTITION_TRANSLATED) { + Disposition::Translated + } else { + return; + }; + + if !self.check_config(attr) { + debug!("check_attr: config does not match, ignoring attr"); + return; + } + + let mname = self.field(attr, MODULE); + let mtrans = self.modules.iter().find(|mtrans| &mtrans.name[..] == &mname[..]); + let mtrans = match mtrans { + Some(m) => m, + None => { + debug!("module name `{}` not found amongst:", mname); + for mtrans in self.modules { + debug!("module named `{}` with disposition {:?}", + mtrans.name, + self.disposition(mtrans)); + } + + self.tcx.sess.span_err( + attr.span, + &format!("no module named `{}`", mname)); + return; + } + }; + + let mtrans_disposition = self.disposition(mtrans); + if disposition != mtrans_disposition { + self.tcx.sess.span_err( + attr.span, + &format!("expected module named `{}` to be {:?} but is {:?}", + mname, + disposition, + mtrans_disposition)); + } + } + + fn disposition(&self, mtrans: &ModuleTranslation) -> Disposition { + match mtrans.source { + ModuleSource::Preexisting(_) => Disposition::Reused, + ModuleSource::Translated(_) => Disposition::Translated, + } + } + + fn field(&self, attr: &ast::Attribute, name: &str) -> InternedString { + for item in attr.meta_item_list().unwrap_or(&[]) { + if item.check_name(name) { + if let Some(value) = item.value_str() { + return value; + } else { + self.tcx.sess.span_fatal( + item.span, + &format!("associated value expected for `{}`", name)); + } + } + } + + self.tcx.sess.span_fatal( + attr.span, + &format!("no field `{}`", name)); + } + + /// Scan for a `cfg="foo"` attribute and check whether we have a + /// cfg flag called `foo`. + fn check_config(&self, attr: &ast::Attribute) -> bool { + let config = &self.tcx.map.krate().config; + let value = self.field(attr, CFG); + debug!("check_config(config={:?}, value={:?})", config, value); + if config.iter().any(|c| c.check_name(&value[..])) { + debug!("check_config: matched"); + return true; + } + debug!("check_config: no match found"); + return false; + } + +} diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index 01e9970dc76c..62eac35e0abd 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -9,8 +9,8 @@ // except according to those terms. //! Set and unset common attributes on LLVM values. -use libc::c_uint; -use llvm::{self, ValueRef}; +use llvm::{self, Attribute, ValueRef}; +use llvm::AttributePlace::Function; pub use syntax::attr::InlineAttr; use syntax::ast; use context::CrateContext; @@ -20,14 +20,14 @@ use context::CrateContext; pub fn inline(val: ValueRef, inline: InlineAttr) { use self::InlineAttr::*; match inline { - Hint => llvm::SetFunctionAttribute(val, llvm::Attribute::InlineHint), - Always => llvm::SetFunctionAttribute(val, llvm::Attribute::AlwaysInline), - Never => llvm::SetFunctionAttribute(val, llvm::Attribute::NoInline), + Hint => Attribute::InlineHint.apply_llfn(Function, val), + Always => Attribute::AlwaysInline.apply_llfn(Function, val), + Never => Attribute::NoInline.apply_llfn(Function, val), None => { - let attr = llvm::Attribute::InlineHint | - llvm::Attribute::AlwaysInline | - llvm::Attribute::NoInline; - llvm::RemoveFunctionAttributes(val, attr) + let attr = Attribute::InlineHint | + Attribute::AlwaysInline | + Attribute::NoInline; + attr.unapply_llfn(Function, val) }, }; } @@ -35,56 +35,37 @@ pub fn inline(val: ValueRef, inline: InlineAttr) { /// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function. #[inline] pub fn emit_uwtable(val: ValueRef, emit: bool) { - if emit { - llvm::SetFunctionAttribute(val, llvm::Attribute::UWTable); - } else { - llvm::RemoveFunctionAttributes(val, llvm::Attribute::UWTable); - } + Attribute::UWTable.toggle_llfn(Function, val, emit); } /// Tell LLVM whether the function can or cannot unwind. #[inline] pub fn unwind(val: ValueRef, can_unwind: bool) { - if can_unwind { - llvm::RemoveFunctionAttributes(val, llvm::Attribute::NoUnwind); - } else { - llvm::SetFunctionAttribute(val, llvm::Attribute::NoUnwind); - } + Attribute::NoUnwind.toggle_llfn(Function, val, !can_unwind); } /// Tell LLVM whether it should optimise function for size. #[inline] #[allow(dead_code)] // possibly useful function pub fn set_optimize_for_size(val: ValueRef, optimize: bool) { - if optimize { - llvm::SetFunctionAttribute(val, llvm::Attribute::OptimizeForSize); - } else { - llvm::RemoveFunctionAttributes(val, llvm::Attribute::OptimizeForSize); - } + Attribute::OptimizeForSize.toggle_llfn(Function, val, optimize); } /// Tell LLVM if this function should be 'naked', i.e. skip the epilogue and prologue. #[inline] pub fn naked(val: ValueRef, is_naked: bool) { - if is_naked { - llvm::SetFunctionAttribute(val, llvm::Attribute::Naked); - } else { - llvm::RemoveFunctionAttributes(val, llvm::Attribute::Naked); - } + Attribute::Naked.toggle_llfn(Function, val, is_naked); } pub fn set_frame_pointer_elimination(ccx: &CrateContext, llfn: ValueRef) { // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a // parameter. if ccx.sess().must_not_eliminate_frame_pointers() { - unsafe { - let attr = "no-frame-pointer-elim\0".as_ptr() as *const _; - let val = "true\0".as_ptr() as *const _; - llvm::LLVMAddFunctionAttrStringValue(llfn, - llvm::FunctionIndex as c_uint, - attr, - val); - } + llvm::AddFunctionAttrStringValue( + llfn, + llvm::AttributePlace::Function, + "no-frame-pointer-elim\0", + "true\0") } } @@ -98,13 +79,12 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe for attr in attrs { if attr.check_name("cold") { - llvm::Attributes::default().set(llvm::Attribute::Cold) - .apply_llfn(llvm::FunctionIndex as usize, llfn) + Attribute::Cold.apply_llfn(Function, llfn); } else if attr.check_name("naked") { naked(llfn, true); } else if attr.check_name("allocator") { - llvm::Attributes::default().set(llvm::Attribute::NoAlias) - .apply_llfn(llvm::ReturnIndex as usize, llfn) + Attribute::NoAlias.apply_llfn( + llvm::AttributePlace::ReturnValue(), llfn); } else if attr.check_name("unwind") { unwind(llfn, true); } diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index 29019f3683de..e063209799f1 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -293,7 +293,7 @@ impl<'a> ArchiveBuilder<'a> { members.as_ptr(), self.should_update_symbols, kind); - let ret = if r != 0 { + let ret = if r.into_result().is_err() { let err = llvm::LLVMRustGetLastError(); let msg = if err.is_null() { "failed to write archive".to_string() diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 422e3d436b42..4e6c6013576f 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -10,18 +10,21 @@ use back::lto; use back::link::{get_linker, remove}; +use rustc_incremental::save_trans_partition; use session::config::{OutputFilenames, Passes, SomePasses, AllPasses}; use session::Session; use session::config::{self, OutputType}; use llvm; use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef}; use llvm::SMDiagnosticRef; -use {CrateTranslation, ModuleTranslation}; +use {CrateTranslation, ModuleLlvm, ModuleSource, ModuleTranslation}; use util::common::time; use util::common::path2cstr; +use util::fs::link_or_copy; use errors::{self, Handler, Level, DiagnosticBuilder}; use errors::emitter::Emitter; use syntax_pos::MultiSpan; +use context::{is_pie_binary, get_reloc_model}; use std::collections::HashMap; use std::ffi::{CStr, CString}; @@ -34,18 +37,18 @@ use std::thread; use libc::{c_uint, c_void}; pub const RELOC_MODEL_ARGS : [(&'static str, llvm::RelocMode); 4] = [ - ("pic", llvm::RelocPIC), - ("static", llvm::RelocStatic), - ("default", llvm::RelocDefault), - ("dynamic-no-pic", llvm::RelocDynamicNoPic), + ("pic", llvm::RelocMode::PIC), + ("static", llvm::RelocMode::Static), + ("default", llvm::RelocMode::Default), + ("dynamic-no-pic", llvm::RelocMode::DynamicNoPic), ]; -pub const CODE_GEN_MODEL_ARGS : [(&'static str, llvm::CodeGenModel); 5] = [ - ("default", llvm::CodeModelDefault), - ("small", llvm::CodeModelSmall), - ("kernel", llvm::CodeModelKernel), - ("medium", llvm::CodeModelMedium), - ("large", llvm::CodeModelLarge), +pub const CODE_GEN_MODEL_ARGS : [(&'static str, llvm::CodeModel); 5] = [ + ("default", llvm::CodeModel::Default), + ("small", llvm::CodeModel::Small), + ("kernel", llvm::CodeModel::Kernel), + ("medium", llvm::CodeModel::Medium), + ("large", llvm::CodeModel::Large), ]; pub fn llvm_err(handler: &errors::Handler, msg: String) -> ! { @@ -66,7 +69,7 @@ pub fn write_output_file( let output_c = path2cstr(output); let result = llvm::LLVMRustWriteOutputFile( target, pm, m, output_c.as_ptr(), file_type); - if !result { + if result.into_result().is_err() { llvm_err(handler, format!("could not write output to {}", output.display())); } } @@ -150,11 +153,11 @@ fn target_feature(sess: &Session) -> String { fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel { match optimize { - config::OptLevel::No => llvm::CodeGenLevelNone, - config::OptLevel::Less => llvm::CodeGenLevelLess, - config::OptLevel::Default => llvm::CodeGenLevelDefault, - config::OptLevel::Aggressive => llvm::CodeGenLevelAggressive, - _ => llvm::CodeGenLevelDefault, + config::OptLevel::No => llvm::CodeGenOptLevel::None, + config::OptLevel::Less => llvm::CodeGenOptLevel::Less, + config::OptLevel::Default => llvm::CodeGenOptLevel::Default, + config::OptLevel::Aggressive => llvm::CodeGenOptLevel::Aggressive, + _ => llvm::CodeGenOptLevel::Default, } } @@ -167,30 +170,11 @@ fn get_llvm_opt_size(optimize: config::OptLevel) -> llvm::CodeGenOptSize { } pub fn create_target_machine(sess: &Session) -> TargetMachineRef { - let reloc_model_arg = match sess.opts.cg.relocation_model { - Some(ref s) => &s[..], - None => &sess.target.target.options.relocation_model[..], - }; - let reloc_model = match RELOC_MODEL_ARGS.iter().find( - |&&arg| arg.0 == reloc_model_arg) { - Some(x) => x.1, - _ => { - sess.err(&format!("{:?} is not a valid relocation mode", - sess.opts - .cg - .relocation_model)); - sess.abort_if_errors(); - bug!(); - } - }; + let reloc_model = get_reloc_model(sess); let opt_level = get_llvm_opt_level(sess.opts.optimize); let use_softfp = sess.opts.cg.soft_float; - let any_library = sess.crate_types.borrow().iter().any(|ty| { - *ty != config::CrateTypeExecutable - }); - let ffunction_sections = sess.target.target.options.function_sections; let fdata_sections = ffunction_sections; @@ -228,7 +212,7 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef { reloc_model, opt_level, use_softfp, - !any_library && reloc_model == llvm::RelocPIC, + is_pie_binary(sess), ffunction_sections, fdata_sections, ) @@ -345,6 +329,8 @@ struct CodegenContext<'a> { remark: Passes, // Worker thread number worker: usize, + // Directory where incremental data is stored (if any) + incremental: Option, } impl<'a> CodegenContext<'a> { @@ -355,6 +341,7 @@ impl<'a> CodegenContext<'a> { plugin_passes: sess.plugin_llvm_passes.borrow().clone(), remark: sess.opts.cg.remark.clone(), worker: 0, + incremental: sess.opts.incremental.clone(), } } } @@ -390,7 +377,7 @@ unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef, cookie: c_uint) { let HandlerFreeVars { cgcx, .. } = *(user as *const HandlerFreeVars); - let msg = llvm::build_string(|s| llvm::LLVMWriteSMDiagnosticToString(diag, s)) + let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s)) .expect("non-UTF8 SMDiagnostic"); report_inline_asm(cgcx, &msg[..], cookie); @@ -432,10 +419,11 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo // Unsafe due to LLVM calls. unsafe fn optimize_and_codegen(cgcx: &CodegenContext, mtrans: ModuleTranslation, + mllvm: ModuleLlvm, config: ModuleConfig, output_names: OutputFilenames) { - let llmod = mtrans.llmod; - let llcx = mtrans.llcx; + let llmod = mllvm.llmod; + let llcx = mllvm.llcx; let tm = config.tm; // llcx doesn't outlive this function, so we can put this on the stack. @@ -445,7 +433,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, }; let fv = &fv as *const HandlerFreeVars as *mut c_void; - llvm::LLVMSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv); + llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv); llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, fv); let module_name = Some(&mtrans.name[..]); @@ -473,9 +461,9 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, return false; } let pass_manager = match llvm::LLVMRustPassKind(pass) { - llvm::SupportedPassKind::Function => fpm, - llvm::SupportedPassKind::Module => mpm, - llvm::SupportedPassKind::Unsupported => { + llvm::PassKind::Function => fpm, + llvm::PassKind::Module => mpm, + llvm::PassKind::Other => { cgcx.handler.err("Encountered LLVM pass kind we can't handle"); return true }, @@ -603,7 +591,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, }; with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file(cgcx.handler, tm, cpm, llmod, &path, - llvm::AssemblyFileType); + llvm::FileType::AssemblyFile); }); if config.emit_obj { llvm::LLVMDisposeModule(llmod); @@ -612,14 +600,15 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if write_obj { with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(cgcx.handler, tm, cpm, llmod, &obj_out, llvm::ObjectFileType); + write_output_file(cgcx.handler, tm, cpm, llmod, &obj_out, + llvm::FileType::ObjectFile); }); } }); if copy_bc_to_obj { debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out); - if let Err(e) = fs::copy(&bc_out, &obj_out) { + if let Err(e) = link_or_copy(&bc_out, &obj_out) { cgcx.handler.err(&format!("failed to copy bitcode to object file: {}", e)); } } @@ -638,8 +627,14 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, pub fn cleanup_llvm(trans: &CrateTranslation) { for module in trans.modules.iter() { unsafe { - llvm::LLVMDisposeModule(module.llmod); - llvm::LLVMContextDispose(module.llcx); + match module.source { + ModuleSource::Translated(llvm) => { + llvm::LLVMDisposeModule(llvm.llmod); + llvm::LLVMContextDispose(llvm.llcx); + } + ModuleSource::Preexisting(_) => { + } + } } } } @@ -753,6 +748,23 @@ pub fn run_passes(sess: &Session, run_work_multithreaded(sess, work_items, num_workers); } + // If in incr. comp. mode, preserve the `.o` files for potential re-use + for mtrans in trans.modules.iter() { + let mut files = vec![]; + + if modules_config.emit_obj { + let path = crate_output.temp_path(OutputType::Object, Some(&mtrans.name)); + files.push((OutputType::Object, path)); + } + + if modules_config.emit_bc { + let path = crate_output.temp_path(OutputType::Bitcode, Some(&mtrans.name)); + files.push((OutputType::Bitcode, path)); + } + + save_trans_partition(sess, &mtrans.name, mtrans.symbol_name_hash, &files); + } + // All codegen is finished. unsafe { llvm::LLVMRustDisposeTargetMachine(tm); @@ -926,10 +938,37 @@ fn build_work_item(sess: &Session, fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) { unsafe { - optimize_and_codegen(cgcx, - work_item.mtrans, - work_item.config, - work_item.output_names); + match work_item.mtrans.source { + ModuleSource::Translated(mllvm) => { + debug!("llvm-optimizing {:?}", work_item.mtrans.name); + optimize_and_codegen(cgcx, + work_item.mtrans, + mllvm, + work_item.config, + work_item.output_names); + } + ModuleSource::Preexisting(wp) => { + let incremental = cgcx.incremental.as_ref().unwrap(); + let name = &work_item.mtrans.name; + for (kind, saved_file) in wp.saved_files { + let obj_out = work_item.output_names.temp_path(kind, Some(name)); + let source_file = incremental.join(&saved_file); + debug!("copying pre-existing module `{}` from {:?} to {}", + work_item.mtrans.name, + source_file, + obj_out.display()); + match link_or_copy(&source_file, &obj_out) { + Ok(()) => { } + Err(err) => { + cgcx.handler.err(&format!("unable to copy {} to {}: {}", + source_file.display(), + obj_out.display(), + err)); + } + } + } + } + } } } @@ -965,6 +1004,8 @@ fn run_work_multithreaded(sess: &Session, let mut tx = Some(tx); futures.push(rx); + let incremental = sess.opts.incremental.clone(); + thread::Builder::new().name(format!("codegen-{}", i)).spawn(move || { let diag_handler = Handler::with_emitter(true, false, box diag_emitter); @@ -976,6 +1017,7 @@ fn run_work_multithreaded(sess: &Session, plugin_passes: plugin_passes, remark: remark, worker: i, + incremental: incremental, }; loop { @@ -1049,7 +1091,7 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef, // reasonable defaults and prepare it to actually populate the pass // manager. let builder = llvm::LLVMPassManagerBuilderCreate(); - let opt_level = config.opt_level.unwrap_or(llvm::CodeGenLevelNone); + let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone); let inline_threshold = config.inline_threshold; @@ -1073,7 +1115,7 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef, (_, _, Some(t)) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32); } - (llvm::CodeGenLevelAggressive, _, _) => { + (llvm::CodeGenOptLevel::Aggressive, _, _) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275); } (_, llvm::CodeGenOptSizeDefault, _) => { @@ -1082,15 +1124,18 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef, (_, llvm::CodeGenOptSizeAggressive, _) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25); } - (llvm::CodeGenLevelNone, _, _) => { + (llvm::CodeGenOptLevel::None, _, _) => { llvm::LLVMRustAddAlwaysInlinePass(builder, false); } - (llvm::CodeGenLevelLess, _, _) => { + (llvm::CodeGenOptLevel::Less, _, _) => { llvm::LLVMRustAddAlwaysInlinePass(builder, true); } - (llvm::CodeGenLevelDefault, _, _) => { + (llvm::CodeGenOptLevel::Default, _, _) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225); } + (llvm::CodeGenOptLevel::Other, _, _) => { + bug!("CodeGenOptLevel::Other selected") + } } f(builder); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index c8b9fea15ba8..1077cb296c1a 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -26,8 +26,11 @@ #![allow(non_camel_case_types)] use super::CrateTranslation; +use super::ModuleLlvm; +use super::ModuleSource; use super::ModuleTranslation; +use assert_module_sources; use back::link; use back::linker::LinkerInfo; use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; @@ -40,7 +43,7 @@ use rustc::ty::subst::{self, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::adjustment::CustomCoerceUnsized; -use rustc::dep_graph::DepNode; +use rustc::dep_graph::{DepNode, WorkProduct}; use rustc::hir::map as hir_map; use rustc::util::common::time; use rustc::mir::mir_map::MirMap; @@ -89,13 +92,14 @@ use value::Value; use Disr; use util::common::indenter; use util::sha2::Sha256; -use util::nodemap::{NodeMap, NodeSet}; +use util::nodemap::{NodeMap, NodeSet, FnvHashSet}; use arena::TypedArena; use libc::c_uint; use std::ffi::{CStr, CString}; +use std::borrow::Cow; use std::cell::{Cell, RefCell}; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::ptr; use std::rc::Rc; use std::str; @@ -1914,9 +1918,9 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) { - let instance = inline::maybe_inline_instance(ccx, instance); + let local_instance = inline::maybe_inline_instance(ccx, instance); - let fn_node_id = ccx.tcx().map.as_local_node_id(instance.def).unwrap(); + let fn_node_id = ccx.tcx().map.as_local_node_id(local_instance.def).unwrap(); let _s = StatRecorder::new(ccx, ccx.tcx().node_path_str(fn_node_id)); debug!("trans_instance(instance={:?})", instance); @@ -1932,7 +1936,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance let sig = ccx.tcx().normalize_associated_type(&sig); let abi = fn_ty.fn_abi(); - let lldecl = match ccx.instances().borrow().get(&instance) { + let lldecl = match ccx.instances().borrow().get(&local_instance) { Some(&val) => val, None => bug!("Instance `{:?}` not already declared", instance) }; @@ -2132,7 +2136,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) { let instance = Instance::mono(ccx.shared(), main_def_id); - if !ccx.codegen_unit().items.contains_key(&TransItem::Fn(instance)) { + if !ccx.codegen_unit().contains_item(&TransItem::Fn(instance)) { // We want to create the wrapper in the same codegen unit as Rust's main // function. return; @@ -2256,12 +2260,28 @@ fn write_metadata(cx: &SharedCrateContext, /// Find any symbols that are defined in one compilation unit, but not declared /// in any other compilation unit. Give these symbols internal linkage. -fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) { - unsafe { - let mut declared = HashSet::new(); +fn internalize_symbols<'a, 'tcx>(sess: &Session, + ccxs: &CrateContextList<'a, 'tcx>, + symbol_map: &SymbolMap<'tcx>, + reachable: &FnvHashSet<&str>) { + let scx = ccxs.shared(); + let tcx = scx.tcx(); - // Collect all external declarations in all compilation units. - for ccx in cx.iter() { + // In incr. comp. mode, we can't necessarily see all refs since we + // don't generate LLVM IR for reused modules, so skip this + // step. Later we should get smarter. + if sess.opts.debugging_opts.incremental.is_some() { + return; + } + + // 'unsafe' because we are holding on to CStr's from the LLVM module within + // this block. + unsafe { + let mut referenced_somewhere = FnvHashSet(); + + // Collect all symbols that need to stay externally visible because they + // are referenced via a declaration in some other codegen unit. + for ccx in ccxs.iter_need_trans() { for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { let linkage = llvm::LLVMGetLinkage(val); // We only care about external declarations (not definitions) @@ -2270,39 +2290,68 @@ fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) { let is_decl = llvm::LLVMIsDeclaration(val) != 0; if is_decl || is_available_externally { - let name = CStr::from_ptr(llvm::LLVMGetValueName(val)); - declared.insert(name); + let symbol_name = CStr::from_ptr(llvm::LLVMGetValueName(val)); + referenced_somewhere.insert(symbol_name); } } } + // Also collect all symbols for which we cannot adjust linkage, because + // it is fixed by some directive in the source code (e.g. #[no_mangle]). + let linkage_fixed_explicitly: FnvHashSet<_> = scx + .translation_items() + .borrow() + .iter() + .cloned() + .filter(|trans_item|{ + let def_id = match *trans_item { + TransItem::DropGlue(..) => { + return false + }, + TransItem::Fn(ref instance) => { + instance.def + } + TransItem::Static(node_id) => { + tcx.map.local_def_id(node_id) + } + }; + + trans_item.explicit_linkage(tcx).is_some() || + attr::contains_extern_indicator(tcx.sess.diagnostic(), + &tcx.get_attrs(def_id)) + }) + .map(|trans_item| symbol_map.get_or_compute(scx, trans_item)) + .collect(); + // Examine each external definition. If the definition is not used in // any other compilation unit, and is not reachable from other crates, // then give it internal linkage. - for ccx in cx.iter() { + for ccx in ccxs.iter_need_trans() { for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { let linkage = llvm::LLVMGetLinkage(val); let is_externally_visible = (linkage == llvm::ExternalLinkage as c_uint) || (linkage == llvm::LinkOnceODRLinkage as c_uint) || (linkage == llvm::WeakODRLinkage as c_uint); - let is_definition = llvm::LLVMIsDeclaration(val) != 0; + let is_definition = llvm::LLVMIsDeclaration(val) == 0; // If this is a definition (as opposed to just a declaration) // and externally visible, check if we can internalize it if is_definition && is_externally_visible { let name_cstr = CStr::from_ptr(llvm::LLVMGetValueName(val)); let name_str = name_cstr.to_str().unwrap(); + let name_cow = Cow::Borrowed(name_str); - let is_referenced_somewhere = declared.contains(&name_cstr); - let is_reachable = reachable.contains(name_str); + let is_referenced_somewhere = referenced_somewhere.contains(&name_cstr); + let is_reachable = reachable.contains(&name_str); + let has_fixed_linkage = linkage_fixed_explicitly.contains(&name_cow); - if !is_referenced_somewhere && !is_reachable { - llvm::SetLinkage(val, llvm::InternalLinkage); - llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass); + if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage { + llvm::LLVMSetLinkage(val, llvm::InternalLinkage); + llvm::LLVMSetDLLStorageClass(val, + llvm::DLLStorageClass::Default); llvm::UnsetComdat(val); } - } } } @@ -2325,7 +2374,7 @@ fn create_imps(cx: &CrateContextList) { "\x01__imp_" }; unsafe { - for ccx in cx.iter() { + for ccx in cx.iter_need_trans() { let exported: Vec<_> = iter_globals(ccx.llmod()) .filter(|&val| { llvm::LLVMGetLinkage(val) == @@ -2345,7 +2394,7 @@ fn create_imps(cx: &CrateContextList) { imp_name.as_ptr() as *const _); let init = llvm::LLVMConstBitCast(val, i8p_ty.to_ref()); llvm::LLVMSetInitializer(imp, init); - llvm::SetLinkage(imp, llvm::ExternalLinkage); + llvm::LLVMSetLinkage(imp, llvm::ExternalLinkage); } } } @@ -2477,8 +2526,11 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let metadata_module = ModuleTranslation { name: "metadata".to_string(), - llcx: shared_ccx.metadata_llcx(), - llmod: shared_ccx.metadata_llmod(), + symbol_name_hash: 0, // we always rebuild metadata, at least for now + source: ModuleSource::Translated(ModuleLlvm { + llcx: shared_ccx.metadata_llcx(), + llmod: shared_ccx.metadata_llmod(), + }), }; let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); @@ -2488,17 +2540,34 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let symbol_map = Rc::new(symbol_map); + let previous_work_products = trans_reuse_previous_work_products(tcx, + &codegen_units, + &symbol_map); + let crate_context_list = CrateContextList::new(&shared_ccx, codegen_units, + previous_work_products, symbol_map.clone()); - let modules = crate_context_list.iter() - .map(|ccx| ModuleTranslation { - name: String::from(&ccx.codegen_unit().name[..]), - llcx: ccx.llcx(), - llmod: ccx.llmod() + let modules: Vec<_> = crate_context_list.iter_all() + .map(|ccx| { + let source = match ccx.previous_work_product() { + Some(buf) => ModuleSource::Preexisting(buf.clone()), + None => ModuleSource::Translated(ModuleLlvm { + llcx: ccx.llcx(), + llmod: ccx.llmod(), + }), + }; + + ModuleTranslation { + name: String::from(ccx.codegen_unit().name()), + symbol_name_hash: ccx.codegen_unit().compute_symbol_name_hash(tcx, &symbol_map), + source: source, + } }) .collect(); + assert_module_sources::assert_module_sources(tcx, &modules); + // Skip crate items and just output metadata in -Z no-trans mode. if tcx.sess.opts.no_trans { let linker_info = LinkerInfo::new(&shared_ccx, &[]); @@ -2514,41 +2583,44 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // Instantiate translation items without filling out definitions yet... - for ccx in crate_context_list.iter() { - let trans_items = ccx.codegen_unit() - .items_in_deterministic_order(tcx, &symbol_map); + for ccx in crate_context_list.iter_need_trans() { + let cgu = ccx.codegen_unit(); + let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map); - for (trans_item, linkage) in trans_items { - trans_item.predefine(&ccx, linkage); - } + tcx.dep_graph.with_task(cgu.work_product_dep_node(), || { + for (trans_item, linkage) in trans_items { + trans_item.predefine(&ccx, linkage); + } + }); } // ... and now that we have everything pre-defined, fill out those definitions. - for ccx in crate_context_list.iter() { - let trans_items = ccx.codegen_unit() - .items_in_deterministic_order(tcx, &symbol_map); - - for (trans_item, _) in trans_items { - trans_item.define(&ccx); - } - - // If this codegen unit contains the main function, also create the - // wrapper here - maybe_create_entry_wrapper(&ccx); - - // Run replace-all-uses-with for statics that need it - for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() { - unsafe { - let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g)); - llvm::LLVMReplaceAllUsesWith(old_g, bitcast); - llvm::LLVMDeleteGlobal(old_g); + for ccx in crate_context_list.iter_need_trans() { + let cgu = ccx.codegen_unit(); + let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map); + tcx.dep_graph.with_task(cgu.work_product_dep_node(), || { + for (trans_item, _) in trans_items { + trans_item.define(&ccx); } - } - // Finalize debuginfo - if ccx.sess().opts.debuginfo != NoDebugInfo { - debuginfo::finalize(&ccx); - } + // If this codegen unit contains the main function, also create the + // wrapper here + maybe_create_entry_wrapper(&ccx); + + // Run replace-all-uses-with for statics that need it + for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() { + unsafe { + let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g)); + llvm::LLVMReplaceAllUsesWith(old_g, bitcast); + llvm::LLVMDeleteGlobal(old_g); + } + } + + // Finalize debuginfo + if ccx.sess().opts.debuginfo != NoDebugInfo { + debuginfo::finalize(&ccx); + } + }); } symbol_names_test::report_symbol_names(&shared_ccx); @@ -2616,8 +2688,14 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, })); } - internalize_symbols(&crate_context_list, - &reachable_symbols.iter().map(|x| &x[..]).collect()); + time(shared_ccx.sess().time_passes(), "internalize symbols", || { + internalize_symbols(sess, + &crate_context_list, + &symbol_map, + &reachable_symbols.iter() + .map(|s| &s[..]) + .collect()) + }); if sess.target.target.options.is_like_msvc && sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) { @@ -2637,6 +2715,38 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +/// For each CGU, identify if we can reuse an existing object file (or +/// maybe other context). +fn trans_reuse_previous_work_products(tcx: TyCtxt, + codegen_units: &[CodegenUnit], + symbol_map: &SymbolMap) + -> Vec> { + debug!("trans_reuse_previous_work_products()"); + codegen_units + .iter() + .map(|cgu| { + let id = cgu.work_product_id(); + + let hash = cgu.compute_symbol_name_hash(tcx, symbol_map); + + debug!("trans_reuse_previous_work_products: id={:?} hash={}", id, hash); + + if let Some(work_product) = tcx.dep_graph.previous_work_product(&id) { + if work_product.input_hash == hash { + debug!("trans_reuse_previous_work_products: reusing {:?}", work_product); + return Some(work_product); + } else { + debug!("trans_reuse_previous_work_products: \ + not reusing {:?} because hash changed to {:?}", + work_product, hash); + } + } + + None + }) + .collect() +} + fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) -> (Vec>, SymbolMap<'tcx>) { let time_passes = scx.sess().time_passes(); @@ -2697,10 +2807,10 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a let mut item_to_cgus = HashMap::new(); for cgu in &codegen_units { - for (&trans_item, &linkage) in &cgu.items { + for (&trans_item, &linkage) in cgu.items() { item_to_cgus.entry(trans_item) .or_insert(Vec::new()) - .push((cgu.name.clone(), linkage)); + .push((cgu.name().clone(), linkage)); } } diff --git a/src/librustc_trans/build.rs b/src/librustc_trans/build.rs index 4a7a5736b13a..8cd47bd148d0 100644 --- a/src/librustc_trans/build.rs +++ b/src/librustc_trans/build.rs @@ -12,7 +12,7 @@ #![allow(non_snake_case)] use llvm; -use llvm::{AtomicBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; +use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; use llvm::{Opcode, IntPredicate, RealPredicate}; use llvm::{ValueRef, BasicBlockRef}; use common::*; @@ -1117,7 +1117,7 @@ pub fn AtomicCmpXchg(cx: Block, dst: ValueRef, weak: llvm::Bool) -> ValueRef { B(cx).atomic_cmpxchg(dst, cmp, src, order, failure_order, weak) } -pub fn AtomicRMW(cx: Block, op: AtomicBinOp, +pub fn AtomicRMW(cx: Block, op: AtomicRmwBinOp, dst: ValueRef, src: ValueRef, order: AtomicOrdering) -> ValueRef { B(cx).atomic_rmw(op, dst, src, order) diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index e88257dcd4cf..90f96af54969 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -11,7 +11,7 @@ #![allow(dead_code)] // FFI wrappers use llvm; -use llvm::{AtomicBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; +use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; use llvm::{Opcode, IntPredicate, RealPredicate, False, OperandBundleDef}; use llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef}; use base; @@ -503,8 +503,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unsafe { let ty = Type::from_ref(llvm::LLVMTypeOf(ptr)); let align = llalign_of_pref(self.ccx, ty.element_type()); - llvm::LLVMBuildAtomicLoad(self.llbuilder, ptr, noname(), order, - align as c_uint) + llvm::LLVMRustBuildAtomicLoad(self.llbuilder, ptr, noname(), order, + align as c_uint) } } @@ -565,7 +565,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unsafe { let ty = Type::from_ref(llvm::LLVMTypeOf(ptr)); let align = llalign_of_pref(self.ccx, ty.element_type()); - llvm::LLVMBuildAtomicStore(self.llbuilder, val, ptr, order, align as c_uint); + llvm::LLVMRustBuildAtomicStore(self.llbuilder, val, ptr, order, align as c_uint); } } @@ -840,8 +840,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("Asm Output Type: {:?}", output); let fty = Type::func(&argtys[..], &output); unsafe { - let v = llvm::LLVMInlineAsm( - fty.to_ref(), asm, cons, volatile, alignstack, dia as c_uint); + let v = llvm::LLVMRustInlineAsm( + fty.to_ref(), asm, cons, volatile, alignstack, dia); self.call(v, inputs, None) } } @@ -1083,11 +1083,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { failure_order: AtomicOrdering, weak: llvm::Bool) -> ValueRef { unsafe { - llvm::LLVMBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src, + llvm::LLVMRustBuildAtomicCmpXchg(self.llbuilder, dst, cmp, src, order, failure_order, weak) } } - pub fn atomic_rmw(&self, op: AtomicBinOp, + pub fn atomic_rmw(&self, op: AtomicRmwBinOp, dst: ValueRef, src: ValueRef, order: AtomicOrdering) -> ValueRef { unsafe { @@ -1097,7 +1097,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn atomic_fence(&self, order: AtomicOrdering, scope: SynchronizationScope) { unsafe { - llvm::LLVMBuildAtomicFence(self.llbuilder, order, scope); + llvm::LLVMRustBuildAtomicFence(self.llbuilder, order, scope); } } } diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs index 90443d9ec4f7..e53a5edfc668 100644 --- a/src/librustc_trans/closure.rs +++ b/src/librustc_trans/closure.rs @@ -181,6 +181,41 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfn } +fn translating_closure_body_via_mir_will_fail(ccx: &CrateContext, + closure_def_id: DefId) + -> bool { + let default_to_mir = ccx.sess().opts.debugging_opts.orbit; + let invert = if default_to_mir { "rustc_no_mir" } else { "rustc_mir" }; + let use_mir = default_to_mir ^ ccx.tcx().has_attr(closure_def_id, invert); + + !use_mir +} + +pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + closure_def_id: DefId, + closure_substs: ty::ClosureSubsts<'tcx>) { + use syntax::ast::DUMMY_NODE_ID; + use syntax_pos::DUMMY_SP; + use syntax::ptr::P; + + trans_closure_expr(Dest::Ignore(ccx), + &hir::FnDecl { + inputs: P::new(), + output: hir::NoReturn(DUMMY_SP), + variadic: false + }, + &hir::Block { + stmts: P::new(), + expr: None, + id: DUMMY_NODE_ID, + rules: hir::DefaultBlock, + span: DUMMY_SP + }, + DUMMY_NODE_ID, + closure_def_id, + closure_substs); +} + pub enum Dest<'a, 'tcx: 'a> { SaveIn(Block<'a, 'tcx>, ValueRef), Ignore(&'a CrateContext<'a, 'tcx>) @@ -213,8 +248,15 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>, // If we have not done so yet, translate this closure's body if !ccx.instances().borrow().contains_key(&instance) { let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs); - llvm::SetLinkage(llfn, llvm::WeakODRLinkage); - llvm::SetUniqueComdat(ccx.llmod(), llfn); + + unsafe { + if ccx.sess().target.target.options.allows_weak_linkage { + llvm::LLVMSetLinkage(llfn, llvm::WeakODRLinkage); + llvm::SetUniqueComdat(ccx.llmod(), llfn); + } else { + llvm::LLVMSetLinkage(llfn, llvm::InternalLinkage); + } + } // set an inline hint for all closures attributes::inline(llfn, attributes::InlineAttr::Hint); @@ -296,6 +338,39 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, // If this is a closure, redirect to it. let llfn = get_or_create_closure_declaration(ccx, closure_def_id, substs); + // If weak linkage is not allowed, we have to make sure that a local, + // private copy of the closure is available in this codegen unit + if !ccx.sess().target.target.options.allows_weak_linkage && + !ccx.sess().opts.single_codegen_unit() { + + if let Some(node_id) = ccx.tcx().map.as_local_node_id(closure_def_id) { + // If the closure is defined in the local crate, we can always just + // translate it. + let (decl, body) = match ccx.tcx().map.expect_expr(node_id).node { + hir::ExprClosure(_, ref decl, ref body, _) => (decl, body), + _ => { unreachable!() } + }; + + trans_closure_expr(Dest::Ignore(ccx), + decl, + body, + node_id, + closure_def_id, + substs); + } else { + // If the closure is defined in an upstream crate, we can only + // translate it if MIR-trans is active. + + if translating_closure_body_via_mir_will_fail(ccx, closure_def_id) { + ccx.sess().fatal("You have run into a known limitation of the \ + MingW toolchain. Either compile with -Zorbit or \ + with -Ccodegen-units=1 to work around it."); + } + + trans_closure_body_via_mir(ccx, closure_def_id, substs); + } + } + // If the closure is a Fn closure, but a FnOnce is needed (etc), // then adapt the self type let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index d057f623383d..a1783e9c0a38 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -980,7 +980,7 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va }); llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); - llvm::SetLinkage(g, llvm::InternalLinkage); + llvm::LLVMSetLinkage(g, llvm::InternalLinkage); cx.const_cstr_cache().borrow_mut().insert(s, g); g @@ -1235,7 +1235,6 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, inlined_vid: ast::NodeId) -> ty::VariantDef<'tcx> { - let ctor_ty = ccx.tcx().node_id_to_type(inlined_vid); debug!("inlined_variant_def: ctor_ty={:?} inlined_vid={:?}", ctor_ty, inlined_vid); @@ -1245,13 +1244,18 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }), ..}) => ty, _ => ctor_ty }.ty_adt_def().unwrap(); - let inlined_vid_def_id = ccx.tcx().map.local_def_id(inlined_vid); - adt_def.variants.iter().find(|v| { - inlined_vid_def_id == v.did || - ccx.external().borrow().get(&v.did) == Some(&Some(inlined_vid)) - }).unwrap_or_else(|| { - bug!("no variant for {:?}::{}", adt_def, inlined_vid) - }) + let variant_def_id = if ccx.tcx().map.is_inlined(inlined_vid) { + ccx.defid_for_inlined_node(inlined_vid).unwrap() + } else { + ccx.tcx().map.local_def_id(inlined_vid) + }; + + adt_def.variants + .iter() + .find(|v| variant_def_id == v.did) + .unwrap_or_else(|| { + bug!("no variant for {:?}::{}", adt_def, inlined_vid) + }) } // To avoid UB from LLVM, these two functions mask RHS with an diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 00feb2cd1de0..7afb5257258e 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -10,11 +10,11 @@ use llvm; -use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr}; +use llvm::{SetUnnamedAddr}; use llvm::{InternalLinkage, ValueRef, Bool, True}; use middle::const_qualif::ConstQualif; use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind}; -use rustc_const_eval::eval_repeat_count; +use rustc_const_eval::{eval_length, report_const_eval_err, note_const_eval_err}; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; @@ -44,7 +44,6 @@ use rustc_const_math::{ConstInt, ConstUsize, ConstIsize}; use rustc::hir; use std::ffi::{CStr, CString}; -use std::borrow::Cow; use libc::c_uint; use syntax::ast::{self, LitKind}; use syntax::attr::{self, AttrMetaMethods}; @@ -126,7 +125,7 @@ pub fn addr_of_mut(ccx: &CrateContext, }); llvm::LLVMSetInitializer(gv, cv); llvm::LLVMSetAlignment(gv, align); - SetLinkage(gv, InternalLinkage); + llvm::LLVMSetLinkage(gv, InternalLinkage); SetUnnamedAddr(gv, true); gv } @@ -250,10 +249,11 @@ impl ConstEvalFailure { Compiletime(e) => e, } } - pub fn description(&self) -> Cow { + + pub fn as_inner(&self) -> &ConstEvalErr { match self { - &Runtime(ref e) => e.description(), - &Compiletime(ref e) => e.description(), + &Runtime(ref e) => e, + &Compiletime(ref e) => e, } } } @@ -274,7 +274,7 @@ fn get_const_val<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let empty_substs = ccx.tcx().mk_substs(Substs::empty()); match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) { Err(Runtime(err)) => { - ccx.tcx().sess.span_err(expr.span, &err.description()); + report_const_eval_err(ccx.tcx(), &err, expr.span, "expression").emit(); Err(Compiletime(err)) }, other => other, @@ -526,12 +526,15 @@ pub fn const_err(cx: &CrateContext, (Ok(x), _) => Ok(x), (Err(err), TrueConst::Yes) => { let err = ConstEvalErr{ span: span, kind: err }; - cx.tcx().sess.span_err(span, &err.description()); + report_const_eval_err(cx.tcx(), &err, span, "expression").emit(); Err(Compiletime(err)) }, (Err(err), TrueConst::No) => { let err = ConstEvalErr{ span: span, kind: err }; - cx.tcx().sess.span_warn(span, &err.description()); + let mut diag = cx.tcx().sess.struct_span_warn( + span, "this expression will panic at run-time"); + note_const_eval_err(cx.tcx(), &err, span, "expression", &mut diag); + diag.emit(); Err(Runtime(err)) }, } @@ -634,10 +637,10 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, hir::BiEq | hir::BiNe | hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe => { if is_float { let cmp = base::bin_op_to_fcmp_predicate(b.node); - ConstFCmp(cmp, te1, te2) + llvm::LLVMConstFCmp(cmp, te1, te2) } else { let cmp = base::bin_op_to_icmp_predicate(b.node, signed); - ConstICmp(cmp, te1, te2) + llvm::LLVMConstICmp(cmp, te1, te2) } }, } } // unsafe { match b.node { @@ -875,7 +878,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, hir::ExprRepeat(ref elem, ref count) => { let unit_ty = ety.sequence_element_type(cx.tcx()); let llunitty = type_of::type_of(cx, unit_ty); - let n = eval_repeat_count(cx.tcx(), count); + let n = eval_length(cx.tcx(), count, "repeat count").unwrap(); let unit_val = const_expr(cx, &elem, param_substs, fn_args, trueconst)?.0; let vs = vec![unit_val; n]; if val_ty(unit_val) != llunitty { @@ -1023,10 +1026,10 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) .get(TransItem::Static(id)) .expect("Local statics should always be in the SymbolMap"); // Make sure that this is never executed for something inlined. - assert!(!ccx.external_srcs().borrow().contains_key(&id)); + assert!(!ccx.tcx().map.is_inlined(id)); let defined_in_current_codegen_unit = ccx.codegen_unit() - .items + .items() .contains_key(&TransItem::Static(id)); if defined_in_current_codegen_unit { if declare::get_declared_value(ccx, sym).is_none() { @@ -1069,7 +1072,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) unsafe { // Declare a symbol `foo` with the desired linkage. let g1 = declare::declare_global(ccx, &sym, llty2); - llvm::SetLinkage(g1, linkage); + llvm::LLVMSetLinkage(g1, linkage); // Declare an internal global `extern_with_linkage_foo` which // is initialized with the address of `foo`. If `foo` is @@ -1083,7 +1086,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) ccx.sess().span_fatal(span, &format!("symbol `{}` is already defined", &sym)) }); - llvm::SetLinkage(g2, llvm::InternalLinkage); + llvm::LLVMSetLinkage(g2, llvm::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); g2 } @@ -1123,7 +1126,9 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) } } if ccx.use_dll_storage_attrs() { - llvm::SetDLLStorageClass(g, llvm::DLLImportStorageClass); + unsafe { + llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); + } } g }; @@ -1179,7 +1184,7 @@ pub fn trans_static(ccx: &CrateContext, let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(datum.val)); let name_string = CString::new(name_str_ref.to_bytes()).unwrap(); llvm::LLVMSetValueName(datum.val, empty_string.as_ptr()); - let new_g = llvm::LLVMGetOrInsertGlobal( + let new_g = llvm::LLVMRustGetOrInsertGlobal( ccx.llmod(), name_string.as_ptr(), val_llty.to_ref()); // To avoid breaking any invariants, we leave around the old // global for the moment; we'll replace all references to it diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 88903726d64f..246c037c030b 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -10,7 +10,7 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef, BuilderRef}; -use rustc::dep_graph::{DepNode, DepTrackingMap, DepTrackingMapConfig}; +use rustc::dep_graph::{DepNode, DepTrackingMap, DepTrackingMapConfig, WorkProduct}; use middle::cstore::LinkMeta; use rustc::hir::def::ExportMap; use rustc::hir::def_id::DefId; @@ -34,9 +34,10 @@ use rustc::ty::subst::{Substs, VecPerParamSpace}; use rustc::ty::{self, Ty, TyCtxt}; use session::config::NoDebugInfo; use session::Session; +use session::config; use symbol_map::SymbolMap; use util::sha2::Sha256; -use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; +use util::nodemap::{NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; @@ -95,16 +96,12 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { pub struct LocalCrateContext<'tcx> { llmod: ModuleRef, llcx: ContextRef, + previous_work_product: Option, tn: TypeNames, // FIXME: This seems to be largely unused. codegen_unit: CodegenUnit<'tcx>, needs_unwind_cleanup_cache: RefCell, bool>>, fn_pointer_shims: RefCell, ValueRef>>, drop_glues: RefCell, (ValueRef, FnType)>>, - /// Track mapping of external ids to local items imported for inlining - external: RefCell>>, - /// Backwards version of the `external` map (inlined items to where they - /// came from) - external_srcs: RefCell>, /// Cache instances of monomorphic and polymorphic items instances: RefCell, ValueRef>>, monomorphizing: RefCell>, @@ -198,24 +195,39 @@ pub struct CrateContextList<'a, 'tcx: 'a> { } impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> { - pub fn new(shared_ccx: &'a SharedCrateContext<'a, 'tcx>, codegen_units: Vec>, + previous_work_products: Vec>, symbol_map: Rc>) -> CrateContextList<'a, 'tcx> { CrateContextList { shared: shared_ccx, - local_ccxs: codegen_units.into_iter().map(|codegen_unit| { - LocalCrateContext::new(shared_ccx, codegen_unit, symbol_map.clone()) + local_ccxs: codegen_units.into_iter().zip(previous_work_products).map(|(cgu, wp)| { + LocalCrateContext::new(shared_ccx, cgu, wp, symbol_map.clone()) }).collect() } } - pub fn iter<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> { + /// Iterate over all crate contexts, whether or not they need + /// translation. That is, whether or not a `.o` file is available + /// for re-use from a previous incr. comp.). + pub fn iter_all<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> { CrateContextIterator { shared: self.shared, index: 0, - local_ccxs: &self.local_ccxs[..] + local_ccxs: &self.local_ccxs[..], + filter_to_previous_work_product_unavail: false, + } + } + + /// Iterator over all CCX that need translation (cannot reuse results from + /// previous incr. comp.). + pub fn iter_need_trans<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> { + CrateContextIterator { + shared: self.shared, + index: 0, + local_ccxs: &self.local_ccxs[..], + filter_to_previous_work_product_unavail: true, } } @@ -239,24 +251,38 @@ pub struct CrateContextIterator<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, local_ccxs: &'a [LocalCrateContext<'tcx>], index: usize, + + /// if true, only return results where `previous_work_product` is none + filter_to_previous_work_product_unavail: bool, } impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> { type Item = CrateContext<'a, 'tcx>; fn next(&mut self) -> Option> { - if self.index >= self.local_ccxs.len() { - return None; + loop { + if self.index >= self.local_ccxs.len() { + return None; + } + + let index = self.index; + self.index += 1; + + let ccx = CrateContext { + shared: self.shared, + index: index, + local_ccxs: self.local_ccxs, + }; + + if + self.filter_to_previous_work_product_unavail && + ccx.previous_work_product().is_some() + { + continue; + } + + return Some(ccx); } - - let index = self.index; - self.index += 1; - - Some(CrateContext { - shared: self.shared, - index: index, - local_ccxs: self.local_ccxs, - }) } } @@ -292,6 +318,36 @@ impl<'a, 'tcx> Iterator for CrateContextMaybeIterator<'a, 'tcx> { } } +pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode { + let reloc_model_arg = match sess.opts.cg.relocation_model { + Some(ref s) => &s[..], + None => &sess.target.target.options.relocation_model[..], + }; + + match ::back::write::RELOC_MODEL_ARGS.iter().find( + |&&arg| arg.0 == reloc_model_arg) { + Some(x) => x.1, + _ => { + sess.err(&format!("{:?} is not a valid relocation mode", + sess.opts + .cg + .code_model)); + sess.abort_if_errors(); + bug!(); + } + } +} + +fn is_any_library(sess: &Session) -> bool { + sess.crate_types.borrow().iter().any(|ty| { + *ty != config::CrateTypeExecutable + }) +} + +pub fn is_pie_binary(sess: &Session) -> bool { + !is_any_library(sess) && get_reloc_model(sess) == llvm::RelocMode::PIC +} + unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { let llcx = llvm::LLVMContextCreate(); let mod_name = CString::new(mod_name).unwrap(); @@ -307,7 +363,25 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR let data_layout = str::from_utf8(CStr::from_ptr(data_layout).to_bytes()) .ok().expect("got a non-UTF8 data-layout from LLVM"); - if sess.target.target.data_layout != data_layout { + // Unfortunately LLVM target specs change over time, and right now we + // don't have proper support to work with any more than one + // `data_layout` than the one that is in the rust-lang/rust repo. If + // this compiler is configured against a custom LLVM, we may have a + // differing data layout, even though we should update our own to use + // that one. + // + // As an interim hack, if CFG_LLVM_ROOT is not an empty string then we + // disable this check entirely as we may be configured with something + // that has a different target layout. + // + // Unsure if this will actually cause breakage when rustc is configured + // as such. + // + // FIXME(#34960) + let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or(""); + let custom_llvm_used = cfg_llvm_root.trim() != ""; + + if !custom_llvm_used && sess.target.target.data_layout != data_layout { bug!("data-layout for builtin `{}` target, `{}`, \ differs from LLVM default, `{}`", sess.target.target.llvm_target, @@ -322,6 +396,11 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR let llvm_target = sess.target.target.llvm_target.as_bytes(); let llvm_target = CString::new(llvm_target).unwrap(); llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); + + if is_pie_binary(sess) { + llvm::LLVMRustSetModulePIELevel(llmod); + } + (llcx, llmod) } @@ -510,6 +589,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { impl<'tcx> LocalCrateContext<'tcx> { fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, codegen_unit: CodegenUnit<'tcx>, + previous_work_product: Option, symbol_map: Rc>) -> LocalCrateContext<'tcx> { unsafe { @@ -521,13 +601,15 @@ impl<'tcx> LocalCrateContext<'tcx> { // crashes if the module identifier is same as other symbols // such as a function name in the module. // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 - let llmod_id = format!("{}.rs", codegen_unit.name); + let llmod_id = format!("{}.rs", codegen_unit.name()); let (llcx, llmod) = create_context_and_module(&shared.tcx.sess, &llmod_id[..]); let dbg_cx = if shared.tcx.sess.opts.debuginfo != NoDebugInfo { - Some(debuginfo::CrateDebugContext::new(llmod)) + let dctx = debuginfo::CrateDebugContext::new(llmod); + debuginfo::metadata::compile_unit_metadata(shared, &dctx, shared.tcx.sess); + Some(dctx) } else { None }; @@ -535,13 +617,12 @@ impl<'tcx> LocalCrateContext<'tcx> { let local_ccx = LocalCrateContext { llmod: llmod, llcx: llcx, + previous_work_product: previous_work_product, codegen_unit: codegen_unit, tn: TypeNames::new(), needs_unwind_cleanup_cache: RefCell::new(FnvHashMap()), fn_pointer_shims: RefCell::new(FnvHashMap()), drop_glues: RefCell::new(FnvHashMap()), - external: RefCell::new(DefIdMap()), - external_srcs: RefCell::new(NodeMap()), instances: RefCell::new(FnvHashMap()), monomorphizing: RefCell::new(DefIdMap()), vtables: RefCell::new(FnvHashMap()), @@ -694,6 +775,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local().llcx } + pub fn previous_work_product(&self) -> Option<&WorkProduct> { + self.local().previous_work_product.as_ref() + } + pub fn codegen_unit(&self) -> &CodegenUnit<'tcx> { &self.local().codegen_unit } @@ -731,12 +816,12 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().drop_glues } - pub fn external<'a>(&'a self) -> &'a RefCell>> { - &self.local().external + pub fn local_node_for_inlined_defid<'a>(&'a self, def_id: DefId) -> Option { + self.sess().cstore.local_node_for_inlined_defid(def_id) } - pub fn external_srcs<'a>(&'a self) -> &'a RefCell> { - &self.local().external_srcs + pub fn defid_for_inlined_node<'a>(&'a self, node_id: ast::NodeId) -> Option { + self.sess().cstore.defid_for_inlined_node(node_id) } pub fn instances<'a>(&'a self) -> &'a RefCell, ValueRef>> { diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index 0b7540248681..fe6a48d4c559 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -133,7 +133,7 @@ fn make_mir_scope(ccx: &CrateContext, let loc = span_start(ccx, scope_data.span); scopes[scope] = unsafe { let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path); - llvm::LLVMDIBuilderCreateLexicalBlock( + llvm::LLVMRustDIBuilderCreateLexicalBlock( DIB(ccx), parent_scope, file_metadata, @@ -156,7 +156,7 @@ fn with_new_scope(cx: &CrateContext, let parent_scope = scope_stack.last().unwrap().scope_metadata; let scope_metadata = unsafe { - llvm::LLVMDIBuilderCreateLexicalBlock( + llvm::LLVMRustDIBuilderCreateLexicalBlock( DIB(cx), parent_scope, file_metadata, @@ -272,7 +272,7 @@ fn walk_pattern(cx: &CrateContext, let parent_scope = scope_stack.last().unwrap().scope_metadata; let scope_metadata = unsafe { - llvm::LLVMDIBuilderCreateLexicalBlock( + llvm::LLVMRustDIBuilderCreateLexicalBlock( DIB(cx), parent_scope, file_metadata, diff --git a/src/librustc_trans/debuginfo/gdb.rs b/src/librustc_trans/debuginfo/gdb.rs index cf312855d75b..0a8d490dcd2d 100644 --- a/src/librustc_trans/debuginfo/gdb.rs +++ b/src/librustc_trans/debuginfo/gdb.rs @@ -77,7 +77,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddr(section_var, llvm::True); - llvm::SetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage); + llvm::LLVMSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage); // This should make sure that the whole section is not larger than // the string it contains. Otherwise we get a warning from GDB. llvm::LLVMSetAlignment(section_var, 1); diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 46813d957dce..8011347d3eb1 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -18,7 +18,9 @@ use super::utils::{debug_context, DIB, span_start, bytes_to_bits, size_and_align fn_should_be_ignored, is_node_local_to_unit}; use super::namespace::mangled_name_of_item; use super::type_names::{compute_debuginfo_type_name, push_debuginfo_type_name}; -use super::{declare_local, VariableKind, VariableAccess}; +use super::{declare_local, VariableKind, VariableAccess, CrateDebugContext}; +use context::SharedCrateContext; +use session::Session; use llvm::{self, ValueRef}; use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType}; @@ -48,7 +50,6 @@ use syntax::ast; use syntax::parse::token; use syntax_pos::{self, Span}; - // From DWARF 5. // See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1 const DW_LANG_RUST: c_uint = 0x1c; @@ -67,7 +68,6 @@ pub const UNKNOWN_LINE_NUMBER: c_uint = 0; pub const UNKNOWN_COLUMN_NUMBER: c_uint = 0; // ptr::null() doesn't work :( -pub const NO_FILE_METADATA: DIFile = (0 as DIFile); pub const NO_SCOPE_METADATA: DIScope = (0 as DIScope); const FLAGS_NONE: c_uint = 0; @@ -326,13 +326,12 @@ impl<'tcx> TypeMap<'tcx> { // First, find out the 'real' def_id of the type. Items inlined from // other crates have to be mapped back to their source. let def_id = if let Some(node_id) = cx.tcx().map.as_local_node_id(def_id) { - match cx.external_srcs().borrow().get(&node_id).cloned() { - Some(source_def_id) => { - // The given def_id identifies the inlined copy of a - // type definition, let's take the source of the copy. - source_def_id - } - None => def_id + if cx.tcx().map.is_inlined(node_id) { + // The given def_id identifies the inlined copy of a + // type definition, let's take the source of the copy. + cx.defid_for_inlined_node(node_id).unwrap() + } else { + def_id } } else { def_id @@ -505,12 +504,12 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }; let subrange = unsafe { - llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) + llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) }; let subscripts = create_DIArray(DIB(cx), &[subrange]); let metadata = unsafe { - llvm::LLVMDIBuilderCreateArrayType( + llvm::LLVMRustDIBuilderCreateArrayType( DIB(cx), bytes_to_bits(array_size_in_bytes), bytes_to_bits(element_type_align), @@ -613,9 +612,9 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return MetadataCreationResult::new( unsafe { - llvm::LLVMDIBuilderCreateSubroutineType( + llvm::LLVMRustDIBuilderCreateSubroutineType( DIB(cx), - NO_FILE_METADATA, + unknown_file_metadata(cx), create_DIArray(DIB(cx), &signature_metadata[..])) }, false); @@ -652,6 +651,7 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id); let trait_llvm_type = type_of::type_of(cx, trait_object_type); + let file_metadata = unknown_file_metadata(cx); composite_type_metadata(cx, trait_llvm_type, @@ -659,7 +659,7 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id, &[], containing_scope, - NO_FILE_METADATA, + file_metadata, syntax_pos::DUMMY_SP) } @@ -885,8 +885,8 @@ fn file_metadata_(cx: &CrateContext, key: &str, file_name: &str, work_dir: &str) let file_name = CString::new(file_name).unwrap(); let work_dir = CString::new(work_dir).unwrap(); let file_metadata = unsafe { - llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name.as_ptr(), - work_dir.as_ptr()) + llvm::LLVMRustDIBuilderCreateFile(DIB(cx), file_name.as_ptr(), + work_dir.as_ptr()) }; let mut created_files = debug_context(cx).created_files.borrow_mut(); @@ -916,7 +916,7 @@ pub fn scope_metadata(fcx: &FunctionContext, pub fn diverging_type_metadata(cx: &CrateContext) -> DIType { unsafe { - llvm::LLVMDIBuilderCreateBasicType( + llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), "!\0".as_ptr() as *const _, bytes_to_bits(0), @@ -951,7 +951,7 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let (size, align) = size_and_align_of(cx, llvm_type); let name = CString::new(name).unwrap(); let ty_metadata = unsafe { - llvm::LLVMDIBuilderCreateBasicType( + llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), name.as_ptr(), bytes_to_bits(size), @@ -971,7 +971,7 @@ fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let name = compute_debuginfo_type_name(cx, pointer_type, false); let name = CString::new(name).unwrap(); let ptr_metadata = unsafe { - llvm::LLVMDIBuilderCreatePointerType( + llvm::LLVMRustDIBuilderCreatePointerType( DIB(cx), pointee_type_metadata, bytes_to_bits(pointer_size), @@ -981,14 +981,17 @@ fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return ptr_metadata; } -pub fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { - let work_dir = &cx.sess().working_dir; - let compile_unit_name = match cx.sess().local_crate_source_file { - None => fallback_path(cx), +pub fn compile_unit_metadata(scc: &SharedCrateContext, + debug_context: &CrateDebugContext, + sess: &Session) + -> DIDescriptor { + let work_dir = &sess.working_dir; + let compile_unit_name = match sess.local_crate_source_file { + None => fallback_path(scc), Some(ref abs_path) => { if abs_path.is_relative() { - cx.sess().warn("debuginfo: Invalid path to crate's local root source file!"); - fallback_path(cx) + sess.warn("debuginfo: Invalid path to crate's local root source file!"); + fallback_path(scc) } else { match abs_path.strip_prefix(work_dir) { Ok(ref p) if p.is_relative() => { @@ -998,7 +1001,7 @@ pub fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { path2cstr(&Path::new(".").join(p)) } } - _ => fallback_path(cx) + _ => fallback_path(scc) } } } @@ -1014,20 +1017,20 @@ pub fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { let flags = "\0"; let split_name = "\0"; return unsafe { - llvm::LLVMDIBuilderCreateCompileUnit( - debug_context(cx).builder, + llvm::LLVMRustDIBuilderCreateCompileUnit( + debug_context.builder, DW_LANG_RUST, compile_unit_name, work_dir.as_ptr(), producer.as_ptr(), - cx.sess().opts.optimize != config::OptLevel::No, + sess.opts.optimize != config::OptLevel::No, flags.as_ptr() as *const _, 0, split_name.as_ptr() as *const _) }; - fn fallback_path(cx: &CrateContext) -> CString { - CString::new(cx.link_meta().crate_name.clone()).unwrap() + fn fallback_path(scc: &SharedCrateContext) -> CString { + CString::new(scc.link_meta().crate_name.clone()).unwrap() } } @@ -1593,7 +1596,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let token = v.name.as_str(); let name = CString::new(token.as_bytes()).unwrap(); unsafe { - llvm::LLVMDIBuilderCreateEnumerator( + llvm::LLVMRustDIBuilderCreateEnumerator( DIB(cx), name.as_ptr(), v.disr_val.to_u64_unchecked()) @@ -1620,11 +1623,11 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let name = CString::new(discriminant_name.as_bytes()).unwrap(); let discriminant_type_metadata = unsafe { - llvm::LLVMDIBuilderCreateEnumerationType( + llvm::LLVMRustDIBuilderCreateEnumerationType( DIB(cx), containing_scope, name.as_ptr(), - NO_FILE_METADATA, + file_metadata, UNKNOWN_LINE_NUMBER, bytes_to_bits(discriminant_size), bytes_to_bits(discriminant_align), @@ -1664,7 +1667,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let enum_name = CString::new(enum_name).unwrap(); let unique_type_id_str = CString::new(unique_type_id_str.as_bytes()).unwrap(); let enum_metadata = unsafe { - llvm::LLVMDIBuilderCreateUnionType( + llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), containing_scope, enum_name.as_ptr(), @@ -1766,11 +1769,11 @@ fn set_members_of_composite_type(cx: &CrateContext, let member_name = member_description.name.as_bytes(); let member_name = CString::new(member_name).unwrap(); unsafe { - llvm::LLVMDIBuilderCreateMemberType( + llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), composite_type_metadata, member_name.as_ptr(), - NO_FILE_METADATA, + unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, bytes_to_bits(member_size), bytes_to_bits(member_align), @@ -1783,13 +1786,14 @@ fn set_members_of_composite_type(cx: &CrateContext, unsafe { let type_array = create_DIArray(DIB(cx), &member_metadata[..]); - llvm::LLVMDICompositeTypeSetTypeArray(DIB(cx), composite_type_metadata, type_array); + llvm::LLVMRustDICompositeTypeSetTypeArray( + DIB(cx), composite_type_metadata, type_array); } } -// A convenience wrapper around LLVMDIBuilderCreateStructType(). Does not do any -// caching, does not add any fields to the struct. This can be done later with -// set_members_of_composite_type(). +// A convenience wrapper around LLVMRustDIBuilderCreateStructType(). Does not do +// any caching, does not add any fields to the struct. This can be done later +// with set_members_of_composite_type(). fn create_struct_stub(cx: &CrateContext, struct_llvm_type: Type, struct_type_name: &str, @@ -1804,16 +1808,16 @@ fn create_struct_stub(cx: &CrateContext, let name = CString::new(struct_type_name).unwrap(); let unique_type_id = CString::new(unique_type_id_str.as_bytes()).unwrap(); let metadata_stub = unsafe { - // LLVMDIBuilderCreateStructType() wants an empty array. A null + // LLVMRustDIBuilderCreateStructType() wants an empty array. A null // pointer will lead to hard to trace and debug LLVM assertions // later on in llvm/lib/IR/Value.cpp. let empty_array = create_DIArray(DIB(cx), &[]); - llvm::LLVMDIBuilderCreateStructType( + llvm::LLVMRustDIBuilderCreateStructType( DIB(cx), containing_scope, name.as_ptr(), - NO_FILE_METADATA, + unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, bytes_to_bits(struct_size), bytes_to_bits(struct_align), @@ -1842,7 +1846,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, // crate should already contain debuginfo for it. More importantly, the // global might not even exist in un-inlined form anywhere which would lead // to a linker errors. - if cx.external_srcs().borrow().contains_key(&node_id) { + if cx.tcx().map.is_inlined(node_id) { return; } @@ -1853,7 +1857,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, let loc = span_start(cx, span); (file_metadata(cx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint) } else { - (NO_FILE_METADATA, UNKNOWN_LINE_NUMBER) + (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER) }; let is_local_to_unit = is_node_local_to_unit(cx, node_id); @@ -1865,16 +1869,16 @@ pub fn create_global_var_metadata(cx: &CrateContext, let var_name = CString::new(var_name).unwrap(); let linkage_name = CString::new(linkage_name).unwrap(); unsafe { - llvm::LLVMDIBuilderCreateStaticVariable(DIB(cx), - var_scope, - var_name.as_ptr(), - linkage_name.as_ptr(), - file_metadata, - line_number, - type_metadata, - is_local_to_unit, - global, - ptr::null_mut()); + llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx), + var_scope, + var_name.as_ptr(), + linkage_name.as_ptr(), + file_metadata, + line_number, + type_metadata, + is_local_to_unit, + global, + ptr::null_mut()); } } @@ -1977,10 +1981,10 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, env_index); let address_operations = unsafe { - [llvm::LLVMDIBuilderCreateOpDeref(), - llvm::LLVMDIBuilderCreateOpPlus(), + [llvm::LLVMRustDIBuilderCreateOpDeref(), + llvm::LLVMRustDIBuilderCreateOpPlus(), byte_offset_of_var_in_env as i64, - llvm::LLVMDIBuilderCreateOpDeref()] + llvm::LLVMRustDIBuilderCreateOpDeref()] }; let address_op_count = if captured_by_ref { @@ -2018,7 +2022,7 @@ pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let scope_metadata = scope_metadata(bcx.fcx, binding.id, binding.span); let aops = unsafe { - [llvm::LLVMDIBuilderCreateOpDeref()] + [llvm::LLVMRustDIBuilderCreateOpDeref()] }; // Regardless of the actual type (`T`) we're always passed the stack slot // (alloca) for the binding. For ByRef bindings that's a `T*` but for ByMove diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 8c5b3ed54c2f..464c32c3cc72 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -18,7 +18,7 @@ use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit}; use self::namespace::mangled_name_of_item; use self::type_names::compute_debuginfo_type_name; use self::metadata::{type_metadata, diverging_type_metadata}; -use self::metadata::{file_metadata, scope_metadata, TypeMap, compile_unit_metadata}; +use self::metadata::{file_metadata, scope_metadata, TypeMap}; use self::source_loc::InternalDebugLocation::{self, UnknownLocation}; use llvm; @@ -32,6 +32,7 @@ use rustc::hir; use abi::Abi; use common::{NodeIdAndSpan, CrateContext, FunctionContext, Block, BlockAndBuilder}; +use inline; use monomorphize::{self, Instance}; use rustc::ty::{self, Ty}; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; @@ -50,7 +51,7 @@ pub mod gdb; mod utils; mod namespace; mod type_names; -mod metadata; +pub mod metadata; mod create_scope_map; mod source_loc; @@ -88,7 +89,7 @@ pub struct CrateDebugContext<'tcx> { impl<'tcx> CrateDebugContext<'tcx> { pub fn new(llmod: ModuleRef) -> CrateDebugContext<'tcx> { debug!("CrateDebugContext::new"); - let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) }; + let builder = unsafe { llvm::LLVMRustDIBuilderCreate(llmod) }; // DIBuilder inherits context from the module, so we'd better use the same one let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; return CrateDebugContext { @@ -168,7 +169,6 @@ pub fn finalize(cx: &CrateContext) { } debug!("finalize"); - let _ = compile_unit_metadata(cx); if gdb::needs_gdb_debug_scripts_section(cx) { // Add a .debug_gdb_scripts section to this compile-unit. This will @@ -179,8 +179,8 @@ pub fn finalize(cx: &CrateContext) { } unsafe { - llvm::LLVMDIBuilderFinalize(DIB(cx)); - llvm::LLVMDIBuilderDispose(DIB(cx)); + llvm::LLVMRustDIBuilderFinalize(DIB(cx)); + llvm::LLVMRustDIBuilderDispose(DIB(cx)); // Debuginfo generation in LLVM by default uses a higher // version of dwarf than OS X currently understands. We can // instruct LLVM to emit an older version of dwarf, however, @@ -239,6 +239,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Do this here already, in case we do an early exit from this function. source_loc::set_debug_location(cx, None, UnknownLocation); + let instance = inline::maybe_inline_instance(cx, instance); let (containing_scope, span) = get_containing_scope_and_span(cx, instance); // This can be the case for functions inlined from another crate @@ -251,7 +252,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let function_type_metadata = unsafe { let fn_signature = get_function_signature(cx, sig, abi); - llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature) + llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature) }; // Find the enclosing function, in case this is a closure. @@ -285,7 +286,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let linkage_name = CString::new(linkage_name).unwrap(); let fn_metadata = unsafe { - llvm::LLVMDIBuilderCreateFunction( + llvm::LLVMRustDIBuilderCreateFunction( DIB(cx), containing_scope, function_name.as_ptr(), @@ -389,7 +390,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); let name = CString::new(param.name.as_str().as_bytes()).unwrap(); unsafe { - llvm::LLVMDIBuilderCreateTemplateTypeParameter( + llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), ptr::null_mut(), name.as_ptr(), @@ -439,10 +440,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }); // Try to get some span information, if we have an inlined item. - let definition_span = match cx.external().borrow().get(&instance.def) { - Some(&Some(node_id)) => cx.tcx().map.span(node_id), - _ => cx.tcx().map.def_id_span(instance.def, syntax_pos::DUMMY_SP) - }; + let definition_span = cx.tcx() + .map + .def_id_span(instance.def, syntax_pos::DUMMY_SP); (containing_scope, definition_span) } @@ -494,7 +494,7 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, (DirectVariable { alloca }, address_operations) | (IndirectVariable {alloca, address_operations}, _) => { let metadata = unsafe { - llvm::LLVMDIBuilderCreateVariable( + llvm::LLVMRustDIBuilderCreateVariable( DIB(cx), dwarf_tag, scope_metadata, @@ -512,7 +512,7 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize())); unsafe { let debug_loc = llvm::LLVMGetCurrentDebugLocation(cx.raw_builder()); - let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd( + let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd( DIB(cx), alloca, metadata, diff --git a/src/librustc_trans/debuginfo/namespace.rs b/src/librustc_trans/debuginfo/namespace.rs index 167229ddfd98..5953ec4aaedf 100644 --- a/src/librustc_trans/debuginfo/namespace.rs +++ b/src/librustc_trans/debuginfo/namespace.rs @@ -10,7 +10,7 @@ // Namespace Handling. -use super::metadata::{file_metadata, NO_FILE_METADATA, UNKNOWN_LINE_NUMBER}; +use super::metadata::{file_metadata, unknown_file_metadata, UNKNOWN_LINE_NUMBER}; use super::utils::{DIB, debug_context, span_start}; use llvm; @@ -74,11 +74,11 @@ pub fn item_namespace(ccx: &CrateContext, def_id: DefId) -> DIScope { let loc = span_start(ccx, span); (file_metadata(ccx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint) } else { - (NO_FILE_METADATA, UNKNOWN_LINE_NUMBER) + (unknown_file_metadata(ccx), UNKNOWN_LINE_NUMBER) }; let scope = unsafe { - llvm::LLVMDIBuilderCreateNameSpace( + llvm::LLVMRustDIBuilderCreateNameSpace( DIB(ccx), parent_scope, namespace_name.as_ptr(), diff --git a/src/librustc_trans/debuginfo/source_loc.rs b/src/librustc_trans/debuginfo/source_loc.rs index 9726001b4d42..d288b9dcef70 100644 --- a/src/librustc_trans/debuginfo/source_loc.rs +++ b/src/librustc_trans/debuginfo/source_loc.rs @@ -206,7 +206,7 @@ pub fn set_debug_location(cx: &CrateContext, debug!("setting debug location to {} {}", line, col); unsafe { - llvm::LLVMDIBuilderCreateDebugLocation( + llvm::LLVMRustDIBuilderCreateDebugLocation( debug_context(cx).llcontext, line as c_uint, col as c_uint, diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index 1e0afa4534b1..5734a1239411 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -40,7 +40,7 @@ pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool #[allow(non_snake_case)] pub fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray { return unsafe { - llvm::LLVMDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) + llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) }; } @@ -86,10 +86,7 @@ pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId) }); // Try to get some span information, if we have an inlined item. - let definition_span = match cx.external().borrow().get(&def_id) { - Some(&Some(node_id)) => cx.tcx().map.span(node_id), - _ => cx.tcx().map.def_id_span(def_id, syntax_pos::DUMMY_SP) - }; + let definition_span = cx.tcx().map.def_id_span(def_id, syntax_pos::DUMMY_SP); (containing_scope, definition_span) } diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 2746d3fb6b0b..324e8697ecae 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -20,6 +20,7 @@ //! * Use define_* family of methods when you might be defining the ValueRef. //! * When in doubt, define. use llvm::{self, ValueRef}; +use llvm::AttributePlace::Function; use rustc::ty; use abi::{Abi, FnType}; use attributes; @@ -40,7 +41,7 @@ pub fn declare_global(ccx: &CrateContext, name: &str, ty: Type) -> llvm::ValueRe bug!("name {:?} contains an interior null byte", name) }); unsafe { - llvm::LLVMGetOrInsertGlobal(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) + llvm::LLVMRustGetOrInsertGlobal(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) } } @@ -55,7 +56,7 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: bug!("name {:?} contains an interior null byte", name) }); let llfn = unsafe { - llvm::LLVMGetOrInsertFunction(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) + llvm::LLVMRustGetOrInsertFunction(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) }; llvm::SetFunctionCallConv(llfn, callconv); @@ -65,16 +66,16 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: if ccx.tcx().sess.opts.cg.no_redzone .unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) { - llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoRedZone) + llvm::Attribute::NoRedZone.apply_llfn(Function, llfn); } match ccx.tcx().sess.opts.cg.opt_level.as_ref().map(String::as_ref) { Some("s") => { - llvm::SetFunctionAttribute(llfn, llvm::Attribute::OptimizeForSize); + llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); }, Some("z") => { - llvm::SetFunctionAttribute(llfn, llvm::Attribute::MinSize); - llvm::SetFunctionAttribute(llfn, llvm::Attribute::OptimizeForSize); + llvm::Attribute::MinSize.apply_llfn(Function, llfn); + llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); }, _ => {}, } @@ -111,7 +112,7 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx)); if sig.output == ty::FnDiverging { - llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoReturn); + llvm::Attribute::NoReturn.apply_llfn(Function, llfn); } if abi != Abi::Rust && abi != Abi::RustCall { @@ -162,7 +163,7 @@ pub fn define_internal_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, fn_type: ty::Ty<'tcx>) -> ValueRef { let llfn = define_fn(ccx, name, fn_type); - llvm::SetLinkage(llfn, llvm::InternalLinkage); + unsafe { llvm::LLVMSetLinkage(llfn, llvm::InternalLinkage) }; llfn } @@ -173,7 +174,7 @@ pub fn get_declared_value(ccx: &CrateContext, name: &str) -> Option { let namebuf = CString::new(name).unwrap_or_else(|_|{ bug!("name {:?} contains an interior null byte", name) }); - let val = unsafe { llvm::LLVMGetNamedValue(ccx.llmod(), namebuf.as_ptr()) }; + let val = unsafe { llvm::LLVMRustGetNamedValue(ccx.llmod(), namebuf.as_ptr()) }; if val.is_null() { debug!("get_declared_value: {:?} value is null", name); None diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs index b8dd7273a833..2a60dd174467 100644 --- a/src/librustc_trans/expr.rs +++ b/src/librustc_trans/expr.rs @@ -1512,7 +1512,7 @@ fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, C_integral(llty, min, true), debug_loc); with_cond(bcx, is_min, |bcx| { let msg = InternedString::new( - "attempted to negate with overflow"); + "attempt to negate with overflow"); controlflow::trans_fail(bcx, expr_info(expr), msg) }) } else { diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index ef7d0ea165d6..6bc48546dfa8 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -239,7 +239,7 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, Falling back to on-demand instantiation.", g, TransItem::DropGlue(g).to_raw_string(), - ccx.codegen_unit().name); + ccx.codegen_unit().name()); ccx.stats().n_fallback_instantiations.set(ccx.stats() .n_fallback_instantiations diff --git a/src/librustc_trans/inline.rs b/src/librustc_trans/inline.rs index 4077b894d62d..8581fccf10ab 100644 --- a/src/librustc_trans/inline.rs +++ b/src/librustc_trans/inline.rs @@ -8,14 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::cstore::{FoundAst, InlinedItem}; use rustc::hir::def_id::DefId; use base::push_ctxt; use common::*; use monomorphize::Instance; use rustc::dep_graph::DepNode; -use rustc::hir; fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option { debug!("instantiate_inline({:?})", fn_id); @@ -23,104 +21,12 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option { let tcx = ccx.tcx(); let _task = tcx.dep_graph.in_task(DepNode::TransInlinedItem(fn_id)); - match ccx.external().borrow().get(&fn_id) { - Some(&Some(node_id)) => { - // Already inline - debug!("instantiate_inline({}): already inline as node id {}", - tcx.item_path_str(fn_id), node_id); - let node_def_id = tcx.map.local_def_id(node_id); - return Some(node_def_id); - } - Some(&None) => { - return None; // Not inlinable - } - None => { - // Not seen yet - } - } - - let inlined = tcx.sess.cstore.maybe_get_item_ast(tcx, fn_id); - let inline_id = match inlined { - FoundAst::NotFound => { - ccx.external().borrow_mut().insert(fn_id, None); - return None; - } - FoundAst::Found(&InlinedItem::Item(ref item)) => { - ccx.external().borrow_mut().insert(fn_id, Some(item.id)); - ccx.external_srcs().borrow_mut().insert(item.id, fn_id); - - ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1); - - item.id - } - FoundAst::Found(&InlinedItem::Foreign(ref item)) => { - ccx.external().borrow_mut().insert(fn_id, Some(item.id)); - ccx.external_srcs().borrow_mut().insert(item.id, fn_id); - item.id - } - FoundAst::FoundParent(parent_id, item) => { - ccx.external().borrow_mut().insert(parent_id, Some(item.id)); - ccx.external_srcs().borrow_mut().insert(item.id, parent_id); - - let mut my_id = 0; - match item.node { - hir::ItemEnum(ref ast_def, _) => { - let ast_vs = &ast_def.variants; - let ty_vs = &tcx.lookup_adt_def(parent_id).variants; - assert_eq!(ast_vs.len(), ty_vs.len()); - for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) { - if ty_v.did == fn_id { my_id = ast_v.node.data.id(); } - ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.data.id())); - ccx.external_srcs().borrow_mut().insert(ast_v.node.data.id(), ty_v.did); - } - } - hir::ItemStruct(ref struct_def, _) => { - if struct_def.is_struct() { - bug!("instantiate_inline: called on a \ - non-tuple struct") - } else { - ccx.external().borrow_mut().insert(fn_id, Some(struct_def.id())); - ccx.external_srcs().borrow_mut().insert(struct_def.id(), fn_id); - my_id = struct_def.id(); - } - } - _ => bug!("instantiate_inline: item has a \ - non-enum, non-struct parent") - } - my_id - } - FoundAst::Found(&InlinedItem::TraitItem(_, ref trait_item)) => { - ccx.external().borrow_mut().insert(fn_id, Some(trait_item.id)); - ccx.external_srcs().borrow_mut().insert(trait_item.id, fn_id); - - ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1); - - // Associated consts already have to be evaluated in `typeck`, so - // the logic to do that already exists in `middle`. In order to - // reuse that code, it needs to be able to look up the traits for - // inlined items. - let ty_trait_item = tcx.impl_or_trait_item(fn_id).clone(); - let trait_item_def_id = tcx.map.local_def_id(trait_item.id); - tcx.impl_or_trait_items.borrow_mut() - .insert(trait_item_def_id, ty_trait_item); - - // If this is a default method, we can't look up the - // impl type. But we aren't going to translate anyways, so - // don't. - trait_item.id - } - FoundAst::Found(&InlinedItem::ImplItem(_, ref impl_item)) => { - ccx.external().borrow_mut().insert(fn_id, Some(impl_item.id)); - ccx.external_srcs().borrow_mut().insert(impl_item.id, fn_id); - - ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1); - - impl_item.id - } - }; - - let inline_def_id = tcx.map.local_def_id(inline_id); - Some(inline_def_id) + tcx.sess + .cstore + .maybe_get_item_ast(tcx, fn_id) + .map(|(_, inline_id)| { + tcx.map.local_def_id(inline_id) + }) } pub fn get_local_instance(ccx: &CrateContext, fn_id: DefId) diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index a721361fce0e..2f27aed065d8 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -19,7 +19,6 @@ use rustc::ty::subst; use rustc::ty::subst::FnSpace; use abi::{Abi, FnType}; use adt; -use attributes; use base::*; use build::*; use callee::{self, Callee}; @@ -37,13 +36,13 @@ use machine; use type_::Type; use rustc::ty::{self, Ty}; use Disr; -use rustc::ty::subst::Substs; use rustc::hir; use syntax::ast; use syntax::ptr::P; use syntax::parse::token; use rustc::session::Session; +use rustc_const_eval::fatal_const_eval_err; use syntax_pos::{Span, DUMMY_SP}; use std::cmp::Ordering; @@ -641,28 +640,30 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, // This requires that atomic intrinsics follow a specific naming pattern: // "atomic_[_]", and no ordering means SeqCst (_, name) if name.starts_with("atomic_") => { + use llvm::AtomicOrdering::*; + let split: Vec<&str> = name.split('_').collect(); let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; let (order, failorder) = match split.len() { - 2 => (llvm::SequentiallyConsistent, llvm::SequentiallyConsistent), + 2 => (SequentiallyConsistent, SequentiallyConsistent), 3 => match split[2] { - "unordered" => (llvm::Unordered, llvm::Unordered), - "relaxed" => (llvm::Monotonic, llvm::Monotonic), - "acq" => (llvm::Acquire, llvm::Acquire), - "rel" => (llvm::Release, llvm::Monotonic), - "acqrel" => (llvm::AcquireRelease, llvm::Acquire), + "unordered" => (Unordered, Unordered), + "relaxed" => (Monotonic, Monotonic), + "acq" => (Acquire, Acquire), + "rel" => (Release, Monotonic), + "acqrel" => (AcquireRelease, Acquire), "failrelaxed" if is_cxchg => - (llvm::SequentiallyConsistent, llvm::Monotonic), + (SequentiallyConsistent, Monotonic), "failacq" if is_cxchg => - (llvm::SequentiallyConsistent, llvm::Acquire), + (SequentiallyConsistent, Acquire), _ => ccx.sess().fatal("unknown ordering in atomic intrinsic") }, 4 => match (split[2], split[3]) { ("acq", "failrelaxed") if is_cxchg => - (llvm::Acquire, llvm::Monotonic), + (Acquire, Monotonic), ("acqrel", "failrelaxed") if is_cxchg => - (llvm::AcquireRelease, llvm::Monotonic), + (AcquireRelease, Monotonic), _ => ccx.sess().fatal("unknown ordering in atomic intrinsic") }, _ => ccx.sess().fatal("Atomic intrinsic not in correct format"), @@ -715,12 +716,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } "fence" => { - AtomicFence(bcx, order, llvm::CrossThread); + AtomicFence(bcx, order, llvm::SynchronizationScope::CrossThread); C_nil(ccx) } "singlethreadfence" => { - AtomicFence(bcx, order, llvm::SingleThread); + AtomicFence(bcx, order, llvm::SynchronizationScope::SingleThread); C_nil(ccx) } @@ -1172,7 +1173,6 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, dloc: DebugLoc) -> Block<'blk, 'tcx> { let llfn = get_rust_try_fn(bcx.fcx, &mut |bcx| { let ccx = bcx.ccx(); - let tcx = ccx.tcx(); let dloc = DebugLoc::None; // Translates the shims described above: @@ -1192,14 +1192,6 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // expected to be `*mut *mut u8` for this to actually work, but that's // managed by the standard library. - attributes::emit_uwtable(bcx.fcx.llfn, true); - let catch_pers = match tcx.lang_items.eh_personality_catch() { - Some(did) => { - Callee::def(ccx, did, tcx.mk_substs(Substs::empty())).reify(ccx).val - } - None => bug!("eh_personality_catch not defined"), - }; - let then = bcx.fcx.new_temp_block("then"); let catch = bcx.fcx.new_temp_block("catch"); @@ -1217,7 +1209,7 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // rust_try ignores the selector. let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false); - let vals = LandingPad(catch, lpad_ty, catch_pers, 1); + let vals = LandingPad(catch, lpad_ty, bcx.fcx.eh_personality(), 1); AddClause(catch, vals, C_null(Type::i8p(ccx))); let ptr = ExtractValue(catch, vals, 0); Store(catch, ptr, BitCast(catch, local_ptr, Type::i8p(ccx).ptr_to())); @@ -1408,7 +1400,10 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> // this should probably help simd error reporting consts::TrueConst::Yes) { Ok((vector, _)) => vector, - Err(err) => bcx.sess().span_fatal(span, &err.description()), + Err(err) => { + fatal_const_eval_err(bcx.tcx(), err.as_inner(), span, + "shuffle indices"); + } } } None => llargs[2] diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index fa0a1fdc3752..81a1dbeb7fe7 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -37,6 +37,8 @@ #![feature(unicode)] #![feature(question_mark)] +use rustc::dep_graph::WorkProduct; + extern crate arena; extern crate flate; extern crate getopts; @@ -86,6 +88,7 @@ mod macros; mod abi; mod adt; mod asm; +mod assert_module_sources; mod attributes; mod base; mod basic_block; @@ -132,7 +135,27 @@ mod value; #[derive(Clone)] pub struct ModuleTranslation { + /// The name of the module. When the crate may be saved between + /// compilations, incremental compilation requires that name be + /// unique amongst **all** crates. Therefore, it should contain + /// something unique to this crate (e.g., a module path) as well + /// as the crate name and disambiguator. pub name: String, + pub symbol_name_hash: u64, + pub source: ModuleSource, +} + +#[derive(Clone)] +pub enum ModuleSource { + /// Copy the `.o` files or whatever from the incr. comp. directory. + Preexisting(WorkProduct), + + /// Rebuild from this LLVM module. + Translated(ModuleLlvm), +} + +#[derive(Copy, Clone)] +pub struct ModuleLlvm { pub llcx: llvm::ContextRef, pub llmod: llvm::ModuleRef, } diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 7a7f1901736c..9bfdb511c623 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -261,7 +261,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => { let cond = self.trans_operand(&bcx, cond).immediate(); - let const_cond = common::const_to_opt_uint(cond).map(|c| c == 1); + let mut const_cond = common::const_to_opt_uint(cond).map(|c| c == 1); + + // This case can currently arise only from functions marked + // with #[rustc_inherit_overflow_checks] and inlined from + // another crate (mostly core::num generic/#[inline] fns), + // while the current crate doesn't use overflow checks. + // NOTE: Unlike binops, negation doesn't have its own + // checked operation, just a comparison with the minimum + // value, so we have to check for the assert message. + if !bcx.ccx().check_overflow() { + use rustc_const_math::ConstMathErr::Overflow; + use rustc_const_math::Op::Neg; + + if let mir::AssertMessage::Math(Overflow(Neg)) = *msg { + const_cond = Some(expected); + } + } // Don't translate the panic block if success if known. if const_cond == Some(expected) { @@ -284,6 +300,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // After this point, bcx is the block for the call to panic. bcx = panic_block.build(); + debug_loc.apply_to_bcx(&bcx); // Get the location information. let loc = bcx.sess().codemap().lookup_char_pos(span.lo); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index da72793abf6d..00db19d2739c 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -530,26 +530,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { // FIXME Shouldn't need to manually trigger closure instantiations. if let mir::AggregateKind::Closure(def_id, substs) = *kind { - use rustc::hir; - use syntax::ast::DUMMY_NODE_ID; - use syntax::ptr::P; use closure; - - closure::trans_closure_expr(closure::Dest::Ignore(self.ccx), - &hir::FnDecl { - inputs: P::new(), - output: hir::NoReturn(DUMMY_SP), - variadic: false - }, - &hir::Block { - stmts: P::new(), - expr: None, - id: DUMMY_NODE_ID, - rules: hir::DefaultBlock, - span: DUMMY_SP - }, - DUMMY_NODE_ID, def_id, - self.monomorphize(&substs)); + closure::trans_closure_body_via_mir(self.ccx, + def_id, + self.monomorphize(&substs)); } let val = if let mir::AggregateKind::Adt(adt_def, index, _) = *kind { @@ -840,11 +824,11 @@ pub fn const_scalar_binop(op: mir::BinOp, mir::BinOp::Gt | mir::BinOp::Ge => { if is_float { let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop()); - llvm::ConstFCmp(cmp, lhs, rhs) + llvm::LLVMConstFCmp(cmp, lhs, rhs) } else { let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(), signed); - llvm::ConstICmp(cmp, lhs, rhs) + llvm::LLVMConstICmp(cmp, lhs, rhs) } } } @@ -925,7 +909,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } Err(ConstEvalFailure::Runtime(err)) => { span_bug!(constant.span, - "MIR constant {:?} results in runtime panic: {}", + "MIR constant {:?} results in runtime panic: {:?}", constant, err.description()) } } diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 0221232a77df..8f723d288c9e 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -324,8 +324,8 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, machine::llelement_offset(bcx.ccx(), lltuplety, i); let ops = unsafe { - [llvm::LLVMDIBuilderCreateOpDeref(), - llvm::LLVMDIBuilderCreateOpPlus(), + [llvm::LLVMRustDIBuilderCreateOpDeref(), + llvm::LLVMRustDIBuilderCreateOpPlus(), byte_offset_of_var_in_tuple as i64] }; @@ -450,10 +450,10 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, machine::llelement_offset(bcx.ccx(), llclosurety, i); let ops = unsafe { - [llvm::LLVMDIBuilderCreateOpDeref(), - llvm::LLVMDIBuilderCreateOpPlus(), + [llvm::LLVMRustDIBuilderCreateOpDeref(), + llvm::LLVMRustDIBuilderCreateOpPlus(), byte_offset_of_var_in_env as i64, - llvm::LLVMDIBuilderCreateOpDeref()] + llvm::LLVMRustDIBuilderCreateOpDeref()] }; // The environment and the capture can each be indirect. diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index c3f2c4f2c8bf..97d65ce9c536 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -131,27 +131,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { _ => { // FIXME Shouldn't need to manually trigger closure instantiations. if let mir::AggregateKind::Closure(def_id, substs) = *kind { - use rustc::hir; - use syntax::ast::DUMMY_NODE_ID; - use syntax::ptr::P; - use syntax_pos::DUMMY_SP; use closure; - closure::trans_closure_expr(closure::Dest::Ignore(bcx.ccx()), - &hir::FnDecl { - inputs: P::new(), - output: hir::NoReturn(DUMMY_SP), - variadic: false - }, - &hir::Block { - stmts: P::new(), - expr: None, - id: DUMMY_NODE_ID, - rules: hir::DefaultBlock, - span: DUMMY_SP - }, - DUMMY_NODE_ID, def_id, - bcx.monomorphize(&substs)); + closure::trans_closure_body_via_mir(bcx.ccx(), + def_id, + bcx.monomorphize(&substs)); } for (i, operand) in operands.iter().enumerate() { @@ -260,18 +244,46 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } } - mir::CastKind::Misc if common::type_is_immediate(bcx.ccx(), operand.ty) => { + mir::CastKind::Misc if common::type_is_fat_ptr(bcx.tcx(), operand.ty) => { + let ll_cast_ty = type_of::immediate_type_of(bcx.ccx(), cast_ty); + let ll_from_ty = type_of::immediate_type_of(bcx.ccx(), operand.ty); + if let OperandValue::Pair(data_ptr, meta_ptr) = operand.val { + if common::type_is_fat_ptr(bcx.tcx(), cast_ty) { + let ll_cft = ll_cast_ty.field_types(); + let ll_fft = ll_from_ty.field_types(); + let data_cast = bcx.pointercast(data_ptr, ll_cft[0]); + assert_eq!(ll_cft[1].kind(), ll_fft[1].kind()); + OperandValue::Pair(data_cast, meta_ptr) + } else { // cast to thin-ptr + // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and + // pointer-cast of that pointer to desired pointer type. + let llval = bcx.pointercast(data_ptr, ll_cast_ty); + OperandValue::Immediate(llval) + } + } else { + bug!("Unexpected non-Pair operand") + } + } + mir::CastKind::Misc => { debug_assert!(common::type_is_immediate(bcx.ccx(), cast_ty)); let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast"); let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); let ll_t_in = type_of::immediate_type_of(bcx.ccx(), operand.ty); let ll_t_out = type_of::immediate_type_of(bcx.ccx(), cast_ty); - let llval = operand.immediate(); - let signed = if let CastTy::Int(IntTy::CEnum) = r_t_in { + let (llval, signed) = if let CastTy::Int(IntTy::CEnum) = r_t_in { let repr = adt::represent_type(bcx.ccx(), operand.ty); - adt::is_discr_signed(&repr) + let discr = match operand.val { + OperandValue::Immediate(llval) => llval, + OperandValue::Ref(llptr) => { + bcx.with_block(|bcx| { + adt::trans_get_discr(bcx, &repr, llptr, None, true) + }) + } + OperandValue::Pair(..) => bug!("Unexpected Pair operand") + }; + (discr, adt::is_discr_signed(&repr)) } else { - operand.ty.is_signed() + (operand.immediate(), operand.ty.is_signed()) }; let newval = match (r_t_in, r_t_out) { @@ -320,26 +332,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { }; OperandValue::Immediate(newval) } - mir::CastKind::Misc => { // Casts from a fat-ptr. - let ll_cast_ty = type_of::immediate_type_of(bcx.ccx(), cast_ty); - let ll_from_ty = type_of::immediate_type_of(bcx.ccx(), operand.ty); - if let OperandValue::Pair(data_ptr, meta_ptr) = operand.val { - if common::type_is_fat_ptr(bcx.tcx(), cast_ty) { - let ll_cft = ll_cast_ty.field_types(); - let ll_fft = ll_from_ty.field_types(); - let data_cast = bcx.pointercast(data_ptr, ll_cft[0]); - assert_eq!(ll_cft[1].kind(), ll_fft[1].kind()); - OperandValue::Pair(data_cast, meta_ptr) - } else { // cast to thin-ptr - // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and - // pointer-cast of that pointer to desired pointer type. - let llval = bcx.pointercast(data_ptr, ll_cast_ty); - OperandValue::Immediate(llval) - } - } else { - bug!("Unexpected non-Pair operand") - } - } }; let operand = OperandRef { val: val, diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 00c0e9110350..e9aacaa0f954 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -52,7 +52,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("leaving monomorphic fn {:?}", instance); return (val, mono_ty); } else { - assert!(!ccx.codegen_unit().items.contains_key(&TransItem::Fn(instance))); + assert!(!ccx.codegen_unit().contains_item(&TransItem::Fn(instance))); } debug!("monomorphic_fn({:?})", instance); @@ -125,7 +125,9 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if ccx.shared().translation_items().borrow().contains(&trans_item) { attributes::from_fn_attrs(ccx, attrs, lldecl); - llvm::SetLinkage(lldecl, llvm::ExternalLinkage); + unsafe { + llvm::LLVMSetLinkage(lldecl, llvm::ExternalLinkage); + } } else { // FIXME: #34151 // Normally, getting here would indicate a bug in trans::collector, diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 8073359ede87..ade6e8abeb32 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -119,12 +119,15 @@ use collector::InliningMap; use llvm; use monomorphize; +use rustc::dep_graph::{DepNode, WorkProductId}; use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER; use rustc::ty::TyCtxt; use rustc::ty::item_path::characteristic_def_id_of_type; use std::cmp::Ordering; +use std::hash::{Hash, Hasher, SipHasher}; +use std::sync::Arc; use symbol_map::SymbolMap; use syntax::ast::NodeId; use syntax::parse::token::{self, InternedString}; @@ -140,11 +143,59 @@ pub enum PartitioningStrategy { } pub struct CodegenUnit<'tcx> { - pub name: InternedString, - pub items: FnvHashMap, llvm::Linkage>, + /// A name for this CGU. Incremental compilation requires that + /// name be unique amongst **all** crates. Therefore, it should + /// contain something unique to this crate (e.g., a module path) + /// as well as the crate name and disambiguator. + name: InternedString, + + items: FnvHashMap, llvm::Linkage>, } impl<'tcx> CodegenUnit<'tcx> { + pub fn new(name: InternedString, + items: FnvHashMap, llvm::Linkage>) + -> Self { + CodegenUnit { + name: name, + items: items, + } + } + + pub fn empty(name: InternedString) -> Self { + Self::new(name, FnvHashMap()) + } + + pub fn contains_item(&self, item: &TransItem<'tcx>) -> bool { + self.items.contains_key(item) + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn items(&self) -> &FnvHashMap, llvm::Linkage> { + &self.items + } + + pub fn work_product_id(&self) -> Arc { + Arc::new(WorkProductId(self.name().to_string())) + } + + pub fn work_product_dep_node(&self) -> DepNode { + DepNode::WorkProduct(self.work_product_id()) + } + + pub fn compute_symbol_name_hash(&self, tcx: TyCtxt, symbol_map: &SymbolMap) -> u64 { + let mut state = SipHasher::new(); + let all_items = self.items_in_deterministic_order(tcx, symbol_map); + for (item, _) in all_items { + let symbol_name = symbol_map.get(item).unwrap(); + symbol_name.hash(&mut state); + } + state.finish() + } + pub fn items_in_deterministic_order(&self, tcx: TyCtxt, symbol_map: &SymbolMap) @@ -277,10 +328,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let make_codegen_unit = || { - CodegenUnit { - name: codegen_unit_name.clone(), - items: FnvHashMap(), - } + CodegenUnit::empty(codegen_unit_name.clone()) }; let mut codegen_unit = codegen_units.entry(codegen_unit_name.clone()) @@ -319,10 +367,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if codegen_units.is_empty() { let codegen_unit_name = InternedString::new(FALLBACK_CODEGEN_UNIT); codegen_units.entry(codegen_unit_name.clone()) - .or_insert_with(|| CodegenUnit { - name: codegen_unit_name.clone(), - items: FnvHashMap(), - }); + .or_insert_with(|| CodegenUnit::empty(codegen_unit_name.clone())); } PreInliningPartitioning { @@ -362,10 +407,8 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning< // we reach the target count while codegen_units.len() < target_cgu_count { let index = codegen_units.len(); - codegen_units.push(CodegenUnit { - name: numbered_codegen_unit_name(crate_name, index), - items: FnvHashMap() - }); + codegen_units.push( + CodegenUnit::empty(numbered_codegen_unit_name(crate_name, index))); } } @@ -381,10 +424,8 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit follow_inlining(*root, inlining_map, &mut reachable); } - let mut new_codegen_unit = CodegenUnit { - name: codegen_unit.name.clone(), - items: FnvHashMap(), - }; + let mut new_codegen_unit = + CodegenUnit::empty(codegen_unit.name.clone()); // Add all translation items that are not already there for trans_item in reachable { @@ -560,10 +601,9 @@ fn single_codegen_unit<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, items.insert(trans_item, linkage); } - CodegenUnit { - name: numbered_codegen_unit_name(&tcx.crate_name[..], 0), - items: items - } + CodegenUnit::new( + numbered_codegen_unit_name(&tcx.crate_name[..], 0), + items) } fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString { diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 8b8e658533ed..35bb0481c8e9 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -23,12 +23,13 @@ use glue::DropGlueKind; use llvm; use monomorphize::{self, Instance}; use inline; +use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst; -use rustc::dep_graph::DepNode; +use rustc_const_eval::fatal_const_eval_err; use std::hash::{Hash, Hasher}; use syntax::ast::{self, NodeId}; use syntax::{attr,errors}; @@ -67,27 +68,45 @@ impl<'tcx> Hash for TransItem<'tcx> { impl<'a, 'tcx> TransItem<'tcx> { pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) { - debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}", self.to_string(ccx.tcx()), self.to_raw_string(), - ccx.codegen_unit().name); + ccx.codegen_unit().name()); + + // (*) This code executes in the context of a dep-node for the + // entire CGU. In some cases, we introduce dep-nodes for + // particular items that we are translating (these nodes will + // have read edges coming into the CGU node). These smaller + // nodes are not needed for correctness -- we always + // invalidate an entire CGU at a time -- but they enable + // finer-grained testing, since you can write tests that check + // that the incoming edges to a particular fn are from a + // particular set. self.register_reads(ccx); match *self { TransItem::Static(node_id) => { + let def_id = ccx.tcx().map.local_def_id(node_id); + let _task = ccx.tcx().dep_graph.in_task(DepNode::TransCrateItem(def_id)); // (*) let item = ccx.tcx().map.expect_item(node_id); if let hir::ItemStatic(_, m, ref expr) = item.node { match consts::trans_static(&ccx, m, expr, item.id, &item.attrs) { Ok(_) => { /* Cool, everything's alright. */ }, - Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()), + Err(err) => { + // FIXME: shouldn't this be a `span_err`? + fatal_const_eval_err( + ccx.tcx(), &err, expr.span, "static"); + } }; } else { span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") } } TransItem::Fn(instance) => { + let _task = ccx.tcx().dep_graph.in_task( + DepNode::TransCrateItem(instance.def)); // (*) + base::trans_instance(&ccx, instance); } TransItem::DropGlue(dg) => { @@ -98,7 +117,7 @@ impl<'a, 'tcx> TransItem<'tcx> { debug!("END IMPLEMENTING '{} ({})' in cgu {}", self.to_string(ccx.tcx()), self.to_raw_string(), - ccx.codegen_unit().name); + ccx.codegen_unit().name()); } /// If necessary, creates a subtask for trans'ing a particular item and registers reads on @@ -147,7 +166,7 @@ impl<'a, 'tcx> TransItem<'tcx> { debug!("BEGIN PREDEFINING '{} ({})' in cgu {}", self.to_string(ccx.tcx()), self.to_raw_string(), - ccx.codegen_unit().name); + ccx.codegen_unit().name()); let symbol_name = ccx.symbol_map() .get_or_compute(ccx.shared(), *self); @@ -169,7 +188,7 @@ impl<'a, 'tcx> TransItem<'tcx> { debug!("END PREDEFINING '{} ({})' in cgu {}", self.to_string(ccx.tcx()), self.to_raw_string(), - ccx.codegen_unit().name); + ccx.codegen_unit().name()); } fn predefine_static(ccx: &CrateContext<'a, 'tcx>, @@ -189,7 +208,7 @@ impl<'a, 'tcx> TransItem<'tcx> { &format!("symbol `{}` is already defined", symbol_name)) }); - llvm::SetLinkage(g, linkage); + unsafe { llvm::LLVMSetLinkage(g, linkage) }; } item => bug!("predefine_static: expected static, found {:?}", item) @@ -231,7 +250,7 @@ impl<'a, 'tcx> TransItem<'tcx> { ref attrs, node: hir::ImplItemKind::Method(..), .. }) => { let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); - llvm::SetLinkage(lldecl, linkage); + unsafe { llvm::LLVMSetLinkage(lldecl, linkage) }; base::set_link_section(ccx, lldecl, attrs); if linkage == llvm::LinkOnceODRLinkage || linkage == llvm::WeakODRLinkage { @@ -268,7 +287,7 @@ impl<'a, 'tcx> TransItem<'tcx> { assert!(declare::get_defined_value(ccx, symbol_name).is_none()); let llfn = declare::declare_cfn(ccx, symbol_name, llfnty); - llvm::SetLinkage(llfn, linkage); + unsafe { llvm::LLVMSetLinkage(llfn, linkage) }; if linkage == llvm::LinkOnceODRLinkage || linkage == llvm::WeakODRLinkage { llvm::SetUniqueComdat(ccx.llmod(), llfn); diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs index f5b9bef5313f..92a2d3787bfd 100644 --- a/src/librustc_trans/tvec.rs +++ b/src/librustc_trans/tvec.rs @@ -30,7 +30,7 @@ use value::Value; use rustc::ty::{self, Ty}; use rustc::hir; -use rustc_const_eval::eval_repeat_count; +use rustc_const_eval::eval_length; use syntax::ast; use syntax::parse::token::InternedString; @@ -218,7 +218,7 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return expr::trans_into(bcx, &element, Ignore); } SaveIn(lldest) => { - match eval_repeat_count(bcx.tcx(), &count_expr) { + match eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() { 0 => expr::trans_into(bcx, &element, Ignore), 1 => expr::trans_into(bcx, &element, SaveIn(lldest)), count => { @@ -268,7 +268,7 @@ fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize { }, hir::ExprVec(ref es) => es.len(), hir::ExprRepeat(_, ref count_expr) => { - eval_repeat_count(bcx.tcx(), &count_expr) + eval_length(bcx.tcx(), &count_expr, "repeat count").unwrap() } _ => span_bug!(content_expr.span, "unexpected vec content") } diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index 001cd197e60b..d191591e082a 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -36,7 +36,7 @@ pub struct Type { impl fmt::Debug for Type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(&llvm::build_string(|s| unsafe { - llvm::LLVMWriteTypeToString(self.to_ref(), s); + llvm::LLVMRustWriteTypeToString(self.to_ref(), s); }).expect("non-UTF8 type description from LLVM")) } } @@ -72,7 +72,7 @@ impl Type { } pub fn metadata(ccx: &CrateContext) -> Type { - ty!(llvm::LLVMMetadataTypeInContext(ccx.llcx())) + ty!(llvm::LLVMRustMetadataTypeInContext(ccx.llcx())) } pub fn i1(ccx: &CrateContext) -> Type { @@ -208,7 +208,7 @@ impl Type { pub fn kind(&self) -> TypeKind { unsafe { - llvm::LLVMGetTypeKind(self.to_ref()) + llvm::LLVMRustGetTypeKind(self.to_ref()) } } diff --git a/src/librustc_trans/value.rs b/src/librustc_trans/value.rs index 00b316cc420e..79e0c11515fc 100644 --- a/src/librustc_trans/value.rs +++ b/src/librustc_trans/value.rs @@ -23,7 +23,7 @@ pub struct Value(pub ValueRef); impl fmt::Debug for Value { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(&llvm::build_string(|s| unsafe { - llvm::LLVMWriteValueToString(self.0, s); + llvm::LLVMRustWriteValueToString(self.0, s); }).expect("nun-UTF8 value description from LLVM")) } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9ff30f9ede26..a11df5ae05d6 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -48,10 +48,7 @@ //! case but `&a` in the second. Basically, defaults that appear inside //! an rptr (`&r.T`) use the region `r` that appears in the rptr. -use middle::const_val::ConstVal; -use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr}; -use rustc_const_eval::EvalHint::UncheckedExprHint; -use rustc_const_eval::ErrKind::ErroneousReferencedConstant; +use rustc_const_eval::eval_length; use hir::{self, SelfKind}; use hir::def::{Def, PathResolution}; use hir::def_id::DefId; @@ -70,7 +67,6 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::{NodeMap, FnvHashSet}; -use rustc_const_math::ConstInt; use std::cell::RefCell; use syntax::{abi, ast}; use syntax::feature_gate::{GateIssue, emit_feature_err}; @@ -1079,8 +1075,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Ok((trait_ref, projection_bounds)) } _ => { - span_err!(self.tcx().sess, ty.span, E0172, - "expected a reference to a trait"); + struct_span_err!(self.tcx().sess, ty.span, E0172, + "expected a reference to a trait") + .span_label(ty.span, &format!("expected a trait")) + .emit(); Err(ErrorReported) } } @@ -1090,6 +1088,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { "expected a path on the left-hand side \ of `+`, not `{}`", pprust::ty_to_string(ty)); + err.span_label(ty.span, &format!("expected a path")); let hi = bounds.iter().map(|x| match *x { hir::TraitTyParamBound(ref tr, _) => tr.span.hi, hir::RegionTyParamBound(ref r) => r.span.hi, @@ -1317,6 +1316,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // item is declared. let bound = match (&ty.sty, ty_path_def) { (_, Def::SelfTy(Some(trait_did), Some(impl_id))) => { + // For Def::SelfTy() values inlined from another crate, the + // impl_id will be DUMMY_NODE_ID, which would cause problems + // here. But we should never run into an impl from another crate + // in this pass. + assert!(impl_id != ast::DUMMY_NODE_ID); + // `Self` in an impl of a trait - we have a concrete self type and a // trait reference. let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap(); @@ -1522,6 +1527,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } Def::SelfTy(_, Some(impl_id)) => { // Self in impl (we know the concrete type). + + // For Def::SelfTy() values inlined from another crate, the + // impl_id will be DUMMY_NODE_ID, which would cause problems + // here. But we should never run into an impl from another crate + // in this pass. + assert!(impl_id != ast::DUMMY_NODE_ID); + tcx.prohibit_type_params(base_segments); let ty = tcx.node_id_to_type(impl_id); if let Some(free_substs) = self.get_free_substs() { @@ -1741,33 +1753,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty } hir::TyFixedLengthVec(ref ty, ref e) => { - let hint = UncheckedExprHint(tcx.types.usize); - match eval_const_expr_partial(tcx.global_tcx(), &e, hint, None) { - Ok(ConstVal::Integral(ConstInt::Usize(i))) => { - let i = i.as_u64(tcx.sess.target.uint_type); - assert_eq!(i as usize as u64, i); - tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), i as usize) - }, - Ok(val) => { - span_err!(tcx.sess, ast_ty.span, E0249, - "expected usize value for array length, got {}", - val.description()); - self.tcx().types.err - }, - // array length errors happen before the global constant check - // so we need to report the real error - Err(ConstEvalErr { kind: ErroneousReferencedConstant(box r), ..}) | - Err(r) => { - let mut err = struct_span_err!(tcx.sess, r.span, E0250, - "array length constant \ - evaluation error: {}", - r.description()); - if !ast_ty.span.contains(r.span) { - span_note!(&mut err, ast_ty.span, "for array length here") - } - err.emit(); - self.tcx().types.err - } + if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") { + tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length) + } else { + self.tcx().types.err } } hir::TyTypeof(ref _e) => { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index e90b32cd5dfc..aae6e3ad36df 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -103,15 +103,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return; } - // Check that the types of the end-points can be unified. - let types_unify = self.require_same_types(pat.span, rhs_ty, lhs_ty, - "mismatched types in range"); - - // It's ok to return without a message as `require_same_types` prints an error. - if !types_unify { - return; - } - // Now that we know the types can be unified we find the unified type and use // it to type the entire expression. let common_type = self.resolve_type_vars_if_possible(&lhs_ty); @@ -120,6 +111,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // subtyping doesn't matter here, as the value is some kind of scalar self.demand_eqtype(pat.span, expected, lhs_ty); + self.demand_eqtype(pat.span, expected, rhs_ty); } PatKind::Binding(bm, _, ref sub) => { let typ = self.local_ty(pat.span, pat.id); diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 3c176744fca5..265422468fe2 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -54,9 +54,11 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { if self.steps.len() == tcx.sess.recursion_limit.get() { // We've reached the recursion limit, error gracefully. - span_err!(tcx.sess, self.span, E0055, + struct_span_err!(tcx.sess, self.span, E0055, "reached the recursion limit while auto-dereferencing {:?}", - self.cur_ty); + self.cur_ty) + .span_label(self.span, &format!("deref recursion limit reached")) + .emit(); return None; } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 2c7e7d284fa1..bd2c05ba66d4 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -27,33 +27,8 @@ use rustc::hir; /// to `trait_id` (this only cares about the trait, not the specific /// method that is called) pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: DefId) { - let tcx = ccx.tcx; - let did = Some(trait_id); - let li = &tcx.lang_items; - - if did == li.drop_trait() { - span_err!(tcx.sess, span, E0040, "explicit use of destructor method"); - } else if !tcx.sess.features.borrow().unboxed_closures { - // the #[feature(unboxed_closures)] feature isn't - // activated so we need to enforce the closure - // restrictions. - - let method = if did == li.fn_trait() { - "call" - } else if did == li.fn_mut_trait() { - "call_mut" - } else if did == li.fn_once_trait() { - "call_once" - } else { - return // not a closure method, everything is OK. - }; - - struct_span_err!(tcx.sess, span, E0174, - "explicit use of unboxed closure method `{}` is experimental", - method) - .help("add `#![feature(unboxed_closures)]` to the crate \ - attributes to enable") - .emit(); + if ccx.tcx.lang_items.drop_trait() == Some(trait_id) { + span_err!(ccx.tcx.sess, span, E0040, "explicit use of destructor method"); } } @@ -216,7 +191,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => { let mut err = self.type_error_struct(call_expr.span, |actual| { format!("expected function, found `{}`", actual) - }, callee_ty, None); + }, callee_ty); if let hir::ExprCall(ref expr, _) = call_expr.node { let tcx = self.tcx; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 22ac8bc56907..7a4cc09a7d50 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -149,7 +149,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { format!("casting `{}` as `{}` is invalid", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None) + }, self.expr_ty) .help(&format!("cast through {} first", match e { CastError::NeedViaPtr => "a raw pointer", CastError::NeedViaThinPtr => "a thin pointer", @@ -167,35 +167,35 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { CastError::CastToChar => { fcx.type_error_message(self.span, |actual| { format!("only `u8` can be cast as `char`, not `{}`", actual) - }, self.expr_ty, None); + }, self.expr_ty); } CastError::NonScalar => { fcx.type_error_message(self.span, |actual| { format!("non-scalar cast: `{}` as `{}`", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None); + }, self.expr_ty); } CastError::IllegalCast => { fcx.type_error_message(self.span, |actual| { format!("casting `{}` as `{}` is invalid", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None); + }, self.expr_ty); } CastError::SizedUnsizedCast => { fcx.type_error_message(self.span, |actual| { format!("cannot cast thin pointer `{}` to fat pointer `{}`", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None) + }, self.expr_ty) } CastError::DifferingKinds => { fcx.type_error_struct(self.span, |actual| { format!("casting `{}` as `{}` is invalid", actual, fcx.ty_to_string(self.cast_ty)) - }, self.expr_ty, None) + }, self.expr_ty) .note("vtable kinds may not match") .emit(); } @@ -213,7 +213,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { let tstr = fcx.ty_to_string(self.cast_ty); let mut err = fcx.type_error_struct(self.span, |actual| { format!("cast to unsized type: `{}` as `{}`", actual, tstr) - }, self.expr_ty, None); + }, self.expr_ty); match self.expr_ty.sty { ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => { let mtstr = match mt { @@ -484,4 +484,3 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span) } } - diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 35a5bc9c6096..9844377d0bd3 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -12,6 +12,7 @@ use middle::free_region::FreeRegionMap; use rustc::infer::{self, InferOk, TypeOrigin}; use rustc::ty; use rustc::traits::{self, ProjectionMode}; +use rustc::ty::error::ExpectedFound; use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace}; use syntax::ast; @@ -324,10 +325,19 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); - span_err!(tcx.sess, impl_m_span, E0053, - "method `{}` has an incompatible type for trait: {}", - trait_m.name, - terr); + + let mut diag = struct_span_err!( + tcx.sess, origin.span(), E0053, + "method `{}` has an incompatible type for trait", trait_m.name + ); + infcx.note_type_err( + &mut diag, origin, + Some(infer::ValuePairs::Types(ExpectedFound { + expected: trait_fty, + found: impl_fty + })), &terr + ); + diag.emit(); return } @@ -437,10 +447,9 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Compute skolemized form of impl and trait const tys. let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs); let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs); + let origin = TypeOrigin::Misc(impl_c_span); let err = infcx.commit_if_ok(|_| { - let origin = TypeOrigin::Misc(impl_c_span); - // There is no "body" here, so just pass dummy id. let impl_ty = assoc::normalize_associated_types_in(&infcx, @@ -473,11 +482,19 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}", impl_ty, trait_ty); - span_err!(tcx.sess, impl_c_span, E0326, - "implemented const `{}` has an incompatible type for \ - trait: {}", - trait_c.name, - terr); + let mut diag = struct_span_err!( + tcx.sess, origin.span(), E0326, + "implemented const `{}` has an incompatible type for trait", + trait_c.name + ); + infcx.note_type_err( + &mut diag, origin, + Some(infer::ValuePairs::Types(ExpectedFound { + expected: trait_ty, + found: impl_ty + })), &terr + ); + diag.emit(); } }); } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index eeebd6a7f626..1f3a83ebc1d5 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -33,7 +33,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - let origin = TypeOrigin::Misc(sp); + self.demand_eqtype_with_origin(TypeOrigin::Misc(sp), expected, actual); + } + + pub fn demand_eqtype_with_origin(&self, + origin: TypeOrigin, + expected: Ty<'tcx>, + actual: Ty<'tcx>) + { match self.eq_types(false, origin, actual, expected) { Ok(InferOk { obligations, .. }) => { // FIXME(#32730) propagate obligations @@ -54,16 +61,4 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.report_mismatched_types(origin, expected, expr_ty, e); } } - - pub fn require_same_types(&self, span: Span, t1: Ty<'tcx>, t2: Ty<'tcx>, msg: &str) - -> bool { - if let Err(err) = self.eq_types(false, TypeOrigin::Misc(span), t1, t2) { - let found_ty = self.resolve_type_vars_if_possible(&t1); - let expected_ty = self.resolve_type_vars_if_possible(&t2); - ::emit_type_err(self.tcx, span, found_ty, expected_ty, &err, msg); - false - } else { - true - } - } } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 5a3268e9e447..8a53c59b4c7f 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -12,6 +12,7 @@ //! intrinsics that the compiler exposes. use intrinsics; +use rustc::infer::TypeOrigin; use rustc::ty::subst::{self, Substs}; use rustc::ty::FnSig; use rustc::ty::{self, Ty}; @@ -56,10 +57,9 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, i_n_tps, n_tps); } else { require_same_types(ccx, - it.span, + TypeOrigin::IntrinsicType(it.span), i_ty.ty, - fty, - "intrinsic has wrong type"); + fty); } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f20dcdc35aea..346449d0a513 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -160,8 +160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { item_name, actual) }, - rcvr_ty, - None); + rcvr_ty); // If the item has the name of a field, give a help note if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fc1d2236f3fe..97788c9fb339 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -126,7 +126,7 @@ use rustc::hir::intravisit::{self, Visitor}; use rustc::hir::{self, PatKind}; use rustc::hir::print as pprust; use rustc_back::slice; -use rustc_const_eval::eval_repeat_count; +use rustc_const_eval::eval_length; mod assoc; mod autoderef; @@ -2384,6 +2384,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { arg_count, if arg_count == 1 {" was"} else {"s were"}), error_code); + + err.span_label(sp, &format!("expected {}{} parameter{}", + if variadic {"at least "} else {""}, + expected_count, + if expected_count == 1 {""} else {"s"})); + let input_types = fn_inputs.iter().map(|i| format!("{:?}", i)).collect::>(); if input_types.len() > 0 { err.note(&format!("the following parameter type{} expected: {}", @@ -2541,21 +2547,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.type_error_message(arg.span, |t| { format!("can't pass an `{}` to variadic \ function, cast to `c_double`", t) - }, arg_ty, None); + }, arg_ty); } ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => { self.type_error_message(arg.span, |t| { format!("can't pass `{}` to variadic \ function, cast to `c_int`", t) - }, arg_ty, None); + }, arg_ty); } ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => { self.type_error_message(arg.span, |t| { format!("can't pass `{}` to variadic \ function, cast to `c_uint`", t) - }, arg_ty, None); + }, arg_ty); } ty::TyFnDef(_, _, f) => { let ptr_ty = self.tcx.mk_fn_ptr(f); @@ -2564,7 +2570,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { |t| { format!("can't pass `{}` to variadic \ function, cast to `{}`", t, ptr_ty) - }, arg_ty, None); + }, arg_ty); } _ => {} } @@ -2908,9 +2914,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.type_error_struct(field.span, |actual| { format!("attempted to take value of method `{}` on type \ `{}`", field.node, actual) - }, expr_t, None) - .help( - "maybe a `()` to call it is missing? \ + }, expr_t) + .help("maybe a `()` to call it is missing? \ If not, try an anonymous function") .emit(); self.write_error(expr.id); @@ -2919,7 +2924,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { format!("attempted access of field `{}` on type `{}`, \ but no field with that name was found", field.node, actual) - }, expr_t, None); + }, expr_t); if let ty::TyStruct(def, _) = expr_t.sty { Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]); } @@ -3019,7 +3024,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { actual) } }, - expr_t, None); + expr_t); self.write_error(expr.id); } @@ -3029,17 +3034,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { variant: ty::VariantDef<'tcx>, field: &hir::Field, skip_fields: &[hir::Field]) { - let mut err = self.type_error_struct( + let mut err = self.type_error_struct_with_diag( field.name.span, |actual| if let ty::TyEnum(..) = ty.sty { - format!("struct variant `{}::{}` has no field named `{}`", - actual, variant.name.as_str(), field.name.node) + struct_span_err!(self.tcx.sess, field.name.span, E0559, + "struct variant `{}::{}` has no field named `{}`", + actual, variant.name.as_str(), field.name.node) } else { - format!("structure `{}` has no field named `{}`", - actual, field.name.node) + struct_span_err!(self.tcx.sess, field.name.span, E0560, + "structure `{}` has no field named `{}`", + actual, field.name.node) }, - ty, - None); + ty); // prevent all specified fields from being suggested let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str()); Self::suggest_field_names(&mut err, variant, &field.name, skip_fields.collect()); @@ -3063,6 +3069,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { remaining_fields.insert(field.name, field); } + let mut seen_fields = FnvHashMap(); + let mut error_happened = false; // Typecheck each field. @@ -3071,13 +3079,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(v_field) = remaining_fields.remove(&field.name.node) { expected_field_type = self.field_ty(field.span, v_field, substs); + + seen_fields.insert(field.name.node, field.span); } else { error_happened = true; expected_field_type = tcx.types.err; if let Some(_) = variant.find_field_named(field.name.node) { - span_err!(self.tcx.sess, field.name.span, E0062, - "field `{}` specified more than once", - field.name.node); + let mut err = struct_span_err!(self.tcx.sess, + field.name.span, + E0062, + "field `{}` specified more than once", + field.name.node); + + err.span_label(field.name.span, &format!("used more than once")); + + if let Some(prev_span) = seen_fields.get(&field.name.node) { + err.span_label(*prev_span, &format!("first use of `{}`", field.name.node)); + } + + err.emit(); } else { self.report_unknown_field(adt_ty, variant, field, ast_fields); } @@ -3147,9 +3167,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if variant.is_none() || variant.unwrap().kind == ty::VariantKind::Tuple { // Reject tuple structs for now, braced and unit structs are allowed. - span_err!(self.tcx.sess, span, E0071, - "`{}` does not name a struct or a struct variant", - pprust::path_to_string(path)); + struct_span_err!(self.tcx.sess, path.span, E0071, + "`{}` does not name a struct or a struct variant", + pprust::path_to_string(path)) + .span_label(path.span, &format!("not a struct")) + .emit(); + return None; } @@ -3272,7 +3295,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.type_error_message(expr.span, |actual| { format!("type `{}` cannot be \ dereferenced", actual) - }, oprnd_t, None); + }, oprnd_t); oprnd_t = tcx.types.err; } } @@ -3541,7 +3564,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprRepeat(ref element, ref count_expr) => { self.check_expr_has_type(&count_expr, tcx.types.usize); - let count = eval_repeat_count(self.tcx.global_tcx(), &count_expr); + let count = eval_length(self.tcx.global_tcx(), &count_expr, "repeat count") + .unwrap_or(0); let uty = match expected { ExpectHasType(uty) => { @@ -3647,8 +3671,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { format!("cannot index a value of type `{}`", actual) }, - base_t, - None); + base_t); // Try to give some advice about indexing tuples. if let ty::TyTuple(_) = base_t.sty { let mut needs_note = true; @@ -4523,7 +4546,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !self.is_tainted_by_errors() { self.type_error_message(sp, |_actual| { "the type of this value must be known in this context".to_string() - }, ty, None); + }, ty); } self.demand_suptype(sp, self.tcx.types.err, ty); ty = self.tcx.types.err; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 8604dadf46df..63487683ec3b 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -176,11 +176,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // error types are considered "builtin" if !lhs_ty.references_error() { if let IsAssign::Yes = is_assign { - span_err!(self.tcx.sess, lhs_expr.span, E0368, - "binary assignment operation `{}=` \ - cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty); + struct_span_err!(self.tcx.sess, lhs_expr.span, E0368, + "binary assignment operation `{}=` \ + cannot be applied to type `{}`", + op.node.as_str(), + lhs_ty) + .span_label(lhs_expr.span, + &format!("cannot use `{}=` on type `{}`", + op.node.as_str(), lhs_ty)) + .emit(); } else { let mut err = struct_span_err!(self.tcx.sess, lhs_expr.span, E0369, "binary operation `{}` cannot be applied to type `{}`", @@ -239,7 +243,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.type_error_message(ex.span, |actual| { format!("cannot apply unary operator `{}` to type `{}`", op_str, actual) - }, operand_ty, None); + }, operand_ty); self.tcx.types.err } } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 702dd5f8de58..030491b521d9 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -47,11 +47,11 @@ use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; use rustc::ty::{self, Ty}; use rustc::infer::UpvarRegion; -use std::collections::HashSet; use syntax::ast; use syntax_pos::Span; use rustc::hir; use rustc::hir::intravisit::{self, Visitor}; +use rustc::util::nodemap::NodeMap; /////////////////////////////////////////////////////////////////////////// // PUBLIC ENTRY POINTS @@ -60,9 +60,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn closure_analyze_fn(&self, body: &hir::Block) { let mut seed = SeedBorrowKind::new(self); seed.visit_block(body); - let closures_with_inferred_kinds = seed.closures_with_inferred_kinds; - let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds); + let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds); adjust.visit_block(body); // it's our job to process these. @@ -72,9 +71,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn closure_analyze_const(&self, body: &hir::Expr) { let mut seed = SeedBorrowKind::new(self); seed.visit_expr(body); - let closures_with_inferred_kinds = seed.closures_with_inferred_kinds; - let mut adjust = AdjustBorrowKind::new(self, &closures_with_inferred_kinds); + let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds); adjust.visit_expr(body); // it's our job to process these. @@ -87,7 +85,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - closures_with_inferred_kinds: HashSet, + temp_closure_kinds: NodeMap, } impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'gcx, 'tcx> { @@ -106,7 +104,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>) -> SeedBorrowKind<'a, 'gcx, 'tcx> { - SeedBorrowKind { fcx: fcx, closures_with_inferred_kinds: HashSet::new() } + SeedBorrowKind { fcx: fcx, temp_closure_kinds: NodeMap() } } fn check_closure(&mut self, @@ -116,11 +114,8 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { { let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id); if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) { - self.closures_with_inferred_kinds.insert(expr.id); - self.fcx.tables.borrow_mut().closure_kinds - .insert(closure_def_id, ty::ClosureKind::Fn); - debug!("check_closure: adding closure_id={:?} to closures_with_inferred_kinds", - closure_def_id); + self.temp_closure_kinds.insert(expr.id, ty::ClosureKind::Fn); + debug!("check_closure: adding closure {:?} as Fn", expr.id); } self.fcx.tcx.with_freevars(expr.id, |freevars| { @@ -154,14 +149,14 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - closures_with_inferred_kinds: &'a HashSet, + temp_closure_kinds: NodeMap, } impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - closures_with_inferred_kinds: &'a HashSet) + temp_closure_kinds: NodeMap) -> AdjustBorrowKind<'a, 'gcx, 'tcx> { - AdjustBorrowKind { fcx: fcx, closures_with_inferred_kinds: closures_with_inferred_kinds } + AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds } } fn analyze_closure(&mut self, @@ -176,7 +171,12 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id); { - let mut euv = euv::ExprUseVisitor::new(self, self.fcx); + let mut euv = + euv::ExprUseVisitor::with_options(self, + self.fcx, + mc::MemCategorizationOptions { + during_closure_kind_inference: true + }); euv.walk_fn(decl, body); } @@ -211,10 +211,14 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty); } - // Now we must process and remove any deferred resolutions, - // since we have a concrete closure kind. + // If we are also inferred the closure kind here, update the + // main table and process any deferred resolutions. let closure_def_id = self.fcx.tcx.map.local_def_id(id); - if self.closures_with_inferred_kinds.contains(&id) { + if let Some(&kind) = self.temp_closure_kinds.get(&id) { + self.fcx.tables.borrow_mut().closure_kinds + .insert(closure_def_id, kind); + debug!("closure_kind({:?}) = {:?}", closure_def_id, kind); + let mut deferred_call_resolutions = self.fcx.remove_deferred_call_resolutions(closure_def_id); for deferred_call_resolution in &mut deferred_call_resolutions { @@ -259,7 +263,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { }) } - fn adjust_upvar_borrow_kind_for_consume(&self, + fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) { @@ -350,7 +354,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } } - fn adjust_upvar_borrow_kind_for_unique(&self, cmt: mc::cmt<'tcx>) { + fn adjust_upvar_borrow_kind_for_unique(&mut self, cmt: mc::cmt<'tcx>) { debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})", cmt); @@ -381,7 +385,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } } - fn try_adjust_upvar_deref(&self, + fn try_adjust_upvar_deref(&mut self, note: &mc::Note, borrow_kind: ty::BorrowKind) -> bool @@ -430,7 +434,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { /// moving from left to right as needed (but never right to left). /// Here the argument `mutbl` is the borrow_kind that is required by /// some particular use. - fn adjust_upvar_borrow_kind(&self, + fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, upvar_capture: &mut ty::UpvarCapture, kind: ty::BorrowKind) { @@ -460,36 +464,30 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } } - fn adjust_closure_kind(&self, + fn adjust_closure_kind(&mut self, closure_id: ast::NodeId, new_kind: ty::ClosureKind) { debug!("adjust_closure_kind(closure_id={}, new_kind={:?})", closure_id, new_kind); - if !self.closures_with_inferred_kinds.contains(&closure_id) { - return; - } + if let Some(&existing_kind) = self.temp_closure_kinds.get(&closure_id) { + debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", + closure_id, existing_kind, new_kind); - let closure_def_id = self.fcx.tcx.map.local_def_id(closure_id); - let closure_kinds = &mut self.fcx.tables.borrow_mut().closure_kinds; - let existing_kind = *closure_kinds.get(&closure_def_id).unwrap(); + match (existing_kind, new_kind) { + (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | + (ty::ClosureKind::FnOnce, _) => { + // no change needed + } - debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", - closure_id, existing_kind, new_kind); - - match (existing_kind, new_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, _) => { - // no change needed - } - - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) | - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // new kind is stronger than the old kind - closure_kinds.insert(closure_def_id, new_kind); + (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) | + (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | + (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { + // new kind is stronger than the old kind + self.temp_closure_kinds.insert(closure_id, new_kind); + } } } } @@ -503,7 +501,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'gcx, 'tcx> { span: Span, id: ast::NodeId) { - intravisit::walk_fn(self, fn_kind, decl, body, span); + intravisit::walk_fn(self, fn_kind, decl, body, span, id); self.analyze_closure(id, span, decl, body); } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index d101381e2565..34a91b22981e 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -13,6 +13,7 @@ use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; use hir::def_id::DefId; use middle::region::{CodeExtent}; +use rustc::infer::TypeOrigin; use rustc::ty::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; @@ -157,7 +158,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } - fn check_trait_or_impl_item(&mut self, item_id: ast::NodeId, span: Span) { + fn check_trait_or_impl_item(&mut self, + item_id: ast::NodeId, + span: Span, + sig_if_method: Option<&hir::MethodSig>) { let code = self.code.clone(); self.for_id(item_id, span).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; @@ -182,7 +186,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates); this.check_fn_or_method(fcx, span, &method_ty, &predicates, free_id_outlive, &mut implied_bounds); - this.check_method_receiver(fcx, span, &method, + let sig_if_method = sig_if_method.expect("bad signature for method"); + this.check_method_receiver(fcx, sig_if_method, &method, free_id_outlive, self_ty); } ty::TypeTraitItem(assoc_type) => { @@ -405,20 +410,15 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { fn check_method_receiver<'fcx, 'tcx>(&mut self, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, - span: Span, + method_sig: &hir::MethodSig, method: &ty::Method<'tcx>, free_id_outlive: CodeExtent, self_ty: ty::Ty<'tcx>) { // check that the type of the method's receiver matches the // method's first parameter. - - let free_substs = &fcx.parameter_environment.free_substs; - let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty); - let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig); - - debug!("check_method_receiver({:?},cat={:?},self_ty={:?},sig={:?})", - method.name, method.explicit_self, self_ty, sig); + debug!("check_method_receiver({:?},cat={:?},self_ty={:?})", + method.name, method.explicit_self, self_ty); let rcvr_ty = match method.explicit_self { ty::ExplicitSelfCategory::Static => return, @@ -431,20 +431,34 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } ty::ExplicitSelfCategory::ByBox => fcx.tcx.mk_box(self_ty) }; + + let span = method_sig.decl.inputs[0].pat.span; + + let free_substs = &fcx.parameter_environment.free_substs; + let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty); + let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig); + + debug!("check_method_receiver: sig={:?}", sig); + let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty); let rcvr_ty = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(rcvr_ty)); debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty); - fcx.require_same_types(span, sig.inputs[0], rcvr_ty, - "mismatched method receiver"); + let origin = TypeOrigin::MethodReceiver(span); + fcx.demand_eqtype_with_origin(origin, rcvr_ty, sig.inputs[0]); } fn check_variances_for_type_defn(&self, item: &hir::Item, ast_generics: &hir::Generics) { + let ty = self.tcx().node_id_to_type(item.id); + if self.tcx().has_error_field(ty) { + return; + } + let item_def_id = self.tcx().map.local_def_id(item.id); let ty_predicates = self.tcx().lookup_predicates(item_def_id); let variances = self.tcx().item_variances(item_def_id); @@ -553,13 +567,21 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) { debug!("visit_trait_item: {:?}", trait_item); - self.check_trait_or_impl_item(trait_item.id, trait_item.span); + let method_sig = match trait_item.node { + hir::TraitItem_::MethodTraitItem(ref sig, _) => Some(sig), + _ => None + }; + self.check_trait_or_impl_item(trait_item.id, trait_item.span, method_sig); intravisit::walk_trait_item(self, trait_item) } fn visit_impl_item(&mut self, impl_item: &'v hir::ImplItem) { debug!("visit_impl_item: {:?}", impl_item); - self.check_trait_or_impl_item(impl_item.id, impl_item.span); + let method_sig = match impl_item.node { + hir::ImplItemKind::Method(ref sig, _) => Some(sig), + _ => None + }; + self.check_trait_or_impl_item(impl_item.id, impl_item.span, method_sig); intravisit::walk_impl_item(self, impl_item) } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 198e9afd5e12..2d14b0dacf24 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -249,8 +249,17 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_did) { match tcx.map.find(impl_node_id) { Some(hir_map::NodeItem(item)) => { - span_err!(tcx.sess, item.span, E0120, - "the Drop trait may only be implemented on structures"); + let span = match item.node { + ItemImpl(_, _, _, _, ref ty, _) => { + ty.span + }, + _ => item.span + }; + struct_span_err!(tcx.sess, span, E0120, + "the Drop trait may only be implemented on structures") + .span_label(span, + &format!("implementing Drop requires a struct")) + .emit(); } _ => { bug!("didn't find impl in ast map"); @@ -258,7 +267,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } } else { bug!("found external impl of Drop trait on \ - :omething other than a struct"); + something other than a struct"); } } } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index dcaa5cfb20a4..54bd141304d7 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -141,12 +141,18 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { self.tcx.sess, self.tcx.span_of_impl(impl_def_id).unwrap(), E0119, "conflicting implementations of trait `{}`{}:", overlap.trait_desc, - overlap.self_desc.map_or(String::new(), - |ty| format!(" for type `{}`", ty))); + overlap.self_desc.clone().map_or(String::new(), + |ty| format!(" for type `{}`", ty))); match self.tcx.span_of_impl(overlap.with_impl) { Ok(span) => { - err.span_note(span, "conflicting implementation is here:"); + err.span_label(span, + &format!("first implementation here")); + err.span_label(self.tcx.span_of_impl(impl_def_id).unwrap(), + &format!("conflicting implementation{}", + overlap.self_desc + .map_or(String::new(), + |ty| format!(" for `{}`", ty)))); } Err(cname) => { err.note(&format!("conflicting implementation in crate `{}`", diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 41e7a467fa33..cb9c0496246d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -60,14 +60,11 @@ There are some shortcomings in this design: use astconv::{AstConv, ast_region_to_region, Bounds, PartitionedBounds, partition_bounds}; use lint; -use hir::def::Def; -use hir::def_id::DefId; use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use rustc_const_eval::EvalHint::UncheckedExprHint; -use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr}; -use rustc_const_eval::ErrKind::ErroneousReferencedConstant; +use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; @@ -75,7 +72,6 @@ use rustc::ty::{VariantKind}; use rustc::ty::util::IntTypeExt; use rscope::*; use rustc::dep_graph::DepNode; -use rustc::hir::map as hir_map; use util::common::{ErrorReported, MemoizationMap}; use util::nodemap::{NodeMap, FnvHashMap}; use {CrateCtxt, write_ty_to_tcx}; @@ -92,9 +88,9 @@ use syntax::parse::token::keywords; use syntax::ptr::P; use syntax_pos::Span; -use rustc::hir::{self, PatKind}; -use rustc::hir::intravisit; -use rustc::hir::print as pprust; +use rustc::hir::{self, intravisit, map as hir_map, print as pprust}; +use rustc::hir::def::Def; +use rustc::hir::def_id::DefId; /////////////////////////////////////////////////////////////////////////// // Main entry point @@ -188,6 +184,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { let mut err = struct_span_err!(tcx.sess, span, E0391, "unsupported cyclic reference between types/traits detected"); + err.span_label(span, &format!("cyclic reference")); match cycle[0] { AstConvRequest::GetItemTypeScheme(def_id) | @@ -1014,11 +1011,12 @@ fn convert_struct_variant<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let fid = ccx.tcx.map.local_def_id(f.id); let dup_span = seen_fields.get(&f.name).cloned(); if let Some(prev_span) = dup_span { - let mut err = struct_span_err!(ccx.tcx.sess, f.span, E0124, - "field `{}` is already declared", - f.name); - span_note!(&mut err, prev_span, "previously declared here"); - err.emit(); + struct_span_err!(ccx.tcx.sess, f.span, E0124, + "field `{}` is already declared", + f.name) + .span_label(f.span, &"field already declared") + .span_label(prev_span, &format!("`{}` first declared here", f.name)) + .emit(); } else { seen_fields.insert(f.name, f.span); } @@ -1061,6 +1059,7 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let print_err = |cv: ConstVal| { struct_span_err!(ccx.tcx.sess, e.span, E0079, "mismatched types") .note_expected_found(&"type", &ty_hint, &format!("{}", cv.description())) + .span_label(e.span, &format!("expected '{}' type", ty_hint)) .emit(); }; @@ -1091,14 +1090,9 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, }, // enum variant evaluation happens before the global constant check // so we need to report the real error - Err(ConstEvalErr { kind: ErroneousReferencedConstant(box err), ..}) | Err(err) => { - let mut diag = struct_span_err!(ccx.tcx.sess, err.span, E0080, - "constant evaluation error: {}", - err.description()); - if !e.span.contains(err.span) { - diag.span_note(e.span, "for enum discriminant here"); - } + let mut diag = report_const_eval_err( + ccx.tcx, &err, e.span, "enum discriminant"); diag.emit(); None } @@ -2150,14 +2144,6 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( abi: abi::Abi) -> ty::TypeScheme<'tcx> { - for i in &decl.inputs { - match i.pat.node { - PatKind::Binding(..) | PatKind::Wild => {} - _ => span_err!(ccx.tcx.sess, i.pat.span, E0130, - "patterns aren't allowed in foreign function declarations") - } - } - let ty_generics = ty_generics_for_fn(ccx, ast_generics, &ty::Generics::empty()); let rb = BindingRscope::new(); @@ -2243,9 +2229,9 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // reachable from there, to start (if this is an inherent impl, // then just examine the self type). let mut input_parameters: HashSet<_> = - ctp::parameters_for_type(impl_scheme.ty, false).into_iter().collect(); + ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); if let Some(ref trait_ref) = impl_trait_ref { - input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref, false)); + input_parameters.extend(ctp::parameters_for(trait_ref, false)); } ctp::setup_constraining_predicates(impl_predicates.predicates.get_mut_slice(TypeSpace), @@ -2273,9 +2259,9 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); let mut input_parameters: HashSet<_> = - ctp::parameters_for_type(impl_scheme.ty, false).into_iter().collect(); + ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); if let Some(ref trait_ref) = impl_trait_ref { - input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref, false)); + input_parameters.extend(ctp::parameters_for(trait_ref, false)); } ctp::identify_constrained_type_params( &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); @@ -2286,7 +2272,7 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty, ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None }) - .flat_map(|ty| ctp::parameters_for_type(ty, true)) + .flat_map(|ty| ctp::parameters_for(&ty, true)) .filter_map(|p| match p { ctp::Parameter::Type(_) => None, ctp::Parameter::Region(r) => Some(r), diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 08c1b5fcc82c..7909584bfabd 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::ty::{self, subst, Ty}; - +use rustc::ty::{self, Ty}; +use rustc::ty::fold::{TypeFoldable, TypeVisitor}; use std::collections::HashSet; #[derive(Clone, PartialEq, Eq, Hash, Debug)] @@ -19,77 +19,53 @@ pub enum Parameter { } /// If `include_projections` is false, returns the list of parameters that are -/// constrained by the type `ty` - i.e. the value of each parameter in the list is -/// uniquely determined by `ty` (see RFC 447). If it is true, return the list +/// constrained by `t` - i.e. the value of each parameter in the list is +/// uniquely determined by `t` (see RFC 447). If it is true, return the list /// of parameters whose values are needed in order to constrain `ty` - these /// differ, with the latter being a superset, in the presence of projections. -pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>, - include_projections: bool) -> Vec { - let mut result = vec![]; - ty.maybe_walk(|t| match t.sty { - ty::TyProjection(..) if !include_projections => { +pub fn parameters_for<'tcx, T>(t: &T, + include_nonconstraining: bool) + -> Vec + where T: TypeFoldable<'tcx> +{ - false // projections are not injective. - } - _ => { - result.append(&mut parameters_for_type_shallow(t)); - // non-projection type constructors are injective. - true - } - }); - result + let mut collector = ParameterCollector { + parameters: vec![], + include_nonconstraining: include_nonconstraining + }; + t.visit_with(&mut collector); + collector.parameters } -pub fn parameters_for_trait_ref<'tcx>(trait_ref: &ty::TraitRef<'tcx>, - include_projections: bool) -> Vec { - let mut region_parameters = - parameters_for_regions_in_substs(&trait_ref.substs); - - let type_parameters = - trait_ref.substs - .types - .iter() - .flat_map(|ty| parameters_for_type(ty, include_projections)); - - region_parameters.extend(type_parameters); - - region_parameters +struct ParameterCollector { + parameters: Vec, + include_nonconstraining: bool } -fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec { - match ty.sty { - ty::TyParam(ref d) => - vec![Parameter::Type(d.clone())], - ty::TyRef(region, _) => - parameters_for_region(region).into_iter().collect(), - ty::TyStruct(_, substs) | - ty::TyEnum(_, substs) => - parameters_for_regions_in_substs(substs), - ty::TyTrait(ref data) => - parameters_for_regions_in_substs(&data.principal.skip_binder().substs), - ty::TyProjection(ref pi) => - parameters_for_regions_in_substs(&pi.trait_ref.substs), - ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) | - ty::TyFloat(..) | ty::TyBox(..) | ty::TyStr | - ty::TyArray(..) | ty::TySlice(..) | - ty::TyFnDef(..) | ty::TyFnPtr(_) | - ty::TyTuple(..) | ty::TyRawPtr(..) | - ty::TyInfer(..) | ty::TyClosure(..) | ty::TyError => - vec![] +impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.sty { + ty::TyProjection(..) if !self.include_nonconstraining => { + // projections are not injective + return false; + } + ty::TyParam(ref d) => { + self.parameters.push(Parameter::Type(d.clone())); + } + _ => {} + } + + t.super_visit_with(self) } -} -fn parameters_for_regions_in_substs(substs: &subst::Substs) -> Vec { - substs.regions - .iter() - .filter_map(|r| parameters_for_region(r)) - .collect() -} - -fn parameters_for_region(region: &ty::Region) -> Option { - match *region { - ty::ReEarlyBound(data) => Some(Parameter::Region(data)), - _ => None, + fn visit_region(&mut self, r: ty::Region) -> bool { + match r { + ty::ReEarlyBound(data) => { + self.parameters.push(Parameter::Region(data)); + } + _ => {} + } + false } } @@ -191,12 +167,12 @@ pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx> // Then the projection only applies if `T` is known, but it still // does not determine `U`. - let inputs = parameters_for_trait_ref(&projection.projection_ty.trait_ref, true); + let inputs = parameters_for(&projection.projection_ty.trait_ref, true); let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p)); if !relies_only_on_inputs { continue; } - input_parameters.extend(parameters_for_type(projection.ty, false)); + input_parameters.extend(parameters_for(&projection.ty, false)); } else { continue; } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 8769bc1a32b5..64b27857d2c6 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1079,25 +1079,6 @@ impl Foo { ``` "##, -E0080: r##" -This error indicates that the compiler was unable to sensibly evaluate an -integer expression provided as an enum discriminant. Attempting to divide by 0 -or causing integer overflow are two ways to induce this error. For example: - -```compile_fail -enum Enum { - X = (1 << 500), - Y = (1 / 0) -} -``` - -Ensure that the expressions given can be evaluated as the desired integer type. -See the FFI section of the Reference for more information about using a custom -integer type: - -https://doc.rust-lang.org/reference.html#ffi-attributes -"##, - E0081: r##" Enum discriminants are used to differentiate enum variants stored in memory. This error indicates that the same value was used for two or more variants, @@ -1819,39 +1800,6 @@ Please also verify that this wasn't because of a name-clash and rename the type parameter if so. "##, -E0130: r##" -You declared a pattern as an argument in a foreign function declaration. -Erroneous code example: - -```compile_fail -extern { - fn foo((a, b): (u32, u32)); // error: patterns aren't allowed in foreign - // function declarations -} -``` - -Please replace the pattern argument with a regular one. Example: - -``` -struct SomeStruct { - a: u32, - b: u32, -} - -extern { - fn foo(s: SomeStruct); // ok! -} -``` - -Or: - -``` -extern { - fn foo(a: (u32, u32)); // ok! -} -``` -"##, - E0131: r##" It is not possible to define `main` with type parameters, or even with function parameters. When `main` is present, it must take no arguments and return `()`. @@ -1963,89 +1911,6 @@ To learn more about traits, take a look at the Book: https://doc.rust-lang.org/book/traits.html "##, -E0174: r##" -This error occurs because of the explicit use of unboxed closure methods -that are an experimental feature in current Rust version. - -Example of erroneous code: - -```compile_fail -fn foo(mut f: F) { - f.call(("call",)); - // error: explicit use of unboxed closure method `call` - f.call_mut(("call_mut",)); - // error: explicit use of unboxed closure method `call_mut` - f.call_once(("call_once",)); - // error: explicit use of unboxed closure method `call_once` -} - -fn bar(text: &str) { - println!("Calling {} it works!", text); -} - -fn main() { - foo(bar); -} -``` - -Rust's implementation of closures is a bit different than other languages. -They are effectively syntax sugar for traits `Fn`, `FnMut` and `FnOnce`. -To understand better how the closures are implemented see here: -https://doc.rust-lang.org/book/closures.html#closure-implementation - -To fix this you can call them using parenthesis, like this: `foo()`. -When you execute the closure with parenthesis, under the hood you are executing -the method `call`, `call_mut` or `call_once`. However, using them explicitly is -currently an experimental feature. - -Example of an implicit call: - -``` -fn foo(f: F) { - f("using ()"); // Calling using () it works! -} - -fn bar(text: &str) { - println!("Calling {} it works!", text); -} - -fn main() { - foo(bar); -} -``` - -To enable the explicit calls you need to add `#![feature(unboxed_closures)]`. - -This feature is still unstable so you will also need to add -`#![feature(fn_traits)]`. -More details about this issue here: -https://github.com/rust-lang/rust/issues/29625 - -Example of use: - -``` -#![feature(fn_traits)] -#![feature(unboxed_closures)] - -fn foo(mut f: F) { - f.call(("call",)); // Calling 'call' it works! - f.call_mut(("call_mut",)); // Calling 'call_mut' it works! - f.call_once(("call_once",)); // Calling 'call_once' it works! -} - -fn bar(text: &str) { - println!("Calling '{}' it works!", text); -} - -fn main() { - foo(bar); -} -``` - -To see more about closures take a look here: -https://doc.rust-lang.org/book/closures.html` -"##, - E0178: r##" In types, the `+` type operator has low precedence, so it is often necessary to use parentheses. @@ -2660,6 +2525,7 @@ For information on the design of the orphan rules, see [RFC 1023]. [RFC 1023]: https://github.com/rust-lang/rfcs/pull/1023 "##, +/* E0211: r##" You used a function or type which doesn't fit the requirements for where it was used. Erroneous code examples: @@ -2739,6 +2605,7 @@ impl Foo { } ``` "##, + */ E0214: r##" A generic type was described using parentheses rather than angle brackets. For @@ -2968,38 +2835,6 @@ not a distinct static type. Likewise, it's not legal to attempt to behavior for specific enum variants. "##, -E0249: r##" -This error indicates a constant expression for the array length was found, but -it was not an integer (signed or unsigned) expression. - -Some examples of code that produces this error are: - -```compile_fail -const A: [u32; "hello"] = []; // error -const B: [u32; true] = []; // error -const C: [u32; 0.0] = []; // error -"##, - -E0250: r##" -There was an error while evaluating the expression for the length of a fixed- -size array type. - -Some examples of this error are: - -```compile_fail -// divide by zero in the length expression -const A: [u32; 1/0] = []; - -// Rust currently will not evaluate the function `foo` at compile time -fn foo() -> usize { 12 } -const B: [u32; foo()] = []; - -// it is an error to try to add `u8` and `f64` -use std::{f64, u8}; -const C: [u32; u8::MAX + f64::EPSILON] = []; -``` -"##, - E0318: r##" Default impls for a trait must be located in the same crate where the trait was defined. For more information see the [opt-in builtin traits RFC](https://github @@ -4029,6 +3864,155 @@ impl SpaceLlama for i32 { ``` "##, +E0527: r##" +The number of elements in an array or slice pattern differed from the number of +elements in the array being matched. + +Example of erroneous code: + +```compile_fail,E0527 +#![feature(slice_patterns)] + +let r = &[1, 2, 3, 4]; +match r { + &[a, b] => { // error: pattern requires 2 elements but array + // has 4 + println!("a={}, b={}", a, b); + } +} +``` + +Ensure that the pattern is consistent with the size of the matched +array. Additional elements can be matched with `..`: + +``` +#![feature(slice_patterns)] + +let r = &[1, 2, 3, 4]; +match r { + &[a, b, ..] => { // ok! + println!("a={}, b={}", a, b); + } +} +``` +"##, + +E0528: r##" +An array or slice pattern required more elements than were present in the +matched array. + +Example of erroneous code: + +```compile_fail,E0528 +#![feature(slice_patterns)] + +let r = &[1, 2]; +match r { + &[a, b, c, rest..] => { // error: pattern requires at least 3 + // elements but array has 2 + println!("a={}, b={}, c={} rest={:?}", a, b, c, rest); + } +} +``` + +Ensure that the matched array has at least as many elements as the pattern +requires. You can match an arbitrary number of remaining elements with `..`: + +``` +#![feature(slice_patterns)] + +let r = &[1, 2, 3, 4, 5]; +match r { + &[a, b, c, rest..] => { // ok! + // prints `a=1, b=2, c=3 rest=[4, 5]` + println!("a={}, b={}, c={} rest={:?}", a, b, c, rest); + } +} +``` +"##, + +E0529: r##" +An array or slice pattern was matched against some other type. + +Example of erroneous code: + +```compile_fail,E0529 +#![feature(slice_patterns)] + +let r: f32 = 1.0; +match r { + [a, b] => { // error: expected an array or slice, found `f32` + println!("a={}, b={}", a, b); + } +} +``` + +Ensure that the pattern and the expression being matched on are of consistent +types: + +``` +#![feature(slice_patterns)] + +let r = [1.0, 2.0]; +match r { + [a, b] => { // ok! + println!("a={}, b={}", a, b); + } +} +``` +"##, + +E0559: r##" +An unknown field was specified into an enum's structure variant. + +Erroneous code example: + +```compile_fail,E0559 +enum Field { + Fool { x: u32 }, +} + +let s = Field::Fool { joke: 0 }; +// error: struct variant `Field::Fool` has no field named `joke` +``` + +Verify you didn't misspell the field's name or that the field exists. Example: + +``` +enum Field { + Fool { joke: u32 }, +} + +let s = Field::Fool { joke: 0 }; // ok! +``` +"##, + +E0560: r##" +An unknown field was specified into a structure. + +Erroneous code example: + +```compile_fail,E0560 +struct Simba { + mother: u32, +} + +let s = Simba { mother: 1, father: 0 }; +// error: structure `Simba` has no field named `father` +``` + +Verify you didn't misspell the field's name or that the field exists. Example: + +``` +struct Simba { + mother: u32, + father: u32, +} + +let s = Simba { mother: 1, father: 0 }; // ok! +``` +"##, + } register_diagnostics! { @@ -4047,6 +4031,7 @@ register_diagnostics! { E0167, // E0168, // E0173, // manual implementations of unboxed closure traits are experimental +// E0174, E0182, E0183, // E0187, // can't infer the kind of the closure @@ -4086,6 +4071,7 @@ register_diagnostics! { E0245, // not a trait // E0246, // invalid recursive type // E0247, +// E0249, // E0319, // trait impls for defaulted traits allowed just for structs/enums E0320, // recursive overflow during dropck E0328, // cannot implement Unsize explicitly @@ -4097,8 +4083,5 @@ register_diagnostics! { E0436, // functional record update requires a struct E0513, // no type for local variable .. E0521, // redundant default implementations of trait - E0527, // expected {} elements, found {} - E0528, // expected at least {} elements, found {} - E0529, // slice pattern expects array or slice, not `{}` E0533, // `{}` does not name a unit variant, unit struct or a constant } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 84452589dfda..6f0892cdcdf1 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -186,28 +186,14 @@ fn require_c_abi_if_variadic(tcx: TyCtxt, } } -pub fn emit_type_err<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - span: Span, - found_ty: Ty<'tcx>, - expected_ty: Ty<'tcx>, - terr: &ty::error::TypeError<'tcx>, - msg: &str) { - let mut err = struct_span_err!(tcx.sess, span, E0211, "{}", msg); - err.span_label(span, &terr); - err.note_expected_found(&"type", &expected_ty, &found_ty); - tcx.note_and_explain_type_err(&mut err, terr, span); - err.emit(); -} - fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - span: Span, + origin: TypeOrigin, t1: Ty<'tcx>, - t2: Ty<'tcx>, - msg: &str) + t2: Ty<'tcx>) -> bool { ccx.tcx.infer_ctxt(None, None, ProjectionMode::AnyFinal).enter(|infcx| { - if let Err(err) = infcx.eq_types(false, TypeOrigin::Misc(span), t1, t2) { - emit_type_err(infcx.tcx, span, t1, t2, &err, msg); + if let Err(err) = infcx.eq_types(false, origin.clone(), t1, t2) { + infcx.report_mismatched_types(origin, t1, t2, err); false } else { true @@ -249,8 +235,11 @@ fn check_main_fn_ty(ccx: &CrateCtxt, }) })); - require_same_types(ccx, main_span, main_t, se_ty, - "main function has wrong type"); + require_same_types( + ccx, + TypeOrigin::MainFunctionType(main_span), + main_t, + se_ty); } _ => { span_bug!(main_span, @@ -272,8 +261,11 @@ fn check_start_fn_ty(ccx: &CrateCtxt, match it.node { hir::ItemFn(_,_,_,_,ref ps,_) if ps.is_parameterized() => { - span_err!(tcx.sess, start_span, E0132, - "start function is not allowed to have type parameters"); + struct_span_err!(tcx.sess, start_span, E0132, + "start function is not allowed to have type parameters") + .span_label(ps.span().unwrap(), + &format!("start function cannot have type parameters")) + .emit(); return; } _ => () @@ -298,8 +290,11 @@ fn check_start_fn_ty(ccx: &CrateCtxt, }), })); - require_same_types(ccx, start_span, start_t, se_ty, - "start function has wrong type"); + require_same_types( + ccx, + TypeOrigin::StartFunctionType(start_span), + start_t, + se_ty); } _ => { span_bug!(start_span, diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index 7445ff94eb50..81856cb87c7c 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -36,7 +36,7 @@ use tables::{conversions, derived_property, general_category, property}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::char::{MAX, from_digit, from_u32, from_u32_unchecked}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::char::{EncodeUtf16, EncodeUtf8, EscapeDefault, EscapeUnicode}; +pub use core::char::{EncodeUtf16, EncodeUtf8, EscapeDebug, EscapeDefault, EscapeUnicode}; // unstable reexports #[unstable(feature = "decode_utf8", issue = "33906")] @@ -267,6 +267,41 @@ impl char { C::escape_unicode(self) } + /// Returns an iterator that yields the literal escape code of a `char`. + /// + /// This will escape the characters similar to the `Debug` implementations + /// of `str` or `char`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// for i in '\n'.escape_default() { + /// println!("{}", i); + /// } + /// ``` + /// + /// This prints: + /// + /// ```text + /// \ + /// n + /// ``` + /// + /// Collecting into a `String`: + /// + /// ``` + /// let quote: String = '\n'.escape_default().collect(); + /// + /// assert_eq!(quote, "\\n"); + /// ``` + #[unstable(feature = "char_escape_debug", issue = "35068")] + #[inline] + pub fn escape_debug(self) -> EscapeDebug { + C::escape_debug(self) + } + /// Returns an iterator that yields the literal escape code of a `char`. /// /// The default is chosen with a bias toward producing literals that are @@ -392,7 +427,7 @@ impl char { C::len_utf16(self) } - /// Returns an interator over the bytes of this character as UTF-8. + /// Returns an iterator over the bytes of this character as UTF-8. /// /// The returned iterator also has an `as_slice()` method to view the /// encoded bytes as a byte slice. @@ -415,7 +450,7 @@ impl char { C::encode_utf8(self) } - /// Returns an interator over the `u16` entries of this character as UTF-16. + /// Returns an iterator over the `u16` entries of this character as UTF-16. /// /// The returned iterator also has an `as_slice()` method to view the /// encoded form as a slice. diff --git a/src/librustc_unicode/lib.rs b/src/librustc_unicode/lib.rs index f91a754ab57d..3ae905eba279 100644 --- a/src/librustc_unicode/lib.rs +++ b/src/librustc_unicode/lib.rs @@ -32,6 +32,7 @@ #![cfg_attr(not(stage0), deny(warnings))] #![no_std] +#![feature(char_escape_debug)] #![feature(core_char_ext)] #![feature(decode_utf8)] #![feature(lang_items)] diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index a41d3b0253a3..3e510bdc9002 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -28,4 +28,4 @@ log = { path = "../liblog" } [build-dependencies] build_helper = { path = "../build_helper" } -gcc = "0.3" +gcc = "0.3.27" diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0211b2c9bc7b..d609ad84a838 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -498,21 +498,20 @@ pub enum Attribute { impl Clean for ast::MetaItem { fn clean(&self, cx: &DocContext) -> Attribute { - match self.node { - ast::MetaItemKind::Word(ref s) => Word(s.to_string()), - ast::MetaItemKind::List(ref s, ref l) => { - List(s.to_string(), l.clean(cx)) - } - ast::MetaItemKind::NameValue(ref s, ref v) => { - NameValue(s.to_string(), lit_to_string(v)) - } - } + if self.is_word() { + Word(self.name().to_string()) + } else if let Some(v) = self.value_str() { + NameValue(self.name().to_string(), v.to_string()) + } else { // must be a list + let l = self.meta_item_list().unwrap(); + List(self.name().to_string(), l.clean(cx)) + } } } impl Clean for ast::Attribute { fn clean(&self, cx: &DocContext) -> Attribute { - self.with_desugared_doc(|a| a.node.value.clean(cx)) + self.with_desugared_doc(|a| a.meta().clean(cx)) } } @@ -535,6 +534,28 @@ impl attr::AttrMetaMethods for Attribute { } } fn meta_item_list<'a>(&'a self) -> Option<&'a [P]> { None } + + fn is_word(&self) -> bool { + match *self { + Word(_) => true, + _ => false, + } + } + + fn is_value_str(&self) -> bool { + match *self { + NameValue(..) => true, + _ => false, + } + } + + fn is_meta_item_list(&self) -> bool { + match *self { + List(..) => true, + _ => false, + } + } + fn span(&self) -> syntax_pos::Span { unimplemented!() } } @@ -2568,26 +2589,6 @@ impl ToSource for syntax_pos::Span { } } -fn lit_to_string(lit: &ast::Lit) -> String { - match lit.node { - ast::LitKind::Str(ref st, _) => st.to_string(), - ast::LitKind::ByteStr(ref data) => format!("{:?}", data), - ast::LitKind::Byte(b) => { - let mut res = String::from("b'"); - for c in (b as char).escape_default() { - res.push(c); - } - res.push('\''); - res - }, - ast::LitKind::Char(c) => format!("'{}'", c), - ast::LitKind::Int(i, _t) => i.to_string(), - ast::LitKind::Float(ref f, _t) => f.to_string(), - ast::LitKind::FloatUnsuffixed(ref f) => f.to_string(), - ast::LitKind::Bool(b) => b.to_string(), - } -} - fn name_from_pat(p: &hir::Pat) -> String { use rustc::hir::*; debug!("Trying to get a name from pattern: {:?}", p); @@ -2690,7 +2691,12 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { Def::Static(i, _) => (i, TypeStatic), Def::Variant(i, _) => (i, TypeEnum), Def::SelfTy(Some(def_id), _) => (def_id, TypeTrait), - Def::SelfTy(_, Some(impl_id)) => return cx.map.local_def_id(impl_id), + Def::SelfTy(_, Some(impl_id)) => { + // For Def::SelfTy() values inlined from another crate, the + // impl_id will be DUMMY_NODE_ID, which would cause problems. + // But we should never run into an impl from another crate here. + return cx.map.local_def_id(impl_id) + } _ => return def.def_id() }; if did.is_local() { return did } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 096e1ecc9ffb..6cb79d6e8630 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -233,6 +233,7 @@ impl<'a> Classifier<'a> { token::Dot | token::DotDot | token::DotDotDot | token::Comma | token::Semi | token::Colon | token::ModSep | token::LArrow | token::OpenDelim(_) | token::CloseDelim(token::Brace) | token::CloseDelim(token::Paren) | + token::CloseDelim(token::NoDelim) | token::Question => Class::None, token::Dollar => { if self.lexer.peek().tok.is_ident() { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2e2fc011ddbe..e4e886c85334 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2409,10 +2409,13 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, if structhead {"struct "} else {""}, it.name.as_ref().unwrap())?; if let Some(g) = g { - write!(w, "{}{}", *g, WhereClause(g))? + write!(w, "{}", g)? } match ty { doctree::Plain => { + if let Some(g) = g { + write!(w, "{}", WhereClause(g))? + } write!(w, " {{\n{}", tab)?; for field in fields { if let clean::StructFieldItem(ref ty) = field.inner { @@ -2445,9 +2448,17 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, _ => unreachable!() } } - write!(w, ");")?; + write!(w, ")")?; + if let Some(g) = g { + write!(w, "{}", WhereClause(g))? + } + write!(w, ";")?; } doctree::Unit => { + // Needed for PhantomData. + if let Some(g) = g { + write!(w, "{}", WhereClause(g))? + } write!(w, ";")?; } } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 303cc671f4a2..de0457592fc8 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -636,8 +636,11 @@ span.since { margin-right: 5px; } -.enum > .toggle-wrapper > .collapse-toggle, .struct > .toggle-wrapper > .collapse-toggle { +.toggle-wrapper > .collapse-toggle { left: 0; +} + +.variant + .toggle-wrapper > a { margin-top: 5px; } diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index eded6e24f3ef..3ce6841fdd4c 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -24,8 +24,9 @@ unwind = { path = "../libunwind" } [build-dependencies] build_helper = { path = "../build_helper" } -gcc = "0.3" +gcc = "0.3.27" [features] +backtrace = [] jemalloc = ["alloc_jemalloc"] debug-jemalloc = ["alloc_jemalloc/debug"] diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 9c408366f8b4..9018e48d06bd 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -25,7 +25,8 @@ fn main() { let target = env::var("TARGET").unwrap(); let host = env::var("HOST").unwrap(); - if !target.contains("apple") && !target.contains("msvc") && !target.contains("emscripten"){ + if cfg!(feature = "backtrace") && !target.contains("apple") && !target.contains("msvc") && + !target.contains("emscripten") { build_libbacktrace(&host, &target); } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 60d7e01d9881..fd7b0a2e6bbf 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -877,7 +877,7 @@ impl HashMap /// } /// /// for val in map.values() { - /// print!("{}", val); + /// println!("{}", val); /// } /// ``` #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -1336,6 +1336,10 @@ impl<'a, K, V> InternalEntry> { } /// A view into a single location in a map, which may be vacant or occupied. +/// This enum is constructed from the [`entry`] method on [`HashMap`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`entry`]: struct.HashMap.html#method.entry #[stable(feature = "rust1", since = "1.0.0")] pub enum Entry<'a, K: 'a, V: 'a> { /// An occupied Entry. @@ -1351,14 +1355,44 @@ pub enum Entry<'a, K: 'a, V: 'a> { ), } +#[stable(feature= "debug_hash_map", since = "1.12.0")] +impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for Entry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry") + .field(v) + .finish(), + Occupied(ref o) => f.debug_tuple("Entry") + .field(o) + .finish(), + } + } +} + /// A view into a single occupied location in a HashMap. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { key: Option, elem: FullBucket>, } +#[stable(feature= "debug_hash_map", since = "1.12.0")] +impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + /// A view into a single empty location in a HashMap. +/// It is part of the [`Entry`] enum. +/// +/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { hash: SafeHash, @@ -1366,6 +1400,15 @@ pub struct VacantEntry<'a, K: 'a, V: 'a> { elem: VacantEntryState>, } +#[stable(feature= "debug_hash_map", since = "1.12.0")] +impl<'a, K: 'a + Debug, V: 'a> Debug for VacantEntry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("VacantEntry") + .field(self.key()) + .finish() + } +} + /// Possible states of a VacantEntry. enum VacantEntryState { /// The index is occupied, but the key to insert has precedence, @@ -1518,6 +1561,20 @@ impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// + /// *map.entry("poneyland").or_insert(12) += 10; + /// assert_eq!(map["poneyland"], 22); + /// ``` pub fn or_insert(self, default: V) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), @@ -1528,6 +1585,19 @@ impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the result of the default function if empty, /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// let s = "hoho".to_owned(); + /// + /// map.entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_owned()); + /// ``` pub fn or_insert_with V>(self, default: F) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), @@ -1536,6 +1606,15 @@ impl<'a, K, V> Entry<'a, K, V> { } /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { match *self { @@ -1547,37 +1626,130 @@ impl<'a, K, V> Entry<'a, K, V> { impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { self.elem.read().0 } /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_entry_recover_keys)] + /// + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_pair(); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` #[unstable(feature = "map_entry_recover_keys", issue = "34285")] pub fn remove_pair(self) -> (K, V) { pop_internal(self.elem) } /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get(&self) -> &V { self.elem.read().1 } /// Gets a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut V { self.elem.read_mut().1 } /// Converts the OccupiedEntry into a mutable reference to the value in the entry - /// with a lifetime bound to the map itself + /// with a lifetime bound to the map itself. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_mut(self) -> &'a mut V { self.elem.into_mut_refs().1 } - /// Sets the value of the entry, and returns the entry's old value + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, mut value: V) -> V { let old_value = self.get_mut(); @@ -1585,7 +1757,23 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { value } - /// Takes the value out of the entry, and returns it + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(self) -> V { pop_internal(self.elem).1 @@ -1601,20 +1789,58 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// Gets a reference to the key that would be used when inserting a value - /// through the VacantEntry. + /// through the `VacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` #[stable(feature = "map_entry_keys", since = "1.10.0")] pub fn key(&self) -> &K { &self.key } /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_entry_recover_keys)] + /// + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("poneyland") { + /// v.into_key(); + /// } + /// ``` #[unstable(feature = "map_entry_recover_keys", issue = "34285")] pub fn into_key(self) -> K { self.key } /// Sets the value of the entry with the VacantEntry's key, - /// and returns a mutable reference to it + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { match self.elem { @@ -1666,6 +1892,17 @@ impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap /// A particular instance `RandomState` will create the same instances of /// `Hasher`, but the hashers created by two different `RandomState` /// instances are unlikely to produce the same result for the same values. +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashMap; +/// use std::collections::hash_map::RandomState; +/// +/// let s = RandomState::new(); +/// let mut map = HashMap::with_hasher(s); +/// map.insert(1, 2); +/// ``` #[derive(Clone)] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub struct RandomState { @@ -1675,6 +1912,14 @@ pub struct RandomState { impl RandomState { /// Constructs a new `RandomState` that is initialized with random keys. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::RandomState; + /// + /// let s = RandomState::new(); + /// ``` #[inline] #[allow(deprecated)] // rand #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 6956dc0d901a..d6d62ce79d4e 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -493,6 +493,44 @@ pub fn temp_dir() -> PathBuf { /// that can fail for a good number of reasons. Some errors can include, but not /// be limited to, filesystem operations failing or general syscall failures. /// +/// # Security +/// +/// The output of this function should not be used in anything that might have +/// security implications. For example: +/// +/// ``` +/// fn main() { +/// println!("{:?}", std::env::current_exe()); +/// } +/// ``` +/// +/// On Linux systems, if this is compiled as `foo`: +/// +/// ```bash +/// $ rustc foo.rs +/// $ ./foo +/// Ok("/home/alex/foo") +/// ``` +/// +/// And you make a symbolic link of the program: +/// +/// ```bash +/// $ ln foo bar +/// ``` +/// +/// When you run it, you won't get the original executable, you'll get the +/// symlink: +/// +/// ```bash +/// $ ./bar +/// Ok("/home/alex/bar") +/// ``` +/// +/// This sort of behavior has been known to [lead to privledge escalation] when +/// used incorrectly, for example. +/// +/// [lead to privledge escalation]: http://securityvulns.com/Wdocument183.html +/// /// # Examples /// /// ``` @@ -587,6 +625,13 @@ impl ExactSizeIterator for Args { fn len(&self) -> usize { self.inner.len() } } +#[stable(feature = "env_iterators", since = "1.11.0")] +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + self.inner.next_back().map(|s| s.into_string().unwrap()) + } +} + #[stable(feature = "env", since = "1.0.0")] impl Iterator for ArgsOs { type Item = OsString; @@ -599,6 +644,10 @@ impl ExactSizeIterator for ArgsOs { fn len(&self) -> usize { self.inner.len() } } +#[stable(feature = "env_iterators", since = "1.11.0")] +impl DoubleEndedIterator for ArgsOs { + fn next_back(&mut self) -> Option { self.inner.next_back() } +} /// Constants associated with the current target #[stable(feature = "env", since = "1.0.0")] pub mod consts { diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 0d3e18f9b966..f800a6e228e9 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -356,6 +356,18 @@ impl Borrow for CString { impl NulError { /// Returns the position of the nul byte in the slice that was provided to /// `CString::new`. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CString; + /// + /// let nul_error = CString::new("foo\0bar").unwrap_err(); + /// assert_eq!(nul_error.nul_position(), 3); + /// + /// let nul_error = CString::new("foo bar\0").unwrap_err(); + /// assert_eq!(nul_error.nul_position(), 7); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn nul_position(&self) -> usize { self.0 } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 83439b3f1321..b78db24e44b7 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -58,28 +58,37 @@ pub struct File { /// Metadata information about a file. /// -/// This structure is returned from the `metadata` function or method and +/// This structure is returned from the [`metadata`] function or method and /// represents known metadata about a file such as its permissions, size, /// modification times, etc. +/// +/// [`metadata`]: fn.metadata.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct Metadata(fs_imp::FileAttr); /// Iterator over the entries in a directory. /// -/// This iterator is returned from the `read_dir` function of this module and -/// will yield instances of `io::Result`. Through a `DirEntry` +/// This iterator is returned from the [`read_dir`] function of this module and +/// will yield instances of `io::Result`. Through a [`DirEntry`] /// information like the entry's path and possibly other metadata can be /// learned. /// +/// [`read_dir`]: fn.read_dir.html +/// [`DirEntry`]: struct.DirEntry.html +/// /// # Errors /// -/// This `io::Result` will be an `Err` if there's some sort of intermittent +/// This [`io::Result`] will be an `Err` if there's some sort of intermittent /// IO error during iteration. +/// +/// [`io::Result`]: ../io/type.Result.html #[stable(feature = "rust1", since = "1.0.0")] pub struct ReadDir(fs_imp::ReadDir); -/// Entries returned by the `ReadDir` iterator. +/// Entries returned by the [`ReadDir`] iterator. +/// +/// [`ReadDir`]: struct.ReadDir.html /// /// An instance of `DirEntry` represents an entry inside of a directory on the /// filesystem. Each entry can be inspected via methods to learn about the full @@ -89,17 +98,23 @@ pub struct DirEntry(fs_imp::DirEntry); /// Options and flags which can be used to configure how a file is opened. /// -/// This builder exposes the ability to configure how a `File` is opened and -/// what operations are permitted on the open file. The `File::open` and -/// `File::create` methods are aliases for commonly used options using this +/// This builder exposes the ability to configure how a [`File`] is opened and +/// what operations are permitted on the open file. The [`File::open`] and +/// [`File::create`] methods are aliases for commonly used options using this /// builder. /// -/// Generally speaking, when using `OpenOptions`, you'll first call `new()`, -/// then chain calls to methods to set each option, then call `open()`, passing -/// the path of the file you're trying to open. This will give you a +/// [`File`]: struct.File.html +/// [`File::open`]: struct.File.html#method.open +/// [`File::create`]: struct.File.html#method.create +/// +/// Generally speaking, when using `OpenOptions`, you'll first call [`new()`], +/// then chain calls to methods to set each option, then call [`open()`], +/// passing the path of the file you're trying to open. This will give you a /// [`io::Result`][result] with a [`File`][file] inside that you can further /// operate on. /// +/// [`new()`]: struct.OpenOptions.html#method.new +/// [`open()`]: struct.OpenOptions.html#method.open /// [result]: ../io/type.Result.html /// [file]: struct.File.html /// @@ -131,15 +146,20 @@ pub struct OpenOptions(fs_imp::OpenOptions); /// Representation of the various permissions on a file. /// -/// This module only currently provides one bit of information, `readonly`, +/// This module only currently provides one bit of information, [`readonly`], /// which is exposed on all currently supported platforms. Unix-specific /// functionality, such as mode bits, is available through the /// `os::unix::PermissionsExt` trait. +/// +/// [`readonly`]: struct.Permissions.html#method.readonly #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Permissions(fs_imp::FilePermissions); -/// An structure representing a type of file with accessors for each file type. +/// A structure representing a type of file with accessors for each file type. +/// It is returned by [`Metadata::file_type`] method. +/// +/// [`Metadata::file_type`]: struct.Metadata.html#method.file_type #[stable(feature = "file_type", since = "1.1.0")] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct FileType(fs_imp::FileType); @@ -156,12 +176,14 @@ pub struct DirBuilder { impl File { /// Attempts to open a file in read-only mode. /// - /// See the `OpenOptions::open` method for more details. + /// See the [`OpenOptions::open`] method for more details. /// /// # Errors /// /// This function will return an error if `path` does not already exist. - /// Other errors may also be returned according to `OpenOptions::open`. + /// Other errors may also be returned according to [`OpenOptions::open`]. + /// + /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open /// /// # Examples /// @@ -183,7 +205,9 @@ impl File { /// This function will create a file if it does not exist, /// and will truncate it if it does. /// - /// See the `OpenOptions::open` function for more details. + /// See the [`OpenOptions::open`] function for more details. + /// + /// [`OpenOptions::open`]: struct.OpenOptions.html#method.open /// /// # Examples /// @@ -224,7 +248,7 @@ impl File { self.inner.fsync() } - /// This function is similar to `sync_all`, except that it may not + /// This function is similar to [`sync_all`], except that it may not /// synchronize file metadata to the filesystem. /// /// This is intended for use cases that must synchronize content, but don't @@ -232,7 +256,9 @@ impl File { /// operations. /// /// Note that some platforms may simply implement this in terms of - /// `sync_all`. + /// [`sync_all`]. + /// + /// [`sync_all`]: struct.File.html#method.sync_all /// /// # Examples /// @@ -304,6 +330,18 @@ impl File { /// The returned `File` is a reference to the same state that this object /// references. Both handles will read and write with the same cursor /// position. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let file_copy = try!(f.try_clone()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_try_clone", since = "1.9.0")] pub fn try_clone(&self) -> io::Result { Ok(File { @@ -575,6 +613,19 @@ impl AsInnerMut for OpenOptions { impl Metadata { /// Returns the file type for this metadata. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// + /// println!("{:?}", metadata.file_type()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn file_type(&self) -> FileType { FileType(self.0.file_type()) @@ -659,6 +710,23 @@ impl Metadata { /// /// This field may not be available on all platforms, and will return an /// `Err` on platforms where it is not available. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// + /// if let Ok(time) = metadata.modified() { + /// println!("{:?}", time); + /// } else { + /// println!("Not supported on this platform"); + /// } + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "fs_time", since = "1.10.0")] pub fn modified(&self) -> io::Result { self.0.modified().map(FromInner::from_inner) @@ -677,6 +745,23 @@ impl Metadata { /// /// This field may not be available on all platforms, and will return an /// `Err` on platforms where it is not available. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// + /// if let Ok(time) = metadata.accessed() { + /// println!("{:?}", time); + /// } else { + /// println!("Not supported on this platform"); + /// } + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "fs_time", since = "1.10.0")] pub fn accessed(&self) -> io::Result { self.0.accessed().map(FromInner::from_inner) @@ -691,6 +776,23 @@ impl Metadata { /// /// This field may not be available on all platforms, and will return an /// `Err` on platforms where it is not available. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// + /// if let Ok(time) = metadata.created() { + /// println!("{:?}", time); + /// } else { + /// println!("Not supported on this platform"); + /// } + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "fs_time", since = "1.10.0")] pub fn created(&self) -> io::Result { self.0.created().map(FromInner::from_inner) @@ -753,14 +855,56 @@ impl Permissions { impl FileType { /// Test whether this file type represents a directory. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// let file_type = metadata.file_type(); + /// + /// assert_eq!(file_type.is_dir(), false); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn is_dir(&self) -> bool { self.0.is_dir() } /// Test whether this file type represents a regular file. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// let file_type = metadata.file_type(); + /// + /// assert_eq!(file_type.is_file(), true); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn is_file(&self) -> bool { self.0.is_file() } /// Test whether this file type represents a symbolic link. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// let file_type = metadata.file_type(); + /// + /// assert_eq!(file_type.is_symlink(), false); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_type", since = "1.1.0")] pub fn is_symlink(&self) -> bool { self.0.is_symlink() } } @@ -791,8 +935,8 @@ impl Iterator for ReadDir { impl DirEntry { /// Returns the full path to the file that this entry represents. /// - /// The full path is created by joining the original path to `read_dir` or - /// `walk_dir` with the filename of this entry. + /// The full path is created by joining the original path to `read_dir` + /// with the filename of this entry. /// /// # Examples /// @@ -829,6 +973,26 @@ impl DirEntry { /// On Windows this function is cheap to call (no extra system calls /// needed), but on Unix platforms this function is the equivalent of /// calling `symlink_metadata` on the path. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// + /// if let Ok(entries) = fs::read_dir(".") { + /// for entry in entries { + /// if let Ok(entry) = entry { + /// // Here, `entry` is a `DirEntry`. + /// if let Ok(metadata) = entry.metadata() { + /// // Now let's show our entry's permissions! + /// println!("{:?}: {:?}", entry.path(), metadata.permissions()); + /// } else { + /// println!("Couldn't get metadata for {:?}", entry.path()); + /// } + /// } + /// } + /// } + /// ``` #[stable(feature = "dir_entry_ext", since = "1.1.0")] pub fn metadata(&self) -> io::Result { self.0.metadata().map(Metadata) @@ -844,6 +1008,26 @@ impl DirEntry { /// On Windows and most Unix platforms this function is free (no extra /// system calls needed), but some Unix platforms may require the equivalent /// call to `symlink_metadata` to learn about the target file type. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// + /// if let Ok(entries) = fs::read_dir(".") { + /// for entry in entries { + /// if let Ok(entry) = entry { + /// // Here, `entry` is a `DirEntry`. + /// if let Ok(file_type) = entry.file_type() { + /// // Now let's show our entry's file type! + /// println!("{:?}: {:?}", entry.path(), file_type); + /// } else { + /// println!("Couldn't get file type for {:?}", entry.path()); + /// } + /// } + /// } + /// } + /// ``` #[stable(feature = "dir_entry_ext", since = "1.1.0")] pub fn file_type(&self) -> io::Result { self.0.file_type().map(FileType) @@ -851,6 +1035,21 @@ impl DirEntry { /// Returns the bare file name of this directory entry without any other /// leading path component. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// + /// if let Ok(entries) = fs::read_dir(".") { + /// for entry in entries { + /// if let Ok(entry) = entry { + /// // Here, `entry` is a `DirEntry`. + /// println!("{:?}", entry.file_name()); + /// } + /// } + /// } + /// ``` #[stable(feature = "dir_entry_ext", since = "1.1.0")] pub fn file_name(&self) -> OsString { self.0.file_name() @@ -1397,6 +1596,14 @@ pub fn set_permissions>(path: P, perm: Permissions) impl DirBuilder { /// Creates a new set of options with default mode/security settings for all /// platforms and also non-recursive. + /// + /// # Examples + /// + /// ``` + /// use std::fs::DirBuilder; + /// + /// let builder = DirBuilder::new(); + /// ``` #[stable(feature = "dir_builder", since = "1.6.0")] pub fn new() -> DirBuilder { DirBuilder { @@ -1409,7 +1616,16 @@ impl DirBuilder { /// all parent directories if they do not exist with the same security and /// permissions settings. /// - /// This option defaults to `false` + /// This option defaults to `false`. + /// + /// # Examples + /// + /// ``` + /// use std::fs::DirBuilder; + /// + /// let mut builder = DirBuilder::new(); + /// builder.recursive(true); + /// ``` #[stable(feature = "dir_builder", since = "1.6.0")] pub fn recursive(&mut self, recursive: bool) -> &mut Self { self.recursive = recursive; diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 05ae8ed5b0b6..5333b0a531ea 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -55,7 +55,9 @@ pub type Result = result::Result; /// /// Errors mostly originate from the underlying OS, but custom instances of /// `Error` can be created with crafted error messages and a particular value of -/// `ErrorKind`. +/// [`ErrorKind`]. +/// +/// [`ErrorKind`]: enum.ErrorKind.html #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Error { @@ -77,6 +79,10 @@ struct Custom { /// /// This list is intended to grow over time and it is not recommended to /// exhaustively match against it. +/// +/// It is used with the [`io::Error`] type. +/// +/// [`io::Error`]: struct.Error.html #[derive(Copy, PartialEq, Eq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] @@ -208,6 +214,14 @@ impl Error { /// This function reads the value of `errno` for the target platform (e.g. /// `GetLastError` on Windows) and will return a corresponding instance of /// `Error` for the error code. + /// + /// # Examples + /// + /// ``` + /// use std::io::Error; + /// + /// println!("last OS error: {:?}", Error::last_os_error()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn last_os_error() -> Error { Error::from_raw_os_error(sys::os::errno() as i32) @@ -248,6 +262,27 @@ impl Error { /// If this `Error` was constructed via `last_os_error` or /// `from_raw_os_error`, then this function will return `Some`, otherwise /// it will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_os_error(err: &Error) { + /// if let Some(raw_os_err) = err.raw_os_error() { + /// println!("raw OS error: {:?}", raw_os_err); + /// } else { + /// println!("Not an OS error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "raw OS error: ...". + /// print_os_error(&Error::last_os_error()); + /// // Will print "Not an OS error". + /// print_os_error(&Error::new(ErrorKind::Other, "oh no!")); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn raw_os_error(&self) -> Option { match self.repr { @@ -260,6 +295,27 @@ impl Error { /// /// If this `Error` was constructed via `new` then this function will /// return `Some`, otherwise it will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_error(err: &Error) { + /// if let Some(inner_err) = err.get_ref() { + /// println!("Inner error: {:?}", inner_err); + /// } else { + /// println!("No inner error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(&Error::last_os_error()); + /// // Will print "Inner error: ...". + /// print_error(&Error::new(ErrorKind::Other, "oh no!")); + /// } + /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> { match self.repr { @@ -273,6 +329,63 @@ impl Error { /// /// If this `Error` was constructed via `new` then this function will /// return `Some`, otherwise it will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// use std::{error, fmt}; + /// use std::fmt::Display; + /// + /// #[derive(Debug)] + /// struct MyError { + /// v: String, + /// } + /// + /// impl MyError { + /// fn new() -> MyError { + /// MyError { + /// v: "oh no!".to_owned() + /// } + /// } + /// + /// fn change_message(&mut self, new_message: &str) { + /// self.v = new_message.to_owned(); + /// } + /// } + /// + /// impl error::Error for MyError { + /// fn description(&self) -> &str { &self.v } + /// } + /// + /// impl Display for MyError { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "MyError: {}", &self.v) + /// } + /// } + /// + /// fn change_error(mut err: Error) -> Error { + /// if let Some(inner_err) = err.get_mut() { + /// inner_err.downcast_mut::().unwrap().change_message("I've been changed!"); + /// } + /// err + /// } + /// + /// fn print_error(err: &Error) { + /// if let Some(inner_err) = err.get_ref() { + /// println!("Inner error: {}", inner_err); + /// } else { + /// println!("No inner error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(&change_error(Error::last_os_error())); + /// // Will print "Inner error: ...". + /// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new()))); + /// } + /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> { match self.repr { @@ -285,6 +398,27 @@ impl Error { /// /// If this `Error` was constructed via `new` then this function will /// return `Some`, otherwise it will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_error(err: Error) { + /// if let Some(inner_err) = err.into_inner() { + /// println!("Inner error: {}", inner_err); + /// } else { + /// println!("No inner error"); + /// } + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(Error::last_os_error()); + /// // Will print "Inner error: ...". + /// print_error(Error::new(ErrorKind::Other, "oh no!")); + /// } + /// ``` #[stable(feature = "io_error_inner", since = "1.3.0")] pub fn into_inner(self) -> Option> { match self.repr { @@ -294,6 +428,23 @@ impl Error { } /// Returns the corresponding `ErrorKind` for this error. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// fn print_error(err: Error) { + /// println!("{:?}", err.kind()); + /// } + /// + /// fn main() { + /// // Will print "No inner error". + /// print_error(Error::last_os_error()); + /// // Will print "Inner error: ...". + /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!")); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> ErrorKind { match self.repr { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index a058337a50af..88fd4186e0a2 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1082,16 +1082,22 @@ pub trait Seek { /// /// If the seek operation completed successfully, /// this method returns the new position from the start of the stream. - /// That position can be used later with `SeekFrom::Start`. + /// That position can be used later with [`SeekFrom::Start`]. /// /// # Errors /// /// Seeking to a negative offset is considered an error. + /// + /// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start #[stable(feature = "rust1", since = "1.0.0")] fn seek(&mut self, pos: SeekFrom) -> Result; } /// Enumeration of possible methods to seek within an I/O object. +/// +/// It is used by the [`Seek`] trait. +/// +/// [`Seek`]: trait.Seek.html #[derive(Copy, PartialEq, Eq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum SeekFrom { @@ -1482,6 +1488,24 @@ impl Take { /// /// This instance may reach EOF after reading fewer bytes than indicated by /// this method if the underlying `Read` instance reaches EOF. + /// + /// # Examples + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let f = try!(File::open("foo.txt")); + /// + /// // read at most five bytes + /// let handle = f.take(5); + /// + /// println!("limit: {}", handle.limit()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn limit(&self) -> u64 { self.limit } } @@ -1522,6 +1546,18 @@ impl BufRead for Take { } } +fn read_one_byte(reader: &mut Read) -> Option> { + let mut buf = [0]; + loop { + return match reader.read(&mut buf) { + Ok(0) => None, + Ok(..) => Some(Ok(buf[0])), + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => Some(Err(e)), + }; + } +} + /// An iterator over `u8` values of a reader. /// /// This struct is generally created by calling [`bytes()`][bytes] on a reader. @@ -1538,12 +1574,7 @@ impl Iterator for Bytes { type Item = Result; fn next(&mut self) -> Option> { - let mut buf = [0]; - match self.inner.read(&mut buf) { - Ok(0) => None, - Ok(..) => Some(Ok(buf[0])), - Err(e) => Some(Err(e)), - } + read_one_byte(&mut self.inner) } } @@ -1579,11 +1610,10 @@ impl Iterator for Chars { type Item = result::Result; fn next(&mut self) -> Option> { - let mut buf = [0]; - let first_byte = match self.inner.read(&mut buf) { - Ok(0) => return None, - Ok(..) => buf[0], - Err(e) => return Some(Err(CharsError::Other(e))), + let first_byte = match read_one_byte(&mut self.inner) { + None => return None, + Some(Ok(b)) => b, + Some(Err(e)) => return Some(Err(CharsError::Other(e))), }; let width = core_str::utf8_char_width(first_byte); if width == 1 { return Some(Ok(first_byte as char)) } @@ -1595,6 +1625,7 @@ impl Iterator for Chars { match self.inner.read(&mut buf[start..width]) { Ok(0) => return Some(Err(CharsError::NotUtf8)), Ok(n) => start += n, + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, Err(e) => return Some(Err(CharsError::Other(e))), } } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index c4b573db5f2d..b8b66a58359e 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -240,6 +240,21 @@ impl Stdin { /// /// [`Read`]: trait.Read.html /// [`BufRead`]: trait.BufRead.html + /// + /// # Examples + /// + /// ``` + /// use std::io::{self, Read}; + /// + /// # fn foo() -> io::Result { + /// let mut buffer = String::new(); + /// let stdin = io::stdin(); + /// let mut handle = stdin.lock(); + /// + /// try!(handle.read_to_string(&mut buffer)); + /// # Ok(buffer) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StdinLock { StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } @@ -399,6 +414,21 @@ impl Stdout { /// /// The lock is released when the returned lock goes out of scope. The /// returned guard also implements the `Write` trait for writing data. + /// + /// # Examples + /// + /// ``` + /// use std::io::{self, Write}; + /// + /// # fn foo() -> io::Result<()> { + /// let stdout = io::stdout(); + /// let mut handle = stdout.lock(); + /// + /// try!(handle.write(b"hello world")); + /// + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StdoutLock { StdoutLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } @@ -505,6 +535,21 @@ impl Stderr { /// /// The lock is released when the returned lock goes out of scope. The /// returned guard also implements the `Write` trait for writing data. + /// + /// # Examples + /// + /// ``` + /// use std::io::{self, Write}; + /// + /// fn foo() -> io::Result<()> { + /// let stderr = io::stderr(); + /// let mut handle = stderr.lock(); + /// + /// try!(handle.write(b"hello world")); + /// + /// Ok(()) + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StderrLock { StderrLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d05a5a096148..865d067cdb6d 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -218,8 +218,9 @@ #![feature(associated_consts)] #![feature(borrow_state)] #![feature(box_syntax)] -#![feature(cfg_target_vendor)] #![feature(cfg_target_thread_local)] +#![feature(cfg_target_vendor)] +#![feature(char_escape_debug)] #![feature(char_internals)] #![feature(collections)] #![feature(collections_bound)] @@ -229,10 +230,10 @@ #![feature(dropck_parametricity)] #![feature(float_extras)] #![feature(float_from_str_radix)] -#![feature(fnbox)] #![feature(fn_traits)] -#![feature(heap_api)] +#![feature(fnbox)] #![feature(hashmap_hasher)] +#![feature(heap_api)] #![feature(inclusive_range)] #![feature(int_error_internals)] #![feature(into_cow)] @@ -242,6 +243,7 @@ #![feature(linkage)] #![feature(macro_reexport)] #![cfg_attr(test, feature(map_values_mut))] +#![feature(needs_panic_runtime)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] @@ -249,10 +251,11 @@ #![feature(optin_builtin_traits)] #![feature(panic_unwind)] #![feature(placement_in_syntax)] +#![feature(question_mark)] #![feature(rand)] #![feature(raw)] -#![feature(repr_simd)] #![feature(reflect_marker)] +#![feature(repr_simd)] #![feature(rustc_attrs)] #![feature(shared)] #![feature(sip_hash_13)] @@ -266,6 +269,7 @@ #![feature(str_utf16)] #![feature(test, rustc_private)] #![feature(thread_local)] +#![feature(try_from)] #![feature(unboxed_closures)] #![feature(unicode)] #![feature(unique)] @@ -273,9 +277,6 @@ #![feature(unwind_attributes)] #![feature(vec_push_all)] #![feature(zero_one)] -#![feature(question_mark)] -#![feature(try_from)] -#![feature(needs_panic_runtime)] // Issue# 30592: Systematically use alloc_system during stage0 since jemalloc // might be unavailable or disabled diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 67410e87a8be..2a8bd0c88beb 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -59,6 +59,66 @@ pub enum Ipv6MulticastScope { Global } +impl IpAddr { + /// Returns true for the special 'unspecified' address ([IPv4], [IPv6]). + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_unspecified + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_unspecified + #[unstable(feature="ip", issue="27709", + reason="recently added and depends on unstable Ipv4Addr.is_unspecified()")] + pub fn is_unspecified(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_unspecified(), + IpAddr::V6(ref a) => a.is_unspecified(), + } + } + + /// Returns true if this is a loopback address ([IPv4], [IPv6]). + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_loopback + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_loopback + #[unstable(feature="ip", reason="recently added", issue="27709")] + pub fn is_loopback(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_loopback(), + IpAddr::V6(ref a) => a.is_loopback(), + } + } + + /// Returns true if the address appears to be globally routable ([IPv4], [IPv6]). + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global + #[unstable(feature="ip", issue="27709", + reason="recently added and depends on unstable Ip{v4,v6}Addr.is_global()")] + pub fn is_global(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_global(), + IpAddr::V6(ref a) => a.is_global(), + } + } + + /// Returns true if this is a multicast address ([IPv4], [IPv6]). + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_multicast + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_multicast + #[unstable(feature="ip", reason="recently added", issue="27709")] + pub fn is_multicast(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_multicast(), + IpAddr::V6(ref a) => a.is_multicast(), + } + } + + /// Returns true if this address is in a range designated for documentation ([IPv4], [IPv6]). + /// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation + /// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation + #[unstable(feature="ip", issue="27709", + reason="recently added and depends on unstable Ipv6Addr.is_documentation()")] + pub fn is_documentation(&self) -> bool { + match *self { + IpAddr::V4(ref a) => a.is_documentation(), + IpAddr::V6(ref a) => a.is_documentation(), + } + } +} + impl Ipv4Addr { /// Creates a new IPv4 address from four eight-bit octets. /// @@ -760,6 +820,67 @@ mod tests { None); } + #[test] + fn ip_properties() { + fn check4(octets: &[u8; 4], unspec: bool, loopback: bool, + global: bool, multicast: bool, documentation: bool) { + let ip = IpAddr::V4(Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])); + assert_eq!(ip.is_unspecified(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_global(), global); + assert_eq!(ip.is_multicast(), multicast); + assert_eq!(ip.is_documentation(), documentation); + } + + fn check6(str_addr: &str, unspec: bool, loopback: bool, + global: bool, u_doc: bool, mcast: bool) { + let ip = IpAddr::V6(str_addr.parse().unwrap()); + assert_eq!(ip.is_unspecified(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_global(), global); + assert_eq!(ip.is_documentation(), u_doc); + assert_eq!(ip.is_multicast(), mcast); + } + + // address unspec loopbk global multicast doc + check4(&[0, 0, 0, 0], true, false, false, false, false); + check4(&[0, 0, 0, 1], false, false, true, false, false); + check4(&[0, 1, 0, 0], false, false, true, false, false); + check4(&[10, 9, 8, 7], false, false, false, false, false); + check4(&[127, 1, 2, 3], false, true, false, false, false); + check4(&[172, 31, 254, 253], false, false, false, false, false); + check4(&[169, 254, 253, 242], false, false, false, false, false); + check4(&[192, 0, 2, 183], false, false, false, false, true); + check4(&[192, 1, 2, 183], false, false, true, false, false); + check4(&[192, 168, 254, 253], false, false, false, false, false); + check4(&[198, 51, 100, 0], false, false, false, false, true); + check4(&[203, 0, 113, 0], false, false, false, false, true); + check4(&[203, 2, 113, 0], false, false, true, false, false); + check4(&[224, 0, 0, 0], false, false, true, true, false); + check4(&[239, 255, 255, 255], false, false, true, true, false); + check4(&[255, 255, 255, 255], false, false, false, false, false); + + // address unspec loopbk global doc mcast + check6("::", true, false, false, false, false); + check6("::1", false, true, false, false, false); + check6("::0.0.0.2", false, false, true, false, false); + check6("1::", false, false, true, false, false); + check6("fc00::", false, false, false, false, false); + check6("fdff:ffff::", false, false, false, false, false); + check6("fe80:ffff::", false, false, false, false, false); + check6("febf:ffff::", false, false, false, false, false); + check6("fec0::", false, false, false, false, false); + check6("ff01::", false, false, false, false, true); + check6("ff02::", false, false, false, false, true); + check6("ff03::", false, false, false, false, true); + check6("ff04::", false, false, false, false, true); + check6("ff05::", false, false, false, false, true); + check6("ff08::", false, false, false, false, true); + check6("ff0e::", false, false, true, false, true); + check6("2001:db8:85a3::8a2e:370:7334", false, false, false, true, false); + check6("102:304:506:708:90a:b0c:d0e:f10", false, false, true, false, false); + } + #[test] fn ipv4_properties() { fn check(octets: &[u8; 4], unspec: bool, loopback: bool, diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index ac13b23ebee5..11a16b271133 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -35,7 +35,11 @@ mod udp; mod parser; #[cfg(test)] mod test; -/// Possible values which can be passed to the `shutdown` method of `TcpStream`. +/// Possible values which can be passed to the [`shutdown`] method of +/// [`TcpStream`]. +/// +/// [`shutdown`]: struct.TcpStream.html#method.shutdown +/// [`TcpStream`]: struct.TcpStream.html #[derive(Copy, Clone, PartialEq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Shutdown { diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 5ab0d5a0877b..76617f159707 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -77,6 +77,11 @@ pub struct TcpListener(net_imp::TcpListener); /// /// This iterator will infinitely yield `Some` of the accepted connections. It /// is equivalent to calling `accept` in a loop. +/// +/// This `struct` is created by the [`incoming`] method on [`TcpListener`]. +/// +/// [`incoming`]: struct.TcpListener.html#method.incoming +/// [`TcpListener`]: struct.TcpListener.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Incoming<'a> { listener: &'a TcpListener } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index d73e9542d212..57a4c3df70a4 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -28,9 +28,7 @@ use intrinsics; use mem; use raw; use sys_common::rwlock::RWLock; -use sync::atomic::{AtomicBool, Ordering}; use sys::stdio::Stderr; -use sys_common::backtrace; use sys_common::thread_info; use sys_common::util; use thread; @@ -71,7 +69,6 @@ enum Hook { static HOOK_LOCK: RWLock = RWLock::new(); static mut HOOK: Hook = Hook::Default; -static FIRST_PANIC: AtomicBool = AtomicBool::new(true); /// Registers a custom panic hook, replacing any that was previously registered. /// @@ -183,11 +180,17 @@ impl<'a> Location<'a> { } fn default_hook(info: &PanicInfo) { - let panics = PANIC_COUNT.with(|c| c.get()); + #[cfg(any(not(cargobuild), feature = "backtrace"))] + use sys_common::backtrace; // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. - let log_backtrace = panics >= 2 || backtrace::log_enabled(); + #[cfg(any(not(cargobuild), feature = "backtrace"))] + let log_backtrace = { + let panics = PANIC_COUNT.with(|c| c.get()); + + panics >= 2 || backtrace::log_enabled() + }; let file = info.location.file; let line = info.location.line; @@ -207,10 +210,17 @@ fn default_hook(info: &PanicInfo) { let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}", name, msg, file, line); - if log_backtrace { - let _ = backtrace::write(err); - } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) { - let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace."); + #[cfg(any(not(cargobuild), feature = "backtrace"))] + { + use sync::atomic::{AtomicBool, Ordering}; + + static FIRST_PANIC: AtomicBool = AtomicBool::new(true); + + if log_backtrace { + let _ = backtrace::write(err); + } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) { + let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace."); + } } }; diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index d96fd6228e62..11f785dffd16 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -311,6 +311,17 @@ pub struct Iter<'a, T: 'a> { rx: &'a Receiver } +/// An iterator that attempts to yield all pending values for a receiver. +/// `None` will be returned when there are no pending values remaining or +/// if the corresponding channel has hung up. +/// +/// This Iterator will never block the caller in order to wait for data to +/// become available. Instead, it will return `None`. +#[unstable(feature = "receiver_try_iter", issue = "34931")] +pub struct TryIter<'a, T: 'a> { + rx: &'a Receiver +} + /// An owning iterator over messages on a receiver, this iterator will block /// whenever `next` is called, waiting for a new message, and `None` will be /// returned when the corresponding channel has hung up. @@ -982,6 +993,16 @@ impl Receiver { pub fn iter(&self) -> Iter { Iter { rx: self } } + + /// Returns an iterator that will attempt to yield all pending values. + /// It will return `None` if there are no more pending values or if the + /// channel has hung up. The iterator will never `panic!` or block the + /// user by waiting for values. + #[unstable(feature = "receiver_try_iter", issue = "34931")] + pub fn try_iter(&self) -> TryIter { + TryIter { rx: self } + } + } impl select::Packet for Receiver { @@ -1077,6 +1098,13 @@ impl<'a, T> Iterator for Iter<'a, T> { fn next(&mut self) -> Option { self.rx.recv().ok() } } +#[unstable(feature = "receiver_try_iter", issue = "34931")] +impl<'a, T> Iterator for TryIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { self.rx.try_recv().ok() } +} + #[stable(feature = "receiver_into_iter", since = "1.1.0")] impl<'a, T> IntoIterator for &'a Receiver { type Item = T; @@ -1814,6 +1842,34 @@ mod tests { assert_eq!(count_rx.recv().unwrap(), 4); } + #[test] + fn test_recv_try_iter() { + let (request_tx, request_rx) = channel(); + let (response_tx, response_rx) = channel(); + + // Request `x`s until we have `6`. + let t = thread::spawn(move|| { + let mut count = 0; + loop { + for x in response_rx.try_iter() { + count += x; + if count == 6 { + return count; + } + } + request_tx.send(()).unwrap(); + } + }); + + for _ in request_rx.iter() { + if response_tx.send(2).is_err() { + break; + } + } + + assert_eq!(t.join().unwrap(), 6); + } + #[test] fn test_recv_into_iter_owned() { let mut iter = { diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index c9279883ae59..a1f3f477b3ab 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -28,6 +28,7 @@ macro_rules! rtassert { pub mod args; pub mod at_exit_imp; +#[cfg(any(not(cargobuild), feature = "backtrace"))] pub mod backtrace; pub mod condvar; pub mod io; @@ -42,6 +43,7 @@ pub mod thread_local; pub mod util; pub mod wtf8; +#[cfg(any(not(cargobuild), feature = "backtrace"))] #[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios", target_os = "emscripten"))), all(windows, target_env = "gnu")))] pub mod gnu; diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index 2c1a656290f9..c1b4f8a8c88c 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -390,7 +390,7 @@ impl fmt::Debug for Wtf8 { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn write_str_escaped(f: &mut fmt::Formatter, s: &str) -> fmt::Result { use fmt::Write; - for c in s.chars().flat_map(|c| c.escape_default()) { + for c in s.chars().flat_map(|c| c.escape_debug()) { f.write_char(c)? } Ok(()) @@ -408,7 +408,7 @@ impl fmt::Debug for Wtf8 { &self.bytes[pos .. surrogate_pos] )}, )?; - write!(formatter, "\\u{{{:X}}}", surrogate)?; + write!(formatter, "\\u{{{:x}}}", surrogate)?; pos = surrogate_pos + 3; } } @@ -1064,9 +1064,9 @@ mod tests { #[test] fn wtf8buf_show() { - let mut string = Wtf8Buf::from_str("a\té 💩\r"); + let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r"); string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(format!("{:?}", string), r#""a\t\u{e9} \u{1f4a9}\r\u{D800}""#); + assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\""); } #[test] diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index bb90a977433e..77587918ac94 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -25,15 +25,53 @@ use sys::platform::fs::MetadataExt as UnixMetadataExt; pub trait PermissionsExt { /// Returns the underlying raw `mode_t` bits that are the standard Unix /// permissions for this file. + /// + /// # Examples + /// + /// ```rust,ignore + /// use std::fs::File; + /// use std::os::unix::fs::PermissionsExt; + /// + /// let f = try!(File::create("foo.txt")); + /// let metadata = try!(f.metadata()); + /// let permissions = metadata.permissions(); + /// + /// println!("permissions: {}", permissions.mode()); + /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn mode(&self) -> u32; /// Sets the underlying raw bits for this set of permissions. + /// + /// # Examples + /// + /// ```rust,ignore + /// use std::fs::File; + /// use std::os::unix::fs::PermissionsExt; + /// + /// let f = try!(File::create("foo.txt")); + /// let metadata = try!(f.metadata()); + /// let mut permissions = metadata.permissions(); + /// + /// permissions.set_mode(0o644); // Read/write for owner and read for others. + /// assert_eq!(permissions.mode(), 0o644); + /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn set_mode(&mut self, mode: u32); /// Creates a new instance of `Permissions` from the given set of Unix /// permission bits. + /// + /// # Examples + /// + /// ```rust,ignore + /// use std::fs::Permissions; + /// use std::os::unix::fs::PermissionsExt; + /// + /// // Read/write for owner and read for others. + /// let permissions = Permissions::from_mode(0o644); + /// assert_eq!(permissions.mode(), 0o644); + /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn from_mode(mode: u32) -> Self; } @@ -63,6 +101,18 @@ pub trait OpenOptionsExt { /// If no `mode` is set, the default of `0o666` will be used. /// The operating system masks out bits with the systems `umask`, to produce /// the final permissions. + /// + /// # Examples + /// + /// ```rust,ignore + /// extern crate libc; + /// use std::fs::OpenOptions; + /// use std::os::unix::fs::OpenOptionsExt; + /// + /// let mut options = OpenOptions::new(); + /// options.mode(0o644); // Give read/write for owner and read for others. + /// let file = options.open("foo.txt"); + /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn mode(&mut self, mode: u32) -> &mut Self; @@ -196,6 +246,22 @@ impl FileTypeExt for fs::FileType { pub trait DirEntryExt { /// Returns the underlying `d_ino` field in the contained `dirent` /// structure. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// use std::os::unix::fs::DirEntryExt; + /// + /// if let Ok(entries) = fs::read_dir(".") { + /// for entry in entries { + /// if let Ok(entry) = entry { + /// // Here, `entry` is a `DirEntry`. + /// println!("{:?}: {}", entry.file_name(), entry.ino()); + /// } + /// } + /// } + /// ``` #[stable(feature = "dir_entry_ext", since = "1.1.0")] fn ino(&self) -> u64; } @@ -239,6 +305,16 @@ pub fn symlink, Q: AsRef>(src: P, dst: Q) -> io::Result<()> pub trait DirBuilderExt { /// Sets the mode to create new directories with. This option defaults to /// 0o777. + /// + /// # Examples + /// + /// ```ignore + /// use std::fs::DirBuilder; + /// use std::os::unix::fs::DirBuilderExt; + /// + /// let mut builder = DirBuilder::new(); + /// builder.mode(0o755); + /// ``` #[stable(feature = "dir_builder", since = "1.6.0")] fn mode(&mut self, mode: u32) -> &mut Self; } diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index f0fd42fc99b8..1c25c8f77c19 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -30,6 +30,7 @@ use libc; pub mod weak; pub mod android; +#[cfg(any(not(cargobuild), feature = "backtrace"))] pub mod backtrace; pub mod condvar; pub mod ext; diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index a784741c88cc..6f1b70acb60b 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -67,7 +67,7 @@ impl Socket { // this option, however, was added in 2.6.27, and we still support // 2.6.18 as a kernel, so if the returned error is EINVAL we // fallthrough to the fallback. - if cfg!(linux) { + if cfg!(target_os = "linux") { match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) { Ok(fd) => return Ok(Socket(FileDesc::new(fd))), Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} @@ -87,7 +87,7 @@ impl Socket { let mut fds = [0, 0]; // Like above, see if we can set cloexec atomically - if cfg!(linux) { + if cfg!(target_os = "linux") { match cvt(libc::socketpair(fam, ty | SOCK_CLOEXEC, 0, fds.as_mut_ptr())) { Ok(_) => { return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1])))); diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 63e13f0bb473..4c3558f91f5f 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -317,6 +317,10 @@ impl ExactSizeIterator for Args { fn len(&self) -> usize { self.iter.len() } } +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { self.iter.next_back() } +} + /// Returns the command line arguments /// /// Returns a list of the command line arguments. diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 32ca32e76cb6..0cea7f81e363 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -278,23 +278,30 @@ pub struct Args { cur: *mut *mut u16, } +unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString { + let mut len = 0; + while *ptr.offset(len) != 0 { len += 1; } + + // Push it onto the list. + let ptr = ptr as *const u16; + let buf = slice::from_raw_parts(ptr, len as usize); + OsStringExt::from_wide(buf) +} + impl Iterator for Args { type Item = OsString; fn next(&mut self) -> Option { - self.range.next().map(|i| unsafe { - let ptr = *self.cur.offset(i); - let mut len = 0; - while *ptr.offset(len) != 0 { len += 1; } - - // Push it onto the list. - let ptr = ptr as *const u16; - let buf = slice::from_raw_parts(ptr, len as usize); - OsStringExt::from_wide(buf) - }) + self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) } fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } } +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option { + self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) + } +} + impl ExactSizeIterator for Args { fn len(&self) -> usize { self.range.len() } } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index e9736fea7b37..f06c105d30e6 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -447,6 +447,8 @@ pub fn park() { *guard = false; } +/// Use [park_timeout]. +/// /// Blocks unless or until the current thread's token is made available or /// the specified duration has been reached (may wake spuriously). /// @@ -456,7 +458,10 @@ pub fn park() { /// preemption or platform differences that may not cause the maximum /// amount of time waited to be precisely `ms` long. /// -/// See the module doc for more detail. +/// See the [module documentation][thread] for more detail. +/// +/// [thread]: index.html +/// [park_timeout]: fn.park_timeout.html #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::park_timeout`")] pub fn park_timeout_ms(ms: u32) { @@ -478,6 +483,25 @@ pub fn park_timeout_ms(ms: u32) { /// /// Platforms which do not support nanosecond precision for sleeping will have /// `dur` rounded up to the nearest granularity of time they can sleep for. +/// +/// # Example +/// +/// Waiting for the complete expiration of the timeout: +/// +/// ```rust,no_run +/// use std::thread::park_timeout; +/// use std::time::{Instant, Duration}; +/// +/// let timeout = Duration::from_secs(2); +/// let beginning_park = Instant::now(); +/// park_timeout(timeout); +/// +/// while beginning_park.elapsed() < timeout { +/// println!("restarting park_timeout after {:?}", beginning_park.elapsed()); +/// let timeout = timeout - beginning_park.elapsed(); +/// park_timeout(timeout); +/// } +/// ``` #[stable(feature = "park_timeout", since = "1.4.0")] pub fn park_timeout(dur: Duration) { let thread = current(); diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 67f73d4dd4f7..b622f6861b38 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -17,8 +17,8 @@ pub use self::IntType::*; use ast; use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaItemKind}; use ast::{Expr, Item, Local, Stmt, StmtKind}; -use codemap::{spanned, dummy_spanned, Spanned}; -use syntax_pos::{Span, BytePos}; +use codemap::{respan, spanned, dummy_spanned, Spanned}; +use syntax_pos::{Span, BytePos, DUMMY_SP}; use errors::Handler; use feature_gate::{Features, GatedCfg}; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; @@ -92,6 +92,19 @@ pub trait AttrMetaMethods { /// Gets a list of inner meta items from a list MetaItem type. fn meta_item_list(&self) -> Option<&[P]>; + /// Indicates if the attribute is a Word. + fn is_word(&self) -> bool; + + /// Indicates if the attribute is a Value String. + fn is_value_str(&self) -> bool { + self.value_str().is_some() + } + + /// Indicates if the attribute is a Meta-Item List. + fn is_meta_item_list(&self) -> bool { + self.meta_item_list().is_some() + } + fn span(&self) -> Span; } @@ -108,8 +121,11 @@ impl AttrMetaMethods for Attribute { self.meta().value_str() } fn meta_item_list(&self) -> Option<&[P]> { - self.node.value.meta_item_list() + self.meta().meta_item_list() } + + fn is_word(&self) -> bool { self.meta().is_word() } + fn span(&self) -> Span { self.meta().span } } @@ -140,6 +156,14 @@ impl AttrMetaMethods for MetaItem { _ => None } } + + fn is_word(&self) -> bool { + match self.node { + MetaItemKind::Word(_) => true, + _ => false, + } + } + fn span(&self) -> Span { self.span } } @@ -150,6 +174,9 @@ impl AttrMetaMethods for P { fn meta_item_list(&self) -> Option<&[P]> { (**self).meta_item_list() } + fn is_word(&self) -> bool { (**self).is_word() } + fn is_value_str(&self) -> bool { (**self).is_value_str() } + fn is_meta_item_list(&self) -> bool { (**self).is_meta_item_list() } fn span(&self) -> Span { (**self).span() } } @@ -194,22 +221,38 @@ impl AttributeMethods for Attribute { pub fn mk_name_value_item_str(name: InternedString, value: InternedString) -> P { let value_lit = dummy_spanned(ast::LitKind::Str(value, ast::StrStyle::Cooked)); - mk_name_value_item(name, value_lit) + mk_spanned_name_value_item(DUMMY_SP, name, value_lit) } pub fn mk_name_value_item(name: InternedString, value: ast::Lit) -> P { - P(dummy_spanned(MetaItemKind::NameValue(name, value))) + mk_spanned_name_value_item(DUMMY_SP, name, value) } pub fn mk_list_item(name: InternedString, items: Vec>) -> P { - P(dummy_spanned(MetaItemKind::List(name, items))) + mk_spanned_list_item(DUMMY_SP, name, items) } pub fn mk_word_item(name: InternedString) -> P { - P(dummy_spanned(MetaItemKind::Word(name))) + mk_spanned_word_item(DUMMY_SP, name) } +pub fn mk_spanned_name_value_item(sp: Span, name: InternedString, value: ast::Lit) + -> P { + P(respan(sp, MetaItemKind::NameValue(name, value))) +} + +pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec>) + -> P { + P(respan(sp, MetaItemKind::List(name, items))) +} + +pub fn mk_spanned_word_item(sp: Span, name: InternedString) -> P { + P(respan(sp, MetaItemKind::Word(name))) +} + + + thread_local! { static NEXT_ATTR_ID: Cell = Cell::new(0) } pub fn mk_attr_id() -> AttrId { @@ -223,21 +266,43 @@ pub fn mk_attr_id() -> AttrId { /// Returns an inner attribute with the given value. pub fn mk_attr_inner(id: AttrId, item: P) -> Attribute { - dummy_spanned(Attribute_ { - id: id, - style: ast::AttrStyle::Inner, - value: item, - is_sugared_doc: false, - }) + mk_spanned_attr_inner(DUMMY_SP, id, item) } +/// Returns an innter attribute with the given value and span. +pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: P) -> Attribute { + respan(sp, + Attribute_ { + id: id, + style: ast::AttrStyle::Inner, + value: item, + is_sugared_doc: false, + }) +} + + /// Returns an outer attribute with the given value. pub fn mk_attr_outer(id: AttrId, item: P) -> Attribute { + mk_spanned_attr_outer(DUMMY_SP, id, item) +} + +/// Returns an outer attribute with the given value and span. +pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: P) -> Attribute { + respan(sp, + Attribute_ { + id: id, + style: ast::AttrStyle::Outer, + value: item, + is_sugared_doc: false, + }) +} + +pub fn mk_doc_attr_outer(id: AttrId, item: P, is_sugared_doc: bool) -> Attribute { dummy_spanned(Attribute_ { id: id, style: ast::AttrStyle::Outer, value: item, - is_sugared_doc: false, + is_sugared_doc: is_sugared_doc, }) } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index a8aca90e6238..b176b8fefc61 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -71,6 +71,23 @@ pub fn dummy_spanned(t: T) -> Spanned { respan(DUMMY_SP, t) } +/// Build a span that covers the two provided spans. +pub fn combine_spans(sp1: Span, sp2: Span) -> Span { + if sp1 == DUMMY_SP && sp2 == DUMMY_SP { + DUMMY_SP + } else if sp1 == DUMMY_SP { + sp2 + } else if sp2 == DUMMY_SP { + sp1 + } else { + Span { + lo: if sp1.lo < sp2.lo { sp1.lo } else { sp2.lo }, + hi: if sp1.hi > sp2.hi { sp1.hi } else { sp2.hi }, + expn_id: if sp1.expn_id == sp2.expn_id { sp1.expn_id } else { NO_EXPANSION }, + } + } +} + #[derive(Clone, Hash, Debug)] pub struct NameAndSpan { /// The format with which the macro was invoked. diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index ff75149f518a..a825cf866a87 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -124,7 +124,7 @@ pub fn strip_unconfigured_items(mut krate: ast::Crate, sess: &ParseSess, should_ }; let err_count = sess.span_diagnostic.err_count(); - let krate_attrs = strip_unconfigured.process_cfg_attrs(krate.attrs.clone()); + let krate_attrs = strip_unconfigured.configure(krate.attrs.clone()).unwrap_or_default(); features = get_features(&sess.span_diagnostic, &krate_attrs); if err_count < sess.span_diagnostic.err_count() { krate.attrs = krate_attrs.clone(); // Avoid reconfiguring malformed `cfg_attr`s diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 435241f426ec..5d6429f7bdff 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -1135,30 +1135,19 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn attribute(&self, sp: Span, mi: P) -> ast::Attribute { - respan(sp, ast::Attribute_ { - id: attr::mk_attr_id(), - style: ast::AttrStyle::Outer, - value: mi, - is_sugared_doc: false, - }) + attr::mk_spanned_attr_outer(sp, attr::mk_attr_id(), mi) } fn meta_word(&self, sp: Span, w: InternedString) -> P { - P(respan(sp, ast::MetaItemKind::Word(w))) + attr::mk_spanned_word_item(sp, w) } - fn meta_list(&self, - sp: Span, - name: InternedString, - mis: Vec> ) + fn meta_list(&self, sp: Span, name: InternedString, mis: Vec>) -> P { - P(respan(sp, ast::MetaItemKind::List(name, mis))) + attr::mk_spanned_list_item(sp, name, mis) } - fn meta_name_value(&self, - sp: Span, - name: InternedString, - value: ast::LitKind) + fn meta_name_value(&self, sp: Span, name: InternedString, value: ast::LitKind) -> P { - P(respan(sp, ast::MetaItemKind::NameValue(name, respan(sp, value)))) + attr::mk_spanned_name_value_item(sp, name, respan(sp, value)) } fn item_use(&self, sp: Span, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 18342f2e38c1..5293d2ab0001 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -302,9 +302,8 @@ fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool }; if is_use { - match attr.node.value.node { - ast::MetaItemKind::Word(..) => (), - _ => fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here"), + if !attr.is_word() { + fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here"); } return true; } diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index ffc950d76dd2..b70e270df54d 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -581,9 +581,10 @@ fn mk_binop(cx: &ExtCtxt, sp: Span, bop: token::BinOpToken) -> P { fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P { let name = match delim { - token::Paren => "Paren", - token::Bracket => "Bracket", - token::Brace => "Brace", + token::Paren => "Paren", + token::Bracket => "Bracket", + token::Brace => "Brace", + token::NoDelim => "NoDelim", }; mk_token_path(cx, sp, name) } diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 7c0d10669f30..29a300b172e7 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -14,7 +14,7 @@ use syntax_pos::{Span, DUMMY_SP}; use errors::{Handler, DiagnosticBuilder}; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; use parse::token::{DocComment, MatchNt, SubstNt}; -use parse::token::{Token, NtIdent, SpecialMacroVar}; +use parse::token::{Token, Interpolated, NtIdent, NtTT, SpecialMacroVar}; use parse::token; use parse::lexer::TokenAndSpan; use tokenstream::{self, TokenTree}; @@ -278,9 +278,9 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { } // FIXME #2887: think about span stuff here TokenTree::Token(sp, SubstNt(ident)) => { - r.stack.last_mut().unwrap().idx += 1; match lookup_cur_matched(r, ident) { None => { + r.stack.last_mut().unwrap().idx += 1; r.cur_span = sp; r.cur_tok = SubstNt(ident); return ret_val; @@ -292,14 +292,24 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { // (a) idents can be in lots of places, so it'd be a pain // (b) we actually can, since it's a token. MatchedNonterminal(NtIdent(ref sn)) => { + r.stack.last_mut().unwrap().idx += 1; r.cur_span = sn.span; r.cur_tok = token::Ident(sn.node); return ret_val; } + MatchedNonterminal(NtTT(ref tt)) => { + r.stack.push(TtFrame { + forest: TokenTree::Token(sp, Interpolated(NtTT(tt.clone()))), + idx: 0, + dotdotdoted: false, + sep: None, + }); + } MatchedNonterminal(ref other_whole_nt) => { + r.stack.last_mut().unwrap().idx += 1; // FIXME(pcwalton): Bad copy. r.cur_span = sp; - r.cur_tok = token::Interpolated((*other_whole_nt).clone()); + r.cur_tok = Interpolated((*other_whole_nt).clone()); return ret_val; } MatchedSeq(..) => { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 27485ee65fcc..29da0fb1a273 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -481,6 +481,16 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), + ("rustc_partition_reused", Whitelisted, Gated("rustc_attrs", + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), + ("rustc_partition_translated", Whitelisted, Gated("rustc_attrs", + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs", "internal rustc attributes will never be stable", cfg_fn!(rustc_attrs))), @@ -800,6 +810,29 @@ macro_rules! gate_feature_post { }} } +impl<'a> PostExpansionVisitor<'a> { + fn check_abi(&self, abi: Abi, span: Span) { + match abi { + Abi::RustIntrinsic => + gate_feature_post!(&self, intrinsics, span, + "intrinsics are subject to change"), + Abi::PlatformIntrinsic => { + gate_feature_post!(&self, platform_intrinsics, span, + "platform intrinsics are experimental and possibly buggy") + }, + Abi::Vectorcall => { + gate_feature_post!(&self, abi_vectorcall, span, + "vectorcall is experimental and subject to change") + } + Abi::RustCall => { + gate_feature_post!(&self, unboxed_closures, span, + "rust-call ABI is subject to change"); + } + _ => {} + } + } +} + impl<'a> Visitor for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { if !self.context.cm.span_allows_unstable(attr.span) { @@ -831,21 +864,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { across platforms, it is recommended to \ use `#[link(name = \"foo\")]` instead") } - match foreign_module.abi { - Abi::RustIntrinsic => - gate_feature_post!(&self, intrinsics, i.span, - "intrinsics are subject to change"), - Abi::PlatformIntrinsic => { - gate_feature_post!(&self, platform_intrinsics, i.span, - "platform intrinsics are experimental \ - and possibly buggy") - }, - Abi::Vectorcall => { - gate_feature_post!(&self, abi_vectorcall, i.span, - "vectorcall is experimental and subject to change") - } - _ => () - } + self.check_abi(foreign_module.abi, i.span); } ast::ItemKind::Fn(..) => { @@ -928,6 +947,16 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { visit::walk_foreign_item(self, i) } + fn visit_ty(&mut self, ty: &ast::Ty) { + match ty.node { + ast::TyKind::BareFn(ref bare_fn_ty) => { + self.check_abi(bare_fn_ty.abi, ty.span); + } + _ => {} + } + visit::walk_ty(self, ty) + } + fn visit_expr(&mut self, e: &ast::Expr) { match e.node { ast::ExprKind::Box(_) => { @@ -1015,23 +1044,10 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { } match fn_kind { - FnKind::ItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => { - gate_feature_post!(&self, intrinsics, - span, - "intrinsics are subject to change") - } FnKind::ItemFn(_, _, _, _, abi, _) | - FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => match abi { - Abi::RustCall => { - gate_feature_post!(&self, unboxed_closures, span, - "rust-call ABI is subject to change"); - }, - Abi::Vectorcall => { - gate_feature_post!(&self, abi_vectorcall, span, - "vectorcall is experimental and subject to change"); - }, - _ => {} - }, + FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => { + self.check_abi(abi, span); + } _ => {} } visit::walk_fn(self, fn_kind, fn_decl, block, span); @@ -1044,7 +1060,10 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { ti.span, "associated constants are experimental") } - ast::TraitItemKind::Method(ref sig, _) => { + ast::TraitItemKind::Method(ref sig, ref block) => { + if block.is_none() { + self.check_abi(sig.abi, ti.span); + } if sig.constness == ast::Constness::Const { gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); } @@ -1108,14 +1127,13 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> F } Some(list) => { for mi in list { - let name = match mi.node { - ast::MetaItemKind::Word(ref word) => (*word).clone(), - _ => { - span_err!(span_handler, mi.span, E0556, - "malformed feature, expected just one word"); - continue - } - }; + let name = if mi.is_word() { + mi.name() + } else { + span_err!(span_handler, mi.span, E0556, + "malformed feature, expected just one word"); + continue + }; if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter() .find(|& &(n, _, _, _)| name == n) { *(setter(&mut features)) = true; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 2147e8ec2eb1..7b28952aff6b 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -237,7 +237,7 @@ pub fn new_parser_from_ts<'a>(sess: &'a ParseSess, cfg: ast::CrateConfig, ts: tokenstream::TokenStream) -> Parser<'a> { - tts_to_parser(sess, ts.tts, cfg) + tts_to_parser(sess, ts.to_tts(), cfg) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 125f1abb062b..c143e190c6fc 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -258,6 +258,7 @@ pub struct Parser<'a> { pub tokens_consumed: usize, pub restrictions: Restrictions, pub quote_depth: usize, // not (yet) related to the quasiquoter + parsing_token_tree: bool, pub reader: Box, /// The set of seen errors about obsolete syntax. Used to suppress /// extra detail when the same error is seen twice @@ -374,6 +375,7 @@ impl<'a> Parser<'a> { tokens_consumed: 0, restrictions: Restrictions::empty(), quote_depth: 0, + parsing_token_tree: false, obsolete_set: HashSet::new(), mod_path_stack: Vec::new(), filename: filename, @@ -2663,7 +2665,7 @@ impl<'a> Parser<'a> { } pub fn check_unknown_macro_variable(&mut self) { - if self.quote_depth == 0 { + if self.quote_depth == 0 && !self.parsing_token_tree { match self.token { token::SubstNt(name) => self.fatal(&format!("unknown macro variable `{}`", name)).emit(), @@ -2723,6 +2725,7 @@ impl<'a> Parser<'a> { Err(err) }, token::OpenDelim(delim) => { + let parsing_token_tree = ::std::mem::replace(&mut self.parsing_token_tree, true); // The span for beginning of the delimited section let pre_span = self.span; @@ -2787,6 +2790,7 @@ impl<'a> Parser<'a> { _ => {} } + self.parsing_token_tree = parsing_token_tree; Ok(TokenTree::Delimited(span, Rc::new(Delimited { delim: delim, open_span: open_span, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index f0a6f8edeec7..6fdc9b714d34 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -48,6 +48,8 @@ pub enum DelimToken { Bracket, /// A curly brace: `{` or `}` Brace, + /// An empty delimiter + NoDelim, } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 8866ffc2575c..a619da84b2d5 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -242,6 +242,8 @@ pub fn token_to_string(tok: &Token) -> String { token::CloseDelim(token::Bracket) => "]".to_string(), token::OpenDelim(token::Brace) => "{".to_string(), token::CloseDelim(token::Brace) => "}".to_string(), + token::OpenDelim(token::NoDelim) => " ".to_string(), + token::CloseDelim(token::NoDelim) => " ".to_string(), token::Pound => "#".to_string(), token::Dollar => "$".to_string(), token::Question => "?".to_string(), @@ -1777,12 +1779,14 @@ impl<'a> State<'a> { try!(self.head("")); try!(self.bopen()); } + token::NoDelim => {} } try!(self.print_tts(&m.node.tts)); match delim { token::Paren => self.pclose(), token::Bracket => word(&mut self.s, "]"), token::Brace => self.bclose(m.span), + token::NoDelim => Ok(()), } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 0ad09fd0f7df..89ead21cc10c 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -16,27 +16,27 @@ //! or a SequenceRepetition specifier (for the purpose of sequence generation during macro //! expansion). //! -//! A TokenStream also has a slice view, `TokenSlice`, that is analogous to `str` for -//! `String`: it allows the programmer to divvy up, explore, and otherwise partition a -//! TokenStream as borrowed subsequences. +//! ## Ownership +//! TokenStreams are persistant data structures construced as ropes with reference +//! counted-children. In general, this means that calling an operation on a TokenStream +//! (such as `slice`) produces an entirely new TokenStream from the borrowed reference to +//! the original. This essentially coerces TokenStreams into 'views' of their subparts, +//! and a borrowed TokenStream is sufficient to build an owned TokenStream without taking +//! ownership of the original. use ast::{self, AttrStyle, LitKind}; use syntax_pos::{Span, DUMMY_SP, NO_EXPANSION}; -use codemap::Spanned; +use codemap::{Spanned, combine_spans}; use ext::base; use ext::tt::macro_parser; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use parse::lexer; use parse; -use parse::token::{self, Token, Lit, InternedString, Nonterminal}; -use parse::token::Lit as TokLit; +use parse::token::{self, Token, Lit, Nonterminal}; use std::fmt; -use std::mem; -use std::ops::Index; -use std::ops; use std::iter::*; - +use std::ops::{self, Index}; use std::rc::Rc; /// A delimited sequence of token trees @@ -135,6 +135,7 @@ impl TokenTree { } TokenTree::Token(_, token::SpecialVarNt(..)) => 2, TokenTree::Token(_, token::MatchNt(..)) => 3, + TokenTree::Token(_, token::Interpolated(Nonterminal::NtTT(..))) => 1, TokenTree::Delimited(_, ref delimed) => delimed.tts.len() + 2, TokenTree::Sequence(_, ref seq) => seq.tts.len(), TokenTree::Token(..) => 0, @@ -197,6 +198,9 @@ impl TokenTree { TokenTree::Token(sp, token::Ident(kind))]; v[index].clone() } + (&TokenTree::Token(_, token::Interpolated(Nonterminal::NtTT(ref tt))), _) => { + tt.clone().unwrap() + } (&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(), _ => panic!("Cannot expand a token tree"), } @@ -331,27 +335,51 @@ impl TokenTree { /// struct itself shouldn't be directly manipulated; the internal structure is not stable, /// and may be changed at any time in the future. The operators will not, however (except /// for signatures, later on). -#[derive(Eq,Clone,Hash,RustcEncodable,RustcDecodable)] +#[derive(Clone, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct TokenStream { - pub span: Span, - pub tts: Vec, + ts: InternalTS, +} + +// NB If Leaf access proves to be slow, inroducing a secondary Leaf without the bounds +// for unsliced Leafs may lead to some performance improvemenet. +#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub enum InternalTS { + Empty(Span), + Leaf { + tts: Rc>, + offset: usize, + len: usize, + sp: Span, + }, + Node { + left: Rc, + right: Rc, + len: usize, + sp: Span, + }, } impl fmt::Debug for TokenStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.tts.len() == 0 { - write!(f, "([empty")?; - } else { - write!(f, "([")?; - write!(f, "{:?}", self.tts[0])?; + self.ts.fmt(f) + } +} - for tt in self.tts.iter().skip(1) { - write!(f, ",{:?}", tt)?; +impl fmt::Debug for InternalTS { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + InternalTS::Empty(..) => Ok(()), + InternalTS::Leaf { ref tts, offset, len, .. } => { + for t in tts.iter().skip(offset).take(len) { + try!(write!(f, "{:?}", t)); + } + Ok(()) + } + InternalTS::Node { ref left, ref right, .. } => { + try!(left.fmt(f)); + right.fmt(f) } } - write!(f, "|")?; - self.span.fmt(f)?; - write!(f, "])") } } @@ -359,7 +387,7 @@ impl fmt::Debug for TokenStream { /// equality, see `eq_unspanned`. impl PartialEq for TokenStream { fn eq(&self, other: &TokenStream) -> bool { - self.tts == other.tts + self.iter().eq(other.iter()) } } @@ -404,6 +432,59 @@ fn covering_span(trees: &[TokenTree]) -> Span { } } +impl InternalTS { + fn len(&self) -> usize { + match *self { + InternalTS::Empty(..) => 0, + InternalTS::Leaf { len, .. } => len, + InternalTS::Node { len, .. } => len, + } + } + + fn span(&self) -> Span { + match *self { + InternalTS::Empty(sp) | + InternalTS::Leaf { sp, .. } | + InternalTS::Node { sp, .. } => sp, + } + } + + fn slice(&self, range: ops::Range) -> TokenStream { + let from = range.start; + let to = range.end; + if from == to { + return TokenStream::mk_empty(); + } + if from > to { + panic!("Invalid range: {} to {}", from, to); + } + if from == 0 && to == self.len() { + return TokenStream { ts: self.clone() }; /* should be cheap */ + } + match *self { + InternalTS::Empty(..) => panic!("Invalid index"), + InternalTS::Leaf { ref tts, offset, .. } => { + let offset = offset + from; + let len = to - from; + TokenStream::mk_sub_leaf(tts.clone(), + offset, + len, + covering_span(&tts[offset..offset + len])) + } + InternalTS::Node { ref left, ref right, .. } => { + let left_len = left.len(); + if to <= left_len { + left.slice(range) + } else if from >= left_len { + right.slice(from - left_len..to - left_len) + } else { + TokenStream::concat(left.slice(from..left_len), right.slice(0..to - left_len)) + } + } + } + } +} + /// TokenStream operators include basic destructuring, boolean operations, `maybe_...` /// operations, and `maybe_..._prefix` operations. Boolean operations are straightforward, /// indicating information about the structure of the stream. The `maybe_...` operations @@ -415,129 +496,149 @@ fn covering_span(trees: &[TokenTree]) -> Span { /// /// `maybe_path_prefix("a::b::c(a,b,c).foo()") -> (a::b::c, "(a,b,c).foo()")` impl TokenStream { - /// Convert a vector of `TokenTree`s into a `TokenStream`. - pub fn from_tts(trees: Vec) -> TokenStream { - let span = covering_span(&trees); + pub fn mk_empty() -> TokenStream { + TokenStream { ts: InternalTS::Empty(DUMMY_SP) } + } + + fn mk_spanned_empty(sp: Span) -> TokenStream { + TokenStream { ts: InternalTS::Empty(sp) } + } + + fn mk_leaf(tts: Rc>, sp: Span) -> TokenStream { + let len = tts.len(); TokenStream { - tts: trees, - span: span, + ts: InternalTS::Leaf { + tts: tts, + offset: 0, + len: len, + sp: sp, + }, } } - /// Copies all of the TokenTrees from the TokenSlice, appending them to the stream. - pub fn append_stream(mut self, ts2: &TokenSlice) { - for tt in ts2.iter() { - self.tts.push(tt.clone()); + fn mk_sub_leaf(tts: Rc>, offset: usize, len: usize, sp: Span) -> TokenStream { + TokenStream { + ts: InternalTS::Leaf { + tts: tts, + offset: offset, + len: len, + sp: sp, + }, } - self.span = covering_span(&self.tts[..]); + } + + fn mk_int_node(left: Rc, + right: Rc, + len: usize, + sp: Span) + -> TokenStream { + TokenStream { + ts: InternalTS::Node { + left: left, + right: right, + len: len, + sp: sp, + }, + } + } + + /// Convert a vector of `TokenTree`s into a `TokenStream`. + pub fn from_tts(trees: Vec) -> TokenStream { + let span = covering_span(&trees[..]); + TokenStream::mk_leaf(Rc::new(trees), span) } /// Manually change a TokenStream's span. pub fn respan(self, span: Span) -> TokenStream { - TokenStream { - tts: self.tts, - span: span, - } - } - - /// Construct a TokenStream from an ast literal. - pub fn from_ast_lit_str(lit: ast::Lit) -> Option { - match lit.node { - LitKind::Str(val, _) => { - let val = TokLit::Str_(token::intern(&val)); - Some(TokenStream::from_tts(vec![TokenTree::Token(lit.span, - Token::Literal(val, None))])) + match self.ts { + InternalTS::Empty(..) => TokenStream::mk_spanned_empty(span), + InternalTS::Leaf { tts, offset, len, .. } => { + TokenStream::mk_sub_leaf(tts, offset, len, span) + } + InternalTS::Node { left, right, len, .. } => { + TokenStream::mk_int_node(left, right, len, span) } - _ => None, } - } - /// Convert a vector of TokenTrees into a parentheses-delimited TokenStream. - pub fn as_paren_delimited_stream(tts: Vec) -> TokenStream { - let new_sp = covering_span(&tts); - - let new_delim = Rc::new(Delimited { - delim: token::DelimToken::Paren, - open_span: DUMMY_SP, - tts: tts, - close_span: DUMMY_SP, - }); - - TokenStream::from_tts(vec![TokenTree::Delimited(new_sp, new_delim)]) + /// Concatenates two TokenStreams into a new TokenStream + pub fn concat(left: TokenStream, right: TokenStream) -> TokenStream { + let new_len = left.len() + right.len(); + let new_span = combine_spans(left.span(), right.span()); + TokenStream::mk_int_node(Rc::new(left.ts), Rc::new(right.ts), new_len, new_span) } - /// Convert an interned string into a one-element TokenStream. - pub fn from_interned_string_as_ident(s: InternedString) -> TokenStream { - TokenStream::from_tts(vec![TokenTree::Token(DUMMY_SP, - Token::Ident(token::str_to_ident(&s[..])))]) - } -} - -/// TokenSlices are 'views' of `TokenStream's; they fit the same role as `str`s do for -/// `String`s. In general, most TokenStream manipulations will be refocusing their internal -/// contents by taking a TokenSlice and then using indexing and the provided operators. -#[derive(PartialEq, Eq, Debug)] -pub struct TokenSlice([TokenTree]); - -impl ops::Deref for TokenStream { - type Target = TokenSlice; - - fn deref(&self) -> &TokenSlice { - let tts: &[TokenTree] = &*self.tts; - unsafe { mem::transmute(tts) } - } -} - -impl TokenSlice { - /// Convert a borrowed TokenTree slice into a borrowed TokenSlice. - fn from_tts(tts: &[TokenTree]) -> &TokenSlice { - unsafe { mem::transmute(tts) } - } - - /// Indicates whether the `TokenStream` is empty. + /// Indicate if the TokenStream is empty. pub fn is_empty(&self) -> bool { self.len() == 0 } - /// Return the `TokenSlice`'s length. + /// Return a TokenStream's length. pub fn len(&self) -> usize { - self.0.len() + self.ts.len() } - /// Check equality versus another TokenStream, ignoring span information. - pub fn eq_unspanned(&self, other: &TokenSlice) -> bool { - if self.len() != other.len() { - return false; - } - for (tt1, tt2) in self.iter().zip(other.iter()) { - if !tt1.eq_unspanned(tt2) { - return false; + /// Convert a TokenStream into a vector of borrowed TokenTrees. + pub fn to_vec(&self) -> Vec<&TokenTree> { + fn internal_to_vec(ts: &InternalTS) -> Vec<&TokenTree> { + match *ts { + InternalTS::Empty(..) => Vec::new(), + InternalTS::Leaf { ref tts, offset, len, .. } => { + tts[offset..offset + len].iter().collect() + } + InternalTS::Node { ref left, ref right, .. } => { + let mut v1 = internal_to_vec(left); + let mut v2 = internal_to_vec(right); + v1.append(&mut v2); + v1 + } } } - true + internal_to_vec(&self.ts) } - /// Compute a span that covers the entire TokenSlice (eg, one wide enough to include - /// the entire slice). If the inputs share expansion identification, it is preserved. - /// If they do not, it is discarded. - pub fn covering_span(&self) -> Span { - covering_span(&self.0) + /// Convert a TokenStream into a vector of TokenTrees (by cloning the TokenTrees). + /// (This operation is an O(n) deep copy of the underlying structure.) + pub fn to_tts(&self) -> Vec { + self.to_vec().into_iter().cloned().collect::>() } - /// Indicates where the stream is of the form `= `, where `` is a continued - /// `TokenStream`. - pub fn is_assignment(&self) -> bool { - self.maybe_assignment().is_some() + /// Return the TokenStream's span. + pub fn span(&self) -> Span { + self.ts.span() } - /// Returns the RHS of an assigment. - pub fn maybe_assignment(&self) -> Option<&TokenSlice> { - if !(self.len() > 1) { - return None; + /// Returns an iterator over a TokenStream (as a sequence of TokenTrees). + pub fn iter<'a>(&self) -> Iter { + Iter { vs: self, idx: 0 } + } + + /// Splits a TokenStream based on the provided `&TokenTree -> bool` predicate. + pub fn split

(&self, pred: P) -> Split

+ where P: FnMut(&TokenTree) -> bool + { + Split { + vs: self, + pred: pred, + finished: false, + idx: 0, } + } - Some(&self[1..]) + /// Produce a slice of the input TokenStream from the `from` index, inclusive, to the + /// `to` index, non-inclusive. + pub fn slice(&self, range: ops::Range) -> TokenStream { + self.ts.slice(range) + } + + /// Slice starting at the provided index, inclusive. + pub fn slice_from(&self, from: ops::RangeFrom) -> TokenStream { + self.slice(from.start..self.len()) + } + + /// Slice up to the provided index, non-inclusive. + pub fn slice_to(&self, to: ops::RangeTo) -> TokenStream { + self.slice(0..to.end) } /// Indicates where the stream is a single, delimited expression (e.g., `(a,b,c)` or @@ -547,50 +648,15 @@ impl TokenSlice { } /// Returns the inside of the delimited term as a new TokenStream. - pub fn maybe_delimited(&self) -> Option<&TokenSlice> { + pub fn maybe_delimited(&self) -> Option { if !(self.len() == 1) { return None; } + // FIXME It would be nice to change Delimited to move the Rc around the TokenTree + // vector directly in order to avoid the clone here. match self[0] { - TokenTree::Delimited(_, ref rc) => Some(TokenSlice::from_tts(&*rc.tts)), - _ => None, - } - } - - /// Returns a list of `TokenSlice`s if the stream is a delimited list, breaking the - /// stream on commas. - pub fn maybe_comma_list(&self) -> Option> { - let maybe_tts = self.maybe_delimited(); - - let ts: &TokenSlice; - match maybe_tts { - Some(t) => { - ts = t; - } - None => { - return None; - } - } - - let splits: Vec<&TokenSlice> = ts.split(|x| match *x { - TokenTree::Token(_, Token::Comma) => true, - _ => false, - }) - .filter(|x| x.len() > 0) - .collect(); - - Some(splits) - } - - /// Returns a Nonterminal if it is Interpolated. - pub fn maybe_interpolated_nonterminal(&self) -> Option { - if !(self.len() == 1) { - return None; - } - - match self[0] { - TokenTree::Token(_, Token::Interpolated(ref nt)) => Some(nt.clone()), + TokenTree::Delimited(_, ref rc) => Some(TokenStream::from_tts(rc.tts.clone())), _ => None, } } @@ -606,180 +672,54 @@ impl TokenSlice { return None; } - let tok = if let Some(tts) = self.maybe_delimited() { - if tts.len() != 1 { - return None; - } - &tts[0] - } else { - &self[0] - }; - - match *tok { + match self[0] { TokenTree::Token(_, Token::Ident(t)) => Some(t), _ => None, } } - /// Indicates if the stream is exactly one literal - pub fn is_lit(&self) -> bool { - self.maybe_lit().is_some() - } - - /// Returns a literal - pub fn maybe_lit(&self) -> Option { - if !(self.len() == 1) { - return None; - } - - let tok = if let Some(tts) = self.maybe_delimited() { - if tts.len() != 1 { - return None; - } - &tts[0] - } else { - &self[0] - }; - - match *tok { - TokenTree::Token(_, Token::Literal(l, _)) => Some(l), - _ => None, - } - } - - /// Returns an AST string literal if the TokenStream is either a normal ('cooked') or - /// raw string literal. - pub fn maybe_str(&self) -> Option { - if !(self.len() == 1) { - return None; - } - - match self[0] { - TokenTree::Token(sp, Token::Literal(Lit::Str_(s), _)) => { - let l = LitKind::Str(token::intern_and_get_ident(&parse::str_lit(&s.as_str())), - ast::StrStyle::Cooked); - Some(Spanned { - node: l, - span: sp, - }) - } - TokenTree::Token(sp, Token::Literal(Lit::StrRaw(s, n), _)) => { - let l = LitKind::Str(token::intern_and_get_ident(&parse::raw_str_lit(&s.as_str())), - ast::StrStyle::Raw(n)); - Some(Spanned { - node: l, - span: sp, - }) - } - _ => None, - } - } - - /// This operation extracts the path prefix , returning an AST path struct and the remainder - /// of the stream (if it finds one). To be more specific, a tokenstream that has a valid, - /// non-global path as a prefix (eg `foo(bar, baz)`, `foo::bar(bar)`, but *not* - /// `::foo::bar(baz)`) will yield the path and the remaining tokens (as a slice). The previous - /// examples will yield - /// `Some((Path { segments = vec![foo], ... }, [(bar, baz)]))`, - /// `Some((Path { segments = vec![foo, bar] }, [(baz)]))`, - /// and `None`, respectively. - pub fn maybe_path_prefix(&self) -> Option<(ast::Path, &TokenSlice)> { - let mut segments: Vec = Vec::new(); - - let path: Vec<&TokenTree> = self.iter() - .take_while(|x| x.is_ident() || x.eq_token(Token::ModSep)) - .collect::>(); - - let path_size = path.len(); - if path_size == 0 { - return None; - } - - let cov_span = self[..path_size].covering_span(); - let rst = &self[path_size..]; - - let fst_id = path[0]; - - if let Some(id) = fst_id.maybe_ident() { - segments.push(ast::PathSegment { - identifier: id, - parameters: ast::PathParameters::none(), - }); - } else { - return None; - } - - // Let's use a state machine to parse out the rest. - enum State { - Mod, // Expect a `::`, or return None otherwise. - Ident, // Expect an ident, or return None otherwise. - } - let mut state = State::Mod; - - for p in &path[1..] { - match state { - State::Mod => { - // State 0: ['::' -> state 1, else return None] - if p.eq_token(Token::ModSep) { - state = State::Ident; - } else { - return None; - } - } - State::Ident => { - // State 1: [ident -> state 0, else return None] - if let Some(id) = p.maybe_ident() { - segments.push(ast::PathSegment { - identifier: id, - parameters: ast::PathParameters::none(), - }); - state = State::Mod; - } else { - return None; - } - } + /// Compares two TokenStreams, checking equality without regarding span information. + pub fn eq_unspanned(&self, other: &TokenStream) -> bool { + for (t1, t2) in self.iter().zip(other.iter()) { + if !t1.eq_unspanned(t2) { + return false; } } - - let path = ast::Path { - span: cov_span, - global: false, - segments: segments, - }; - Some((path, rst)) + true } - /// Returns an iterator over a TokenSlice (as a sequence of TokenStreams). - fn iter(&self) -> Iter { - Iter { vs: self } - } + /// Convert a vector of TokenTrees into a parentheses-delimited TokenStream. + pub fn as_delimited_stream(tts: Vec, delim: token::DelimToken) -> TokenStream { + let new_sp = covering_span(&tts); - /// Splits a TokenSlice based on the provided `&TokenTree -> bool` predicate. - fn split

(&self, pred: P) -> Split

- where P: FnMut(&TokenTree) -> bool - { - Split { - vs: self, - pred: pred, - finished: false, - } + let new_delim = Rc::new(Delimited { + delim: delim, + open_span: DUMMY_SP, + tts: tts, + close_span: DUMMY_SP, + }); + + TokenStream::from_tts(vec![TokenTree::Delimited(new_sp, new_delim)]) } } +// FIXME Reimplement this iterator to hold onto a slice iterator for a leaf, getting the +// next leaf's iterator when the current one is exhausted. pub struct Iter<'a> { - vs: &'a TokenSlice, + vs: &'a TokenStream, + idx: usize, } impl<'a> Iterator for Iter<'a> { type Item = &'a TokenTree; fn next(&mut self) -> Option<&'a TokenTree> { - if self.vs.is_empty() { + if self.vs.is_empty() || self.idx >= self.vs.len() { return None; } - let ret = Some(&self.vs[0]); - self.vs = &self.vs[1..]; + let ret = Some(&self.vs[self.idx]); + self.idx = self.idx + 1; ret } } @@ -787,29 +727,35 @@ impl<'a> Iterator for Iter<'a> { pub struct Split<'a, P> where P: FnMut(&TokenTree) -> bool { - vs: &'a TokenSlice, + vs: &'a TokenStream, pred: P, finished: bool, + idx: usize, } impl<'a, P> Iterator for Split<'a, P> where P: FnMut(&TokenTree) -> bool { - type Item = &'a TokenSlice; + type Item = TokenStream; - fn next(&mut self) -> Option<&'a TokenSlice> { + fn next(&mut self) -> Option { if self.finished { return None; } + if self.idx >= self.vs.len() { + self.finished = true; + return None; + } - match self.vs.iter().position(|x| (self.pred)(x)) { + let mut lookup = self.vs.iter().skip(self.idx); + match lookup.position(|x| (self.pred)(&x)) { None => { self.finished = true; - Some(&self.vs[..]) + Some(self.vs.slice_from(self.idx..)) } - Some(idx) => { - let ret = Some(&self.vs[..idx]); - self.vs = &self.vs[idx + 1..]; + Some(edx) => { + let ret = Some(self.vs.slice(self.idx..self.idx + edx)); + self.idx += edx + 1; ret } } @@ -820,79 +766,29 @@ impl Index for TokenStream { type Output = TokenTree; fn index(&self, index: usize) -> &TokenTree { - Index::index(&**self, index) + &self.ts[index] } } -impl ops::Index> for TokenStream { - type Output = TokenSlice; - - fn index(&self, index: ops::Range) -> &TokenSlice { - Index::index(&**self, index) - } -} - -impl ops::Index> for TokenStream { - type Output = TokenSlice; - - fn index(&self, index: ops::RangeTo) -> &TokenSlice { - Index::index(&**self, index) - } -} - -impl ops::Index> for TokenStream { - type Output = TokenSlice; - - fn index(&self, index: ops::RangeFrom) -> &TokenSlice { - Index::index(&**self, index) - } -} - -impl ops::Index for TokenStream { - type Output = TokenSlice; - - fn index(&self, _index: ops::RangeFull) -> &TokenSlice { - Index::index(&**self, _index) - } -} - -impl Index for TokenSlice { +impl Index for InternalTS { type Output = TokenTree; fn index(&self, index: usize) -> &TokenTree { - &self.0[index] - } -} - -impl ops::Index> for TokenSlice { - type Output = TokenSlice; - - fn index(&self, index: ops::Range) -> &TokenSlice { - TokenSlice::from_tts(&self.0[index]) - } -} - -impl ops::Index> for TokenSlice { - type Output = TokenSlice; - - fn index(&self, index: ops::RangeTo) -> &TokenSlice { - TokenSlice::from_tts(&self.0[index]) - } -} - -impl ops::Index> for TokenSlice { - type Output = TokenSlice; - - fn index(&self, index: ops::RangeFrom) -> &TokenSlice { - TokenSlice::from_tts(&self.0[index]) - } -} - -impl ops::Index for TokenSlice { - type Output = TokenSlice; - - fn index(&self, _index: ops::RangeFull) -> &TokenSlice { - TokenSlice::from_tts(&self.0[_index]) + if self.len() <= index { + panic!("Index {} too large for {:?}", index, self); + } + match *self { + InternalTS::Empty(..) => panic!("Invalid index"), + InternalTS::Leaf { ref tts, offset, .. } => tts.get(index + offset).unwrap(), + InternalTS::Node { ref left, ref right, .. } => { + let left_len = left.len(); + if index < left_len { + Index::index(&**left, index) + } else { + Index::index(&**right, index - left_len) + } + } + } } } @@ -900,9 +796,8 @@ impl ops::Index for TokenSlice { #[cfg(test)] mod tests { use super::*; - use ast; use syntax_pos::{Span, BytePos, NO_EXPANSION, DUMMY_SP}; - use parse::token::{self, str_to_ident, Token, Lit}; + use parse::token::{self, str_to_ident, Token}; use util::parser_testing::string_to_tts; use std::rc::Rc; @@ -914,6 +809,93 @@ mod tests { } } + fn as_paren_delimited_stream(tts: Vec) -> TokenStream { + TokenStream::as_delimited_stream(tts, token::DelimToken::Paren) + } + + #[test] + fn test_concat() { + let test_res = TokenStream::from_tts(string_to_tts("foo::bar::baz".to_string())); + let test_fst = TokenStream::from_tts(string_to_tts("foo::bar".to_string())); + let test_snd = TokenStream::from_tts(string_to_tts("::baz".to_string())); + let eq_res = TokenStream::concat(test_fst, test_snd); + assert_eq!(test_res.len(), 5); + assert_eq!(eq_res.len(), 5); + assert_eq!(test_res.eq_unspanned(&eq_res), true); + } + + #[test] + fn test_from_to_bijection() { + let test_start = string_to_tts("foo::bar(baz)".to_string()); + let test_end = TokenStream::from_tts(string_to_tts("foo::bar(baz)".to_string())).to_tts(); + assert_eq!(test_start, test_end) + } + + #[test] + fn test_to_from_bijection() { + let test_start = TokenStream::from_tts(string_to_tts("foo::bar(baz)".to_string())); + let test_end = TokenStream::from_tts(test_start.clone().to_tts()); + assert_eq!(test_start, test_end) + } + + #[test] + fn test_eq_0() { + let test_res = TokenStream::from_tts(string_to_tts("foo".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("foo".to_string())); + assert_eq!(test_res, test_eqs) + } + + #[test] + fn test_eq_1() { + let test_res = TokenStream::from_tts(string_to_tts("::bar::baz".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("::bar::baz".to_string())); + assert_eq!(test_res, test_eqs) + } + + #[test] + fn test_eq_2() { + let test_res = TokenStream::from_tts(string_to_tts("foo::bar".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("foo::bar::baz".to_string())); + assert_eq!(test_res, test_eqs.slice(0..3)) + } + + #[test] + fn test_eq_3() { + let test_res = TokenStream::from_tts(string_to_tts("".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("".to_string())); + assert_eq!(test_res, test_eqs) + } + + #[test] + fn test_diseq_0() { + let test_res = TokenStream::from_tts(string_to_tts("::bar::baz".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("bar::baz".to_string())); + assert_eq!(test_res == test_eqs, false) + } + + #[test] + fn test_diseq_1() { + let test_res = TokenStream::from_tts(string_to_tts("(bar,baz)".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("bar,baz".to_string())); + assert_eq!(test_res == test_eqs, false) + } + + #[test] + fn test_slice_0() { + let test_res = TokenStream::from_tts(string_to_tts("foo::bar".to_string())); + let test_eqs = TokenStream::from_tts(string_to_tts("foo::bar::baz".to_string())); + assert_eq!(test_res, test_eqs.slice(0..3)) + } + + #[test] + fn test_slice_1() { + let test_res = TokenStream::from_tts(string_to_tts("foo::bar::baz".to_string())) + .slice(2..3); + let test_eqs = TokenStream::from_tts(vec![TokenTree::Token(sp(5,8), + token::Ident(str_to_ident("bar")))]); + assert_eq!(test_res, test_eqs) + } + #[test] fn test_is_empty() { let test0 = TokenStream::from_tts(Vec::new()); @@ -943,38 +925,6 @@ mod tests { assert_eq!(test5.is_delimited(), false); } - #[test] - fn test_is_assign() { - let test0 = TokenStream::from_tts(string_to_tts("= bar::baz".to_string())); - let test1 = TokenStream::from_tts(string_to_tts("= \"5\"".to_string())); - let test2 = TokenStream::from_tts(string_to_tts("= 5".to_string())); - let test3 = TokenStream::from_tts(string_to_tts("(foo = 10)".to_string())); - let test4 = TokenStream::from_tts(string_to_tts("= (foo,bar,baz)".to_string())); - let test5 = TokenStream::from_tts(string_to_tts("".to_string())); - - assert_eq!(test0.is_assignment(), true); - assert_eq!(test1.is_assignment(), true); - assert_eq!(test2.is_assignment(), true); - assert_eq!(test3.is_assignment(), false); - assert_eq!(test4.is_assignment(), true); - assert_eq!(test5.is_assignment(), false); - } - - #[test] - fn test_is_lit() { - let test0 = TokenStream::from_tts(string_to_tts("\"foo\"".to_string())); - let test1 = TokenStream::from_tts(string_to_tts("5".to_string())); - let test2 = TokenStream::from_tts(string_to_tts("foo".to_string())); - let test3 = TokenStream::from_tts(string_to_tts("foo::bar".to_string())); - let test4 = TokenStream::from_tts(string_to_tts("foo(bar)".to_string())); - - assert_eq!(test0.is_lit(), true); - assert_eq!(test1.is_lit(), true); - assert_eq!(test2.is_lit(), false); - assert_eq!(test3.is_lit(), false); - assert_eq!(test4.is_lit(), false); - } - #[test] fn test_is_ident() { let test0 = TokenStream::from_tts(string_to_tts("\"foo\"".to_string())); @@ -990,62 +940,6 @@ mod tests { assert_eq!(test4.is_ident(), false); } - #[test] - fn test_maybe_assignment() { - let test0_input = TokenStream::from_tts(string_to_tts("= bar::baz".to_string())); - let test1_input = TokenStream::from_tts(string_to_tts("= \"5\"".to_string())); - let test2_input = TokenStream::from_tts(string_to_tts("= 5".to_string())); - let test3_input = TokenStream::from_tts(string_to_tts("(foo = 10)".to_string())); - let test4_input = TokenStream::from_tts(string_to_tts("= (foo,bar,baz)".to_string())); - let test5_input = TokenStream::from_tts(string_to_tts("".to_string())); - - let test0 = test0_input.maybe_assignment(); - let test1 = test1_input.maybe_assignment(); - let test2 = test2_input.maybe_assignment(); - let test3 = test3_input.maybe_assignment(); - let test4 = test4_input.maybe_assignment(); - let test5 = test5_input.maybe_assignment(); - - let test0_expected = TokenStream::from_tts(vec![TokenTree::Token(sp(2, 5), - token::Ident(str_to_ident("bar"))), - TokenTree::Token(sp(5, 7), token::ModSep), - TokenTree::Token(sp(7, 10), - token::Ident(str_to_ident("baz")))]); - assert_eq!(test0, Some(&test0_expected[..])); - - let test1_expected = TokenStream::from_tts(vec![TokenTree::Token(sp(2, 5), - token::Literal(Lit::Str_(token::intern("5")), None))]); - assert_eq!(test1, Some(&test1_expected[..])); - - let test2_expected = TokenStream::from_tts(vec![TokenTree::Token( sp(2,3) - , token::Literal( - Lit::Integer( - token::intern(&(5.to_string()))), - None))]); - assert_eq!(test2, Some(&test2_expected[..])); - - assert_eq!(test3, None); - - - let test4_tts = vec![TokenTree::Token(sp(3, 6), token::Ident(str_to_ident("foo"))), - TokenTree::Token(sp(6, 7), token::Comma), - TokenTree::Token(sp(7, 10), token::Ident(str_to_ident("bar"))), - TokenTree::Token(sp(10, 11), token::Comma), - TokenTree::Token(sp(11, 14), token::Ident(str_to_ident("baz")))]; - - let test4_expected = TokenStream::from_tts(vec![TokenTree::Delimited(sp(2, 15), - Rc::new(Delimited { - delim: token::DelimToken::Paren, - open_span: sp(2, 3), - tts: test4_tts, - close_span: sp(14, 15), - }))]); - assert_eq!(test4, Some(&test4_expected[..])); - - assert_eq!(test5, None); - - } - #[test] fn test_maybe_delimited() { let test0_input = TokenStream::from_tts(string_to_tts("foo(bar::baz)".to_string())); @@ -1070,7 +964,7 @@ mod tests { TokenTree::Token(sp(4, 6), token::ModSep), TokenTree::Token(sp(6, 9), token::Ident(str_to_ident("baz")))]); - assert_eq!(test1, Some(&test1_expected[..])); + assert_eq!(test1, Some(test1_expected)); let test2_expected = TokenStream::from_tts(vec![TokenTree::Token(sp(1, 4), token::Ident(str_to_ident("foo"))), @@ -1080,7 +974,7 @@ mod tests { TokenTree::Token(sp(8, 9), token::Comma), TokenTree::Token(sp(9, 12), token::Ident(str_to_ident("baz")))]); - assert_eq!(test2, Some(&test2_expected[..])); + assert_eq!(test2, Some(test2_expected)); assert_eq!(test3, None); @@ -1089,72 +983,6 @@ mod tests { assert_eq!(test5, None); } - #[test] - fn test_maybe_comma_list() { - let test0_input = TokenStream::from_tts(string_to_tts("foo(bar::baz)".to_string())); - let test1_input = TokenStream::from_tts(string_to_tts("(bar::baz)".to_string())); - let test2_input = TokenStream::from_tts(string_to_tts("(foo,bar,baz)".to_string())); - let test3_input = TokenStream::from_tts(string_to_tts("(foo::bar,bar,baz)".to_string())); - let test4_input = TokenStream::from_tts(string_to_tts("(foo,bar,baz)(zab,rab)" - .to_string())); - let test5_input = TokenStream::from_tts(string_to_tts("(foo,bar,baz)foo".to_string())); - let test6_input = TokenStream::from_tts(string_to_tts("".to_string())); - // The following is supported behavior! - let test7_input = TokenStream::from_tts(string_to_tts("(foo,bar,)".to_string())); - - let test0 = test0_input.maybe_comma_list(); - let test1 = test1_input.maybe_comma_list(); - let test2 = test2_input.maybe_comma_list(); - let test3 = test3_input.maybe_comma_list(); - let test4 = test4_input.maybe_comma_list(); - let test5 = test5_input.maybe_comma_list(); - let test6 = test6_input.maybe_comma_list(); - let test7 = test7_input.maybe_comma_list(); - - assert_eq!(test0, None); - - let test1_stream = TokenStream::from_tts(vec![TokenTree::Token(sp(1, 4), - token::Ident(str_to_ident("bar"))), - TokenTree::Token(sp(4, 6), token::ModSep), - TokenTree::Token(sp(6, 9), - token::Ident(str_to_ident("baz")))]); - - let test1_expected: Vec<&TokenSlice> = vec![&test1_stream[..]]; - assert_eq!(test1, Some(test1_expected)); - - let test2_foo = TokenStream::from_tts(vec![TokenTree::Token(sp(1, 4), - token::Ident(str_to_ident("foo")))]); - let test2_bar = TokenStream::from_tts(vec![TokenTree::Token(sp(5, 8), - token::Ident(str_to_ident("bar")))]); - let test2_baz = TokenStream::from_tts(vec![TokenTree::Token(sp(9, 12), - token::Ident(str_to_ident("baz")))]); - let test2_expected: Vec<&TokenSlice> = vec![&test2_foo[..], &test2_bar[..], &test2_baz[..]]; - assert_eq!(test2, Some(test2_expected)); - - let test3_path = TokenStream::from_tts(vec![TokenTree::Token(sp(1, 4), - token::Ident(str_to_ident("foo"))), - TokenTree::Token(sp(4, 6), token::ModSep), - TokenTree::Token(sp(6, 9), - token::Ident(str_to_ident("bar")))]); - let test3_bar = TokenStream::from_tts(vec![TokenTree::Token(sp(10, 13), - token::Ident(str_to_ident("bar")))]); - let test3_baz = TokenStream::from_tts(vec![TokenTree::Token(sp(14, 17), - token::Ident(str_to_ident("baz")))]); - let test3_expected: Vec<&TokenSlice> = - vec![&test3_path[..], &test3_bar[..], &test3_baz[..]]; - assert_eq!(test3, Some(test3_expected)); - - assert_eq!(test4, None); - - assert_eq!(test5, None); - - assert_eq!(test6, None); - - - let test7_expected: Vec<&TokenSlice> = vec![&test2_foo[..], &test2_bar[..]]; - assert_eq!(test7, Some(test7_expected)); - } - // pub fn maybe_ident(&self) -> Option #[test] fn test_maybe_ident() { @@ -1171,86 +999,10 @@ mod tests { assert_eq!(test4, None); } - // pub fn maybe_lit(&self) -> Option #[test] - fn test_maybe_lit() { - let test0 = TokenStream::from_tts(string_to_tts("\"foo\"".to_string())).maybe_lit(); - let test1 = TokenStream::from_tts(string_to_tts("5".to_string())).maybe_lit(); - let test2 = TokenStream::from_tts(string_to_tts("foo".to_string())).maybe_lit(); - let test3 = TokenStream::from_tts(string_to_tts("foo::bar".to_string())).maybe_lit(); - let test4 = TokenStream::from_tts(string_to_tts("foo(bar)".to_string())).maybe_lit(); - - assert_eq!(test0, Some(Lit::Str_(token::intern("foo")))); - assert_eq!(test1, Some(Lit::Integer(token::intern(&(5.to_string()))))); - assert_eq!(test2, None); - assert_eq!(test3, None); - assert_eq!(test4, None); - } - - #[test] - fn test_maybe_path_prefix() { - let test0_input = TokenStream::from_tts(string_to_tts("foo(bar::baz)".to_string())); - let test1_input = TokenStream::from_tts(string_to_tts("(bar::baz)".to_string())); - let test2_input = TokenStream::from_tts(string_to_tts("(foo,bar,baz)".to_string())); - let test3_input = TokenStream::from_tts(string_to_tts("foo::bar(bar,baz)".to_string())); - - let test0 = test0_input.maybe_path_prefix(); - let test1 = test1_input.maybe_path_prefix(); - let test2 = test2_input.maybe_path_prefix(); - let test3 = test3_input.maybe_path_prefix(); - - let test0_tts = vec![TokenTree::Token(sp(4, 7), token::Ident(str_to_ident("bar"))), - TokenTree::Token(sp(7, 9), token::ModSep), - TokenTree::Token(sp(9, 12), token::Ident(str_to_ident("baz")))]; - - let test0_stream = TokenStream::from_tts(vec![TokenTree::Delimited(sp(3, 13), - Rc::new(Delimited { - delim: token::DelimToken::Paren, - open_span: sp(3, 4), - tts: test0_tts, - close_span: sp(12, 13), - }))]); - - let test0_expected = Some((ast::Path::from_ident(sp(0, 3), str_to_ident("foo")), - &test0_stream[..])); - assert_eq!(test0, test0_expected); - - assert_eq!(test1, None); - assert_eq!(test2, None); - - let test3_path = ast::Path { - span: sp(0, 8), - global: false, - segments: vec![ast::PathSegment { - identifier: str_to_ident("foo"), - parameters: ast::PathParameters::none(), - }, - ast::PathSegment { - identifier: str_to_ident("bar"), - parameters: ast::PathParameters::none(), - }], - }; - - let test3_tts = vec![TokenTree::Token(sp(9, 12), token::Ident(str_to_ident("bar"))), - TokenTree::Token(sp(12, 13), token::Comma), - TokenTree::Token(sp(13, 16), token::Ident(str_to_ident("baz")))]; - - let test3_stream = TokenStream::from_tts(vec![TokenTree::Delimited(sp(8, 17), - Rc::new(Delimited { - delim: token::DelimToken::Paren, - open_span: sp(8, 9), - tts: test3_tts, - close_span: sp(16, 17), - }))]); - let test3_expected = Some((test3_path, &test3_stream[..])); - assert_eq!(test3, test3_expected); - } - - #[test] - fn test_as_paren_delimited_stream() { - let test0 = TokenStream::as_paren_delimited_stream(string_to_tts("foo,bar,".to_string())); - let test1 = TokenStream::as_paren_delimited_stream(string_to_tts("baz(foo,bar)" - .to_string())); + fn test_as_delimited_stream() { + let test0 = as_paren_delimited_stream(string_to_tts("foo,bar,".to_string())); + let test1 = as_paren_delimited_stream(string_to_tts("baz(foo,bar)".to_string())); let test0_tts = vec![TokenTree::Token(sp(0, 3), token::Ident(str_to_ident("foo"))), TokenTree::Token(sp(3, 4), token::Comma), @@ -1290,5 +1042,4 @@ mod tests { assert_eq!(test1, test1_stream); } - } diff --git a/src/libsyntax_ext/deriving/bounds.rs b/src/libsyntax_ext/deriving/bounds.rs index 36818e000b55..cfc98bf36871 100644 --- a/src/libsyntax_ext/deriving/bounds.rs +++ b/src/libsyntax_ext/deriving/bounds.rs @@ -12,15 +12,14 @@ use deriving::generic::*; use deriving::generic::ty::*; use syntax::ast::MetaItem; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax_pos::Span; pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt, span: Span, _: &MetaItem, _: &Annotatable, - _: &mut FnMut(Annotatable)) -{ + _: &mut FnMut(Annotatable)) { cx.span_err(span, "this unsafe trait should be implemented explicitly"); } @@ -28,8 +27,7 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { let mut v = cx.crate_root.map(|s| vec![s]).unwrap_or(Vec::new()); v.push("marker"); v.push("Copy"); diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index 1e47ebb85837..ce8ce2209d8c 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -11,23 +11,25 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{Expr, ItemKind, Generics, MetaItem, VariantData}; +use syntax::ast::{Expr, Generics, ItemKind, MetaItem, VariantData}; use syntax::attr; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::ptr::P; use syntax_pos::Span; #[derive(PartialEq)] -enum Mode { Deep, Shallow } +enum Mode { + Deep, + Shallow, +} pub fn expand_deriving_clone(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { // check if we can use a short form // // the short form is `fn clone(&self) -> Self { *self }` @@ -46,8 +48,8 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, match annitem.node { ItemKind::Struct(_, Generics { ref ty_params, .. }) | ItemKind::Enum(_, Generics { ref ty_params, .. }) - if ty_params.is_empty() - && attr::contains_name(&annitem.attrs, "derive_Copy") => { + if ty_params.is_empty() && + attr::contains_name(&annitem.attrs, "derive_Copy") => { bounds = vec![Literal(path_std!(cx, core::marker::Copy))]; unify_fieldless_variants = true; @@ -66,11 +68,11 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, } } - _ => cx.span_bug(span, "#[derive(Clone)] on trait item or impl item") + _ => cx.span_bug(span, "#[derive(Clone)] on trait item or impl item"), } let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); + let attrs = vec![cx.attribute(span, inline)]; let trait_def = TraitDef { span: span, attributes: Vec::new(), @@ -78,42 +80,41 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, additional_bounds: bounds, generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec!( - MethodDef { - name: "clone", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: Vec::new(), - ret_ty: Self_, - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: unify_fieldless_variants, - combine_substructure: substructure, - } - ), + methods: vec![MethodDef { + name: "clone", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: Vec::new(), + ret_ty: Self_, + attributes: attrs, + is_unsafe: false, + unify_fieldless_variants: unify_fieldless_variants, + combine_substructure: substructure, + }], associated_types: Vec::new(), }; trait_def.expand(cx, mitem, item, push) } -fn cs_clone( - name: &str, - cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure, - mode: Mode) -> P { +fn cs_clone(name: &str, + cx: &mut ExtCtxt, + trait_span: Span, + substr: &Substructure, + mode: Mode) + -> P { let ctor_path; let all_fields; let fn_path = match mode { Mode::Shallow => cx.std_path(&["clone", "assert_receiver_is_clone"]), - Mode::Deep => cx.std_path(&["clone", "Clone", "clone"]), + Mode::Deep => cx.std_path(&["clone", "Clone", "clone"]), }; let subcall = |field: &FieldInfo| { let args = vec![cx.expr_addr_of(field.span, field.self_.clone())]; let span = if mode == Mode::Shallow { // set the expn ID so we can call the unstable method - Span { expn_id: cx.backtrace(), .. trait_span } + Span { expn_id: cx.backtrace(), ..trait_span } } else { field.span }; @@ -131,15 +132,15 @@ fn cs_clone( ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.node.name]); all_fields = af; vdata = &variant.node.data; - }, - EnumNonMatchingCollapsed (..) => { + } + EnumNonMatchingCollapsed(..) => { cx.span_bug(trait_span, &format!("non-matching enum variants in \ - `derive({})`", name)) + `derive({})`", + name)) } StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, - &format!("static method in `derive({})`", name)) + cx.span_bug(trait_span, &format!("static method in `derive({})`", name)) } } @@ -153,17 +154,20 @@ fn cs_clone( Mode::Deep => { match *vdata { VariantData::Struct(..) => { - let fields = all_fields.iter().map(|field| { - let ident = match field.name { - Some(i) => i, - None => { - cx.span_bug(trait_span, - &format!("unnamed field in normal struct in \ - `derive({})`", name)) - } - }; - cx.field_imm(field.span, ident, subcall(field)) - }).collect::>(); + let fields = all_fields.iter() + .map(|field| { + let ident = match field.name { + Some(i) => i, + None => { + cx.span_bug(trait_span, + &format!("unnamed field in normal struct in \ + `derive({})`", + name)) + } + }; + cx.field_imm(field.span, ident, subcall(field)) + }) + .collect::>(); cx.expr_struct(trait_span, ctor_path, fields) } @@ -172,9 +176,7 @@ fn cs_clone( let path = cx.expr_path(ctor_path); cx.expr_call(trait_span, path, subcalls) } - VariantData::Unit(..) => { - cx.expr_path(ctor_path) - } + VariantData::Unit(..) => cx.expr_path(ctor_path), } } } diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 9c5072eeb3e0..2ab0f0ff5466 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -11,8 +11,8 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{Expr, MetaItem}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::ptr::P; @@ -22,30 +22,27 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_same_method( - |cx, span, exprs| { - // create `a.(); b.(); c.(); ...` - // (where method is `assert_receiver_is_total_eq`) - let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect(); - let block = cx.block(span, stmts); - cx.expr_block(block) - }, - Box::new(|cx, sp, _, _| { - cx.span_bug(sp, "non matching enums in derive(Eq)?") }), - cx, - span, - substr - ) + cs_same_method(|cx, span, exprs| { + // create `a.(); b.(); c.(); ...` + // (where method is `assert_receiver_is_total_eq`) + let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect(); + let block = cx.block(span, stmts); + cx.expr_block(block) + }, + Box::new(|cx, sp, _, _| { + cx.span_bug(sp, "non matching enums in derive(Eq)?") + }), + cx, + span, + substr) } let inline = cx.meta_word(span, InternedString::new("inline")); let hidden = cx.meta_word(span, InternedString::new("hidden")); - let doc = cx.meta_list(span, InternedString::new("doc"), vec!(hidden)); - let attrs = vec!(cx.attribute(span, inline), - cx.attribute(span, doc)); + let doc = cx.meta_list(span, InternedString::new("doc"), vec![hidden]); + let attrs = vec![cx.attribute(span, inline), cx.attribute(span, doc)]; let trait_def = TraitDef { span: span, attributes: Vec::new(), @@ -53,21 +50,19 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec!( - MethodDef { - name: "assert_receiver_is_total_eq", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(), - ret_ty: nil_ty(), - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_total_eq_assert(a, b, c) - })) - } - ), + methods: vec![MethodDef { + name: "assert_receiver_is_total_eq", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: vec![], + ret_ty: nil_ty(), + attributes: attrs, + is_unsafe: false, + unify_fieldless_variants: true, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + cs_total_eq_assert(a, b, c) + })), + }], associated_types: Vec::new(), }; trait_def.expand(cx, mitem, item, push) diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index cbd7ac0eadad..8ae77e79310b 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -11,8 +11,8 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr, self}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{self, Expr, MetaItem}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::ptr::P; @@ -22,10 +22,9 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); + let attrs = vec![cx.attribute(span, inline)]; let trait_def = TraitDef { span: span, attributes: Vec::new(), @@ -33,21 +32,19 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec!( - MethodDef { - name: "cmp", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(borrowed_self()), - ret_ty: Literal(path_std!(cx, core::cmp::Ordering)), - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - cs_cmp(a, b, c) - })), - } - ), + methods: vec![MethodDef { + name: "cmp", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: vec![borrowed_self()], + ret_ty: Literal(path_std!(cx, core::cmp::Ordering)), + attributes: attrs, + is_unsafe: false, + unify_fieldless_variants: true, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + cs_cmp(a, b, c) + })), + }], associated_types: Vec::new(), }; @@ -57,76 +54,73 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, pub fn ordering_collapsed(cx: &mut ExtCtxt, span: Span, - self_arg_tags: &[ast::Ident]) -> P { + self_arg_tags: &[ast::Ident]) + -> P { let lft = cx.expr_ident(span, self_arg_tags[0]); let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); cx.expr_method_call(span, lft, cx.ident_of("cmp"), vec![rgt]) } -pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, - substr: &Substructure) -> P { +pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { let test_id = cx.ident_of("__cmp"); - let equals_path = cx.path_global(span, - cx.std_path(&["cmp", "Ordering", "Equal"])); + let equals_path = cx.path_global(span, cx.std_path(&["cmp", "Ordering", "Equal"])); let cmp_path = cx.std_path(&["cmp", "Ord", "cmp"]); - /* - Builds: + // Builds: + // + // match ::std::cmp::Ord::cmp(&self_field1, &other_field1) { + // ::std::cmp::Ordering::Equal => + // match ::std::cmp::Ord::cmp(&self_field2, &other_field2) { + // ::std::cmp::Ordering::Equal => { + // ... + // } + // __cmp => __cmp + // }, + // __cmp => __cmp + // } + // + cs_fold(// foldr nests the if-elses correctly, leaving the first field + // as the outermost one, and the last as the innermost. + false, + |cx, span, old, self_f, other_fs| { + // match new { + // ::std::cmp::Ordering::Equal => old, + // __cmp => __cmp + // } - match ::std::cmp::Ord::cmp(&self_field1, &other_field1) { - ::std::cmp::Ordering::Equal => - match ::std::cmp::Ord::cmp(&self_field2, &other_field2) { - ::std::cmp::Ordering::Equal => { - ... - } - __cmp => __cmp - }, - __cmp => __cmp - } - */ - cs_fold( - // foldr nests the if-elses correctly, leaving the first field - // as the outermost one, and the last as the innermost. - false, - |cx, span, old, self_f, other_fs| { - // match new { - // ::std::cmp::Ordering::Equal => old, - // __cmp => __cmp - // } + let new = { + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"), + }; - let new = { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"), - }; - - let args = vec![ + let args = vec![ cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone()), ]; - cx.expr_call_global(span, cmp_path.clone(), args) - }; + cx.expr_call_global(span, cmp_path.clone(), args) + }; - let eq_arm = cx.arm(span, - vec![cx.pat_enum(span, - equals_path.clone(), - vec![])], - old); - let neq_arm = cx.arm(span, - vec![cx.pat_ident(span, test_id)], - cx.expr_ident(span, test_id)); + let eq_arm = cx.arm(span, + vec![cx.pat_enum(span, equals_path.clone(), vec![])], + old); + let neq_arm = cx.arm(span, + vec![cx.pat_ident(span, test_id)], + cx.expr_ident(span, test_id)); - cx.expr_match(span, new, vec![eq_arm, neq_arm]) - }, - cx.expr_path(equals_path.clone()), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`") - } else { - ordering_collapsed(cx, span, tag_tuple) - } - }), - cx, span, substr) + cx.expr_match(span, new, vec![eq_arm, neq_arm]) + }, + cx.expr_path(equals_path.clone()), + Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { + if self_args.len() != 2 { + cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`") + } else { + ordering_collapsed(cx, span, tag_tuple) + } + }), + cx, + span, + substr) } diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs index b5a8167fb555..f70e0cf4ac45 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs @@ -11,8 +11,8 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr, BinOpKind}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{BinOpKind, Expr, MetaItem}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::ptr::P; @@ -22,43 +22,44 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { // structures are equal if all fields are equal, and non equal, if // any fields are not equal or if the enum variants are different fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_fold( - true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") - }; + cs_fold(true, // use foldl + |cx, span, subexpr, self_f, other_fs| { + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"), + }; - let eq = cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()); + let eq = cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()); - cx.expr_binary(span, BinOpKind::And, subexpr, eq) - }, - cx.expr_bool(span, true), - Box::new(|cx, span, _, _| cx.expr_bool(span, false)), - cx, span, substr) + cx.expr_binary(span, BinOpKind::And, subexpr, eq) + }, + cx.expr_bool(span, true), + Box::new(|cx, span, _, _| cx.expr_bool(span, false)), + cx, + span, + substr) } fn cs_ne(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_fold( - true, // use foldl - |cx, span, subexpr, self_f, other_fs| { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`") - }; + cs_fold(true, // use foldl + |cx, span, subexpr, self_f, other_fs| { + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"), + }; - let eq = cx.expr_binary(span, BinOpKind::Ne, self_f, other_f.clone()); + let eq = cx.expr_binary(span, BinOpKind::Ne, self_f, other_f.clone()); - cx.expr_binary(span, BinOpKind::Or, subexpr, eq) - }, - cx.expr_bool(span, false), - Box::new(|cx, span, _, _| cx.expr_bool(span, true)), - cx, span, substr) + cx.expr_binary(span, BinOpKind::Or, subexpr, eq) + }, + cx.expr_bool(span, false), + Box::new(|cx, span, _, _| cx.expr_bool(span, true)), + cx, + span, + substr) } macro_rules! md { diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 26c14ae934f7..10a9738742e4 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -13,8 +13,8 @@ pub use self::OrderingOp::*; use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr, BinOpKind, self}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{self, BinOpKind, Expr, MetaItem}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::ptr::P; @@ -24,8 +24,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { macro_rules! md { ($name:expr, $op:expr, $equal:expr) => { { let inline = cx.meta_word(span, InternedString::new("inline")); @@ -53,7 +52,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, true)); let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); + let attrs = vec![cx.attribute(span, inline)]; let partial_cmp_def = MethodDef { name: "partial_cmp", @@ -66,7 +65,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { cs_partial_cmp(cx, span, substr) - })) + })), }; // avoid defining extra methods if we can @@ -75,13 +74,11 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, let methods = if is_type_without_fields(item) { vec![partial_cmp_def] } else { - vec![ - partial_cmp_def, - md!("lt", true, false), - md!("le", true, true), - md!("gt", false, false), - md!("ge", false, true) - ] + vec![partial_cmp_def, + md!("lt", true, false), + md!("le", true, true), + md!("gt", false, false), + md!("ge", false, true)] }; let trait_def = TraitDef { @@ -99,142 +96,146 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, #[derive(Copy, Clone)] pub enum OrderingOp { - PartialCmpOp, LtOp, LeOp, GtOp, GeOp, + PartialCmpOp, + LtOp, + LeOp, + GtOp, + GeOp, } pub fn some_ordering_collapsed(cx: &mut ExtCtxt, span: Span, op: OrderingOp, - self_arg_tags: &[ast::Ident]) -> P { + self_arg_tags: &[ast::Ident]) + -> P { let lft = cx.expr_ident(span, self_arg_tags[0]); let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1])); let op_str = match op { PartialCmpOp => "partial_cmp", - LtOp => "lt", LeOp => "le", - GtOp => "gt", GeOp => "ge", + LtOp => "lt", + LeOp => "le", + GtOp => "gt", + GeOp => "ge", }; cx.expr_method_call(span, lft, cx.ident_of(op_str), vec![rgt]) } -pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, - substr: &Substructure) -> P { +pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { let test_id = cx.ident_of("__cmp"); - let ordering = cx.path_global(span, - cx.std_path(&["cmp", "Ordering", "Equal"])); + let ordering = cx.path_global(span, cx.std_path(&["cmp", "Ordering", "Equal"])); let ordering_expr = cx.expr_path(ordering.clone()); let equals_expr = cx.expr_some(span, ordering_expr); let partial_cmp_path = cx.std_path(&["cmp", "PartialOrd", "partial_cmp"]); - /* - Builds: + // Builds: + // + // match ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1) { + // ::std::option::Option::Some(::std::cmp::Ordering::Equal) => + // match ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2) { + // ::std::option::Option::Some(::std::cmp::Ordering::Equal) => { + // ... + // } + // __cmp => __cmp + // }, + // __cmp => __cmp + // } + // + cs_fold(// foldr nests the if-elses correctly, leaving the first field + // as the outermost one, and the last as the innermost. + false, + |cx, span, old, self_f, other_fs| { + // match new { + // Some(::std::cmp::Ordering::Equal) => old, + // __cmp => __cmp + // } - match ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1) { - ::std::option::Option::Some(::std::cmp::Ordering::Equal) => - match ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2) { - ::std::option::Option::Some(::std::cmp::Ordering::Equal) => { - ... - } - __cmp => __cmp - }, - __cmp => __cmp - } - */ - cs_fold( - // foldr nests the if-elses correctly, leaving the first field - // as the outermost one, and the last as the innermost. - false, - |cx, span, old, self_f, other_fs| { - // match new { - // Some(::std::cmp::Ordering::Equal) => old, - // __cmp => __cmp - // } + let new = { + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), + }; - let new = { - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), - }; - - let args = vec![ + let args = vec![ cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone()), ]; - cx.expr_call_global(span, partial_cmp_path.clone(), args) - }; + cx.expr_call_global(span, partial_cmp_path.clone(), args) + }; - let eq_arm = cx.arm(span, - vec![cx.pat_some(span, - cx.pat_enum(span, - ordering.clone(), - vec![]))], - old); - let neq_arm = cx.arm(span, - vec![cx.pat_ident(span, test_id)], - cx.expr_ident(span, test_id)); + let eq_arm = cx.arm(span, + vec![cx.pat_some(span, cx.pat_enum(span, ordering.clone(), vec![]))], + old); + let neq_arm = cx.arm(span, + vec![cx.pat_ident(span, test_id)], + cx.expr_ident(span, test_id)); - cx.expr_match(span, new, vec![eq_arm, neq_arm]) - }, - equals_expr.clone(), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - } else { - some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple) - } - }), - cx, span, substr) + cx.expr_match(span, new, vec![eq_arm, neq_arm]) + }, + equals_expr.clone(), + Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { + if self_args.len() != 2 { + cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") + } else { + some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple) + } + }), + cx, + span, + substr) } /// Strict inequality. -fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, - span: Span, substr: &Substructure) -> P { +fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { let op = if less { BinOpKind::Lt } else { BinOpKind::Gt }; - cs_fold( - false, // need foldr, - |cx, span, subexpr, self_f, other_fs| { - /* - build up a series of chain ||'s and &&'s from the inside - out (hence foldr) to get lexical ordering, i.e. for op == - `ast::lt` + cs_fold(false, // need foldr, + |cx, span, subexpr, self_f, other_fs| { + // build up a series of chain ||'s and &&'s from the inside + // out (hence foldr) to get lexical ordering, i.e. for op == + // `ast::lt` + // + // ``` + // self.f1 < other.f1 || (!(other.f1 < self.f1) && + // (self.f2 < other.f2 || (!(other.f2 < self.f2) && + // (false) + // )) + // ) + // ``` + // + // The optimiser should remove the redundancy. We explicitly + // get use the binops to avoid auto-deref dereferencing too many + // layers of pointers, if the type includes pointers. + // + let other_f = match (other_fs.len(), other_fs.get(0)) { + (1, Some(o_f)) => o_f, + _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"), + }; - ``` - self.f1 < other.f1 || (!(other.f1 < self.f1) && - (self.f2 < other.f2 || (!(other.f2 < self.f2) && - (false) - )) - ) - ``` + let cmp = cx.expr_binary(span, op, self_f.clone(), other_f.clone()); - The optimiser should remove the redundancy. We explicitly - get use the binops to avoid auto-deref dereferencing too many - layers of pointers, if the type includes pointers. - */ - let other_f = match (other_fs.len(), other_fs.get(0)) { - (1, Some(o_f)) => o_f, - _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") + let not_cmp = cx.expr_unary(span, + ast::UnOp::Not, + cx.expr_binary(span, op, other_f.clone(), self_f)); + + let and = cx.expr_binary(span, BinOpKind::And, not_cmp, subexpr); + cx.expr_binary(span, BinOpKind::Or, cmp, and) + }, + cx.expr_bool(span, equal), + Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { + if self_args.len() != 2 { + cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") + } else { + let op = match (less, equal) { + (true, true) => LeOp, + (true, false) => LtOp, + (false, true) => GeOp, + (false, false) => GtOp, }; - - let cmp = cx.expr_binary(span, op, self_f.clone(), other_f.clone()); - - let not_cmp = cx.expr_unary(span, ast::UnOp::Not, - cx.expr_binary(span, op, other_f.clone(), self_f)); - - let and = cx.expr_binary(span, BinOpKind::And, not_cmp, subexpr); - cx.expr_binary(span, BinOpKind::Or, cmp, and) - }, - cx.expr_bool(span, equal), - Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| { - if self_args.len() != 2 { - cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`") - } else { - let op = match (less, equal) { - (true, true) => LeOp, (true, false) => LtOp, - (false, true) => GeOp, (false, false) => GtOp, - }; - some_ordering_collapsed(cx, span, op, tag_tuple) - } - }), - cx, span, substr) + some_ordering_collapsed(cx, span, op, tag_tuple) + } + }), + cx, + span, + substr) } diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index 34c872bef11d..a31c695e3604 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -12,19 +12,18 @@ use deriving::generic::*; use deriving::generic::ty::*; use syntax::ast; -use syntax::ast::{MetaItem, Expr}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{Expr, MetaItem}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token; use syntax::ptr::P; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::{DUMMY_SP, Span}; pub fn expand_deriving_debug(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + span: Span, + mitem: &MetaItem, + item: &Annotatable, + push: &mut FnMut(Annotatable)) { // &mut ::std::fmt::Formatter let fmtr = Ptr(Box::new(Literal(path_std!(cx, core::fmt::Formatter))), Borrowed(None, ast::Mutability::Mutable)); @@ -36,57 +35,54 @@ pub fn expand_deriving_debug(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec![ - MethodDef { - name: "fmt", - generics: LifetimeBounds::empty(), - explicit_self: borrowed_explicit_self(), - args: vec!(fmtr), - ret_ty: Literal(path_std!(cx, core::fmt::Result)), - attributes: Vec::new(), - is_unsafe: false, - unify_fieldless_variants: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - show_substructure(a, b, c) - })) - } - ], + methods: vec![MethodDef { + name: "fmt", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: vec![fmtr], + ret_ty: Literal(path_std!(cx, core::fmt::Result)), + attributes: Vec::new(), + is_unsafe: false, + unify_fieldless_variants: false, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + show_substructure(a, b, c) + })), + }], associated_types: Vec::new(), }; trait_def.expand(cx, mitem, item, push) } /// We use the debug builders to do the heavy lifting here -fn show_substructure(cx: &mut ExtCtxt, span: Span, - substr: &Substructure) -> P { +fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { // build fmt.debug_struct().field(, &)....build() // or fmt.debug_tuple().field(&)....build() // based on the "shape". let (ident, is_struct) = match *substr.fields { Struct(vdata, _) => (substr.type_ident, vdata.is_struct()), EnumMatching(_, v, _) => (v.node.name, v.node.data.is_struct()), - EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => { - cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") - } + EnumNonMatchingCollapsed(..) | + StaticStruct(..) | + StaticEnum(..) => cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"), }; // We want to make sure we have the expn_id set so that we can use unstable methods - let span = Span { expn_id: cx.backtrace(), .. span }; - let name = cx.expr_lit(span, ast::LitKind::Str(ident.name.as_str(), ast::StrStyle::Cooked)); + let span = Span { expn_id: cx.backtrace(), ..span }; + let name = cx.expr_lit(span, + ast::LitKind::Str(ident.name.as_str(), ast::StrStyle::Cooked)); let builder = token::str_to_ident("builder"); let builder_expr = cx.expr_ident(span, builder.clone()); let fmt = substr.nonself_args[0].clone(); let mut stmts = match *substr.fields { - Struct(_, ref fields) | EnumMatching(_, _, ref fields) => { + Struct(_, ref fields) | + EnumMatching(_, _, ref fields) => { let mut stmts = vec![]; if !is_struct { // tuple struct/"normal" variant - let expr = cx.expr_method_call(span, - fmt, - token::str_to_ident("debug_tuple"), - vec![name]); + let expr = + cx.expr_method_call(span, fmt, token::str_to_ident("debug_tuple"), vec![name]); stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr)); for field in fields { @@ -105,16 +101,14 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, } } else { // normal struct/struct variant - let expr = cx.expr_method_call(span, - fmt, - token::str_to_ident("debug_struct"), - vec![name]); + let expr = + cx.expr_method_call(span, fmt, token::str_to_ident("debug_struct"), vec![name]); stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr)); for field in fields { - let name = cx.expr_lit(field.span, ast::LitKind::Str( - field.name.unwrap().name.as_str(), - ast::StrStyle::Cooked)); + let name = cx.expr_lit(field.span, + ast::LitKind::Str(field.name.unwrap().name.as_str(), + ast::StrStyle::Cooked)); // Use double indirection to make sure this works for unsized types let field = cx.expr_addr_of(field.span, field.self_.clone()); @@ -128,22 +122,17 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, } stmts } - _ => unreachable!() + _ => unreachable!(), }; - let expr = cx.expr_method_call(span, - builder_expr, - token::str_to_ident("finish"), - vec![]); + let expr = cx.expr_method_call(span, builder_expr, token::str_to_ident("finish"), vec![]); stmts.push(cx.stmt_expr(expr)); let block = cx.block(span, stmts); cx.expr_block(block) } -fn stmt_let_undescore(cx: &mut ExtCtxt, - sp: Span, - expr: P) -> ast::Stmt { +fn stmt_let_undescore(cx: &mut ExtCtxt, sp: Span, expr: P) -> ast::Stmt { let local = P(ast::Local { pat: cx.pat_wild(sp), ty: None, diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 488402c48f70..9a332227053c 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -15,8 +15,8 @@ use deriving::generic::*; use deriving::generic::ty::*; use syntax::ast; -use syntax::ast::{MetaItem, Expr, Mutability}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{Expr, MetaItem, Mutability}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::parse::token; @@ -27,8 +27,7 @@ pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize") } @@ -36,8 +35,7 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize") } @@ -46,13 +44,13 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, mitem: &MetaItem, item: &Annotatable, push: &mut FnMut(Annotatable), - krate: &'static str) -{ + krate: &'static str) { if cx.crate_root != Some("std") { // FIXME(#21880): lift this requirement. - cx.span_err(span, "this trait cannot be derived with #![no_std] \ + cx.span_err(span, + "this trait cannot be derived with #![no_std] \ or #![no_core]"); - return + return; } let typaram = &*deriving::hygienic_type_parameter(item, "__D"); @@ -60,50 +58,50 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: Path::new_(vec!(krate, "Decodable"), None, vec!(), true), + path: Path::new_(vec![krate, "Decodable"], None, vec![], true), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec!( - MethodDef { - name: "decode", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec![(typaram, - vec![Path::new_(vec!(krate, "Decoder"), None, vec!(), true)])] - }, - explicit_self: None, - args: vec!(Ptr(Box::new(Literal(Path::new_local(typaram))), - Borrowed(None, Mutability::Mutable))), - ret_ty: Literal(Path::new_( - pathvec_std!(cx, core::result::Result), - None, - vec!(Box::new(Self_), Box::new(Literal(Path::new_( + methods: vec![MethodDef { + name: "decode", + generics: LifetimeBounds { + lifetimes: Vec::new(), + bounds: vec![(typaram, + vec![Path::new_(vec![krate, "Decoder"], + None, + vec![], + true)])], + }, + explicit_self: None, + args: vec![Ptr(Box::new(Literal(Path::new_local(typaram))), + Borrowed(None, Mutability::Mutable))], + ret_ty: + Literal(Path::new_(pathvec_std!(cx, core::result::Result), + None, + vec!(Box::new(Self_), Box::new(Literal(Path::new_( vec![typaram, "Error"], None, vec![], false )))), - true - )), - attributes: Vec::new(), - is_unsafe: false, - unify_fieldless_variants: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - decodable_substructure(a, b, c, krate) - })), - } - ), + true)), + attributes: Vec::new(), + is_unsafe: false, + unify_fieldless_variants: false, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + decodable_substructure(a, b, c, krate) + })), + }], associated_types: Vec::new(), }; trait_def.expand(cx, mitem, item, push) } -fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span, +fn decodable_substructure(cx: &mut ExtCtxt, + trait_span: Span, substr: &Substructure, - krate: &str) -> P { + krate: &str) + -> P { let decoder = substr.nonself_args[0].clone(); - let recurse = vec!(cx.ident_of(krate), - cx.ident_of("Decodable"), - cx.ident_of("decode")); + let recurse = vec![cx.ident_of(krate), cx.ident_of("Decodable"), cx.ident_of("decode")]; let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse)); // throw an underscore in front to suppress unused variable warnings let blkarg = cx.ident_of("_d"); @@ -113,31 +111,28 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span, StaticStruct(_, ref summary) => { let nfields = match *summary { Unnamed(ref fields) => fields.len(), - Named(ref fields) => fields.len() + Named(ref fields) => fields.len(), }; let read_struct_field = cx.ident_of("read_struct_field"); let path = cx.path_ident(trait_span, substr.type_ident); - let result = decode_static_fields(cx, - trait_span, - path, - summary, - |cx, span, name, field| { - cx.expr_try(span, - cx.expr_method_call(span, blkdecoder.clone(), read_struct_field, - vec!(cx.expr_str(span, name), - cx.expr_usize(span, field), - exprdecode.clone()))) - }); + let result = + decode_static_fields(cx, trait_span, path, summary, |cx, span, name, field| { + cx.expr_try(span, + cx.expr_method_call(span, + blkdecoder.clone(), + read_struct_field, + vec![cx.expr_str(span, name), + cx.expr_usize(span, field), + exprdecode.clone()])) + }); let result = cx.expr_ok(trait_span, result); cx.expr_method_call(trait_span, decoder, cx.ident_of("read_struct"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.expr_usize(trait_span, nfields), - cx.lambda_expr_1(trait_span, result, blkarg) - )) + vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()), + cx.expr_usize(trait_span, nfields), + cx.lambda_expr_1(trait_span, result, blkarg)]) } StaticEnum(_, ref fields) => { let variant = cx.ident_of("i"); @@ -150,42 +145,39 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span, variants.push(cx.expr_str(v_span, ident.name.as_str())); let path = cx.path(trait_span, vec![substr.type_ident, ident]); - let decoded = decode_static_fields(cx, - v_span, - path, - parts, - |cx, span, _, field| { + let decoded = decode_static_fields(cx, v_span, path, parts, |cx, span, _, field| { let idx = cx.expr_usize(span, field); cx.expr_try(span, - cx.expr_method_call(span, blkdecoder.clone(), rvariant_arg, - vec!(idx, exprdecode.clone()))) + cx.expr_method_call(span, + blkdecoder.clone(), + rvariant_arg, + vec![idx, exprdecode.clone()])) }); arms.push(cx.arm(v_span, - vec!(cx.pat_lit(v_span, cx.expr_usize(v_span, i))), + vec![cx.pat_lit(v_span, cx.expr_usize(v_span, i))], decoded)); } arms.push(cx.arm_unreachable(trait_span)); - let result = cx.expr_ok(trait_span, - cx.expr_match(trait_span, - cx.expr_ident(trait_span, variant), arms)); - let lambda = cx.lambda_expr(trait_span, vec!(blkarg, variant), result); + let result = + cx.expr_ok(trait_span, + cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms)); + let lambda = cx.lambda_expr(trait_span, vec![blkarg, variant], result); let variant_vec = cx.expr_vec(trait_span, variants); let variant_vec = cx.expr_addr_of(trait_span, variant_vec); - let result = cx.expr_method_call(trait_span, blkdecoder, + let result = cx.expr_method_call(trait_span, + blkdecoder, cx.ident_of("read_enum_variant"), - vec!(variant_vec, lambda)); + vec![variant_vec, lambda]); cx.expr_method_call(trait_span, decoder, cx.ident_of("read_enum"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.lambda_expr_1(trait_span, result, blkarg) - )) + vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()), + cx.lambda_expr_1(trait_span, result, blkarg)]) } - _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)") + _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"), }; } @@ -197,8 +189,8 @@ fn decode_static_fields(cx: &mut ExtCtxt, outer_pat_path: ast::Path, fields: &StaticFields, mut getarg: F) - -> P where - F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P, + -> P + where F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P { match *fields { Unnamed(ref fields) => { @@ -206,21 +198,28 @@ fn decode_static_fields(cx: &mut ExtCtxt, if fields.is_empty() { path_expr } else { - let fields = fields.iter().enumerate().map(|(i, &span)| { - getarg(cx, span, - token::intern_and_get_ident(&format!("_field{}", i)), - i) - }).collect(); + let fields = fields.iter() + .enumerate() + .map(|(i, &span)| { + getarg(cx, + span, + token::intern_and_get_ident(&format!("_field{}", i)), + i) + }) + .collect(); cx.expr_call(trait_span, path_expr, fields) } } Named(ref fields) => { // use the field's span to get nicer error messages. - let fields = fields.iter().enumerate().map(|(i, &(ident, span))| { - let arg = getarg(cx, span, ident.name.as_str(), i); - cx.field_imm(span, ident, arg) - }).collect(); + let fields = fields.iter() + .enumerate() + .map(|(i, &(ident, span))| { + let arg = getarg(cx, span, ident.name.as_str(), i); + cx.field_imm(span, ident, arg) + }) + .collect(); cx.expr_struct(trait_span, outer_pat_path, fields) } } diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs index 2711ccba8191..9df3db938b1f 100644 --- a/src/libsyntax_ext/deriving/default.rs +++ b/src/libsyntax_ext/deriving/default.rs @@ -11,8 +11,8 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{Expr, MetaItem}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; use syntax::ptr::P; @@ -22,10 +22,9 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { let inline = cx.meta_word(span, InternedString::new("inline")); - let attrs = vec!(cx.attribute(span, inline)); + let attrs = vec![cx.attribute(span, inline)]; let trait_def = TraitDef { span: span, attributes: Vec::new(), @@ -33,21 +32,19 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec!( - MethodDef { - name: "default", - generics: LifetimeBounds::empty(), - explicit_self: None, - args: Vec::new(), - ret_ty: Self_, - attributes: attrs, - is_unsafe: false, - unify_fieldless_variants: false, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - default_substructure(a, b, c) - })) - } - ), + methods: vec![MethodDef { + name: "default", + generics: LifetimeBounds::empty(), + explicit_self: None, + args: Vec::new(), + ret_ty: Self_, + attributes: attrs, + is_unsafe: false, + unify_fieldless_variants: false, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + default_substructure(a, b, c) + })), + }], associated_types: Vec::new(), }; trait_def.expand(cx, mitem, item, push) @@ -69,18 +66,19 @@ fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructur } } Named(ref fields) => { - let default_fields = fields.iter().map(|&(ident, span)| { - cx.field_imm(span, ident, default_call(span)) - }).collect(); + let default_fields = fields.iter() + .map(|&(ident, span)| cx.field_imm(span, ident, default_call(span))) + .collect(); cx.expr_struct_ident(trait_span, substr.type_ident, default_fields) } } } StaticEnum(..) => { - cx.span_err(trait_span, "`Default` cannot be derived for enums, only structs"); + cx.span_err(trait_span, + "`Default` cannot be derived for enums, only structs"); // let compilation continue cx.expr_usize(trait_span, 0) } - _ => cx.span_bug(trait_span, "Non-static method in `derive(Default)`") + _ => cx.span_bug(trait_span, "Non-static method in `derive(Default)`"), }; } diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index ad3786212475..940fdf037711 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -92,8 +92,8 @@ use deriving; use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr, ExprKind, Mutability}; -use syntax::ext::base::{ExtCtxt,Annotatable}; +use syntax::ast::{Expr, ExprKind, MetaItem, Mutability}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token; use syntax::ptr::P; @@ -103,8 +103,7 @@ pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { expand_deriving_encodable_imp(cx, span, mitem, item, push, "rustc_serialize") } @@ -112,8 +111,7 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize") } @@ -122,11 +120,11 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, mitem: &MetaItem, item: &Annotatable, push: &mut FnMut(Annotatable), - krate: &'static str) -{ + krate: &'static str) { if cx.crate_root != Some("std") { // FIXME(#21880): lift this requirement. - cx.span_err(span, "this trait cannot be derived with #![no_std] \ + cx.span_err(span, + "this trait cannot be derived with #![no_std] \ or #![no_core]"); return; } @@ -136,7 +134,7 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: Path::new_(vec!(krate, "Encodable"), None, vec!(), true), + path: Path::new_(vec![krate, "Encodable"], None, vec![], true), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, @@ -173,40 +171,38 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, trait_def.expand(cx, mitem, item, push) } -fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure, krate: &'static str) -> P { +fn encodable_substructure(cx: &mut ExtCtxt, + trait_span: Span, + substr: &Substructure, + krate: &'static str) + -> P { let encoder = substr.nonself_args[0].clone(); // throw an underscore in front to suppress unused variable warnings let blkarg = cx.ident_of("_e"); let blkencoder = cx.expr_ident(trait_span, blkarg); - let fn_path = cx.expr_path(cx.path_global(trait_span, vec![cx.ident_of(krate), - cx.ident_of("Encodable"), - cx.ident_of("encode")])); + let fn_path = cx.expr_path(cx.path_global(trait_span, + vec![cx.ident_of(krate), + cx.ident_of("Encodable"), + cx.ident_of("encode")])); return match *substr.fields { Struct(_, ref fields) => { let emit_struct_field = cx.ident_of("emit_struct_field"); let mut stmts = Vec::new(); - for (i, &FieldInfo { - name, - ref self_, - span, - .. - }) in fields.iter().enumerate() { + for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() { let name = match name { Some(id) => id.name.as_str(), - None => { - token::intern_and_get_ident(&format!("_field{}", i)) - } + None => token::intern_and_get_ident(&format!("_field{}", i)), }; let self_ref = cx.expr_addr_of(span, self_.clone()); let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); let lambda = cx.lambda_expr_1(span, enc, blkarg); - let call = cx.expr_method_call(span, blkencoder.clone(), + let call = cx.expr_method_call(span, + blkencoder.clone(), emit_struct_field, - vec!(cx.expr_str(span, name), - cx.expr_usize(span, i), - lambda)); + vec![cx.expr_str(span, name), + cx.expr_usize(span, i), + lambda]); // last call doesn't need a try! let last = fields.len() - 1; @@ -229,11 +225,9 @@ fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, cx.expr_method_call(trait_span, encoder, cx.ident_of("emit_struct"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.expr_usize(trait_span, fields.len()), - blk - )) + vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()), + cx.expr_usize(trait_span, fields.len()), + blk]) } EnumMatching(idx, variant, ref fields) => { @@ -248,14 +242,14 @@ fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, if !fields.is_empty() { let last = fields.len() - 1; for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() { - let self_ref = cx.expr_addr_of(span, self_.clone()); - let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, - blkencoder.clone()]); + let self_ref = cx.expr_addr_of(span, self_.clone()); + let enc = + cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); let lambda = cx.lambda_expr_1(span, enc, blkarg); - let call = cx.expr_method_call(span, blkencoder.clone(), + let call = cx.expr_method_call(span, + blkencoder.clone(), emit_variant_arg, - vec!(cx.expr_usize(span, i), - lambda)); + vec![cx.expr_usize(span, i), lambda]); let call = if i != last { cx.expr_try(span, call) } else { @@ -271,23 +265,23 @@ fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg); let name = cx.expr_str(trait_span, variant.node.name.name.as_str()); - let call = cx.expr_method_call(trait_span, blkencoder, + let call = cx.expr_method_call(trait_span, + blkencoder, cx.ident_of("emit_enum_variant"), - vec!(name, - cx.expr_usize(trait_span, idx), - cx.expr_usize(trait_span, fields.len()), - blk)); + vec![name, + cx.expr_usize(trait_span, idx), + cx.expr_usize(trait_span, fields.len()), + blk]); let blk = cx.lambda_expr_1(trait_span, call, blkarg); let ret = cx.expr_method_call(trait_span, encoder, cx.ident_of("emit_enum"), - vec!( - cx.expr_str(trait_span, substr.type_ident.name.as_str()), - blk - )); + vec![cx.expr_str(trait_span, + substr.type_ident.name.as_str()), + blk]); cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(ret)])) } - _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)") + _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"), }; } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index f33898109cc5..cd49e7ec9d2c 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -192,16 +192,16 @@ use std::collections::HashSet; use std::vec; use syntax::abi::Abi; -use syntax::ast::{self, EnumDef, Expr, Ident, Generics, VariantData, BinOpKind, PatKind}; +use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind, VariantData}; use syntax::attr; use syntax::attr::AttrMetaMethods; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::codemap::{self, respan}; use syntax::util::move_map::MoveMap; -use syntax::parse::token::{keywords, InternedString}; +use syntax::parse::token::{InternedString, keywords}; use syntax::ptr::P; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::{DUMMY_SP, Span}; use errors::Handler; use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty}; @@ -273,7 +273,7 @@ pub struct Substructure<'a> { pub self_args: &'a [P], /// verbatim access to any other arguments pub nonself_args: &'a [P], - pub fields: &'a SubstructureFields<'a> + pub fields: &'a SubstructureFields<'a>, } /// Summary of the relevant parts of a struct/enum field. @@ -338,14 +338,17 @@ pub type EnumNonMatchCollapsedFunc<'a> = Box]) -> P + 'a>; pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>) - -> RefCell> { + -> RefCell> { RefCell::new(f) } /// This method helps to extract all the type parameters referenced from a /// type. For a type parameter ``, it looks for either a `TyPath` that /// is not global and starts with `T`, or a `TyQPath`. -fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name], span: Span, cx: &ExtCtxt) +fn find_type_parameters(ty: &ast::Ty, + ty_param_names: &[ast::Name], + span: Span, + cx: &ExtCtxt) -> Vec> { use syntax::visit; @@ -395,23 +398,15 @@ impl<'a> TraitDef<'a> { cx: &mut ExtCtxt, mitem: &ast::MetaItem, item: &'a Annotatable, - push: &mut FnMut(Annotatable)) - { + push: &mut FnMut(Annotatable)) { match *item { Annotatable::Item(ref item) => { let newitem = match item.node { ast::ItemKind::Struct(ref struct_def, ref generics) => { - self.expand_struct_def(cx, - &struct_def, - item.ident, - generics) + self.expand_struct_def(cx, &struct_def, item.ident, generics) } ast::ItemKind::Enum(ref enum_def, ref generics) => { - self.expand_enum_def(cx, - enum_def, - &item.attrs, - item.ident, - generics) + self.expand_enum_def(cx, enum_def, &item.attrs, item.ident, generics) } _ => { cx.span_err(mitem.span, @@ -422,19 +417,20 @@ impl<'a> TraitDef<'a> { // Keep the lint attributes of the previous item to control how the // generated implementations are linted let mut attrs = newitem.attrs.clone(); - attrs.extend(item.attrs.iter().filter(|a| { - match &a.name()[..] { - "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true, - _ => false, - } - }).cloned()); - push(Annotatable::Item(P(ast::Item { - attrs: attrs, - ..(*newitem).clone() - }))) + attrs.extend(item.attrs + .iter() + .filter(|a| { + match &a.name()[..] { + "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true, + _ => false, + } + }) + .cloned()); + push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() }))) } _ => { - cx.span_err(mitem.span, "`derive` may only be applied to structs and enums"); + cx.span_err(mitem.span, + "`derive` may only be applied to structs and enums"); } } } @@ -475,7 +471,8 @@ impl<'a> TraitDef<'a> { type_ident: Ident, generics: &Generics, field_tys: Vec>, - methods: Vec) -> P { + methods: Vec) + -> P { let trait_path = self.path.to_path(cx, self.span, type_ident, generics); // Transform associated types from `deriving::ty::Ty` into `ast::ImplItem` @@ -487,16 +484,12 @@ impl<'a> TraitDef<'a> { vis: ast::Visibility::Inherited, defaultness: ast::Defaultness::Final, attrs: Vec::new(), - node: ast::ImplItemKind::Type(type_def.to_ty(cx, - self.span, - type_ident, - generics - )), + node: ast::ImplItemKind::Type(type_def.to_ty(cx, self.span, type_ident, generics)), } }); - let Generics { mut lifetimes, ty_params, mut where_clause } = - self.generics.to_generics(cx, self.span, type_ident, generics); + let Generics { mut lifetimes, ty_params, mut where_clause } = self.generics + .to_generics(cx, self.span, type_ident, generics); let mut ty_params = ty_params.into_vec(); // Copy the lifetimes @@ -521,10 +514,7 @@ impl<'a> TraitDef<'a> { bounds.push((*declared_bound).clone()); } - cx.typaram(self.span, - ty_param.ident, - P::from_vec(bounds), - None) + cx.typaram(self.span, ty_param.ident, P::from_vec(bounds), None) })); // and similarly for where clauses @@ -542,7 +532,7 @@ impl<'a> TraitDef<'a> { ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { span: self.span, lifetime: rb.lifetime, - bounds: rb.bounds.iter().cloned().collect() + bounds: rb.bounds.iter().cloned().collect(), }) } ast::WherePredicate::EqPredicate(ref we) => { @@ -550,7 +540,7 @@ impl<'a> TraitDef<'a> { id: ast::DUMMY_NODE_ID, span: self.span, path: we.path.clone(), - ty: we.ty.clone() + ty: we.ty.clone(), }) } } @@ -568,16 +558,17 @@ impl<'a> TraitDef<'a> { for ty in tys { // if we have already handled this type, skip it if let ast::TyKind::Path(_, ref p) = ty.node { - if p.segments.len() == 1 - && ty_param_names.contains(&p.segments[0].identifier.name) - || processed_field_types.contains(&p.segments) { + if p.segments.len() == 1 && + ty_param_names.contains(&p.segments[0].identifier.name) || + processed_field_types.contains(&p.segments) { continue; }; processed_field_types.insert(p.segments.clone()); } - let mut bounds: Vec<_> = self.additional_bounds.iter().map(|p| { - cx.typarambound(p.to_path(cx, self.span, type_ident, generics)) - }).collect(); + let mut bounds: Vec<_> = self.additional_bounds + .iter() + .map(|p| cx.typarambound(p.to_path(cx, self.span, type_ident, generics))) + .collect(); // require the current trait bounds.push(cx.typarambound(trait_path.clone())); @@ -598,40 +589,41 @@ impl<'a> TraitDef<'a> { let trait_generics = Generics { lifetimes: lifetimes, ty_params: P::from_vec(ty_params), - where_clause: where_clause + where_clause: where_clause, }; // Create the reference to the trait. let trait_ref = cx.trait_ref(trait_path); // Create the type parameters on the `self` path. - let self_ty_params = generics.ty_params.iter().map(|ty_param| { - cx.ty_ident(self.span, ty_param.ident) - }).collect(); + let self_ty_params = generics.ty_params + .iter() + .map(|ty_param| cx.ty_ident(self.span, ty_param.ident)) + .collect(); - let self_lifetimes: Vec = - generics.lifetimes + let self_lifetimes: Vec = generics.lifetimes .iter() .map(|ld| ld.lifetime) .collect(); // Create the type of `self`. - let self_type = cx.ty_path( - cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes, - self_ty_params, Vec::new())); + let self_type = cx.ty_path(cx.path_all(self.span, + false, + vec![type_ident], + self_lifetimes, + self_ty_params, + Vec::new())); - let attr = cx.attribute( - self.span, - cx.meta_word(self.span, - InternedString::new("automatically_derived"))); + let attr = cx.attribute(self.span, + cx.meta_word(self.span, + InternedString::new("automatically_derived"))); // Just mark it now since we know that it'll end up used downstream attr::mark_used(&attr); let opt_trait_ref = Some(trait_ref); - let unused_qual = cx.attribute( - self.span, - cx.meta_list(self.span, - InternedString::new("allow"), - vec![cx.meta_word(self.span, + let unused_qual = cx.attribute(self.span, + cx.meta_list(self.span, + InternedString::new("allow"), + vec![cx.meta_word(self.span, InternedString::new("unused_qualifications"))])); let mut a = vec![attr, unused_qual]; a.extend(self.attributes.iter().cloned()); @@ -642,58 +634,60 @@ impl<'a> TraitDef<'a> { ast::Unsafety::Normal }; - cx.item( - self.span, - keywords::Invalid.ident(), - a, - ast::ItemKind::Impl(unsafety, - ast::ImplPolarity::Positive, - trait_generics, - opt_trait_ref, - self_type, - methods.into_iter().chain(associated_types).collect())) + cx.item(self.span, + keywords::Invalid.ident(), + a, + ast::ItemKind::Impl(unsafety, + ast::ImplPolarity::Positive, + trait_generics, + opt_trait_ref, + self_type, + methods.into_iter().chain(associated_types).collect())) } fn expand_struct_def(&self, cx: &mut ExtCtxt, struct_def: &'a VariantData, type_ident: Ident, - generics: &Generics) -> P { - let field_tys: Vec> = struct_def.fields().iter() + generics: &Generics) + -> P { + let field_tys: Vec> = struct_def.fields() + .iter() .map(|field| field.ty.clone()) .collect(); - let methods = self.methods.iter().map(|method_def| { - let (explicit_self, self_args, nonself_args, tys) = - method_def.split_self_nonself_args( - cx, self, type_ident, generics); + let methods = self.methods + .iter() + .map(|method_def| { + let (explicit_self, self_args, nonself_args, tys) = + method_def.split_self_nonself_args(cx, self, type_ident, generics); - let body = if method_def.is_static() { - method_def.expand_static_struct_method_body( - cx, - self, - struct_def, - type_ident, - &self_args[..], - &nonself_args[..]) - } else { - method_def.expand_struct_method_body(cx, - self, - struct_def, - type_ident, - &self_args[..], - &nonself_args[..]) - }; + let body = if method_def.is_static() { + method_def.expand_static_struct_method_body(cx, + self, + struct_def, + type_ident, + &self_args[..], + &nonself_args[..]) + } else { + method_def.expand_struct_method_body(cx, + self, + struct_def, + type_ident, + &self_args[..], + &nonself_args[..]) + }; - method_def.create_method(cx, - self, - type_ident, - generics, - Abi::Rust, - explicit_self, - tys, - body) - }).collect(); + method_def.create_method(cx, + self, + type_ident, + generics, + Abi::Rust, + explicit_self, + tys, + body) + }) + .collect(); self.create_derived_impl(cx, type_ident, generics, field_tys, methods) } @@ -703,53 +697,57 @@ impl<'a> TraitDef<'a> { enum_def: &'a EnumDef, type_attrs: &[ast::Attribute], type_ident: Ident, - generics: &Generics) -> P { + generics: &Generics) + -> P { let mut field_tys = Vec::new(); for variant in &enum_def.variants { - field_tys.extend(variant.node.data.fields().iter() + field_tys.extend(variant.node + .data + .fields() + .iter() .map(|field| field.ty.clone())); } - let methods = self.methods.iter().map(|method_def| { - let (explicit_self, self_args, nonself_args, tys) = - method_def.split_self_nonself_args(cx, self, - type_ident, generics); + let methods = self.methods + .iter() + .map(|method_def| { + let (explicit_self, self_args, nonself_args, tys) = + method_def.split_self_nonself_args(cx, self, type_ident, generics); - let body = if method_def.is_static() { - method_def.expand_static_enum_method_body( - cx, - self, - enum_def, - type_ident, - &self_args[..], - &nonself_args[..]) - } else { - method_def.expand_enum_method_body(cx, - self, - enum_def, - type_attrs, - type_ident, - self_args, - &nonself_args[..]) - }; + let body = if method_def.is_static() { + method_def.expand_static_enum_method_body(cx, + self, + enum_def, + type_ident, + &self_args[..], + &nonself_args[..]) + } else { + method_def.expand_enum_method_body(cx, + self, + enum_def, + type_attrs, + type_ident, + self_args, + &nonself_args[..]) + }; - method_def.create_method(cx, - self, - type_ident, - generics, - Abi::Rust, - explicit_self, - tys, - body) - }).collect(); + method_def.create_method(cx, + self, + type_ident, + generics, + Abi::Rust, + explicit_self, + tys, + body) + }) + .collect(); self.create_derived_impl(cx, type_ident, generics, field_tys, methods) } } -fn find_repr_type_name(diagnostic: &Handler, - type_attrs: &[ast::Attribute]) -> &'static str { +fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> &'static str { let mut repr_type_name = "isize"; for a in type_attrs { for r in &attr::find_repr_attrs(diagnostic, a) { @@ -782,13 +780,13 @@ impl<'a> MethodDef<'a> { self_args: &[P], nonself_args: &[P], fields: &SubstructureFields) - -> P { + -> P { let substructure = Substructure { type_ident: type_ident, method_ident: cx.ident_of(self.name), self_args: self_args, nonself_args: nonself_args, - fields: fields + fields: fields, }; let mut f = self.combine_substructure.borrow_mut(); let f: &mut CombineSubstructureFunc = &mut *f; @@ -808,12 +806,13 @@ impl<'a> MethodDef<'a> { self.explicit_self.is_none() } - fn split_self_nonself_args(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef, - type_ident: Ident, - generics: &Generics) - -> (Option, Vec>, Vec>, Vec<(Ident, P)>) { + fn split_self_nonself_args + (&self, + cx: &mut ExtCtxt, + trait_: &TraitDef, + type_ident: Ident, + generics: &Generics) + -> (Option, Vec>, Vec>, Vec<(Ident, P)>) { let mut self_args = Vec::new(); let mut nonself_args = Vec::new(); @@ -839,7 +838,7 @@ impl<'a> MethodDef<'a> { match *ty { // for static methods, just treat any Self // arguments as a normal arg - Self_ if nonstatic => { + Self_ if nonstatic => { self_args.push(arg_expr); } Ptr(ref ty, _) if **ty == Self_ && nonstatic => { @@ -861,18 +860,20 @@ impl<'a> MethodDef<'a> { generics: &Generics, abi: Abi, explicit_self: Option, - arg_types: Vec<(Ident, P)> , - body: P) -> ast::ImplItem { + arg_types: Vec<(Ident, P)>, + body: P) + -> ast::ImplItem { // create the generics that aren't for Self let fn_generics = self.generics.to_generics(cx, trait_.span, type_ident, generics); let args = { let self_args = explicit_self.map(|explicit_self| { - ast::Arg::from_self(explicit_self, respan(trait_.span, keywords::SelfValue.ident())) + ast::Arg::from_self(explicit_self, + respan(trait_.span, keywords::SelfValue.ident())) }); let nonself_args = arg_types.into_iter() - .map(|(name, ty)| cx.arg(trait_.span, name, ty)); + .map(|(name, ty)| cx.arg(trait_.span, name, ty)); self_args.into_iter().chain(nonself_args).collect() }; @@ -897,12 +898,13 @@ impl<'a> MethodDef<'a> { defaultness: ast::Defaultness::Final, ident: method_ident, node: ast::ImplItemKind::Method(ast::MethodSig { - generics: fn_generics, - abi: abi, - unsafety: unsafety, - constness: ast::Constness::NotConst, - decl: fn_decl - }, body_block) + generics: fn_generics, + abi: abi, + unsafety: unsafety, + constness: ast::Constness::NotConst, + decl: fn_decl, + }, + body_block), } } @@ -926,26 +928,24 @@ impl<'a> MethodDef<'a> { /// } /// ``` fn expand_struct_method_body<'b>(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef<'b>, - struct_def: &'b VariantData, - type_ident: Ident, - self_args: &[P], - nonself_args: &[P]) - -> P { + cx: &mut ExtCtxt, + trait_: &TraitDef<'b>, + struct_def: &'b VariantData, + type_ident: Ident, + self_args: &[P], + nonself_args: &[P]) + -> P { let mut raw_fields = Vec::new(); // Vec<[fields of self], // [fields of next Self arg], [etc]> let mut patterns = Vec::new(); for i in 0..self_args.len() { - let struct_path= cx.path(DUMMY_SP, vec!( type_ident )); - let (pat, ident_expr) = - trait_.create_struct_pattern(cx, - struct_path, - struct_def, - &format!("__self_{}", - i), - ast::Mutability::Immutable); + let struct_path = cx.path(DUMMY_SP, vec![type_ident]); + let (pat, ident_expr) = trait_.create_struct_pattern(cx, + struct_path, + struct_def, + &format!("__self_{}", i), + ast::Mutability::Immutable); patterns.push(pat); raw_fields.push(ident_expr); } @@ -954,21 +954,23 @@ impl<'a> MethodDef<'a> { let fields = if !raw_fields.is_empty() { let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter()); let first_field = raw_fields.next().unwrap(); - let mut other_fields: Vec> - = raw_fields.collect(); + let mut other_fields: Vec> = raw_fields.collect(); first_field.map(|(span, opt_id, field, attrs)| { - FieldInfo { - span: span, - name: opt_id, - self_: field, - other: other_fields.iter_mut().map(|l| { - match l.next().unwrap() { - (_, _, ex, _) => ex - } - }).collect(), - attrs: attrs, - } - }).collect() + FieldInfo { + span: span, + name: opt_id, + self_: field, + other: other_fields.iter_mut() + .map(|l| { + match l.next().unwrap() { + (_, _, ex, _) => ex, + } + }) + .collect(), + attrs: attrs, + } + }) + .collect() } else { cx.span_bug(trait_.span, "no self arguments to non-static method in generic \ @@ -976,20 +978,20 @@ impl<'a> MethodDef<'a> { }; // body of the inner most destructuring match - let mut body = self.call_substructure_method( - cx, - trait_, - type_ident, - self_args, - nonself_args, - &Struct(struct_def, fields)); + let mut body = self.call_substructure_method(cx, + trait_, + type_ident, + self_args, + nonself_args, + &Struct(struct_def, fields)); // make a series of nested matches, to destructure the // structs. This is actually right-to-left, but it shouldn't // matter. for (arg_expr, pat) in self_args.iter().zip(patterns) { - body = cx.expr_match(trait_.span, arg_expr.clone(), - vec!( cx.arm(trait_.span, vec!(pat.clone()), body) )) + body = cx.expr_match(trait_.span, + arg_expr.clone(), + vec![cx.arm(trait_.span, vec![pat.clone()], body)]) } body @@ -1002,13 +1004,14 @@ impl<'a> MethodDef<'a> { type_ident: Ident, self_args: &[P], nonself_args: &[P]) - -> P { + -> P { let summary = trait_.summarise_struct(cx, struct_def); self.call_substructure_method(cx, trait_, type_ident, - self_args, nonself_args, + self_args, + nonself_args, &StaticStruct(struct_def, summary)) } @@ -1042,16 +1045,21 @@ impl<'a> MethodDef<'a> { /// as their results are unused. The point of `__self_vi` and /// `__arg_1_vi` is for `PartialOrd`; see #15503.) fn expand_enum_method_body<'b>(&self, - cx: &mut ExtCtxt, - trait_: &TraitDef<'b>, - enum_def: &'b EnumDef, - type_attrs: &[ast::Attribute], - type_ident: Ident, - self_args: Vec>, - nonself_args: &[P]) - -> P { - self.build_enum_match_tuple( - cx, trait_, enum_def, type_attrs, type_ident, self_args, nonself_args) + cx: &mut ExtCtxt, + trait_: &TraitDef<'b>, + enum_def: &'b EnumDef, + type_attrs: &[ast::Attribute], + type_ident: Ident, + self_args: Vec>, + nonself_args: &[P]) + -> P { + self.build_enum_match_tuple(cx, + trait_, + enum_def, + type_attrs, + type_ident, + self_args, + nonself_args) } @@ -1090,20 +1098,21 @@ impl<'a> MethodDef<'a> { /// ... // catch-all remainder can inspect above variant index values. /// } /// ``` - fn build_enum_match_tuple<'b>( - &self, - cx: &mut ExtCtxt, - trait_: &TraitDef<'b>, - enum_def: &'b EnumDef, - type_attrs: &[ast::Attribute], - type_ident: Ident, - self_args: Vec>, - nonself_args: &[P]) -> P { + fn build_enum_match_tuple<'b>(&self, + cx: &mut ExtCtxt, + trait_: &TraitDef<'b>, + enum_def: &'b EnumDef, + type_attrs: &[ast::Attribute], + type_ident: Ident, + self_args: Vec>, + nonself_args: &[P]) + -> P { let sp = trait_.span; let variants = &enum_def.variants; - let self_arg_names = self_args.iter().enumerate() + let self_arg_names = self_args.iter() + .enumerate() .map(|(arg_count, _self_arg)| { if arg_count == 0 { "__self".to_string() @@ -1114,22 +1123,24 @@ impl<'a> MethodDef<'a> { .collect::>(); let self_arg_idents = self_arg_names.iter() - .map(|name|cx.ident_of(&name[..])) + .map(|name| cx.ident_of(&name[..])) .collect::>(); // The `vi_idents` will be bound, solely in the catch-all, to // a series of let statements mapping each self_arg to an int // value corresponding to its discriminant. let vi_idents: Vec = self_arg_names.iter() - .map(|name| { let vi_suffix = format!("{}_vi", &name[..]); - cx.ident_of(&vi_suffix[..]) }) + .map(|name| { + let vi_suffix = format!("{}_vi", &name[..]); + cx.ident_of(&vi_suffix[..]) + }) .collect::>(); // Builds, via callback to call_substructure_method, the // delegated expression that handles the catch-all case, // using `__variants_tuple` to drive logic if necessary. - let catch_all_substructure = EnumNonMatchingCollapsed( - self_arg_idents, &variants[..], &vi_idents[..]); + let catch_all_substructure = + EnumNonMatchingCollapsed(self_arg_idents, &variants[..], &vi_idents[..]); let first_fieldless = variants.iter().find(|v| v.node.data.fields().is_empty()); @@ -1138,15 +1149,16 @@ impl<'a> MethodDef<'a> { // (Variant2, Variant2, ...) => Body2 // ... // where each tuple has length = self_args.len() - let mut match_arms: Vec = variants.iter().enumerate() + let mut match_arms: Vec = variants.iter() + .enumerate() .filter(|&(_, v)| !(self.unify_fieldless_variants && v.node.data.fields().is_empty())) .map(|(index, variant)| { let mk_self_pat = |cx: &mut ExtCtxt, self_arg_name: &str| { - let (p, idents) = trait_.create_enum_variant_pattern( - cx, type_ident, - variant, - self_arg_name, - ast::Mutability::Immutable); + let (p, idents) = trait_.create_enum_variant_pattern(cx, + type_ident, + variant, + self_arg_name, + ast::Mutability::Immutable); (cx.pat(sp, PatKind::Ref(p, ast::Mutability::Immutable)), idents) }; @@ -1213,24 +1225,29 @@ impl<'a> MethodDef<'a> { // expressions for referencing every field of every // Self arg, assuming all are instances of VariantK. // Build up code associated with such a case. - let substructure = EnumMatching(index, - variant, - field_tuples); - let arm_expr = self.call_substructure_method( - cx, trait_, type_ident, &self_args[..], nonself_args, - &substructure); + let substructure = EnumMatching(index, variant, field_tuples); + let arm_expr = self.call_substructure_method(cx, + trait_, + type_ident, + &self_args[..], + nonself_args, + &substructure); cx.arm(sp, vec![single_pat], arm_expr) - }).collect(); + }) + .collect(); let default = match first_fieldless { Some(v) if self.unify_fieldless_variants => { // We need a default case that handles the fieldless variants. // The index and actual variant aren't meaningful in this case, // so just use whatever - Some(self.call_substructure_method( - cx, trait_, type_ident, &self_args[..], nonself_args, - &EnumMatching(0, v, Vec::new()))) + Some(self.call_substructure_method(cx, + trait_, + type_ident, + &self_args[..], + nonself_args, + &EnumMatching(0, v, Vec::new()))) } _ if variants.len() > 1 && self_args.len() > 1 => { // Since we know that all the arguments will match if we reach @@ -1238,7 +1255,7 @@ impl<'a> MethodDef<'a> { // result of the catch all which should help llvm in optimizing it Some(deriving::call_intrinsic(cx, sp, "unreachable", vec![])) } - _ => None + _ => None, }; if let Some(arm) = default { match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], arm)); @@ -1279,20 +1296,17 @@ impl<'a> MethodDef<'a> { // ``` let mut index_let_stmts: Vec = Vec::new(); - //We also build an expression which checks whether all discriminants are equal + // We also build an expression which checks whether all discriminants are equal // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... let mut discriminant_test = cx.expr_bool(sp, true); - let target_type_name = - find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs); + let target_type_name = find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs); let mut first_ident = None; for (&ident, self_arg) in vi_idents.iter().zip(&self_args) { let self_addr = cx.expr_addr_of(sp, self_arg.clone()); - let variant_value = deriving::call_intrinsic(cx, - sp, - "discriminant_value", - vec![self_addr]); + let variant_value = + deriving::call_intrinsic(cx, sp, "discriminant_value", vec![self_addr]); let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name)); let variant_disr = cx.expr_cast(sp, variant_value, target_ty); @@ -1304,8 +1318,8 @@ impl<'a> MethodDef<'a> { let first_expr = cx.expr_ident(sp, first); let id = cx.expr_ident(sp, ident); let test = cx.expr_binary(sp, BinOpKind::Eq, first_expr, id); - discriminant_test = cx.expr_binary(sp, BinOpKind::And, - discriminant_test, test) + discriminant_test = + cx.expr_binary(sp, BinOpKind::And, discriminant_test, test) } None => { first_ident = Some(ident); @@ -1313,9 +1327,12 @@ impl<'a> MethodDef<'a> { } } - let arm_expr = self.call_substructure_method( - cx, trait_, type_ident, &self_args[..], nonself_args, - &catch_all_substructure); + let arm_expr = self.call_substructure_method(cx, + trait_, + type_ident, + &self_args[..], + nonself_args, + &catch_all_substructure); // Final wrinkle: the self_args are expressions that deref // down to desired l-values, but we cannot actually deref @@ -1325,7 +1342,7 @@ impl<'a> MethodDef<'a> { let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); let match_arg = cx.expr(sp, ast::ExprKind::Tup(borrowed_self_args)); - //Lastly we create an expression which branches on all discriminants being equal + // Lastly we create an expression which branches on all discriminants being equal // if discriminant_test { // match (...) { // (Variant1, Variant1, ...) => Body1 @@ -1392,8 +1409,7 @@ impl<'a> MethodDef<'a> { // that needs the feature gate enabled.) deriving::call_intrinsic(cx, sp, "unreachable", vec![]) - } - else { + } else { // Final wrinkle: the self_args are expressions that deref // down to desired l-values, but we cannot actually deref @@ -1413,26 +1429,30 @@ impl<'a> MethodDef<'a> { type_ident: Ident, self_args: &[P], nonself_args: &[P]) - -> P { - let summary = enum_def.variants.iter().map(|v| { - let ident = v.node.name; - let summary = trait_.summarise_struct(cx, &v.node.data); - (ident, v.span, summary) - }).collect(); - self.call_substructure_method(cx, trait_, type_ident, - self_args, nonself_args, + -> P { + let summary = enum_def.variants + .iter() + .map(|v| { + let ident = v.node.name; + let summary = trait_.summarise_struct(cx, &v.node.data); + (ident, v.span, summary) + }) + .collect(); + self.call_substructure_method(cx, + trait_, + type_ident, + self_args, + nonself_args, &StaticEnum(enum_def, summary)) } } // general helper methods. impl<'a> TraitDef<'a> { - fn summarise_struct(&self, - cx: &mut ExtCtxt, - struct_def: &VariantData) -> StaticFields { + fn summarise_struct(&self, cx: &mut ExtCtxt, struct_def: &VariantData) -> StaticFields { let mut named_idents = Vec::new(); let mut just_spans = Vec::new(); - for field in struct_def.fields(){ + for field in struct_def.fields() { let sp = Span { expn_id: self.span.expn_id, ..field.span }; match field.ident { Some(ident) => named_idents.push((ident, sp)), @@ -1441,9 +1461,11 @@ impl<'a> TraitDef<'a> { } match (just_spans.is_empty(), named_idents.is_empty()) { - (false, false) => cx.span_bug(self.span, - "a struct with named and unnamed \ - fields in generic `derive`"), + (false, false) => { + cx.span_bug(self.span, + "a struct with named and unnamed \ + fields in generic `derive`") + } // named fields (_, false) => Named(named_idents), // empty structs @@ -1454,46 +1476,57 @@ impl<'a> TraitDef<'a> { fn create_subpatterns(&self, cx: &mut ExtCtxt, - field_paths: Vec , + field_paths: Vec, mutbl: ast::Mutability) -> Vec> { - field_paths.iter().map(|path| { - cx.pat(path.span, - PatKind::Ident(ast::BindingMode::ByRef(mutbl), (*path).clone(), None)) - }).collect() + field_paths.iter() + .map(|path| { + cx.pat(path.span, + PatKind::Ident(ast::BindingMode::ByRef(mutbl), (*path).clone(), None)) + }) + .collect() } - fn create_struct_pattern(&self, - cx: &mut ExtCtxt, - struct_path: ast::Path, - struct_def: &'a VariantData, - prefix: &str, - mutbl: ast::Mutability) - -> (P, Vec<(Span, Option, - P, - &'a [ast::Attribute])>) { + fn create_struct_pattern + (&self, + cx: &mut ExtCtxt, + struct_path: ast::Path, + struct_def: &'a VariantData, + prefix: &str, + mutbl: ast::Mutability) + -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { let mut paths = Vec::new(); let mut ident_exprs = Vec::new(); for (i, struct_field) in struct_def.fields().iter().enumerate() { let sp = Span { expn_id: self.span.expn_id, ..struct_field.span }; let ident = cx.ident_of(&format!("{}_{}", prefix, i)); - paths.push(codemap::Spanned{span: sp, node: ident}); - let val = cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident))); + paths.push(codemap::Spanned { + span: sp, + node: ident, + }); + let val = cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp, ident))); let val = cx.expr(sp, ast::ExprKind::Paren(val)); ident_exprs.push((sp, struct_field.ident, val, &struct_field.attrs[..])); } let subpats = self.create_subpatterns(cx, paths, mutbl); let pattern = if struct_def.is_struct() { - let field_pats = subpats.into_iter().zip(&ident_exprs).map(|(pat, &(sp, ident, _, _))| { - if ident.is_none() { - cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); - } - codemap::Spanned { - span: pat.span, - node: ast::FieldPat { ident: ident.unwrap(), pat: pat, is_shorthand: false }, - } - }).collect(); + let field_pats = subpats.into_iter() + .zip(&ident_exprs) + .map(|(pat, &(sp, ident, _, _))| { + if ident.is_none() { + cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); + } + codemap::Spanned { + span: pat.span, + node: ast::FieldPat { + ident: ident.unwrap(), + pat: pat, + is_shorthand: false, + }, + } + }) + .collect(); cx.pat_struct(self.span, struct_path, field_pats) } else { cx.pat_enum(self.span, struct_path, subpats) @@ -1502,20 +1535,21 @@ impl<'a> TraitDef<'a> { (pattern, ident_exprs) } - fn create_enum_variant_pattern(&self, - cx: &mut ExtCtxt, - enum_ident: ast::Ident, - variant: &'a ast::Variant, - prefix: &str, - mutbl: ast::Mutability) - -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { + fn create_enum_variant_pattern + (&self, + cx: &mut ExtCtxt, + enum_ident: ast::Ident, + variant: &'a ast::Variant, + prefix: &str, + mutbl: ast::Mutability) + -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { let variant_ident = variant.node.name; let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]); self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl) } } -/* helpful premade recipes */ +// helpful premade recipes /// Fold the fields. `use_foldl` controls whether this is done /// left-to-right (`true`) or right-to-left (`false`). @@ -1526,35 +1560,29 @@ pub fn cs_fold(use_foldl: bool, cx: &mut ExtCtxt, trait_span: Span, substructure: &Substructure) - -> P where - F: FnMut(&mut ExtCtxt, Span, P, P, &[P]) -> P, + -> P + where F: FnMut(&mut ExtCtxt, Span, P, P, &[P]) -> P { match *substructure.fields { - EnumMatching(_, _, ref all_fields) | Struct(_, ref all_fields) => { + EnumMatching(_, _, ref all_fields) | + Struct(_, ref all_fields) => { if use_foldl { all_fields.iter().fold(base, |old, field| { - f(cx, - field.span, - old, - field.self_.clone(), - &field.other) + f(cx, field.span, old, field.self_.clone(), &field.other) }) } else { all_fields.iter().rev().fold(base, |old, field| { - f(cx, - field.span, - old, - field.self_.clone(), - &field.other) + f(cx, field.span, old, field.self_.clone(), &field.other) }) } - }, - EnumNonMatchingCollapsed(ref all_args, _, tuple) => - enum_nonmatch_f(cx, trait_span, (&all_args[..], tuple), - substructure.nonself_args), - StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, "static function in `derive`") } + EnumNonMatchingCollapsed(ref all_args, _, tuple) => { + enum_nonmatch_f(cx, + trait_span, + (&all_args[..], tuple), + substructure.nonself_args) + } + StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"), } } @@ -1572,29 +1600,34 @@ pub fn cs_same_method(f: F, cx: &mut ExtCtxt, trait_span: Span, substructure: &Substructure) - -> P where - F: FnOnce(&mut ExtCtxt, Span, Vec>) -> P, + -> P + where F: FnOnce(&mut ExtCtxt, Span, Vec>) -> P { match *substructure.fields { - EnumMatching(_, _, ref all_fields) | Struct(_, ref all_fields) => { + EnumMatching(_, _, ref all_fields) | + Struct(_, ref all_fields) => { // call self_n.method(other_1_n, other_2_n, ...) - let called = all_fields.iter().map(|field| { - cx.expr_method_call(field.span, - field.self_.clone(), - substructure.method_ident, - field.other.iter() - .map(|e| cx.expr_addr_of(field.span, e.clone())) - .collect()) - }).collect(); + let called = all_fields.iter() + .map(|field| { + cx.expr_method_call(field.span, + field.self_.clone(), + substructure.method_ident, + field.other + .iter() + .map(|e| cx.expr_addr_of(field.span, e.clone())) + .collect()) + }) + .collect(); f(cx, trait_span, called) - }, - EnumNonMatchingCollapsed(ref all_self_args, _, tuple) => - enum_nonmatch_f(cx, trait_span, (&all_self_args[..], tuple), - substructure.nonself_args), - StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, "static function in `derive`") } + EnumNonMatchingCollapsed(ref all_self_args, _, tuple) => { + enum_nonmatch_f(cx, + trait_span, + (&all_self_args[..], tuple), + substructure.nonself_args) + } + StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"), } } @@ -1606,10 +1639,8 @@ pub fn is_type_without_fields(item: &Annotatable) -> bool { ast::ItemKind::Enum(ref enum_def, _) => { enum_def.variants.iter().all(|v| v.node.data.fields().is_empty()) } - ast::ItemKind::Struct(ref variant_data, _) => { - variant_data.fields().is_empty() - } - _ => false + ast::ItemKind::Struct(ref variant_data, _) => variant_data.fields().is_empty(), + _ => false, } } else { false diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index 0fad96c84ef3..81c8e7112dbd 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -12,8 +12,8 @@ use deriving; use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{MetaItem, Expr, Mutability}; -use syntax::ext::base::{ExtCtxt, Annotatable}; +use syntax::ast::{Expr, MetaItem, Mutability}; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::ptr::P; use syntax_pos::Span; @@ -22,11 +22,9 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { - let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None, - vec!(), true); + let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None, vec![], true); let typaram = &*deriving::hygienic_type_parameter(item, "__H"); @@ -38,25 +36,23 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - methods: vec!( - MethodDef { - name: "hash", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec![(typaram, - vec![path_std!(cx, core::hash::Hasher)])], - }, - explicit_self: borrowed_explicit_self(), - args: vec!(Ptr(Box::new(Literal(arg)), Borrowed(None, Mutability::Mutable))), - ret_ty: nil_ty(), - attributes: vec![], - is_unsafe: false, - unify_fieldless_variants: true, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - hash_substructure(a, b, c) - })) - } - ), + methods: vec![MethodDef { + name: "hash", + generics: LifetimeBounds { + lifetimes: Vec::new(), + bounds: vec![(typaram, vec![path_std!(cx, core::hash::Hasher)])], + }, + explicit_self: borrowed_explicit_self(), + args: vec![Ptr(Box::new(Literal(arg)), + Borrowed(None, Mutability::Mutable))], + ret_ty: nil_ty(), + attributes: vec![], + is_unsafe: false, + unify_fieldless_variants: true, + combine_substructure: combine_substructure(Box::new(|a, b, c| { + hash_substructure(a, b, c) + })), + }], associated_types: Vec::new(), }; @@ -66,7 +62,10 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { let state_expr = match (substr.nonself_args.len(), substr.nonself_args.get(0)) { (1, Some(o_f)) => o_f, - _ => cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`") + _ => { + cx.span_bug(trait_span, + "incorrect number of arguments in `derive(Hash)`") + } }; let call_hash = |span, thing_expr| { let hash_path = { @@ -75,7 +74,7 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) cx.expr_path(cx.path_global(span, strs)) }; let ref_thing = cx.expr_addr_of(span, thing_expr); - let expr = cx.expr_call(span, hash_path, vec!(ref_thing, state_expr.clone())); + let expr = cx.expr_call(span, hash_path, vec![ref_thing, state_expr.clone()]); cx.stmt_expr(expr) }; let mut stmts = Vec::new(); @@ -92,7 +91,7 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) fs } - _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`") + _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`"), }; for &FieldInfo { ref self_, span, .. } in fields { diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 169e80736619..e09a64e73449 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -10,9 +10,9 @@ //! The compiler code necessary to implement the `#[derive]` extensions. -use syntax::ast::{MetaItem, MetaItemKind, self}; +use syntax::ast::{MetaItem, self}; use syntax::attr::AttrMetaMethods; -use syntax::ext::base::{ExtCtxt, SyntaxEnv, Annotatable}; +use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; use syntax::ext::build::AstBuilder; use syntax::feature_gate; @@ -98,15 +98,14 @@ fn expand_derive(cx: &mut ExtCtxt, let mut eq_span = None; for titem in traits.iter().rev() { - let tname = match titem.node { - MetaItemKind::Word(ref tname) => tname, - _ => { - cx.span_err(titem.span, "malformed `derive` entry"); - continue; - } - }; + let tname = if titem.is_word() { + titem.name() } + else { + cx.span_err(titem.span, "malformed `derive` entry"); + continue; + }; - if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) { + if !(is_builtin_trait(&tname) || cx.ecfg.enable_custom_derive()) { feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, "custom_derive", titem.span, @@ -123,7 +122,8 @@ fn expand_derive(cx: &mut ExtCtxt, span: Some(titem.span), allow_internal_unstable: true, }, - }), ..titem.span + }), + ..titem.span }; if &tname[..] == "Eq" { @@ -133,8 +133,9 @@ fn expand_derive(cx: &mut ExtCtxt, } // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar] - item.attrs.push(cx.attribute(span, cx.meta_word(titem.span, - intern_and_get_ident(&format!("derive_{}", tname))))); + item.attrs.push(cx.attribute(span, + cx.meta_word(titem.span, + intern_and_get_ident(&format!("derive_{}", tname))))); } // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted) @@ -142,18 +143,18 @@ fn expand_derive(cx: &mut ExtCtxt, if let Some(eq_span) = eq_span { if found_partial_eq { let structural_match = intern_and_get_ident("structural_match"); - item.attrs.push(cx.attribute(eq_span, - cx.meta_word(eq_span, - structural_match))); + item.attrs.push(cx.attribute(eq_span, cx.meta_word(eq_span, structural_match))); } } item }) - }, |a| { - cx.span_err(span, "`derive` can only be applied to items"); - a - }); + }, + |a| { + cx.span_err(span, + "`derive` can only be applied to items"); + a + }); debug!("expand_derive: annotatable output = {:?}", annot); annot } @@ -261,8 +262,10 @@ fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) { "Decodable" => Some("RustcDecodable"), _ => None, } { - ecx.span_warn(sp, &format!("derive({}) is deprecated in favor of derive({})", - name, replacement)); + ecx.span_warn(sp, + &format!("derive({}) is deprecated in favor of derive({})", + name, + replacement)); } } @@ -275,8 +278,7 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String { if let Annotatable::Item(ref item) = *item { match item.node { ast::ItemKind::Struct(_, ast::Generics { ref ty_params, .. }) | - ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => { - + ast::ItemKind::Enum(_, ast::Generics { ref ty_params, .. }) => { for ty in ty_params.iter() { typaram.push_str(&ty.ident.name.as_str()); } @@ -293,7 +295,8 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String { fn call_intrinsic(cx: &ExtCtxt, span: Span, intrinsic: &str, - args: Vec>) -> P { + args: Vec>) + -> P { let path = cx.std_path(&["intrinsics", intrinsic]); let call = cx.expr_call_global(span, path, args); @@ -301,6 +304,6 @@ fn call_intrinsic(cx: &ExtCtxt, stmts: vec![cx.stmt_expr(call)], id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), - span: span })) + span: span, + })) } - diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 94bb78edaacd..1f6f57c70f72 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -406,7 +406,9 @@ impl<'a, 'b> Context<'a, 'b> { let arg_idx = match arg_index_consumed.get_mut(i) { None => 0, // error already emitted elsewhere Some(offset) => { - let arg_idx = self.arg_index_map[i][*offset]; + let ref idx_map = self.arg_index_map[i]; + // unwrap_or branch: error already emitted elsewhere + let arg_idx = *idx_map.get(*offset).unwrap_or(&0); *offset += 1; arg_idx } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 7dfe19452a2a..0f171805bb0a 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -265,6 +265,10 @@ pub const NO_EXPANSION: ExpnId = ExpnId(!0); // For code appearing from the command line pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1); +// For code generated by a procedural macro, without knowing which +// Used in `qquote!` +pub const PROC_EXPN: ExpnId = ExpnId(!2); + impl ExpnId { pub fn from_u32(id: u32) -> ExpnId { ExpnId(id) diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index ebe6fd54799e..fd446f5a4f94 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -16,7 +16,7 @@ fn main() { let target = env::var("TARGET").unwrap(); if target.contains("linux") { - if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) { + if target.contains("musl") && !target.contains("mips") { println!("cargo:rustc-link-lib=static=unwind"); } else if !target.contains("android") { println!("cargo:rustc-link-lib=gcc_s"); diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index aadfe202afe7..5e242db0a888 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -10,38 +10,15 @@ #![allow(bad_style)] -use libc; - -#[cfg(any(not(target_arch = "arm"), target_os = "ios"))] -pub use self::_Unwind_Action::*; -#[cfg(target_arch = "arm")] -pub use self::_Unwind_State::*; -pub use self::_Unwind_Reason_Code::*; - -#[cfg(any(not(target_arch = "arm"), target_os = "ios"))] -#[repr(C)] -#[derive(Clone, Copy)] -pub enum _Unwind_Action { - _UA_SEARCH_PHASE = 1, - _UA_CLEANUP_PHASE = 2, - _UA_HANDLER_FRAME = 4, - _UA_FORCE_UNWIND = 8, - _UA_END_OF_STACK = 16, +macro_rules! cfg_if { + ( $( if #[cfg( $meta:meta )] { $($it1:item)* } else { $($it2:item)* } )* ) => + ( $( $( #[cfg($meta)] $it1)* $( #[cfg(not($meta))] $it2)* )* ) } -#[cfg(target_arch = "arm")] -#[repr(C)] -#[derive(Clone, Copy)] -pub enum _Unwind_State { - _US_VIRTUAL_UNWIND_FRAME = 0, - _US_UNWIND_FRAME_STARTING = 1, - _US_UNWIND_FRAME_RESUME = 2, - _US_ACTION_MASK = 3, - _US_FORCE_UNWIND = 8, - _US_END_OF_STACK = 16, -} +use libc::{c_int, c_void, uintptr_t}; #[repr(C)] +#[derive(Copy, Clone, PartialEq)] pub enum _Unwind_Reason_Code { _URC_NO_REASON = 0, _URC_FOREIGN_EXCEPTION_CAUGHT = 1, @@ -52,16 +29,15 @@ pub enum _Unwind_Reason_Code { _URC_HANDLER_FOUND = 6, _URC_INSTALL_CONTEXT = 7, _URC_CONTINUE_UNWIND = 8, - _URC_FAILURE = 9, // used only by ARM EABI + _URC_FAILURE = 9, // used only by ARM EHABI } +pub use self::_Unwind_Reason_Code::*; pub type _Unwind_Exception_Class = u64; - -pub type _Unwind_Word = libc::uintptr_t; - -pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut libc::c_void) +pub type _Unwind_Word = uintptr_t; +pub type _Unwind_Ptr = uintptr_t; +pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code; - #[cfg(target_arch = "x86")] pub const unwinder_private_data_size: usize = 5; @@ -98,6 +74,164 @@ pub enum _Unwind_Context {} pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception); +extern "C" { + #[unwind] + pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !; + pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception); + pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void; + pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr; + pub fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr; + pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr; +} + +cfg_if! { +if #[cfg(not(any(all(target_os = "android", target_arch = "arm"), + all(target_os = "linux", target_arch = "arm"))))] { + // Not ARM EHABI + #[repr(C)] + #[derive(Copy, Clone, PartialEq)] + pub enum _Unwind_Action { + _UA_SEARCH_PHASE = 1, + _UA_CLEANUP_PHASE = 2, + _UA_HANDLER_FRAME = 4, + _UA_FORCE_UNWIND = 8, + _UA_END_OF_STACK = 16, + } + pub use self::_Unwind_Action::*; + + extern "C" { + pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word; + pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word); + pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word; + pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word); + pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int) + -> _Unwind_Word; + pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void; + } + +} else { + // ARM EHABI + #[repr(C)] + #[derive(Copy, Clone, PartialEq)] + pub enum _Unwind_State { + _US_VIRTUAL_UNWIND_FRAME = 0, + _US_UNWIND_FRAME_STARTING = 1, + _US_UNWIND_FRAME_RESUME = 2, + _US_ACTION_MASK = 3, + _US_FORCE_UNWIND = 8, + _US_END_OF_STACK = 16, + } + pub use self::_Unwind_State::*; + + #[repr(C)] + enum _Unwind_VRS_Result { + _UVRSR_OK = 0, + _UVRSR_NOT_IMPLEMENTED = 1, + _UVRSR_FAILED = 2, + } + #[repr(C)] + enum _Unwind_VRS_RegClass { + _UVRSC_CORE = 0, + _UVRSC_VFP = 1, + _UVRSC_FPA = 2, + _UVRSC_WMMXD = 3, + _UVRSC_WMMXC = 4, + } + use self::_Unwind_VRS_RegClass::*; + #[repr(C)] + enum _Unwind_VRS_DataRepresentation { + _UVRSD_UINT32 = 0, + _UVRSD_VFPX = 1, + _UVRSD_FPAX = 2, + _UVRSD_UINT64 = 3, + _UVRSD_FLOAT = 4, + _UVRSD_DOUBLE = 5, + } + use self::_Unwind_VRS_DataRepresentation::*; + + pub const UNWIND_POINTER_REG: c_int = 12; + pub const UNWIND_IP_REG: c_int = 15; + + extern "C" { + fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context, + regclass: _Unwind_VRS_RegClass, + regno: _Unwind_Word, + repr: _Unwind_VRS_DataRepresentation, + data: *mut c_void) + -> _Unwind_VRS_Result; + + fn _Unwind_VRS_Set(ctx: *mut _Unwind_Context, + regclass: _Unwind_VRS_RegClass, + regno: _Unwind_Word, + repr: _Unwind_VRS_DataRepresentation, + data: *mut c_void) + -> _Unwind_VRS_Result; + } + + // On Android or ARM/Linux, these are implemented as macros: + + pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word { + let mut val: _Unwind_Word = 0; + _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, + &mut val as *mut _ as *mut c_void); + val + } + + pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) { + let mut value = value; + _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, + &mut value as *mut _ as *mut c_void); + } + + pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) + -> _Unwind_Word { + let val = _Unwind_GetGR(ctx, UNWIND_IP_REG); + (val & !1) as _Unwind_Word + } + + pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context, + value: _Unwind_Word) { + // Propagate thumb bit to instruction pointer + let thumb_state = _Unwind_GetGR(ctx, UNWIND_IP_REG) & 1; + let value = value | thumb_state; + _Unwind_SetGR(ctx, UNWIND_IP_REG, value); + } + + pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, + ip_before_insn: *mut c_int) + -> _Unwind_Word { + *ip_before_insn = 0; + _Unwind_GetIP(ctx) + } + + // This function also doesn't exist on Android or ARM/Linux, so make it a no-op + pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void { + pc + } +} + +if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { + // Not 32-bit iOS + extern "C" { + #[unwind] + pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; + pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, + trace_argument: *mut c_void) + -> _Unwind_Reason_Code; + } +} else { + // 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace() + extern "C" { + #[unwind] + pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; + } + + #[inline] + pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code { + _Unwind_SjLj_RaiseException(exc) + } +} +} // cfg_if! #[cfg_attr(any(all(target_os = "linux", not(target_env = "musl")), target_os = "freebsd", @@ -126,115 +260,3 @@ pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reaso link(name = "gcc_eh"))] #[cfg(not(cargobuild))] extern "C" {} - -extern "C" { - // iOS on armv7 uses SjLj exceptions and requires to link - // against corresponding routine (..._SjLj_...) - #[cfg(not(all(target_os = "ios", target_arch = "arm")))] - #[unwind] - pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; - - #[cfg(all(target_os = "ios", target_arch = "arm"))] - #[unwind] - fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code; - - pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception); - - #[unwind] - pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !; - - // No native _Unwind_Backtrace on iOS - #[cfg(not(all(target_os = "ios", target_arch = "arm")))] - pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, - trace_argument: *mut libc::c_void) - -> _Unwind_Reason_Code; - - // available since GCC 4.2.0, should be fine for our purpose - #[cfg(all(not(all(target_os = "android", target_arch = "arm")), - not(all(target_os = "linux", target_arch = "arm"))))] - pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, - ip_before_insn: *mut libc::c_int) - -> libc::uintptr_t; - - #[cfg(all(not(target_os = "android"), - not(all(target_os = "linux", target_arch = "arm"))))] - pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) -> *mut libc::c_void; -} - -// ... and now we just providing access to SjLj counterspart -// through a standard name to hide those details from others -// (see also comment above regarding _Unwind_RaiseException) -#[cfg(all(target_os = "ios", target_arch = "arm"))] -#[inline] -pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code { - _Unwind_SjLj_RaiseException(exc) -} - -// On android, the function _Unwind_GetIP is a macro, and this is the -// expansion of the macro. This is all copy/pasted directly from the -// header file with the definition of _Unwind_GetIP. -#[cfg(any(all(target_os = "android", target_arch = "arm"), - all(target_os = "linux", target_arch = "arm")))] -pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t { - #[repr(C)] - enum _Unwind_VRS_Result { - _UVRSR_OK = 0, - _UVRSR_NOT_IMPLEMENTED = 1, - _UVRSR_FAILED = 2, - } - #[repr(C)] - enum _Unwind_VRS_RegClass { - _UVRSC_CORE = 0, - _UVRSC_VFP = 1, - _UVRSC_FPA = 2, - _UVRSC_WMMXD = 3, - _UVRSC_WMMXC = 4, - } - #[repr(C)] - enum _Unwind_VRS_DataRepresentation { - _UVRSD_UINT32 = 0, - _UVRSD_VFPX = 1, - _UVRSD_FPAX = 2, - _UVRSD_UINT64 = 3, - _UVRSD_FLOAT = 4, - _UVRSD_DOUBLE = 5, - } - - type _Unwind_Word = libc::c_uint; - extern "C" { - fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context, - klass: _Unwind_VRS_RegClass, - word: _Unwind_Word, - repr: _Unwind_VRS_DataRepresentation, - data: *mut libc::c_void) - -> _Unwind_VRS_Result; - } - - let mut val: _Unwind_Word = 0; - let ptr = &mut val as *mut _Unwind_Word; - let _ = _Unwind_VRS_Get(ctx, - _Unwind_VRS_RegClass::_UVRSC_CORE, - 15, - _Unwind_VRS_DataRepresentation::_UVRSD_UINT32, - ptr as *mut libc::c_void); - (val & !1) as libc::uintptr_t -} - -// This function doesn't exist on Android or ARM/Linux, so make it same -// to _Unwind_GetIP -#[cfg(any(all(target_os = "android", target_arch = "arm"), - all(target_os = "linux", target_arch = "arm")))] -pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, - ip_before_insn: *mut libc::c_int) - -> libc::uintptr_t { - *ip_before_insn = 0; - _Unwind_GetIP(ctx) -} - -// This function also doesn't exist on Android or ARM/Linux, so make it -// a no-op -#[cfg(any(target_os = "android", - all(target_os = "linux", target_arch = "arm")))] -pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) -> *mut libc::c_void { - pc -} diff --git a/src/llvm b/src/llvm index a3c12a7ad8a0..d295833b7733 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit a3c12a7ad8a0d32a957f67f127936907b9ba522c +Subproject commit d295833b773313dbef26041f481fc91a2954fbb9 diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 4def60e485f7..0b2287cf233d 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -105,6 +105,7 @@ dependencies = [ "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", + "rustc_errors 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", diff --git a/src/rustc/std_shim/Cargo.lock b/src/rustc/std_shim/Cargo.lock index bad46966ffa6..70aef55d799c 100644 --- a/src/rustc/std_shim/Cargo.lock +++ b/src/rustc/std_shim/Cargo.lock @@ -18,7 +18,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", ] @@ -49,7 +49,7 @@ version = "0.0.0" [[package]] name = "gcc" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -101,7 +101,7 @@ dependencies = [ "build_helper 0.1.0", "collections 0.0.0", "core 0.0.0", - "gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", "panic_abort 0.0.0", "panic_unwind 0.0.0", diff --git a/src/rustc/std_shim/Cargo.toml b/src/rustc/std_shim/Cargo.toml index 5602ef866b83..693cbe06ba98 100644 --- a/src/rustc/std_shim/Cargo.toml +++ b/src/rustc/std_shim/Cargo.toml @@ -46,3 +46,4 @@ std = { path = "../../libstd" } [features] jemalloc = ["std/jemalloc"] debug-jemalloc = ["std/debug-jemalloc"] +backtrace = ["std/backtrace"] diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 1e7b04c814ce..1e873b5345c4 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -16,24 +16,62 @@ using namespace llvm; using namespace llvm::object; -struct LLVMRustArchiveMember { +struct RustArchiveMember { const char *filename; const char *name; Archive::Child child; - LLVMRustArchiveMember(): filename(NULL), name(NULL), + RustArchiveMember(): filename(NULL), name(NULL), #if LLVM_VERSION_MINOR >= 8 child(NULL, NULL, NULL) #else child(NULL, NULL) #endif {} - ~LLVMRustArchiveMember() {} + ~RustArchiveMember() {} }; -typedef OwningBinary RustArchive; -extern "C" void* +struct RustArchiveIterator { + Archive::child_iterator cur; + Archive::child_iterator end; +#if LLVM_VERSION_MINOR >= 9 + Error err; +#endif +}; + +enum class LLVMRustArchiveKind { + Other, + GNU, + MIPS64, + BSD, + COFF, +}; + +static Archive::Kind +from_rust(LLVMRustArchiveKind kind) +{ + switch (kind) { + case LLVMRustArchiveKind::GNU: + return Archive::K_GNU; + case LLVMRustArchiveKind::MIPS64: + return Archive::K_MIPS64; + case LLVMRustArchiveKind::BSD: + return Archive::K_BSD; + case LLVMRustArchiveKind::COFF: + return Archive::K_COFF; + default: + llvm_unreachable("Bad ArchiveKind."); + } +} + +typedef OwningBinary *LLVMRustArchiveRef; +typedef RustArchiveMember *LLVMRustArchiveMemberRef; +typedef Archive::Child *LLVMRustArchiveChildRef; +typedef Archive::Child const *LLVMRustArchiveChildConstRef; +typedef RustArchiveIterator *LLVMRustArchiveIteratorRef; + +extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *path) { ErrorOr> buf_or = MemoryBuffer::getFile(path, -1, @@ -43,11 +81,19 @@ LLVMRustOpenArchive(char *path) { return nullptr; } +#if LLVM_VERSION_MINOR <= 8 ErrorOr> archive_or = +#else + Expected> archive_or = +#endif Archive::create(buf_or.get()->getMemBufferRef()); if (!archive_or) { +#if LLVM_VERSION_MINOR <= 8 LLVMRustSetLastError(archive_or.getError().message().c_str()); +#else + LLVMRustSetLastError(toString(archive_or.takeError()).c_str()); +#endif return nullptr; } @@ -58,29 +104,38 @@ LLVMRustOpenArchive(char *path) { } extern "C" void -LLVMRustDestroyArchive(RustArchive *ar) { +LLVMRustDestroyArchive(LLVMRustArchiveRef ar) { delete ar; } -struct RustArchiveIterator { - Archive::child_iterator cur; - Archive::child_iterator end; -}; - -extern "C" RustArchiveIterator* -LLVMRustArchiveIteratorNew(RustArchive *ra) { +extern "C" LLVMRustArchiveIteratorRef +LLVMRustArchiveIteratorNew(LLVMRustArchiveRef ra) { Archive *ar = ra->getBinary(); RustArchiveIterator *rai = new RustArchiveIterator(); +#if LLVM_VERSION_MINOR <= 8 rai->cur = ar->child_begin(); +#else + rai->cur = ar->child_begin(rai->err); + if (rai->err) { + LLVMRustSetLastError(toString(std::move(rai->err)).c_str()); + return NULL; + } +#endif rai->end = ar->child_end(); return rai; } -extern "C" const Archive::Child* -LLVMRustArchiveIteratorNext(RustArchiveIterator *rai) { +extern "C" LLVMRustArchiveChildConstRef +LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef rai) { +#if LLVM_VERSION_MINOR >= 9 + if (rai->err) { + LLVMRustSetLastError(toString(std::move(rai->err)).c_str()); + return NULL; + } +#endif if (rai->cur == rai->end) return NULL; -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_MINOR == 8 const ErrorOr* cur = rai->cur.operator->(); if (!*cur) { LLVMRustSetLastError(cur->getError().message().c_str()); @@ -97,17 +152,17 @@ LLVMRustArchiveIteratorNext(RustArchiveIterator *rai) { } extern "C" void -LLVMRustArchiveChildFree(Archive::Child *child) { +LLVMRustArchiveChildFree(LLVMRustArchiveChildRef child) { delete child; } extern "C" void -LLVMRustArchiveIteratorFree(RustArchiveIterator *rai) { +LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef rai) { delete rai; } extern "C" const char* -LLVMRustArchiveChildName(const Archive::Child *child, size_t *size) { +LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef child, size_t *size) { ErrorOr name_or_err = child->getName(); if (name_or_err.getError()) return NULL; @@ -117,7 +172,7 @@ LLVMRustArchiveChildName(const Archive::Child *child, size_t *size) { } extern "C" const char* -LLVMRustArchiveChildData(Archive::Child *child, size_t *size) { +LLVMRustArchiveChildData(LLVMRustArchiveChildRef child, size_t *size) { StringRef buf; ErrorOr buf_or_err = child->getBuffer(); if (buf_or_err.getError()) { @@ -129,9 +184,10 @@ LLVMRustArchiveChildData(Archive::Child *child, size_t *size) { return buf.data(); } -extern "C" LLVMRustArchiveMember* -LLVMRustArchiveMemberNew(char *Filename, char *Name, Archive::Child *child) { - LLVMRustArchiveMember *Member = new LLVMRustArchiveMember; +extern "C" LLVMRustArchiveMemberRef +LLVMRustArchiveMemberNew(char *Filename, char *Name, + LLVMRustArchiveChildRef child) { + RustArchiveMember *Member = new RustArchiveMember; Member->filename = Filename; Member->name = Name; if (child) @@ -140,29 +196,51 @@ LLVMRustArchiveMemberNew(char *Filename, char *Name, Archive::Child *child) { } extern "C" void -LLVMRustArchiveMemberFree(LLVMRustArchiveMember *Member) { +LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) { delete Member; } -extern "C" int +extern "C" LLVMRustResult LLVMRustWriteArchive(char *Dst, size_t NumMembers, - const LLVMRustArchiveMember **NewMembers, + const LLVMRustArchiveMemberRef *NewMembers, bool WriteSymbtab, - Archive::Kind Kind) { + LLVMRustArchiveKind rust_kind) { + +#if LLVM_VERSION_MINOR <= 8 std::vector Members; +#else + std::vector Members; +#endif + auto Kind = from_rust(rust_kind); for (size_t i = 0; i < NumMembers; i++) { auto Member = NewMembers[i]; assert(Member->name); if (Member->filename) { -#if LLVM_VERSION_MINOR >= 8 +#if LLVM_VERSION_MINOR >= 9 + Expected MOrErr = NewArchiveMember::getFile(Member->filename, true); + if (!MOrErr) { + LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); + return LLVMRustResult::Failure; + } + Members.push_back(std::move(*MOrErr)); +#elif LLVM_VERSION_MINOR == 8 Members.push_back(NewArchiveIterator(Member->filename)); #else Members.push_back(NewArchiveIterator(Member->filename, Member->name)); #endif } else { +#if LLVM_VERSION_MINOR <= 8 Members.push_back(NewArchiveIterator(Member->child, Member->name)); +#else + Expected MOrErr = NewArchiveMember::getOldMember(Member->child, true); + if (!MOrErr) { + LLVMRustSetLastError(toString(MOrErr.takeError()).c_str()); + return LLVMRustResult::Failure; + } + Members.push_back(std::move(*MOrErr)); +#endif } } #if LLVM_VERSION_MINOR >= 8 @@ -171,7 +249,7 @@ LLVMRustWriteArchive(char *Dst, auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true); #endif if (!pair.second) - return 0; + return LLVMRustResult::Success; LLVMRustSetLastError(pair.second.message().c_str()); - return -1; + return LLVMRustResult::Failure; } diff --git a/src/rustllvm/ExecutionEngineWrapper.cpp b/src/rustllvm/ExecutionEngineWrapper.cpp deleted file mode 100644 index b26ab4460199..000000000000 --- a/src/rustllvm/ExecutionEngineWrapper.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#include "rustllvm.h" - -#include "llvm/ExecutionEngine/SectionMemoryManager.h" - -using namespace llvm; -using namespace llvm::sys; -using namespace llvm::object; - -class RustJITMemoryManager : public SectionMemoryManager -{ - typedef SectionMemoryManager Base; - - public: - - RustJITMemoryManager() {} - - uint64_t getSymbolAddress(const std::string &Name) override - { - return Base::getSymbolAddress(Name); - } -}; - -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RustJITMemoryManager, LLVMRustJITMemoryManagerRef) - -extern "C" LLVMBool LLVMRustLoadDynamicLibrary(const char *path) -{ - std::string err; - DynamicLibrary lib = DynamicLibrary::getPermanentLibrary(path, &err); - - if (!lib.isValid()) - LLVMRustSetLastError(err.c_str()); - - return lib.isValid(); -} - -// Calls LLVMAddModule; -// exists for consistency with LLVMExecutionEngineRemoveModule -extern "C" void LLVMExecutionEngineAddModule( - LLVMExecutionEngineRef eeref, LLVMModuleRef mref) -{ -#ifdef _WIN32 - // On Windows, MCJIT must generate ELF objects - std::string target = getProcessTriple(); - target += "-elf"; - target = Triple::normalize(target); - unwrap(mref)->setTargetTriple(target); -#endif - LLVMAddModule(eeref, mref); -} - -// LLVMRemoveModule exists in LLVM's C bindings, -// but it requires pointless parameters -extern "C" LLVMBool LLVMExecutionEngineRemoveModule( - LLVMExecutionEngineRef eeref, LLVMModuleRef mref) -{ - ExecutionEngine *ee = unwrap(eeref); - Module *m = unwrap(mref); - - return ee->removeModule(m); -} - -extern "C" LLVMExecutionEngineRef LLVMBuildExecutionEngine(LLVMModuleRef mod) -{ - // These are necessary for code generation to work properly. - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - InitializeNativeTargetAsmParser(); - -#ifdef _WIN32 - // On Windows, MCJIT must generate ELF objects - std::string target = getProcessTriple(); - target += "-elf"; - target = Triple::normalize(target); - unwrap(mod)->setTargetTriple(target); -#endif - - std::string error_str; - TargetOptions options; - - RustJITMemoryManager *mm = new RustJITMemoryManager; - - ExecutionEngine *ee = - EngineBuilder(std::unique_ptr(unwrap(mod))) - .setMCJITMemoryManager(std::unique_ptr(mm)) - .setEngineKind(EngineKind::JIT) - .setErrorStr(&error_str) - .setTargetOptions(options) - .create(); - - if (!ee) - LLVMRustSetLastError(error_str.c_str()); - - return wrap(ee); -} - -extern "C" void LLVMExecutionEngineFinalizeObject(LLVMExecutionEngineRef eeref) -{ - ExecutionEngine *ee = unwrap(eeref); - - ee->finalizeObject(); -} diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index b94e667701c8..0555a96ff24c 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -17,6 +17,7 @@ #include "llvm/Support/Host.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/IR/AutoUpgrade.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetSubtargetInfo.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" @@ -54,41 +55,48 @@ LLVMInitializePasses() { initializeTarget(Registry); } - -enum class SupportedPassKind { +enum class LLVMRustPassKind { + Other, Function, Module, - Unsupported }; -extern "C" Pass* +static LLVMRustPassKind +to_rust(PassKind kind) +{ + switch (kind) { + case PT_Function: + return LLVMRustPassKind::Function; + case PT_Module: + return LLVMRustPassKind::Module; + default: + return LLVMRustPassKind::Other; + } +} + +extern "C" LLVMPassRef LLVMRustFindAndCreatePass(const char *PassName) { StringRef SR(PassName); PassRegistry *PR = PassRegistry::getPassRegistry(); const PassInfo *PI = PR->getPassInfo(SR); if (PI) { - return PI->createPass(); + return wrap(PI->createPass()); } return NULL; } -extern "C" SupportedPassKind -LLVMRustPassKind(Pass *pass) { - assert(pass); - PassKind passKind = pass->getPassKind(); - if (passKind == PT_Module) { - return SupportedPassKind::Module; - } else if (passKind == PT_Function) { - return SupportedPassKind::Function; - } else { - return SupportedPassKind::Unsupported; - } +extern "C" LLVMRustPassKind +LLVMRustPassKind(LLVMPassRef rust_pass) { + assert(rust_pass); + Pass *pass = unwrap(rust_pass); + return to_rust(pass->getPassKind()); } extern "C" void -LLVMRustAddPass(LLVMPassManagerRef PM, Pass *pass) { - assert(pass); +LLVMRustAddPass(LLVMPassManagerRef PM, LLVMPassRef rust_pass) { + assert(rust_pass); + Pass *pass = unwrap(rust_pass); PassManagerBase *pm = unwrap(PM); pm->add(pass); } @@ -162,6 +170,62 @@ LLVMRustHasFeature(LLVMTargetMachineRef TM, return (Bits & FeatureEntry->Value) == FeatureEntry->Value; } +enum class LLVMRustCodeModel { + Other, + Default, + JITDefault, + Small, + Kernel, + Medium, + Large, +}; + +static CodeModel::Model +from_rust(LLVMRustCodeModel model) +{ + switch (model) { + case LLVMRustCodeModel::Default: + return CodeModel::Default; + case LLVMRustCodeModel::JITDefault: + return CodeModel::JITDefault; + case LLVMRustCodeModel::Small: + return CodeModel::Small; + case LLVMRustCodeModel::Kernel: + return CodeModel::Kernel; + case LLVMRustCodeModel::Medium: + return CodeModel::Medium; + case LLVMRustCodeModel::Large: + return CodeModel::Large; + default: + llvm_unreachable("Bad CodeModel."); + } +} + +enum class LLVMRustCodeGenOptLevel { + Other, + None, + Less, + Default, + Aggressive, +}; + +static CodeGenOpt::Level +from_rust(LLVMRustCodeGenOptLevel level) +{ + switch (level) { + case LLVMRustCodeGenOptLevel::None: + return CodeGenOpt::None; + case LLVMRustCodeGenOptLevel::Less: + return CodeGenOpt::Less; + case LLVMRustCodeGenOptLevel::Default: + return CodeGenOpt::Default; + case LLVMRustCodeGenOptLevel::Aggressive: + return CodeGenOpt::Aggressive; + default: + llvm_unreachable("Bad CodeGenOptLevel."); + } +} + #if LLVM_RUSTLLVM /// getLongestEntryLength - Return the length of the longest entry in the table. /// @@ -218,13 +282,39 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(const char *triple, const char *cpu, const char *feature, - CodeModel::Model CM, - Reloc::Model RM, - CodeGenOpt::Level OptLevel, + LLVMRustCodeModel rust_CM, + LLVMRelocMode Reloc, + LLVMRustCodeGenOptLevel rust_OptLevel, bool UseSoftFloat, bool PositionIndependentExecutable, bool FunctionSections, bool DataSections) { + +#if LLVM_VERSION_MINOR <= 8 + Reloc::Model RM; +#else + Optional RM; +#endif + auto CM = from_rust(rust_CM); + auto OptLevel = from_rust(rust_OptLevel); + + switch (Reloc){ + case LLVMRelocStatic: + RM = Reloc::Static; + break; + case LLVMRelocPIC: + RM = Reloc::PIC_; + break; + case LLVMRelocDynamicNoPic: + RM = Reloc::DynamicNoPIC; + break; + default: +#if LLVM_VERSION_MINOR <= 8 + RM = Reloc::Default; +#endif + break; + } + std::string Error; Triple Trip(Triple::normalize(triple)); const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Trip.getTriple(), @@ -240,7 +330,10 @@ LLVMRustCreateTargetMachine(const char *triple, } TargetOptions Options; +#if LLVM_VERSION_MINOR <= 8 Options.PositionIndependentExecutable = PositionIndependentExecutable; +#endif + Options.FloatABIType = FloatABI::Default; if (UseSoftFloat) { Options.FloatABIType = FloatABI::Soft; @@ -277,14 +370,14 @@ LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM, extern "C" void LLVMRustConfigurePassManagerBuilder(LLVMPassManagerBuilderRef PMB, - CodeGenOpt::Level OptLevel, + LLVMRustCodeGenOptLevel OptLevel, bool MergeFunctions, bool SLPVectorize, bool LoopVectorize) { // Ignore mergefunc for now as enabling it causes crashes. //unwrap(PMB)->MergeFunctions = MergeFunctions; unwrap(PMB)->SLPVectorize = SLPVectorize; - unwrap(PMB)->OptLevel = OptLevel; + unwrap(PMB)->OptLevel = from_rust(OptLevel); unwrap(PMB)->LoopVectorize = LoopVectorize; } @@ -319,12 +412,19 @@ LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB, // similar code in clang's BackendUtil.cpp file. extern "C" void LLVMRustRunFunctionPassManager(LLVMPassManagerRef PM, LLVMModuleRef M) { - FunctionPassManager *P = unwrap(PM); + llvm::legacy::FunctionPassManager *P = unwrap(PM); P->doInitialization(); + + // Upgrade all calls to old intrinsics first. + for (Module::iterator I = unwrap(M)->begin(), + E = unwrap(M)->end(); I != E;) + UpgradeCallsToIntrinsic(&*I++); // must be post-increment, as we remove + for (Module::iterator I = unwrap(M)->begin(), E = unwrap(M)->end(); I != E; ++I) if (!I->isDeclaration()) P->run(*I); + P->doFinalization(); } @@ -340,13 +440,33 @@ LLVMRustSetLLVMOptions(int Argc, char **Argv) { cl::ParseCommandLineOptions(Argc, Argv); } -extern "C" bool +enum class LLVMRustFileType { + Other, + AssemblyFile, + ObjectFile, +}; + +static TargetMachine::CodeGenFileType +from_rust(LLVMRustFileType type) +{ + switch (type) { + case LLVMRustFileType::AssemblyFile: + return TargetMachine::CGFT_AssemblyFile; + case LLVMRustFileType::ObjectFile: + return TargetMachine::CGFT_ObjectFile; + default: + llvm_unreachable("Bad FileType."); + } +} + +extern "C" LLVMRustResult LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, LLVMModuleRef M, const char *path, - TargetMachine::CodeGenFileType FileType) { - PassManager *PM = unwrap(PMR); + LLVMRustFileType rust_FileType) { + llvm::legacy::PassManager *PM = unwrap(PMR); + auto FileType = from_rust(rust_FileType); std::string ErrorInfo; std::error_code EC; @@ -355,7 +475,7 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, ErrorInfo = EC.message(); if (ErrorInfo != "") { LLVMRustSetLastError(ErrorInfo.c_str()); - return false; + return LLVMRustResult::Failure; } unwrap(Target)->addPassesToEmitFile(*PM, OS, FileType, false); @@ -365,14 +485,14 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, // stream (OS), so the only real safe place to delete this is here? Don't we // wish this was written in Rust? delete PM; - return true; + return LLVMRustResult::Success; } extern "C" void LLVMRustPrintModule(LLVMPassManagerRef PMR, LLVMModuleRef M, const char* path) { - PassManager *PM = unwrap(PMR); + llvm::legacy::PassManager *PM = unwrap(PMR); std::string ErrorInfo; std::error_code EC; @@ -410,9 +530,24 @@ LLVMRustAddAlwaysInlinePass(LLVMPassManagerBuilderRef PMB, bool AddLifetimes) { extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **symbols, size_t len) { - PassManager passes; + llvm::legacy::PassManager passes; + +#if LLVM_VERSION_MINOR <= 8 ArrayRef ref(symbols, len); passes.add(llvm::createInternalizePass(ref)); +#else + auto PreserveFunctions = [=](const GlobalValue &GV) { + for (size_t i=0; igetDataLayout()); } + +extern "C" void +LLVMRustSetModulePIELevel(LLVMModuleRef M) { +#if LLVM_VERSION_MINOR >= 9 + unwrap(M)->setPIELevel(PIELevel::Level::Large); +#endif +} diff --git a/src/rustllvm/README b/src/rustllvm/README index c0db3f68a762..e1c6dd07d2b3 100644 --- a/src/rustllvm/README +++ b/src/rustllvm/README @@ -1,2 +1,16 @@ This directory currently contains some LLVM support code. This will generally be sent upstream to LLVM in time; for now it lives here. + +NOTE: the LLVM C++ ABI is subject to between-version breakage and must *never* +be exposed to Rust. To allow for easy auditing of that, all Rust-exposed types +must be typedef-ed as "LLVMXyz", or "LLVMRustXyz" if they were defined here. + +Functions that return a failure status and leave the error in +the LLVM last error should return an LLVMRustResult rather than an +int or anything to avoid confusion. + +When translating enums, add a single `Other` variant as the first +one to allow for new variants to be added. It should abort when used +as an input. + +All other types must not be typedef-ed as such. diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index fadd95c9a724..0da25e7ac57b 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -13,6 +13,7 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/CallSite.h" @@ -27,6 +28,30 @@ using namespace llvm; using namespace llvm::sys; using namespace llvm::object; +// LLVMAtomicOrdering is already an enum - don't create another +// one. +static AtomicOrdering from_rust(LLVMAtomicOrdering Ordering) { + switch (Ordering) { + case LLVMAtomicOrderingNotAtomic: + return AtomicOrdering::NotAtomic; + case LLVMAtomicOrderingUnordered: + return AtomicOrdering::Unordered; + case LLVMAtomicOrderingMonotonic: + return AtomicOrdering::Monotonic; + case LLVMAtomicOrderingAcquire: + return AtomicOrdering::Acquire; + case LLVMAtomicOrderingRelease: + return AtomicOrdering::Release; + case LLVMAtomicOrderingAcquireRelease: + return AtomicOrdering::AcquireRelease; + case LLVMAtomicOrderingSequentiallyConsistent: + return AtomicOrdering::SequentiallyConsistent; + } + + llvm_unreachable("Invalid LLVMAtomicOrdering value!"); +} + + static char *LastError; extern "C" LLVMMemoryBufferRef @@ -57,49 +82,34 @@ LLVMRustSetNormalizedTarget(LLVMModuleRef M, const char *triple) { unwrap(M)->setTargetTriple(Triple::normalize(triple)); } -extern "C" LLVMValueRef LLVMRustConstSmallInt(LLVMTypeRef IntTy, unsigned N, - LLVMBool SignExtend) { - return LLVMConstInt(IntTy, (unsigned long long)N, SignExtend); -} - -extern "C" LLVMValueRef LLVMRustConstInt(LLVMTypeRef IntTy, - unsigned N_hi, - unsigned N_lo, - LLVMBool SignExtend) { - unsigned long long N = N_hi; - N <<= 32; - N |= N_lo; - return LLVMConstInt(IntTy, N, SignExtend); -} - extern "C" void LLVMRustPrintPassTimings() { raw_fd_ostream OS (2, false); // stderr. TimerGroup::printAll(OS); } -extern "C" LLVMValueRef LLVMGetNamedValue(LLVMModuleRef M, - const char* Name) { +extern "C" LLVMValueRef LLVMRustGetNamedValue(LLVMModuleRef M, + const char* Name) { return wrap(unwrap(M)->getNamedValue(Name)); } -extern "C" LLVMValueRef LLVMGetOrInsertFunction(LLVMModuleRef M, - const char* Name, - LLVMTypeRef FunctionTy) { +extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M, + const char* Name, + LLVMTypeRef FunctionTy) { return wrap(unwrap(M)->getOrInsertFunction(Name, unwrap(FunctionTy))); } -extern "C" LLVMValueRef LLVMGetOrInsertGlobal(LLVMModuleRef M, - const char* Name, - LLVMTypeRef Ty) { +extern "C" LLVMValueRef LLVMRustGetOrInsertGlobal(LLVMModuleRef M, + const char* Name, + LLVMTypeRef Ty) { return wrap(unwrap(M)->getOrInsertGlobal(Name, unwrap(Ty))); } -extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) { +extern "C" LLVMTypeRef LLVMRustMetadataTypeInContext(LLVMContextRef C) { return wrap(Type::getMetadataTy(*unwrap(C))); } -extern "C" void LLVMAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uint64_t Val) { +extern "C" void LLVMRustAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uint64_t Val) { CallSite Call = CallSite(unwrap(Instr)); AttrBuilder B; B.addRawValue(Val); @@ -110,7 +120,10 @@ extern "C" void LLVMAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uin } -extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned idx, uint64_t b) { +extern "C" void LLVMRustAddDereferenceableCallSiteAttr(LLVMValueRef Instr, + unsigned idx, + uint64_t b) +{ CallSite Call = CallSite(unwrap(Instr)); AttrBuilder B; B.addDereferenceableAttr(b); @@ -120,38 +133,50 @@ extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned idx, B))); } -extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, - uint64_t Val) { +extern "C" void LLVMRustAddFunctionAttribute(LLVMValueRef Fn, + unsigned index, + uint64_t Val) +{ Function *A = unwrap(Fn); AttrBuilder B; B.addRawValue(Val); A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); } -extern "C" void LLVMAddDereferenceableAttr(LLVMValueRef Fn, unsigned index, uint64_t bytes) { +extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, + unsigned index, + uint64_t bytes) +{ Function *A = unwrap(Fn); AttrBuilder B; B.addDereferenceableAttr(bytes); A->addAttributes(index, AttributeSet::get(A->getContext(), index, B)); } -extern "C" void LLVMAddFunctionAttrString(LLVMValueRef Fn, unsigned index, const char *Name) { +extern "C" void LLVMRustAddFunctionAttrString(LLVMValueRef Fn, + unsigned index, + const char *Name) +{ Function *F = unwrap(Fn); AttrBuilder B; B.addAttribute(Name); F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); } -extern "C" void LLVMAddFunctionAttrStringValue(LLVMValueRef Fn, unsigned index, - const char *Name, - const char *Value) { +extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn, + unsigned index, + const char *Name, + const char *Value) { Function *F = unwrap(Fn); AttrBuilder B; B.addAttribute(Name, Value); F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); } -extern "C" void LLVMRemoveFunctionAttributes(LLVMValueRef Fn, unsigned index, uint64_t Val) { +extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn, + unsigned index, + uint64_t Val) +{ Function *A = unwrap(Fn); const AttributeSet PAL = A->getAttributes(); AttrBuilder B(Val); @@ -161,7 +186,10 @@ extern "C" void LLVMRemoveFunctionAttributes(LLVMValueRef Fn, unsigned index, ui A->setAttributes(PALnew); } -extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, unsigned index, const char *Name) { +extern "C" void LLVMRustRemoveFunctionAttrString(LLVMValueRef fn, + unsigned index, + const char *Name) +{ Function *f = unwrap(fn); LLVMContext &C = f->getContext(); AttrBuilder B; @@ -181,80 +209,122 @@ extern "C" void LLVMRustSetHasUnsafeAlgebra(LLVMValueRef V) { } } -extern "C" LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B, - LLVMValueRef source, - const char* Name, - AtomicOrdering order, - unsigned alignment) { +extern "C" LLVMValueRef LLVMRustBuildAtomicLoad(LLVMBuilderRef B, + LLVMValueRef source, + const char* Name, + LLVMAtomicOrdering order, + unsigned alignment) { LoadInst* li = new LoadInst(unwrap(source),0); - li->setAtomic(order); + li->setAtomic(from_rust(order)); li->setAlignment(alignment); return wrap(unwrap(B)->Insert(li, Name)); } -extern "C" LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef B, - LLVMValueRef val, - LLVMValueRef target, - AtomicOrdering order, - unsigned alignment) { +extern "C" LLVMValueRef LLVMRustBuildAtomicStore(LLVMBuilderRef B, + LLVMValueRef val, + LLVMValueRef target, + LLVMAtomicOrdering order, + unsigned alignment) { StoreInst* si = new StoreInst(unwrap(val),unwrap(target)); - si->setAtomic(order); + si->setAtomic(from_rust(order)); si->setAlignment(alignment); return wrap(unwrap(B)->Insert(si)); } -extern "C" LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, +extern "C" LLVMValueRef LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef target, LLVMValueRef old, LLVMValueRef source, - AtomicOrdering order, - AtomicOrdering failure_order, + LLVMAtomicOrdering order, + LLVMAtomicOrdering failure_order, LLVMBool weak) { - AtomicCmpXchgInst* acxi = unwrap(B)->CreateAtomicCmpXchg(unwrap(target), - unwrap(old), - unwrap(source), - order, - failure_order); + AtomicCmpXchgInst* acxi = unwrap(B)->CreateAtomicCmpXchg( + unwrap(target), + unwrap(old), + unwrap(source), + from_rust(order), + from_rust(failure_order)); acxi->setWeak(weak); return wrap(acxi); } -extern "C" LLVMValueRef LLVMBuildAtomicFence(LLVMBuilderRef B, - AtomicOrdering order, - SynchronizationScope scope) { - return wrap(unwrap(B)->CreateFence(order, scope)); + +enum class LLVMRustSynchronizationScope { + Other, + SingleThread, + CrossThread, +}; + +static SynchronizationScope +from_rust(LLVMRustSynchronizationScope scope) +{ + switch (scope) { + case LLVMRustSynchronizationScope::SingleThread: + return SingleThread; + case LLVMRustSynchronizationScope::CrossThread: + return CrossThread; + default: + llvm_unreachable("bad SynchronizationScope."); + } } -extern "C" void LLVMSetDebug(int Enabled) { +extern "C" LLVMValueRef LLVMRustBuildAtomicFence( + LLVMBuilderRef B, + LLVMAtomicOrdering order, + LLVMRustSynchronizationScope scope) +{ + return wrap(unwrap(B)->CreateFence(from_rust(order), from_rust(scope))); +} + +extern "C" void LLVMRustSetDebug(int Enabled) { #ifndef NDEBUG DebugFlag = Enabled; #endif } -extern "C" LLVMValueRef LLVMInlineAsm(LLVMTypeRef Ty, - char *AsmString, - char *Constraints, - LLVMBool HasSideEffects, - LLVMBool IsAlignStack, - unsigned Dialect) { - return wrap(InlineAsm::get(unwrap(Ty), AsmString, - Constraints, HasSideEffects, - IsAlignStack, (InlineAsm::AsmDialect) Dialect)); +enum class LLVMRustAsmDialect { + Other, + Att, + Intel, +}; + +static InlineAsm::AsmDialect +from_rust(LLVMRustAsmDialect dialect) +{ + switch (dialect) { + case LLVMRustAsmDialect::Att: + return InlineAsm::AD_ATT; + case LLVMRustAsmDialect::Intel: + return InlineAsm::AD_Intel; + default: + llvm_unreachable("bad AsmDialect."); + } } -typedef DIBuilder* DIBuilderRef; +extern "C" LLVMValueRef LLVMRustInlineAsm(LLVMTypeRef Ty, + char *AsmString, + char *Constraints, + LLVMBool HasSideEffects, + LLVMBool IsAlignStack, + LLVMRustAsmDialect Dialect) { + return wrap(InlineAsm::get(unwrap(Ty), AsmString, + Constraints, HasSideEffects, + IsAlignStack, from_rust(Dialect))); +} -typedef struct LLVMOpaqueMetadata *LLVMMetadataRef; +typedef DIBuilder* LLVMRustDIBuilderRef; + +typedef struct LLVMOpaqueMetadata *LLVMRustMetadataRef; namespace llvm { -DEFINE_ISA_CONVERSION_FUNCTIONS(Metadata, LLVMMetadataRef) +DEFINE_ISA_CONVERSION_FUNCTIONS(Metadata, LLVMRustMetadataRef) -inline Metadata **unwrap(LLVMMetadataRef *Vals) { +inline Metadata **unwrap(LLVMRustMetadataRef *Vals) { return reinterpret_cast(Vals); } } template -DIT* unwrapDIptr(LLVMMetadataRef ref) { +DIT* unwrapDIptr(LLVMRustMetadataRef ref) { return (DIT*) (ref ? unwrap(ref) : NULL); } @@ -266,11 +336,11 @@ extern "C" uint32_t LLVMRustDebugMetadataVersion() { return DEBUG_METADATA_VERSION; } -extern "C" uint32_t LLVMVersionMinor() { +extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; } -extern "C" uint32_t LLVMVersionMajor() { +extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; } @@ -280,20 +350,20 @@ extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, unwrap(M)->addModuleFlag(Module::Warning, name, value); } -extern "C" DIBuilderRef LLVMDIBuilderCreate(LLVMModuleRef M) { +extern "C" LLVMRustDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) { return new DIBuilder(*unwrap(M)); } -extern "C" void LLVMDIBuilderDispose(DIBuilderRef Builder) { +extern "C" void LLVMRustDIBuilderDispose(LLVMRustDIBuilderRef Builder) { delete Builder; } -extern "C" void LLVMDIBuilderFinalize(DIBuilderRef Builder) { +extern "C" void LLVMRustDIBuilderFinalize(LLVMRustDIBuilderRef Builder) { Builder->finalize(); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateCompileUnit( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateCompileUnit( + LLVMRustDIBuilderRef Builder, unsigned Lang, const char* File, const char* Dir, @@ -312,17 +382,17 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateCompileUnit( SplitName)); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateFile( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateFile( + LLVMRustDIBuilderRef Builder, const char* Filename, const char* Directory) { return wrap(Builder->createFile(Filename, Directory)); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateSubroutineType( - DIBuilderRef Builder, - LLVMMetadataRef File, - LLVMMetadataRef ParameterTypes) { +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateSubroutineType( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef File, + LLVMRustMetadataRef ParameterTypes) { return wrap(Builder->createSubroutineType( #if LLVM_VERSION_MINOR == 7 unwrapDI(File), @@ -330,22 +400,22 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateSubroutineType( DITypeRefArray(unwrap(ParameterTypes)))); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateFunction( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateFunction( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, const char* LinkageName, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, + LLVMRustMetadataRef Ty, bool isLocalToUnit, bool isDefinition, unsigned ScopeLine, unsigned Flags, bool isOptimized, LLVMValueRef Fn, - LLVMMetadataRef TParam, - LLVMMetadataRef Decl) { + LLVMRustMetadataRef TParam, + LLVMRustMetadataRef Decl) { #if LLVM_VERSION_MINOR >= 8 DITemplateParameterArray TParams = DITemplateParameterArray(unwrap(TParam)); @@ -370,8 +440,8 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateFunction( #endif } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateBasicType( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateBasicType( + LLVMRustDIBuilderRef Builder, const char* Name, uint64_t SizeInBits, uint64_t AlignInBits, @@ -381,9 +451,9 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateBasicType( AlignInBits, Encoding)); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreatePointerType( - DIBuilderRef Builder, - LLVMMetadataRef PointeeTy, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreatePointerType( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef PointeeTy, uint64_t SizeInBits, uint64_t AlignInBits, const char* Name) { @@ -391,19 +461,19 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreatePointerType( unwrapDI(PointeeTy), SizeInBits, AlignInBits, Name)); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateStructType( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStructType( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, unsigned Flags, - LLVMMetadataRef DerivedFrom, - LLVMMetadataRef Elements, + LLVMRustMetadataRef DerivedFrom, + LLVMRustMetadataRef Elements, unsigned RunTimeLang, - LLVMMetadataRef VTableHolder, + LLVMRustMetadataRef VTableHolder, const char *UniqueId) { return wrap(Builder->createStructType( unwrapDI(Scope), @@ -421,17 +491,17 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateStructType( )); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateMemberType( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateMemberType( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNo, uint64_t SizeInBits, uint64_t AlignInBits, uint64_t OffsetInBits, unsigned Flags, - LLVMMetadataRef Ty) { + LLVMRustMetadataRef Ty) { return wrap(Builder->createMemberType( unwrapDI(Scope), Name, unwrapDI(File), LineNo, @@ -439,10 +509,10 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateMemberType( unwrapDI(Ty))); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateLexicalBlock( - DIBuilderRef Builder, - LLVMMetadataRef Scope, - LLVMMetadataRef File, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateLexicalBlock( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, + LLVMRustMetadataRef File, unsigned Line, unsigned Col) { return wrap(Builder->createLexicalBlock( @@ -451,17 +521,17 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateLexicalBlock( )); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateStaticVariable( - DIBuilderRef Builder, - LLVMMetadataRef Context, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Context, const char* Name, const char* LinkageName, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, + LLVMRustMetadataRef Ty, bool isLocalToUnit, LLVMValueRef Val, - LLVMMetadataRef Decl = NULL) { + LLVMRustMetadataRef Decl = NULL) { return wrap(Builder->createGlobalVariable(unwrapDI(Context), Name, LinkageName, @@ -473,14 +543,14 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateStaticVariable( unwrapDIptr(Decl))); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateVariable( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable( + LLVMRustDIBuilderRef Builder, unsigned Tag, - LLVMMetadataRef Scope, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, + LLVMRustMetadataRef Ty, bool AlwaysPreserve, unsigned Flags, int64_t* AddrOps, @@ -509,50 +579,50 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateVariable( #endif } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateArrayType( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateArrayType( + LLVMRustDIBuilderRef Builder, uint64_t Size, uint64_t AlignInBits, - LLVMMetadataRef Ty, - LLVMMetadataRef Subscripts) { + LLVMRustMetadataRef Ty, + LLVMRustMetadataRef Subscripts) { return wrap(Builder->createArrayType(Size, AlignInBits, unwrapDI(Ty), DINodeArray(unwrapDI(Subscripts)) )); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateVectorType( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVectorType( + LLVMRustDIBuilderRef Builder, uint64_t Size, uint64_t AlignInBits, - LLVMMetadataRef Ty, - LLVMMetadataRef Subscripts) { + LLVMRustMetadataRef Ty, + LLVMRustMetadataRef Subscripts) { return wrap(Builder->createVectorType(Size, AlignInBits, unwrapDI(Ty), DINodeArray(unwrapDI(Subscripts)) )); } -extern "C" LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderGetOrCreateSubrange( + LLVMRustDIBuilderRef Builder, int64_t Lo, int64_t Count) { return wrap(Builder->getOrCreateSubrange(Lo, Count)); } -extern "C" LLVMMetadataRef LLVMDIBuilderGetOrCreateArray( - DIBuilderRef Builder, - LLVMMetadataRef* Ptr, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderGetOrCreateArray( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef* Ptr, unsigned Count) { Metadata **DataValue = unwrap(Ptr); return wrap(Builder->getOrCreateArray( ArrayRef(DataValue, Count)).get()); } -extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( - DIBuilderRef Builder, +extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( + LLVMRustDIBuilderRef Builder, LLVMValueRef Val, - LLVMMetadataRef VarInfo, + LLVMRustMetadataRef VarInfo, int64_t* AddrOps, unsigned AddrOpsCount, LLVMValueRef DL, @@ -566,10 +636,10 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( unwrap(InsertAtEnd))); } -extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore( - DIBuilderRef Builder, +extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareBefore( + LLVMRustDIBuilderRef Builder, LLVMValueRef Val, - LLVMMetadataRef VarInfo, + LLVMRustMetadataRef VarInfo, int64_t* AddrOps, unsigned AddrOpsCount, LLVMValueRef DL, @@ -583,24 +653,24 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore( unwrap(InsertBefore))); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateEnumerator( - DIBuilderRef Builder, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateEnumerator( + LLVMRustDIBuilderRef Builder, const char* Name, uint64_t Val) { return wrap(Builder->createEnumerator(Name, Val)); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateEnumerationType( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateEnumerationType( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, - LLVMMetadataRef Elements, - LLVMMetadataRef ClassType) + LLVMRustMetadataRef Elements, + LLVMRustMetadataRef ClassType) { return wrap(Builder->createEnumerationType( unwrapDI(Scope), @@ -613,16 +683,16 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateEnumerationType( unwrapDI(ClassType))); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateUnionType( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateUnionType( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint64_t AlignInBits, unsigned Flags, - LLVMMetadataRef Elements, + LLVMRustMetadataRef Elements, unsigned RunTimeLang, const char* UniqueId) { @@ -640,12 +710,12 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateUnionType( )); } -extern "C" LLVMMetadataRef LLVMDIBuilderCreateTemplateTypeParameter( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef Ty, - LLVMMetadataRef File, + LLVMRustMetadataRef Ty, + LLVMRustMetadataRef File, unsigned LineNo, unsigned ColumnNo) { @@ -656,21 +726,11 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateTemplateTypeParameter( )); } -extern "C" int64_t LLVMDIBuilderCreateOpDeref() -{ - return dwarf::DW_OP_deref; -} - -extern "C" int64_t LLVMDIBuilderCreateOpPlus() -{ - return dwarf::DW_OP_plus; -} - -extern "C" LLVMMetadataRef LLVMDIBuilderCreateNameSpace( - DIBuilderRef Builder, - LLVMMetadataRef Scope, +extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateNameSpace( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef Scope, const char* Name, - LLVMMetadataRef File, + LLVMRustMetadataRef File, unsigned LineNo) { return wrap(Builder->createNameSpace( @@ -680,22 +740,22 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateNameSpace( LineNo)); } -extern "C" void LLVMDICompositeTypeSetTypeArray( - DIBuilderRef Builder, - LLVMMetadataRef CompositeType, - LLVMMetadataRef TypeArray) +extern "C" void LLVMRustDICompositeTypeSetTypeArray( + LLVMRustDIBuilderRef Builder, + LLVMRustMetadataRef CompositeType, + LLVMRustMetadataRef TypeArray) { DICompositeType *tmp = unwrapDI(CompositeType); Builder->replaceArrays(tmp, DINodeArray(unwrap(TypeArray))); } -extern "C" LLVMValueRef LLVMDIBuilderCreateDebugLocation( +extern "C" LLVMValueRef LLVMRustDIBuilderCreateDebugLocation( LLVMContextRef Context, unsigned Line, unsigned Column, - LLVMMetadataRef Scope, - LLVMMetadataRef InlinedAt) { - + LLVMRustMetadataRef Scope, + LLVMRustMetadataRef InlinedAt) +{ LLVMContext& context = *unwrap(Context); DebugLoc debug_loc = DebugLoc::get(Line, @@ -706,12 +766,22 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateDebugLocation( return wrap(MetadataAsValue::get(context, debug_loc.getAsMDNode())); } -extern "C" void LLVMWriteTypeToString(LLVMTypeRef Type, RustStringRef str) { +extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() +{ + return dwarf::DW_OP_deref; +} + +extern "C" int64_t LLVMRustDIBuilderCreateOpPlus() +{ + return dwarf::DW_OP_plus; +} + +extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Type, RustStringRef str) { raw_rust_string_ostream os(str); unwrap(Type)->print(os); } -extern "C" void LLVMWriteValueToString(LLVMValueRef Value, RustStringRef str) { +extern "C" void LLVMRustWriteValueToString(LLVMValueRef Value, RustStringRef str) { raw_rust_string_ostream os(str); os << "("; unwrap(Value)->getType()->print(os); @@ -746,13 +816,6 @@ LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { return true; } -extern "C" void -LLVMRustSetDLLStorageClass(LLVMValueRef Value, - GlobalValue::DLLStorageClassTypes Class) { - GlobalValue *V = unwrap(Value); - V->setDLLStorageClass(Class); -} - // Note that the two following functions look quite similar to the // LLVMGetSectionName function. Sadly, it appears that this function only // returns a char* pointer, which isn't guaranteed to be null-terminated. The @@ -768,7 +831,7 @@ inline section_iterator *unwrap(LLVMSectionIteratorRef SI) { return reinterpret_cast(SI); } -extern "C" int +extern "C" size_t LLVMRustGetSectionName(LLVMSectionIteratorRef SI, const char **ptr) { StringRef ret; if (std::error_code ec = (*unwrap(SI))->getName(ret)) @@ -787,13 +850,13 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Twine, LLVMTwineRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DebugLoc, LLVMDebugLocRef) extern "C" void -LLVMWriteTwineToString(LLVMTwineRef T, RustStringRef str) { +LLVMRustWriteTwineToString(LLVMTwineRef T, RustStringRef str) { raw_rust_string_ostream os(str); unwrap(T)->print(os); } extern "C" void -LLVMUnpackOptimizationDiagnostic( +LLVMRustUnpackOptimizationDiagnostic( LLVMDiagnosticInfoRef di, const char **pass_name_out, LLVMValueRef *function_out, @@ -811,7 +874,7 @@ LLVMUnpackOptimizationDiagnostic( } extern "C" void -LLVMUnpackInlineAsmDiagnostic( +LLVMRustUnpackInlineAsmDiagnostic( LLVMDiagnosticInfoRef di, unsigned *cookie_out, LLVMTwineRef *message_out, @@ -826,17 +889,111 @@ LLVMUnpackInlineAsmDiagnostic( *instruction_out = wrap(ia->getInstruction()); } -extern "C" void LLVMWriteDiagnosticInfoToString(LLVMDiagnosticInfoRef di, RustStringRef str) { +extern "C" void LLVMRustWriteDiagnosticInfoToString(LLVMDiagnosticInfoRef di, RustStringRef str) { raw_rust_string_ostream os(str); DiagnosticPrinterRawOStream dp(os); unwrap(di)->print(dp); } -extern "C" int LLVMGetDiagInfoKind(LLVMDiagnosticInfoRef di) { - return unwrap(di)->getKind(); +enum class LLVMRustDiagnosticKind { + Other, + InlineAsm, + StackSize, + DebugMetadataVersion, + SampleProfile, + OptimizationRemark, + OptimizationRemarkMissed, + OptimizationRemarkAnalysis, + OptimizationRemarkAnalysisFPCommute, + OptimizationRemarkAnalysisAliasing, + OptimizationRemarkOther, + OptimizationFailure, +}; + +static LLVMRustDiagnosticKind +to_rust(DiagnosticKind kind) +{ + switch (kind) { + case DK_InlineAsm: + return LLVMRustDiagnosticKind::InlineAsm; + case DK_StackSize: + return LLVMRustDiagnosticKind::StackSize; + case DK_DebugMetadataVersion: + return LLVMRustDiagnosticKind::DebugMetadataVersion; + case DK_SampleProfile: + return LLVMRustDiagnosticKind::SampleProfile; + case DK_OptimizationRemark: + return LLVMRustDiagnosticKind::OptimizationRemark; + case DK_OptimizationRemarkMissed: + return LLVMRustDiagnosticKind::OptimizationRemarkMissed; + case DK_OptimizationRemarkAnalysis: + return LLVMRustDiagnosticKind::OptimizationRemarkAnalysis; +#if LLVM_VERSION_MINOR >= 8 + case DK_OptimizationRemarkAnalysisFPCommute: + return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisFPCommute; + case DK_OptimizationRemarkAnalysisAliasing: + return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisAliasing; +#endif + default: +#if LLVM_VERSION_MINOR >= 9 + return (kind >= DK_FirstRemark && kind <= DK_LastRemark) ? + LLVMRustDiagnosticKind::OptimizationRemarkOther : + LLVMRustDiagnosticKind::Other; +#else + return LLVMRustDiagnosticKind::Other; +#endif + } } -extern "C" void LLVMWriteDebugLocToString( +extern "C" LLVMRustDiagnosticKind LLVMRustGetDiagInfoKind(LLVMDiagnosticInfoRef di) { + return to_rust((DiagnosticKind) unwrap(di)->getKind()); +} +// This is kept distinct from LLVMGetTypeKind, because when +// a new type kind is added, the Rust-side enum must be +// updated or UB will result. +extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { + switch (unwrap(Ty)->getTypeID()) { + case Type::VoidTyID: + return LLVMVoidTypeKind; + case Type::HalfTyID: + return LLVMHalfTypeKind; + case Type::FloatTyID: + return LLVMFloatTypeKind; + case Type::DoubleTyID: + return LLVMDoubleTypeKind; + case Type::X86_FP80TyID: + return LLVMX86_FP80TypeKind; + case Type::FP128TyID: + return LLVMFP128TypeKind; + case Type::PPC_FP128TyID: + return LLVMPPC_FP128TypeKind; + case Type::LabelTyID: + return LLVMLabelTypeKind; + case Type::MetadataTyID: + return LLVMMetadataTypeKind; + case Type::IntegerTyID: + return LLVMIntegerTypeKind; + case Type::FunctionTyID: + return LLVMFunctionTypeKind; + case Type::StructTyID: + return LLVMStructTypeKind; + case Type::ArrayTyID: + return LLVMArrayTypeKind; + case Type::PointerTyID: + return LLVMPointerTypeKind; + case Type::VectorTyID: + return LLVMVectorTypeKind; + case Type::X86_MMXTyID: + return LLVMX86_MMXTypeKind; +#if LLVM_VERSION_MINOR >= 8 + case Type::TokenTyID: + return LLVMTokenTypeKind; +#endif + } + llvm_unreachable("Unhandled TypeID."); +} + +extern "C" void LLVMRustWriteDebugLocToString( LLVMContextRef C, LLVMDebugLocRef dl, RustStringRef str) @@ -847,7 +1004,7 @@ extern "C" void LLVMWriteDebugLocToString( DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) -extern "C" void LLVMSetInlineAsmDiagnosticHandler( +extern "C" void LLVMRustSetInlineAsmDiagnosticHandler( LLVMContextRef C, LLVMContext::InlineAsmDiagHandlerTy H, void *CX) @@ -855,7 +1012,8 @@ extern "C" void LLVMSetInlineAsmDiagnosticHandler( unwrap(C)->setInlineAsmDiagnosticHandler(H, CX); } -extern "C" void LLVMWriteSMDiagnosticToString(LLVMSMDiagnosticRef d, RustStringRef str) { +extern "C" void LLVMRustWriteSMDiagnosticToString(LLVMSMDiagnosticRef d, + RustStringRef str) { raw_rust_string_ostream os(str); unwrap(d)->print("", os); } diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 1953fc5a6b48..e871763a48dc 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2016-06-23 +2016-07-25b diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index 2a47e8b08954..5aae11fb456b 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -58,6 +58,11 @@ void LLVMRustSetLastError(const char*); +enum class LLVMRustResult { + Success, + Failure +}; + typedef struct OpaqueRustString *RustStringRef; typedef struct LLVMOpaqueTwine *LLVMTwineRef; typedef struct LLVMOpaqueDebugLoc *LLVMDebugLocRef; diff --git a/src/test/codegen/internalize-closures.rs b/src/test/codegen/internalize-closures.rs new file mode 100644 index 000000000000..90aafd6a3bb3 --- /dev/null +++ b/src/test/codegen/internalize-closures.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes + +pub fn main() { + + // We want to make sure that closures get 'internal' linkage instead of + // 'weak_odr' when they are not shared between codegen units + // CHECK: define internal {{.*}}_ZN20internalize_closures4main{{.*}}$u7b$$u7b$closure$u7d$$u7d$ + let c = |x:i32| { x + 1 }; + let _ = c(1); +} diff --git a/src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs b/src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs index 83c845bfdf96..61a8ee88a708 100644 --- a/src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs +++ b/src/test/compile-fail-fulldeps/lint-plugin-forbid-attrs.rs @@ -14,6 +14,8 @@ #![feature(plugin)] #![plugin(lint_plugin_test)] #![forbid(test_lint)] +//~^ NOTE lint level defined here +//~| NOTE `forbid` lint level set here fn lintme() { } //~ ERROR item is named 'lintme' diff --git a/src/test/compile-fail/E0045.rs b/src/test/compile-fail/E0045.rs index edec911d3c07..2a731596b4be 100644 --- a/src/test/compile-fail/E0045.rs +++ b/src/test/compile-fail/E0045.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern "rust-call" { fn foo(x: u8, ...); } //~ ERROR E0045 +extern "Rust" { fn foo(x: u8, ...); } //~ ERROR E0045 fn main() { } diff --git a/src/test/compile-fail/E0055.rs b/src/test/compile-fail/E0055.rs index f86d7ec114b9..2b2d278ad4cc 100644 --- a/src/test/compile-fail/E0055.rs +++ b/src/test/compile-fail/E0055.rs @@ -18,5 +18,7 @@ impl Foo { fn main() { let foo = Foo; let ref_foo = &&Foo; - ref_foo.foo(); //~ ERROR E0055 + ref_foo.foo(); + //~^ ERROR E0055 + //~| NOTE deref recursion limit reached } diff --git a/src/test/compile-fail/E0060.rs b/src/test/compile-fail/E0060.rs index b4a289874979..e1f2618c180f 100644 --- a/src/test/compile-fail/E0060.rs +++ b/src/test/compile-fail/E0060.rs @@ -13,5 +13,8 @@ extern "C" { } fn main() { - unsafe { printf(); } //~ ERROR E0060 + unsafe { printf(); } + //~^ ERROR E0060 + //~| NOTE expected at least 1 parameter + //~| NOTE the following parameter type was expected } diff --git a/src/test/compile-fail/E0061.rs b/src/test/compile-fail/E0061.rs index 4a8eac2a9e22..ca04b059dc7f 100644 --- a/src/test/compile-fail/E0061.rs +++ b/src/test/compile-fail/E0061.rs @@ -11,5 +11,8 @@ fn f(a: u16, b: &str) {} fn main() { - f(0); //~ ERROR E0061 + f(0); + //~^ ERROR E0061 + //~| NOTE expected 2 parameters + //~| NOTE the following parameter types were expected } diff --git a/src/test/compile-fail/E0062.rs b/src/test/compile-fail/E0062.rs index 86ec7db14b5c..822d93e52d58 100644 --- a/src/test/compile-fail/E0062.rs +++ b/src/test/compile-fail/E0062.rs @@ -14,7 +14,9 @@ struct Foo { fn main() { let x = Foo { + x: 0, //~ NOTE first use of `x` x: 0, - x: 0, //~ ERROR E0062 + //~^ ERROR E0062 + //~| NOTE used more than once }; } diff --git a/src/test/compile-fail/E0071.rs b/src/test/compile-fail/E0071.rs index 658c8fb15511..6f0e55efffc9 100644 --- a/src/test/compile-fail/E0071.rs +++ b/src/test/compile-fail/E0071.rs @@ -11,6 +11,11 @@ enum Foo { FirstValue(i32) } fn main() { - let u = Foo::FirstValue { value: 0 }; //~ ERROR E0071 - let t = u32 { value: 4 }; //~ ERROR E0071 + let u = Foo::FirstValue { value: 0 }; + //~^ ERROR `Foo::FirstValue` does not name a struct or a struct variant [E0071] + //~| NOTE not a struct + + let t = u32 { value: 4 }; + //~^ ERROR `u32` does not name a struct or a struct variant [E0071] + //~| NOTE not a struct } diff --git a/src/test/compile-fail/E0079.rs b/src/test/compile-fail/E0079.rs index 23957c72ff00..c9b7f549d5aa 100644 --- a/src/test/compile-fail/E0079.rs +++ b/src/test/compile-fail/E0079.rs @@ -10,6 +10,7 @@ enum Foo { Q = "32" //~ ERROR E0079 + //~^ expected 'isize' type } fn main() { diff --git a/src/test/compile-fail/E0109.rs b/src/test/compile-fail/E0109.rs index 9fc478422504..2e4cbf869269 100644 --- a/src/test/compile-fail/E0109.rs +++ b/src/test/compile-fail/E0109.rs @@ -9,6 +9,7 @@ // except according to those terms. type X = u32; //~ ERROR E0109 + //~| NOTE type parameter not allowed fn main() { } diff --git a/src/test/compile-fail/E0110.rs b/src/test/compile-fail/E0110.rs index fd169f4acc5e..5a9e7a43de96 100644 --- a/src/test/compile-fail/E0110.rs +++ b/src/test/compile-fail/E0110.rs @@ -9,6 +9,7 @@ // except according to those terms. type X = u32<'static>; //~ ERROR E0110 + //~| NOTE lifetime parameter not allowed on this type fn main() { } diff --git a/src/test/compile-fail/E0119.rs b/src/test/compile-fail/E0119.rs index 9528631b3047..56820bcd1840 100644 --- a/src/test/compile-fail/E0119.rs +++ b/src/test/compile-fail/E0119.rs @@ -12,7 +12,7 @@ trait MyTrait { fn get(&self) -> usize; } -impl MyTrait for T { +impl MyTrait for T { //~ NOTE first implementation here fn get(&self) -> usize { 0 } } @@ -21,6 +21,7 @@ struct Foo { } impl MyTrait for Foo { //~ ERROR E0119 + //~| NOTE conflicting implementation for `Foo` fn get(&self) -> usize { self.value } } diff --git a/src/test/compile-fail/E0120.rs b/src/test/compile-fail/E0120.rs index de084274f6fb..3fdeb7531754 100644 --- a/src/test/compile-fail/E0120.rs +++ b/src/test/compile-fail/E0120.rs @@ -10,7 +10,9 @@ trait MyTrait {} -impl Drop for MyTrait { //~ ERROR E0120 +impl Drop for MyTrait { + //~^ ERROR E0120 + //~| NOTE implementing Drop requires a struct fn drop(&mut self) {} } diff --git a/src/test/compile-fail/E0124.rs b/src/test/compile-fail/E0124.rs index 414b19ead624..18c507461065 100644 --- a/src/test/compile-fail/E0124.rs +++ b/src/test/compile-fail/E0124.rs @@ -9,8 +9,10 @@ // except according to those terms. struct Foo { + field1: i32, //~ NOTE `field1` first declared here field1: i32, - field1: i32, //~ ERROR E0124 + //~^ ERROR field `field1` is already declared [E0124] + //~| NOTE field already declared } fn main() { diff --git a/src/test/compile-fail/E0132.rs b/src/test/compile-fail/E0132.rs index ff19a577f903..1a33fb24ca1a 100644 --- a/src/test/compile-fail/E0132.rs +++ b/src/test/compile-fail/E0132.rs @@ -12,6 +12,7 @@ #[start] fn f() {} //~ ERROR E0132 + //~| NOTE start function cannot have type parameters fn main() { } diff --git a/src/test/compile-fail/E0137.rs b/src/test/compile-fail/E0137.rs index 695ce7995a9a..f45afc9f37bd 100644 --- a/src/test/compile-fail/E0137.rs +++ b/src/test/compile-fail/E0137.rs @@ -11,7 +11,9 @@ #![feature(main)] #[main] -fn foo() {} +fn foo() {} //~ NOTE first #[main] function #[main] -fn f() {} //~ ERROR E0137 +fn f() {} +//~^ ERROR E0137 +//~| NOTE additional #[main] function diff --git a/src/test/compile-fail/E0172.rs b/src/test/compile-fail/E0172.rs index 7011bf0e9373..485a31d96663 100644 --- a/src/test/compile-fail/E0172.rs +++ b/src/test/compile-fail/E0172.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo(bar: i32+std::fmt::Display) {} //~ ERROR E0172 +fn foo(bar: i32+std::fmt::Display) {} + //~^ ERROR E0172 + //~| NOTE expected a trait fn main() { } diff --git a/src/test/compile-fail/E0178.rs b/src/test/compile-fail/E0178.rs index f34f3834e05b..6527465e0b7f 100644 --- a/src/test/compile-fail/E0178.rs +++ b/src/test/compile-fail/E0178.rs @@ -11,10 +11,18 @@ trait Foo {} struct Bar<'a> { - w: &'a Foo + Copy, //~ ERROR E0178 - x: &'a Foo + 'a, //~ ERROR E0178 - y: &'a mut Foo + 'a, //~ ERROR E0178 - z: fn() -> Foo + 'a, //~ ERROR E0178 + w: &'a Foo + Copy, + //~^ ERROR E0178 + //~| NOTE expected a path + x: &'a Foo + 'a, + //~^ ERROR E0178 + //~| NOTE expected a path + y: &'a mut Foo + 'a, + //~^ ERROR E0178 + //~| NOTE expected a path + z: fn() -> Foo + 'a, + //~^ ERROR E0178 + //~| NOTE expected a path } fn main() { diff --git a/src/test/compile-fail/E0201.rs b/src/test/compile-fail/E0201.rs new file mode 100644 index 000000000000..ff6cb55f388c --- /dev/null +++ b/src/test/compile-fail/E0201.rs @@ -0,0 +1,32 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo(u8); + +impl Foo { + fn bar(&self) -> bool { self.0 > 5 } + fn bar() {} //~ ERROR E0201 +} + +trait Baz { + type Quux; + fn baz(&self) -> bool; +} + +impl Baz for Foo { + type Quux = u32; + + fn baz(&self) -> bool { true } + fn baz(&self) -> bool { self.0 > 5 } //~ ERROR E0201 + type Quux = u32; //~ ERROR E0201 +} + +fn main() { +} diff --git a/src/test/compile-fail/feature-gate-abi-vectorcall.rs b/src/test/compile-fail/E0204.rs similarity index 72% rename from src/test/compile-fail/feature-gate-abi-vectorcall.rs rename to src/test/compile-fail/E0204.rs index 79f3c8dc7762..2fa2afa12eb4 100644 --- a/src/test/compile-fail/feature-gate-abi-vectorcall.rs +++ b/src/test/compile-fail/E0204.rs @@ -8,11 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern "vectorcall" { //~ ERROR vectorcall is experimental and subject to change - fn bar(); +struct Foo { + foo: Vec, } -extern "vectorcall" fn baz() { //~ ERROR vectorcall is experimental and subject to change +impl Copy for Foo { } //~ ERROR E0204 + +#[derive(Copy)] //~ ERROR E0204 +struct Foo2<'a> { + ty: &'a mut bool, } fn main() { diff --git a/src/test/compile-fail/E0205.rs b/src/test/compile-fail/E0205.rs new file mode 100644 index 000000000000..e4781bba08aa --- /dev/null +++ b/src/test/compile-fail/E0205.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Foo { + Bar(Vec), + Baz, +} + +impl Copy for Foo { } //~ ERROR E0205 + +#[derive(Copy)] //~ ERROR E0205 +enum Foo2<'a> { + Bar(&'a mut bool), + Baz, +} + +fn main() { +} diff --git a/src/test/compile-fail/E0206.rs b/src/test/compile-fail/E0206.rs new file mode 100644 index 000000000000..31b01da3d75b --- /dev/null +++ b/src/test/compile-fail/E0206.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +type Foo = i32; + +impl Copy for Foo { } //~ ERROR E0206 + //~^ ERROR E0117 + +#[derive(Copy, Clone)] +struct Bar; + +impl Copy for &'static Bar { } //~ ERROR E0206 + +fn main() { +} diff --git a/src/test/compile-fail/E0207.rs b/src/test/compile-fail/E0207.rs new file mode 100644 index 000000000000..bd87dbaf786a --- /dev/null +++ b/src/test/compile-fail/E0207.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo; + +impl Foo { //~ ERROR E0207 + fn get(&self) -> T { + ::default() + } +} + +fn main() { +} diff --git a/src/test/compile-fail/E0214.rs b/src/test/compile-fail/E0214.rs new file mode 100644 index 000000000000..59609345ee52 --- /dev/null +++ b/src/test/compile-fail/E0214.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let v: Vec(&str) = vec!["foo"]; //~ ERROR E0214 +} diff --git a/src/test/compile-fail/E0220.rs b/src/test/compile-fail/E0220.rs new file mode 100644 index 000000000000..17e2b18b3745 --- /dev/null +++ b/src/test/compile-fail/E0220.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Trait { + type Bar; +} + +type Foo = Trait; //~ ERROR E0220 + //~^ ERROR E0191 + +fn main() { +} diff --git a/src/test/compile-fail/E0221.rs b/src/test/compile-fail/E0221.rs new file mode 100644 index 000000000000..213ec5a04888 --- /dev/null +++ b/src/test/compile-fail/E0221.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait T1 {} +trait T2 {} + +trait Foo { + type A: T1; +} + +trait Bar : Foo { + type A: T2; + fn do_something() { + let _: Self::A; //~ ERROR E0221 + } +} + +fn main() { +} diff --git a/src/test/compile-fail/E0223.rs b/src/test/compile-fail/E0223.rs new file mode 100644 index 000000000000..bbf7d762ef00 --- /dev/null +++ b/src/test/compile-fail/E0223.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait MyTrait { type X; } + +fn main() { + let foo: MyTrait::X; //~ ERROR E0223 +} diff --git a/src/test/compile-fail/E0225.rs b/src/test/compile-fail/E0225.rs new file mode 100644 index 000000000000..190350c5a557 --- /dev/null +++ b/src/test/compile-fail/E0225.rs @@ -0,0 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let _: Box; //~ ERROR E0225 +} diff --git a/src/test/compile-fail/E0229.rs b/src/test/compile-fail/E0229.rs new file mode 100644 index 000000000000..45d5c59592f7 --- /dev/null +++ b/src/test/compile-fail/E0229.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait Foo { + type A; + fn boo(&self) -> ::A; +} + +struct Bar; + +impl Foo for isize { + type A = usize; + fn boo(&self) -> usize { 42 } +} + +fn baz(x: &>::A) {} //~ ERROR E0229 + +fn main() { +} diff --git a/src/test/compile-fail/E0232.rs b/src/test/compile-fail/E0232.rs new file mode 100644 index 000000000000..efeb869d71fa --- /dev/null +++ b/src/test/compile-fail/E0232.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(on_unimplemented)] + +#[rustc_on_unimplemented] //~ ERROR E0232 +trait Bar {} + +fn main() { +} diff --git a/src/test/compile-fail/E0243.rs b/src/test/compile-fail/E0243.rs new file mode 100644 index 000000000000..8cc245c10cbe --- /dev/null +++ b/src/test/compile-fail/E0243.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { x: T } +struct Bar { x: Foo } //~ ERROR E0243 + +fn main() { +} diff --git a/src/test/compile-fail/E0244.rs b/src/test/compile-fail/E0244.rs new file mode 100644 index 000000000000..4c5744710929 --- /dev/null +++ b/src/test/compile-fail/E0244.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { x: bool } +struct Bar { x: Foo } //~ ERROR E0244 + +fn main() { +} diff --git a/src/test/compile-fail/E0248.rs b/src/test/compile-fail/E0248.rs new file mode 100644 index 000000000000..fdfd41a456bf --- /dev/null +++ b/src/test/compile-fail/E0248.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Foo { + Bar(u32), +} + +fn do_something(x: Foo::Bar) { } //~ ERROR E0248 + +fn main() { +} diff --git a/src/test/compile-fail/E0252.rs b/src/test/compile-fail/E0252.rs new file mode 100644 index 000000000000..6b353c8cd1a6 --- /dev/null +++ b/src/test/compile-fail/E0252.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use foo::baz; +use bar::baz; //~ ERROR E0252 + +mod foo { + pub struct baz; +} + +mod bar { + pub mod baz {} +} + +fn main() { +} diff --git a/src/test/compile-fail/E0306.rs b/src/test/compile-fail/E0306.rs new file mode 100644 index 000000000000..61cc8902036e --- /dev/null +++ b/src/test/compile-fail/E0306.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const A: [u32; "hello"] = []; //~ ERROR E0306 +const B: [u32; true] = []; //~ ERROR E0306 +const C: [u32; 0.0] = []; //~ ERROR E0306 + +fn main() { +} diff --git a/src/test/compile-fail/E0308-2.rs b/src/test/compile-fail/E0308-2.rs new file mode 100644 index 000000000000..8c9fc9551561 --- /dev/null +++ b/src/test/compile-fail/E0308-2.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::rc::Rc; + +struct Foo; + +impl Foo { + fn x(self: Rc) {} //~ ERROR E0308 +} + +fn main() { +} diff --git a/src/test/compile-fail/E0308-3.rs b/src/test/compile-fail/E0308-3.rs new file mode 100644 index 000000000000..d7dca056f3fa --- /dev/null +++ b/src/test/compile-fail/E0308-3.rs @@ -0,0 +1,11 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() -> i32 { 0 } //~ ERROR E0308 diff --git a/src/test/compile-fail/E0308-4.rs b/src/test/compile-fail/E0308-4.rs new file mode 100644 index 000000000000..bb4cd1434167 --- /dev/null +++ b/src/test/compile-fail/E0308-4.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let x = 1u8; + match x { + 0u8...3i8 => (), //~ ERROR E0308 + _ => () + } +} diff --git a/src/test/compile-fail/E0308.rs b/src/test/compile-fail/E0308.rs new file mode 100644 index 000000000000..078f1d3a9a1a --- /dev/null +++ b/src/test/compile-fail/E0308.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn size_of(); //~ ERROR E0308 +} + +fn main() { +} diff --git a/src/test/compile-fail/array-not-vector.rs b/src/test/compile-fail/array-not-vector.rs index 1bbccae53a44..47e1c09f380b 100644 --- a/src/test/compile-fail/array-not-vector.rs +++ b/src/test/compile-fail/array-not-vector.rs @@ -12,7 +12,7 @@ fn main() { let _x: i32 = [1, 2, 3]; //~^ ERROR mismatched types //~| expected type `i32` - //~| found type `[_; 3]` + //~| found type `[{integer}; 3]` //~| expected i32, found array of 3 elements let x: &[i32] = &[1, 2, 3]; diff --git a/src/test/compile-fail/array_const_index-0.rs b/src/test/compile-fail/array_const_index-0.rs index e65230389f9c..501c66e75cde 100644 --- a/src/test/compile-fail/array_const_index-0.rs +++ b/src/test/compile-fail/array_const_index-0.rs @@ -10,7 +10,8 @@ const A: &'static [i32] = &[]; const B: i32 = (&A)[1]; -//~^ ERROR index out of bounds: the len is 0 but the index is 1 +//~^ ERROR constant evaluation error +//~| index out of bounds: the len is 0 but the index is 1 fn main() { let _ = B; diff --git a/src/test/compile-fail/array_const_index-1.rs b/src/test/compile-fail/array_const_index-1.rs index 69d84e24c498..d3b43e83bfe5 100644 --- a/src/test/compile-fail/array_const_index-1.rs +++ b/src/test/compile-fail/array_const_index-1.rs @@ -10,7 +10,8 @@ const A: [i32; 0] = []; const B: i32 = A[1]; -//~^ ERROR index out of bounds: the len is 0 but the index is 1 +//~^ ERROR constant evaluation error +//~| index out of bounds: the len is 0 but the index is 1 fn main() { let _ = B; diff --git a/src/test/compile-fail/associated-const-array-len.rs b/src/test/compile-fail/associated-const-array-len.rs index 5d8007defc90..0239986f5ad3 100644 --- a/src/test/compile-fail/associated-const-array-len.rs +++ b/src/test/compile-fail/associated-const-array-len.rs @@ -14,7 +14,7 @@ trait Foo { const ID: usize; } -const X: [i32; ::ID] = [0, 1, 2]; //~ ERROR E0250 +const X: [i32; ::ID] = [0, 1, 2]; //~ ERROR E0080 fn main() { assert_eq!(1, X); diff --git a/src/test/compile-fail/associated-const-impl-wrong-type.rs b/src/test/compile-fail/associated-const-impl-wrong-type.rs index 4658d0f057d7..95508a31044b 100644 --- a/src/test/compile-fail/associated-const-impl-wrong-type.rs +++ b/src/test/compile-fail/associated-const-impl-wrong-type.rs @@ -18,9 +18,8 @@ struct SignedBar; impl Foo for SignedBar { const BAR: i32 = -1; - //~^ ERROR implemented const `BAR` has an incompatible type for trait - //~| expected u32, - //~| found i32 [E0326] + //~^ ERROR implemented const `BAR` has an incompatible type for trait [E0326] + //~| expected u32, found i32 } fn main() {} diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs index 2f687350f34e..c3fa39659b96 100644 --- a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs +++ b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs @@ -25,7 +25,8 @@ impl Foo for Def { } pub fn test() { - let _array = [4; ::Y]; //~ error: expected constant integer + let _array = [4; ::Y]; //~ ERROR E0080 + //~| non-constant path in constant } fn main() { diff --git a/src/test/compile-fail/associated-types-eq-3.rs b/src/test/compile-fail/associated-types-eq-3.rs index 8c66160e8a36..cb952f6534f0 100644 --- a/src/test/compile-fail/associated-types-eq-3.rs +++ b/src/test/compile-fail/associated-types-eq-3.rs @@ -47,10 +47,8 @@ pub fn main() { let a = 42; foo1(a); //~^ ERROR type mismatch resolving - //~| expected usize - //~| found struct `Bar` + //~| expected usize, found struct `Bar` baz(&a); //~^ ERROR type mismatch resolving - //~| expected usize - //~| found struct `Bar` + //~| expected usize, found struct `Bar` } diff --git a/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs b/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs index f60f06b4ec83..de6ce798d635 100644 --- a/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs +++ b/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs @@ -12,7 +12,6 @@ #![allow(dead_code)] #![feature(rustc_attrs)] -#![feature(unboxed_closures)] #![deny(hr_lifetime_in_assoc_type)] trait Foo<'a> { diff --git a/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs b/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs index 01db4770a38b..6ba09acc0e79 100644 --- a/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs +++ b/src/test/compile-fail/associated-types/cache/wasm-issue-32330.rs @@ -13,7 +13,6 @@ #![allow(dead_code, unused_variables)] #![deny(hr_lifetime_in_assoc_type)] -#![feature(unboxed_closures)] use std::str::Chars; diff --git a/src/test/compile-fail/associated-types/higher-ranked-projection.rs b/src/test/compile-fail/associated-types/higher-ranked-projection.rs new file mode 100644 index 000000000000..12341fa8db38 --- /dev/null +++ b/src/test/compile-fail/associated-types/higher-ranked-projection.rs @@ -0,0 +1,38 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] + +// revisions: good bad + +trait Mirror { + type Image; +} + +impl Mirror for T { + type Image = T; +} + +#[cfg(bad)] +fn foo(_t: T) + where for<'a> &'a T: Mirror +{} + +#[cfg(good)] +fn foo(_t: T) + where for<'a> &'a T: Mirror +{} + +#[rustc_error] +fn main() { //[good]~ ERROR compilation successful + foo(()); + //[bad]~^ ERROR type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _` + //[bad]~| expected bound lifetime parameter 'a, found concrete lifetime +} diff --git a/src/test/compile-fail/bad-const-type.rs b/src/test/compile-fail/bad-const-type.rs index ee6ac3307279..5547d19868d3 100644 --- a/src/test/compile-fail/bad-const-type.rs +++ b/src/test/compile-fail/bad-const-type.rs @@ -11,6 +11,6 @@ static i: String = 10; //~^ ERROR mismatched types //~| expected type `std::string::String` -//~| found type `_` +//~| found type `{integer}` //~| expected struct `std::string::String`, found integral variable fn main() { println!("{}", i); } diff --git a/src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs b/src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs index 7626f354eb46..e4ae565fe92f 100644 --- a/src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs +++ b/src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs @@ -10,8 +10,6 @@ // Ensure that invoking a closure counts as a unique immutable borrow -#![feature(unboxed_closures)] - type Fn<'a> = Box; struct Test<'a> { diff --git a/src/test/compile-fail/borrowck/borrowck-unboxed-closures.rs b/src/test/compile-fail/borrowck/borrowck-unboxed-closures.rs index 1c12ca9c1de7..0f9829ab259a 100644 --- a/src/test/compile-fail/borrowck/borrowck-unboxed-closures.rs +++ b/src/test/compile-fail/borrowck/borrowck-unboxed-closures.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(overloaded_calls, unboxed_closures)] - fn a isize>(mut f: F) { let g = &mut f; f(1, 2); //~ ERROR cannot borrow `f` as immutable diff --git a/src/test/compile-fail/coerce-mut.rs b/src/test/compile-fail/coerce-mut.rs index 634d12441a12..86702a7463fd 100644 --- a/src/test/compile-fail/coerce-mut.rs +++ b/src/test/compile-fail/coerce-mut.rs @@ -15,6 +15,6 @@ fn main() { f(&x); //~^ ERROR mismatched types //~| expected type `&mut i32` - //~| found type `&_` + //~| found type `&{integer}` //~| values differ in mutability } diff --git a/src/test/compile-fail/coercion-slice.rs b/src/test/compile-fail/coercion-slice.rs index bd7e6c2a2131..a619f33468f4 100644 --- a/src/test/compile-fail/coercion-slice.rs +++ b/src/test/compile-fail/coercion-slice.rs @@ -14,6 +14,6 @@ fn main() { let _: &[i32] = [0]; //~^ ERROR mismatched types //~| expected type `&[i32]` - //~| found type `[_; 1]` + //~| found type `[{integer}; 1]` //~| expected &-ptr, found array of 1 elements } diff --git a/src/test/compile-fail/const-array-oob.rs b/src/test/compile-fail/const-array-oob.rs index faabed4fd5e4..b980bc02c85a 100644 --- a/src/test/compile-fail/const-array-oob.rs +++ b/src/test/compile-fail/const-array-oob.rs @@ -16,7 +16,8 @@ const FOO: [u32; 3] = [1, 2, 3]; const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval const BLUB: [u32; FOO[4]] = [5, 6]; -//~^ ERROR array length constant evaluation error: index out of bounds: the len is 3 but the index is 4 [E0250] +//~^ ERROR constant evaluation error [E0080] +//~| index out of bounds: the len is 3 but the index is 4 fn main() { let _ = BAR; diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs index 1143d3bd5cd9..7e2eabf412d6 100644 --- a/src/test/compile-fail/const-call.rs +++ b/src/test/compile-fail/const-call.rs @@ -15,5 +15,6 @@ fn f(x: usize) -> usize { } fn main() { - let _ = [0; f(2)]; //~ ERROR: non-constant path in constant expression [E0307] + let _ = [0; f(2)]; //~ ERROR constant evaluation error [E0080] + //~| non-constant path in constant expression } diff --git a/src/test/compile-fail/const-err-early.rs b/src/test/compile-fail/const-err-early.rs index f666140970b6..42fb40394fb2 100644 --- a/src/test/compile-fail/const-err-early.rs +++ b/src/test/compile-fail/const-err-early.rs @@ -11,10 +11,10 @@ #![feature(const_indexing)] #![deny(const_err)] -pub const A: i8 = -std::i8::MIN; //~ ERROR attempted to negate with overflow -pub const B: u8 = 200u8 + 200u8; //~ ERROR attempted to add with overflow -pub const C: u8 = 200u8 * 4; //~ ERROR attempted to multiply with overflow -pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR attempted to subtract with overflow +pub const A: i8 = -std::i8::MIN; //~ ERROR attempt to negate with overflow +pub const B: u8 = 200u8 + 200u8; //~ ERROR attempt to add with overflow +pub const C: u8 = 200u8 * 4; //~ ERROR attempt to multiply with overflow +pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR attempt to subtract with overflow pub const E: u8 = [5u8][1]; //~^ ERROR index out of bounds: the len is 1 but the index is 1 diff --git a/src/test/compile-fail/const-err-multi.rs b/src/test/compile-fail/const-err-multi.rs index 7de93a213b02..d4f9c0fe56da 100644 --- a/src/test/compile-fail/const-err-multi.rs +++ b/src/test/compile-fail/const-err-multi.rs @@ -10,7 +10,7 @@ #![deny(const_err)] -pub const A: i8 = -std::i8::MIN; //~ ERROR attempted to negate with overflow +pub const A: i8 = -std::i8::MIN; //~ ERROR attempt to negate with overflow pub const B: i8 = A; pub const C: u8 = A as u8; pub const D: i8 = 50 - A; diff --git a/src/test/compile-fail/const-err.rs b/src/test/compile-fail/const-err.rs index a1d3888e78ea..944e458c4c0f 100644 --- a/src/test/compile-fail/const-err.rs +++ b/src/test/compile-fail/const-err.rs @@ -22,21 +22,29 @@ fn black_box(_: T) { // Make sure that the two uses get two errors. const FOO: u8 = [5u8][1]; -//~^ ERROR index out of bounds: the len is 1 but the index is 1 -//~^^ ERROR index out of bounds: the len is 1 but the index is 1 +//~^ ERROR constant evaluation error +//~| index out of bounds: the len is 1 but the index is 1 +//~^^^ ERROR constant evaluation error +//~| index out of bounds: the len is 1 but the index is 1 fn main() { let a = -std::i8::MIN; - //~^ WARN attempted to negate with overflow + //~^ WARN this expression will panic at run-time + //~| attempt to negate with overflow let b = 200u8 + 200u8 + 200u8; - //~^ WARN attempted to add with overflow - //~| WARN attempted to add with overflow + //~^ WARN this expression will panic at run-time + //~| attempt to add with overflow + //~^^^ WARN this expression will panic at run-time + //~| attempt to add with overflow let c = 200u8 * 4; - //~^ WARN attempted to multiply with overflow + //~^ WARN this expression will panic at run-time + //~| attempt to multiply with overflow let d = 42u8 - (42u8 + 1); - //~^ WARN attempted to subtract with overflow + //~^ WARN this expression will panic at run-time + //~| attempt to subtract with overflow let _e = [5u8][1]; - //~^ WARN index out of bounds: the len is 1 but the index is 1 + //~^ WARN this expression will panic at run-time + //~| index out of bounds: the len is 1 but the index is 1 black_box(a); black_box(b); black_box(c); diff --git a/src/test/compile-fail/const-err2.rs b/src/test/compile-fail/const-err2.rs index f0d65f1424c4..7c1fb2ccd472 100644 --- a/src/test/compile-fail/const-err2.rs +++ b/src/test/compile-fail/const-err2.rs @@ -18,14 +18,14 @@ fn black_box(_: T) { fn main() { let a = -std::i8::MIN; - //~^ ERROR attempted to negate with overflow + //~^ ERROR attempt to negate with overflow let b = 200u8 + 200u8 + 200u8; - //~^ ERROR attempted to add with overflow - //~| ERROR attempted to add with overflow + //~^ ERROR attempt to add with overflow + //~| ERROR attempt to add with overflow let c = 200u8 * 4; - //~^ ERROR attempted to multiply with overflow + //~^ ERROR attempt to multiply with overflow let d = 42u8 - (42u8 + 1); - //~^ ERROR attempted to subtract with overflow + //~^ ERROR attempt to subtract with overflow let _e = [5u8][1]; black_box(a); black_box(b); diff --git a/src/test/compile-fail/const-eval-overflow-2.rs b/src/test/compile-fail/const-eval-overflow-2.rs index 07e27a7dc9a9..264f02588ae5 100644 --- a/src/test/compile-fail/const-eval-overflow-2.rs +++ b/src/test/compile-fail/const-eval-overflow-2.rs @@ -19,13 +19,16 @@ use std::{u8, u16, u32, u64, usize}; const NEG_128: i8 = -128; const NEG_NEG_128: i8 = -NEG_128; -//~^ ERROR constant evaluation error: attempted to negate with overflow -//~| ERROR attempted to negate with overflow -//~| ERROR attempted to negate with overflow +//~^ ERROR constant evaluation error +//~| attempt to negate with overflow +//~| ERROR constant evaluation error +//~| attempt to negate with overflow +//~| ERROR constant evaluation error +//~| attempt to negate with overflow fn main() { match -128i8 { - NEG_NEG_128 => println!("A"), //~ NOTE in pattern here + NEG_NEG_128 => println!("A"), //~ NOTE for pattern here _ => println!("B"), } } diff --git a/src/test/compile-fail/const-eval-overflow-3.rs b/src/test/compile-fail/const-eval-overflow-3.rs index c90ae045f96b..d930cb770472 100644 --- a/src/test/compile-fail/const-eval-overflow-3.rs +++ b/src/test/compile-fail/const-eval-overflow-3.rs @@ -17,7 +17,7 @@ // self-hosted and a cross-compiled setup; therefore resorting to // error-pattern for now. -// error-pattern: expected constant integer for repeat count, but attempted to add with overflow +// error-pattern: attempt to add with overflow #![allow(unused_imports)] diff --git a/src/test/compile-fail/const-eval-overflow-4.rs b/src/test/compile-fail/const-eval-overflow-4.rs index f1f125adaa7e..67525fc16261 100644 --- a/src/test/compile-fail/const-eval-overflow-4.rs +++ b/src/test/compile-fail/const-eval-overflow-4.rs @@ -23,7 +23,7 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 + 1i8) as usize] - //~^ ERROR error evaluating count: attempted to add with overflow + //~^ ERROR error evaluating count: attempt to add with overflow = [0; (i8::MAX as usize) + 1]; fn main() { diff --git a/src/test/compile-fail/const-eval-overflow-4b.rs b/src/test/compile-fail/const-eval-overflow-4b.rs index 31e1a72967f4..9e7a5ecae105 100644 --- a/src/test/compile-fail/const-eval-overflow-4b.rs +++ b/src/test/compile-fail/const-eval-overflow-4b.rs @@ -20,9 +20,8 @@ use std::{u8, u16, u32, u64, usize}; const A_I8_T : [u32; (i8::MAX as i8 + 1u8) as usize] - //~^ ERROR mismatched types: - //~| expected `i8`, - //~| found `u8` [E0250] + //~^ ERROR constant evaluation error [E0080] + //~| expected i8, found u8 = [0; (i8::MAX as usize) + 1]; @@ -33,7 +32,8 @@ const A_CHAR_USIZE const A_BAD_CHAR_USIZE : [u32; 5i8 as char as usize] - //~^ ERROR only `u8` can be cast as `char`, not `i8` + //~^ ERROR constant evaluation error + //~| only `u8` can be cast as `char`, not `i8` = [0; 5]; fn main() {} diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs index 3dfcb5bb29a2..b8f3f714a84e 100644 --- a/src/test/compile-fail/const-eval-overflow.rs +++ b/src/test/compile-fail/const-eval-overflow.rs @@ -21,86 +21,114 @@ use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8, i8, i8, i8) = (-i8::MIN, - //~^ ERROR attempted to negate with overflow + //~^ ERROR constant evaluation error + //~| attempt to negate with overflow i8::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow i8::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempt to add with overflow i8::MIN * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow ); const VALS_I16: (i16, i16, i16, i16) = (-i16::MIN, - //~^ ERROR attempted to negate with overflow + //~^ ERROR constant evaluation error + //~| attempt to negate with overflow i16::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow i16::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempt to add with overflow i16::MIN * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow ); const VALS_I32: (i32, i32, i32, i32) = (-i32::MIN, - //~^ ERROR attempted to negate with overflow + //~^ ERROR constant evaluation error + //~| attempt to negate with overflow i32::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow i32::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempt to add with overflow i32::MIN * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow ); const VALS_I64: (i64, i64, i64, i64) = (-i64::MIN, - //~^ ERROR attempted to negate with overflow + //~^ ERROR constant evaluation error + //~| attempt to negate with overflow i64::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow i64::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempt to add with overflow i64::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow ); const VALS_U8: (u8, u8, u8, u8) = (-(u8::MIN as i8) as u8, u8::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow u8::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempt to add with overflow u8::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow ); const VALS_U16: (u16, u16, u16, u16) = (-(u16::MIN as i16) as u16, u16::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow u16::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempt to add with overflow u16::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow ); const VALS_U32: (u32, u32, u32, u32) = (-(u32::MIN as i32) as u32, u32::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow u32::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempt to add with overflow u32::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow ); const VALS_U64: (u64, u64, u64, u64) = (-(u64::MIN as i64) as u64, u64::MIN - 1, - //~^ ERROR attempted to subtract with overflow + //~^ ERROR constant evaluation error + //~| attempt to subtract with overflow u64::MAX + 1, - //~^ ERROR attempted to add with overflow + //~^ ERROR constant evaluation error + //~| attempt to add with overflow u64::MAX * 2, - //~^ ERROR attempted to multiply with overflow + //~^ ERROR constant evaluation error + //~| attempt to multiply with overflow ); fn main() { diff --git a/src/test/compile-fail/const-eval-span.rs b/src/test/compile-fail/const-eval-span.rs index 9fdd24c42fdb..73351429b506 100644 --- a/src/test/compile-fail/const-eval-span.rs +++ b/src/test/compile-fail/const-eval-span.rs @@ -14,7 +14,8 @@ struct S(i32); const CONSTANT: S = S(0); -//~^ ERROR: unimplemented constant expression: tuple struct constructors [E0080] +//~^ ERROR E0080 +//~| unimplemented constant expression: tuple struct constructors enum E { V = CONSTANT, diff --git a/src/test/compile-fail/const-fn-error.rs b/src/test/compile-fail/const-fn-error.rs index 45a00de48e71..dd0f058f2c95 100644 --- a/src/test/compile-fail/const-fn-error.rs +++ b/src/test/compile-fail/const-fn-error.rs @@ -17,10 +17,11 @@ const fn f(x: usize) -> usize { for i in 0..x { sum += i; } - sum //~ ERROR: E0250 + sum //~ ERROR E0080 + //~| non-constant path in constant } #[allow(unused_variables)] fn main() { - let a : [i32; f(X)]; + let a : [i32; f(X)]; //~ NOTE for array length here } diff --git a/src/test/compile-fail/const-index-feature-gate.rs b/src/test/compile-fail/const-index-feature-gate.rs index 09822e46cc1a..4f92770df289 100644 --- a/src/test/compile-fail/const-index-feature-gate.rs +++ b/src/test/compile-fail/const-index-feature-gate.rs @@ -9,7 +9,8 @@ // except according to those terms. const ARR: [usize; 1] = [2]; -const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR unstable +const ARR2: [i32; ARR[0]] = [5, 6]; //~ ERROR E0080 + //~| unstable fn main() { } diff --git a/src/test/compile-fail/const-integer-bool-ops.rs b/src/test/compile-fail/const-integer-bool-ops.rs index 0d6cf3bab453..5dadd892f835 100644 --- a/src/test/compile-fail/const-integer-bool-ops.rs +++ b/src/test/compile-fail/const-integer-bool-ops.rs @@ -8,30 +8,34 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -const X: usize = 42 && 39; //~ ERROR: can't do this op on integrals +const X: usize = 42 && 39; //~ ERROR E0080 + //~| can't do this op on integrals const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here -const X1: usize = 42 || 39; //~ ERROR: can't do this op on integrals +const X1: usize = 42 || 39; //~ ERROR E0080 + //~| can't do this op on integrals const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here -const X2: usize = -42 || -39; //~ ERROR: unary negation of unsigned integer +const X2: usize = -42 || -39; //~ ERROR E0080 + //~| unary negation of unsigned integer const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here -const X3: usize = -42 && -39; //~ ERROR: unary negation of unsigned integer +const X3: usize = -42 && -39; //~ ERROR E0080 + //~| unary negation of unsigned integer const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here const Y: usize = 42.0 == 42.0; -const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length +const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length const Y1: usize = 42.0 >= 42.0; -const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length +const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length const Y2: usize = 42.0 <= 42.0; -const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length +const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize for array length const Y3: usize = 42.0 > 42.0; -const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length +const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length const Y4: usize = 42.0 < 42.0; -const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length +const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length const Y5: usize = 42.0 != 42.0; -const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length +const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize for array length fn main() { let _ = ARR; diff --git a/src/test/compile-fail/const-len-underflow-separate-spans.rs b/src/test/compile-fail/const-len-underflow-separate-spans.rs index 9c6b774b9903..c01bb8267630 100644 --- a/src/test/compile-fail/const-len-underflow-separate-spans.rs +++ b/src/test/compile-fail/const-len-underflow-separate-spans.rs @@ -15,7 +15,8 @@ const ONE: usize = 1; const TWO: usize = 2; const LEN: usize = ONE - TWO; -//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250] +//~^ ERROR E0080 +//~| attempt to subtract with overflow fn main() { let a: [i8; LEN] = unimplemented!(); diff --git a/src/test/compile-fail/const-len-underflow-subspans.rs b/src/test/compile-fail/const-len-underflow-subspans.rs index d51f31087d0d..7f2229b5a653 100644 --- a/src/test/compile-fail/const-len-underflow-subspans.rs +++ b/src/test/compile-fail/const-len-underflow-subspans.rs @@ -16,5 +16,6 @@ const TWO: usize = 2; fn main() { let a: [i8; ONE - TWO] = unimplemented!(); - //~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250] + //~^ ERROR constant evaluation error [E0080] + //~| attempt to subtract with overflow } diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs index 4567cd4a74bb..d68d63683a79 100644 --- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs +++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs @@ -17,22 +17,26 @@ enum Cake { use Cake::*; const BOO: (Cake, Cake) = (Marmor, BlackForest); -//~^ ERROR: constant evaluation error: unimplemented constant expression: enum variants [E0471] +//~^ ERROR: constant evaluation error [E0080] +//~| unimplemented constant expression: enum variants const FOO: Cake = BOO.1; const fn foo() -> Cake { - Marmor //~ ERROR: constant evaluation error: unimplemented constant expression: enum variants - //~^ ERROR: unimplemented constant expression: enum variants + Marmor + //~^ ERROR: constant evaluation error [E0080] + //~| unimplemented constant expression: enum variants + //~^^^ ERROR: constant evaluation error [E0080] + //~| unimplemented constant expression: enum variants } const WORKS: Cake = Marmor; -const GOO: Cake = foo(); +const GOO: Cake = foo(); //~ NOTE for expression here fn main() { match BlackForest { - FOO => println!("hi"), //~ NOTE: in pattern here - GOO => println!("meh"), //~ NOTE: in pattern here + FOO => println!("hi"), //~ NOTE: for pattern here + GOO => println!("meh"), //~ NOTE: for pattern here WORKS => println!("möp"), _ => println!("bye"), } diff --git a/src/test/compile-fail/const-slice-oob.rs b/src/test/compile-fail/const-slice-oob.rs index d63b0097e5a0..b1b4bfe2d1c3 100644 --- a/src/test/compile-fail/const-slice-oob.rs +++ b/src/test/compile-fail/const-slice-oob.rs @@ -10,7 +10,8 @@ const FOO: &'static[u32] = &[1, 2, 3]; const BAR: u32 = FOO[5]; -//~^ ERROR index out of bounds: the len is 3 but the index is 5 +//~^ ERROR constant evaluation error [E0080] +//~| index out of bounds: the len is 3 but the index is 5 fn main() { let _ = BAR; diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs index 9d3c432d1487..8f7ec9de58af 100644 --- a/src/test/compile-fail/const-tup-index-span.rs +++ b/src/test/compile-fail/const-tup-index-span.rs @@ -11,7 +11,8 @@ // Test spans of errors const TUP: (usize,) = 5 << 64; -//~^ ERROR: attempted to shift left with overflow [E0250] +//~^ ERROR E0080 +//~| attempt to shift left with overflow const ARR: [i32; TUP.0] = []; fn main() { diff --git a/src/test/compile-fail/deprecation-lint-nested.rs b/src/test/compile-fail/deprecation-lint-nested.rs new file mode 100644 index 000000000000..eedbba59c6f4 --- /dev/null +++ b/src/test/compile-fail/deprecation-lint-nested.rs @@ -0,0 +1,81 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(deprecated)] +#![allow(warnings)] + +#[deprecated] +fn issue_35128() { + format_args!("foo"); +} + +#[deprecated] +fn issue_35128_minimal() { + static FOO: &'static str = "foo"; + let _ = FOO; +} + +#[deprecated] +mod silent { + type DeprecatedType = u8; + struct DeprecatedStruct; + fn deprecated_fn() {} + trait DeprecatedTrait {} + static DEPRECATED_STATIC: u8 = 0; + const DEPRECATED_CONST: u8 = 1; + + struct Foo(DeprecatedType); + + impl DeprecatedTrait for Foo {} + + impl Foo { + fn bar() { + deprecated_fn(); + } + } + + fn foo() -> u8 { + DEPRECATED_STATIC + + DEPRECATED_CONST + } +} + +#[deprecated] +mod loud { + #[deprecated] + type DeprecatedType = u8; + #[deprecated] + struct DeprecatedStruct; + #[deprecated] + fn deprecated_fn() {} + #[deprecated] + trait DeprecatedTrait {} + #[deprecated] + static DEPRECATED_STATIC: u8 = 0; + #[deprecated] + const DEPRECATED_CONST: u8 = 1; + + struct Foo(DeprecatedType); //~ ERROR use of deprecated item + + impl DeprecatedTrait for Foo {} //~ ERROR use of deprecated item + + impl Foo { + fn bar() { //~ ERROR use of deprecated item + deprecated_fn(); //~ ERROR use of deprecated item + } + } + + fn foo() -> u8 { + DEPRECATED_STATIC + //~ ERROR use of deprecated item + DEPRECATED_CONST //~ ERROR use of deprecated item + } +} + +fn main() {} diff --git a/src/test/compile-fail/deprecation-lint.rs b/src/test/compile-fail/deprecation-lint.rs index 5fc8f684a66f..edee24206cd3 100644 --- a/src/test/compile-fail/deprecation-lint.rs +++ b/src/test/compile-fail/deprecation-lint.rs @@ -266,14 +266,14 @@ mod this_crate { #[deprecated(since = "1.0.0", note = "text")] fn test_fn_body() { fn fn_in_body() {} - fn_in_body(); //~ ERROR use of deprecated item: text + fn_in_body(); } impl MethodTester { #[deprecated(since = "1.0.0", note = "text")] fn test_method_body(&self) { fn fn_in_body() {} - fn_in_body(); //~ ERROR use of deprecated item: text + fn_in_body(); } } diff --git a/src/test/compile-fail/discrim-ill-typed.rs b/src/test/compile-fail/discrim-ill-typed.rs index 23106c99594a..c73b7e831b32 100644 --- a/src/test/compile-fail/discrim-ill-typed.rs +++ b/src/test/compile-fail/discrim-ill-typed.rs @@ -25,7 +25,8 @@ fn f_i8() { Ok = i8::MAX - 1, Ok2, OhNo = 0_u8, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected i8, found u8 } let x = A::Ok; @@ -37,7 +38,8 @@ fn f_u8() { Ok = u8::MAX - 1, Ok2, OhNo = 0_i8, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected u8, found i8 } let x = A::Ok; @@ -49,7 +51,8 @@ fn f_i16() { Ok = i16::MAX - 1, Ok2, OhNo = 0_u16, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected i16, found u16 } let x = A::Ok; @@ -61,7 +64,8 @@ fn f_u16() { Ok = u16::MAX - 1, Ok2, OhNo = 0_i16, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected u16, found i16 } let x = A::Ok; @@ -73,7 +77,8 @@ fn f_i32() { Ok = i32::MAX - 1, Ok2, OhNo = 0_u32, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected i32, found u32 } let x = A::Ok; @@ -85,7 +90,8 @@ fn f_u32() { Ok = u32::MAX - 1, Ok2, OhNo = 0_i32, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected u32, found i32 } let x = A::Ok; @@ -97,7 +103,8 @@ fn f_i64() { Ok = i64::MAX - 1, Ok2, OhNo = 0_u64, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected i64, found u64 } let x = A::Ok; @@ -109,7 +116,8 @@ fn f_u64() { Ok = u64::MAX - 1, Ok2, OhNo = 0_i64, - //~^ ERROR mismatched types + //~^ ERROR E0080 + //~| expected u64, found i64 } let x = A::Ok; diff --git a/src/test/compile-fail/enable-orbit-for-incr-comp.rs b/src/test/compile-fail/enable-orbit-for-incr-comp.rs new file mode 100644 index 000000000000..eec6bad731e3 --- /dev/null +++ b/src/test/compile-fail/enable-orbit-for-incr-comp.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-pretty +// compile-flags:-Zincremental=tmp/cfail-tests/enable-orbit-for-incr-comp -Zorbit=off +// error-pattern:Automatically enabling `-Z orbit` because `-Z incremental` was specified + +#![deny(warnings)] + +fn main() { + FAIL! // We just need some compilation error. What we really care about is + // that the error pattern above is checked. +} diff --git a/src/test/compile-fail/enum-discrim-too-small.rs b/src/test/compile-fail/enum-discrim-too-small.rs index d6ba09bb4c5b..bbdb3891d998 100644 --- a/src/test/compile-fail/enum-discrim-too-small.rs +++ b/src/test/compile-fail/enum-discrim-too-small.rs @@ -13,28 +13,32 @@ enum Eu8 { Au8 = 23, Bu8 = 223, - Cu8 = -23, //~ ERROR unary negation of unsigned integer + Cu8 = -23, //~ ERROR E0080 + //~| unary negation of unsigned integer } #[repr(u16)] enum Eu16 { Au16 = 23, Bu16 = 55555, - Cu16 = -22333, //~ ERROR unary negation of unsigned integer + Cu16 = -22333, //~ ERROR E0080 + //~| unary negation of unsigned integer } #[repr(u32)] enum Eu32 { Au32 = 23, Bu32 = 3_000_000_000, - Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer + Cu32 = -2_000_000_000, //~ ERROR E0080 + //~| unary negation of unsigned integer } #[repr(u64)] enum Eu64 { Au32 = 23, Bu32 = 3_000_000_000, - Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer + Cu32 = -2_000_000_000, //~ ERROR E0080 + //~| unary negation of unsigned integer } // u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a diff --git a/src/test/compile-fail/eval-enum.rs b/src/test/compile-fail/eval-enum.rs index 7ca274b81e57..86cc2c144ac0 100644 --- a/src/test/compile-fail/eval-enum.rs +++ b/src/test/compile-fail/eval-enum.rs @@ -9,9 +9,11 @@ // except according to those terms. enum test { - div_zero = 1/0, //~ERROR constant evaluation error: attempted to divide by zero + div_zero = 1/0, //~ ERROR E0080 + //~| attempt to divide by zero rem_zero = 1%0, -//~^ ERROR constant evaluation error: attempted to calculate the remainder with a divisor of zero + //~^ ERROR E0080 + //~| attempt to calculate the remainder with a divisor of zero } fn main() {} diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs index b5432fafb1b8..f8aa1ea95f0f 100644 --- a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs +++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs @@ -14,15 +14,17 @@ struct Foo<'a,'b> { } impl<'a,'b> Foo<'a,'b> { - fn bar(self: Foo<'b,'a>) {} - //~^ ERROR mismatched types + fn bar( + self + //~^ ERROR mismatched method receiver //~| expected type `Foo<'a, 'b>` //~| found type `Foo<'b, 'a>` //~| lifetime mismatch - //~| ERROR mismatched types + //~| ERROR mismatched method receiver //~| expected type `Foo<'a, 'b>` //~| found type `Foo<'b, 'a>` //~| lifetime mismatch + : Foo<'b,'a>) {} } fn main() {} diff --git a/src/test/compile-fail/feature-gate-abi.rs b/src/test/compile-fail/feature-gate-abi.rs new file mode 100644 index 000000000000..0c01f955c063 --- /dev/null +++ b/src/test/compile-fail/feature-gate-abi.rs @@ -0,0 +1,60 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Functions +extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change +extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental +extern "vectorcall" fn f3() {} //~ ERROR vectorcall is experimental and subject to change +extern "rust-call" fn f4() {} //~ ERROR rust-call ABI is subject to change + +// Methods in trait definition +trait Tr { + extern "rust-intrinsic" fn m1(); //~ ERROR intrinsics are subject to change + extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental + extern "vectorcall" fn m3(); //~ ERROR vectorcall is experimental and subject to change + extern "rust-call" fn m4(); //~ ERROR rust-call ABI is subject to change + + extern "rust-intrinsic" fn dm1() {} //~ ERROR intrinsics are subject to change + extern "platform-intrinsic" fn dm2() {} //~ ERROR platform intrinsics are experimental + extern "vectorcall" fn dm3() {} //~ ERROR vectorcall is experimental and subject to change + extern "rust-call" fn dm4() {} //~ ERROR rust-call ABI is subject to change +} + +struct S; + +// Methods in trait impl +impl Tr for S { + extern "rust-intrinsic" fn m1() {} //~ ERROR intrinsics are subject to change + extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental + extern "vectorcall" fn m3() {} //~ ERROR vectorcall is experimental and subject to change + extern "rust-call" fn m4() {} //~ ERROR rust-call ABI is subject to change +} + +// Methods in inherent impl +impl S { + extern "rust-intrinsic" fn im1() {} //~ ERROR intrinsics are subject to change + extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental + extern "vectorcall" fn im3() {} //~ ERROR vectorcall is experimental and subject to change + extern "rust-call" fn im4() {} //~ ERROR rust-call ABI is subject to change +} + +// Function pointer types +type A1 = extern "rust-intrinsic" fn(); //~ ERROR intrinsics are subject to change +type A2 = extern "platform-intrinsic" fn(); //~ ERROR platform intrinsics are experimental +type A3 = extern "vectorcall" fn(); //~ ERROR vectorcall is experimental and subject to change +type A4 = extern "rust-call" fn(); //~ ERROR rust-call ABI is subject to change + +// Foreign modules +extern "rust-intrinsic" {} //~ ERROR intrinsics are subject to change +extern "platform-intrinsic" {} //~ ERROR platform intrinsics are experimental +extern "vectorcall" {} //~ ERROR vectorcall is experimental and subject to change +extern "rust-call" {} //~ ERROR rust-call ABI is subject to change + +fn main() {} diff --git a/src/test/compile-fail/feature-gate-negate-unsigned0.rs b/src/test/compile-fail/feature-gate-negate-unsigned0.rs index 05b194345d40..89ae1a09bd3e 100644 --- a/src/test/compile-fail/feature-gate-negate-unsigned0.rs +++ b/src/test/compile-fail/feature-gate-negate-unsigned0.rs @@ -18,14 +18,17 @@ impl std::ops::Neg for S { fn main() { let a = -1; - //~^ ERROR unary negation of unsigned integer + //~^ ERROR E0080 + //~| unary negation of unsigned integer let _b : u8 = a; // for infering variable a to u8. let _d = -1u8; - //~^ ERROR unary negation of unsigned integer + //~^ ERROR E0080 + //~| unary negation of unsigned integer for _ in -10..10u8 {} - //~^ ERROR unary negation of unsigned integer + //~^ ERROR E0080 + //~| unary negation of unsigned integer -S; // should not trigger the gate; issue 26840 } diff --git a/src/test/compile-fail/feature-gate-unboxed-closures-method-calls.rs b/src/test/compile-fail/feature-gate-unboxed-closures-method-calls.rs index eea1f61d6397..253d1633b1c4 100644 --- a/src/test/compile-fail/feature-gate-unboxed-closures-method-calls.rs +++ b/src/test/compile-fail/feature-gate-unboxed-closures-method-calls.rs @@ -11,9 +11,9 @@ #![allow(dead_code)] fn foo(mut f: F) { - f.call(()); //~ ERROR explicit use of unboxed closure method `call` - f.call_mut(()); //~ ERROR explicit use of unboxed closure method `call_mut` - f.call_once(()); //~ ERROR explicit use of unboxed closure method `call_once` + f.call(()); //~ ERROR use of unstable library feature 'fn_traits' + f.call_mut(()); //~ ERROR use of unstable library feature 'fn_traits' + f.call_once(()); //~ ERROR use of unstable library feature 'fn_traits' } fn main() {} diff --git a/src/test/compile-fail/feature-gate-unboxed-closures-ufcs-calls.rs b/src/test/compile-fail/feature-gate-unboxed-closures-ufcs-calls.rs index f15c5c4da2c4..902b3c1774c1 100644 --- a/src/test/compile-fail/feature-gate-unboxed-closures-ufcs-calls.rs +++ b/src/test/compile-fail/feature-gate-unboxed-closures-ufcs-calls.rs @@ -10,10 +10,10 @@ #![allow(dead_code)] -fn foo(mut f: F, mut g: F) { - Fn::call(&g, ()); //~ ERROR explicit use of unboxed closure method `call` - FnMut::call_mut(&mut g, ()); //~ ERROR explicit use of unboxed closure method `call_mut` - FnOnce::call_once(g, ()); //~ ERROR explicit use of unboxed closure method `call_once` +fn foo(mut f: F) { + Fn::call(&f, ()); //~ ERROR use of unstable library feature 'fn_traits' + FnMut::call_mut(&mut f, ()); //~ ERROR use of unstable library feature 'fn_traits' + FnOnce::call_once(f, ()); //~ ERROR use of unstable library feature 'fn_traits' } fn main() {} diff --git a/src/test/compile-fail/fn-trait-formatting.rs b/src/test/compile-fail/fn-trait-formatting.rs index fd140cd1d391..e01a0412cef4 100644 --- a/src/test/compile-fail/fn-trait-formatting.rs +++ b/src/test/compile-fail/fn-trait-formatting.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] #![feature(box_syntax)] fn needs_fn(x: F) where F: Fn(isize) -> isize {} diff --git a/src/test/compile-fail/fully-qualified-type-name1.rs b/src/test/compile-fail/fully-qualified-type-name1.rs index 5ea8ce226443..1a7ceb2e7639 100644 --- a/src/test/compile-fail/fully-qualified-type-name1.rs +++ b/src/test/compile-fail/fully-qualified-type-name1.rs @@ -15,6 +15,6 @@ fn main() { x = 5; //~^ ERROR mismatched types //~| expected type `std::option::Option` - //~| found type `_` + //~| found type `{integer}` //~| expected enum `std::option::Option`, found integral variable } diff --git a/src/test/compile-fail/if-let-arm-types.rs b/src/test/compile-fail/if-let-arm-types.rs index c7b1e1a62c20..40013a7ee43b 100644 --- a/src/test/compile-fail/if-let-arm-types.rs +++ b/src/test/compile-fail/if-let-arm-types.rs @@ -12,7 +12,7 @@ fn main() { if let Some(b) = None { //~ ERROR: `if let` arms have incompatible types //~^ expected (), found integral variable //~| expected type `()` - //~| found type `_` + //~| found type `{integer}` () } else { //~ NOTE: `if let` arm with an incompatible type 1 diff --git a/src/test/compile-fail/ifmt-bad-arg.rs b/src/test/compile-fail/ifmt-bad-arg.rs index 272ad980feb4..59c61a42e077 100644 --- a/src/test/compile-fail/ifmt-bad-arg.rs +++ b/src/test/compile-fail/ifmt-bad-arg.rs @@ -41,6 +41,12 @@ fn main() { //~^ ERROR invalid reference to argument `0` (no arguments given) //~^^ ERROR invalid reference to argument `1` (no arguments given) + // bad named arguments, #35082 + + format!("{valuea} {valueb}", valuea=5, valuec=7); + //~^ ERROR there is no argument named `valueb` + //~^^ ERROR named argument never used + // bad syntax of the format string format!("{"); //~ ERROR: expected `'}'` but string was terminated diff --git a/src/test/compile-fail/indexing-requires-a-uint.rs b/src/test/compile-fail/indexing-requires-a-uint.rs index 354d7b936485..61d54b3f8e4f 100644 --- a/src/test/compile-fail/indexing-requires-a-uint.rs +++ b/src/test/compile-fail/indexing-requires-a-uint.rs @@ -13,7 +13,7 @@ fn main() { fn bar(_: T) {} - [0][0u8]; //~ ERROR: `[_]: std::ops::Index` is not satisfied + [0][0u8]; //~ ERROR: `[{integer}]: std::ops::Index` is not satisfied [0][0]; // should infer to be a usize diff --git a/src/test/compile-fail/integral-variable-unification-error.rs b/src/test/compile-fail/integral-variable-unification-error.rs index 99f2d2516689..f2686ae4d196 100644 --- a/src/test/compile-fail/integral-variable-unification-error.rs +++ b/src/test/compile-fail/integral-variable-unification-error.rs @@ -12,7 +12,7 @@ fn main() { let mut x = 2; x = 5.0; //~^ ERROR mismatched types - //~| expected type `_` - //~| found type `_` + //~| expected type `{integer}` + //~| found type `{float}` //~| expected integral variable, found floating-point variable } diff --git a/src/test/compile-fail/invalid-path-in-const.rs b/src/test/compile-fail/invalid-path-in-const.rs index 3c4ad5a56ec3..9a9358b787f5 100644 --- a/src/test/compile-fail/invalid-path-in-const.rs +++ b/src/test/compile-fail/invalid-path-in-const.rs @@ -10,5 +10,6 @@ fn main() { fn f(a: [u8; u32::DOESNOTEXIST]) {} - //~^ ERROR unresolved path in constant expression + //~^ ERROR constant evaluation error + //~| unresolved path in constant expression } diff --git a/src/test/compile-fail/issue-13033.rs b/src/test/compile-fail/issue-13033.rs index 43cf70e5bc3c..3d9d81471cb1 100644 --- a/src/test/compile-fail/issue-13033.rs +++ b/src/test/compile-fail/issue-13033.rs @@ -16,7 +16,9 @@ struct Baz; impl Foo for Baz { fn bar(&mut self, other: &Foo) {} - //~^ ERROR method `bar` has an incompatible type for trait: values differ in mutability [E0053] + //~^ ERROR method `bar` has an incompatible type for trait + //~| expected type `fn(&mut Baz, &mut Foo)` + //~| found type `fn(&mut Baz, &Foo)` } fn main() {} diff --git a/src/test/compile-fail/issue-13466.rs b/src/test/compile-fail/issue-13466.rs index 17b96411603e..abddf6ba7a38 100644 --- a/src/test/compile-fail/issue-13466.rs +++ b/src/test/compile-fail/issue-13466.rs @@ -17,13 +17,13 @@ pub fn main() { let _x: usize = match Some(1) { Ok(u) => u, //~^ ERROR mismatched types - //~| expected type `std::option::Option<_>` + //~| expected type `std::option::Option<{integer}>` //~| found type `std::result::Result<_, _>` //~| expected enum `std::option::Option`, found enum `std::result::Result` Err(e) => panic!(e) //~^ ERROR mismatched types - //~| expected type `std::option::Option<_>` + //~| expected type `std::option::Option<{integer}>` //~| found type `std::result::Result<_, _>` //~| expected enum `std::option::Option`, found enum `std::result::Result` }; diff --git a/src/test/compile-fail/issue-15094.rs b/src/test/compile-fail/issue-15094.rs index 42e3456b309b..da48bbb3ecd7 100644 --- a/src/test/compile-fail/issue-15094.rs +++ b/src/test/compile-fail/issue-15094.rs @@ -20,8 +20,8 @@ impl ops::FnOnce<(),> for Debuger { type Output = (); fn call_once(self, _args: ()) { //~^ ERROR `call_once` has an incompatible type for trait - //~| expected "rust-call" fn, - //~| found "Rust" fn + //~| expected type `extern "rust-call" fn + //~| found type `fn println!("{:?}", self.x); } } diff --git a/src/test/compile-fail/issue-16939.rs b/src/test/compile-fail/issue-16939.rs index 7ec3fef5c878..e16c58b8a6c1 100644 --- a/src/test/compile-fail/issue-16939.rs +++ b/src/test/compile-fail/issue-16939.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(overloaded_calls, unboxed_closures)] - // Make sure we don't ICE when making an overloaded call with the // wrong arity. diff --git a/src/test/compile-fail/issue-17033.rs b/src/test/compile-fail/issue-17033.rs index f0fe01b41597..0ec05b941a96 100644 --- a/src/test/compile-fail/issue-17033.rs +++ b/src/test/compile-fail/issue-17033.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(overloaded_calls)] - fn f<'r>(p: &'r mut fn(p: &mut ())) { (*p)(()) //~ ERROR mismatched types //~| expected type `&mut ()` diff --git a/src/test/compile-fail/issue-17545.rs b/src/test/compile-fail/issue-17545.rs index 84800218efc9..49435f83ce3c 100644 --- a/src/test/compile-fail/issue-17545.rs +++ b/src/test/compile-fail/issue-17545.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - pub fn foo<'a, F: Fn(&'a ())>(bar: F) { bar.call(( &(), //~ ERROR borrowed value does not live long enough diff --git a/src/test/compile-fail/issue-17551.rs b/src/test/compile-fail/issue-17551.rs index 5781cb741174..5e69553d3a48 100644 --- a/src/test/compile-fail/issue-17551.rs +++ b/src/test/compile-fail/issue-17551.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::marker; struct B(marker::PhantomData); diff --git a/src/test/compile-fail/issue-17651.rs b/src/test/compile-fail/issue-17651.rs index 0fe01ece558e..3ea136aca4be 100644 --- a/src/test/compile-fail/issue-17651.rs +++ b/src/test/compile-fail/issue-17651.rs @@ -14,5 +14,5 @@ fn main() { // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. (|| Box::new(*(&[0][..])))(); - //~^ ERROR `[_]: std::marker::Sized` is not satisfied + //~^ ERROR `[{integer}]: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/issue-17740.rs b/src/test/compile-fail/issue-17740.rs index 6b9294b2038f..664d62e87ae6 100644 --- a/src/test/compile-fail/issue-17740.rs +++ b/src/test/compile-fail/issue-17740.rs @@ -14,11 +14,11 @@ struct Foo<'a> { impl <'a> Foo<'a>{ fn bar(self: &mut Foo) { - //~^ mismatched types + //~^ mismatched method receiver //~| expected type `&mut Foo<'a>` //~| found type `&mut Foo<'_>` //~| lifetime mismatch - //~| mismatched types + //~| mismatched method receiver //~| expected type `&mut Foo<'a>` //~| found type `&mut Foo<'_>` //~| lifetime mismatch diff --git a/src/test/compile-fail/issue-18532.rs b/src/test/compile-fail/issue-18532.rs index 9cf922ae9900..94eab97c42a1 100644 --- a/src/test/compile-fail/issue-18532.rs +++ b/src/test/compile-fail/issue-18532.rs @@ -12,8 +12,6 @@ // when a type error or unconstrained type variable propagates // into it. -#![feature(unboxed_closures)] - fn main() { (return)((),()); //~^ ERROR the type of this value must be known diff --git a/src/test/compile-fail/issue-18819.rs b/src/test/compile-fail/issue-18819.rs index 3591b9824145..cf650460c3de 100644 --- a/src/test/compile-fail/issue-18819.rs +++ b/src/test/compile-fail/issue-18819.rs @@ -23,6 +23,8 @@ fn print_x(_: &Foo, extra: &str) { } fn main() { - print_x(X); //~error this function takes 2 parameters but 1 parameter was supplied - //~^ NOTE the following parameter types were expected: &Foo, &str + print_x(X); + //~^ ERROR this function takes 2 parameters but 1 parameter was supplied + //~| NOTE the following parameter types were expected: &Foo, &str + //~| NOTE expected 2 parameters } diff --git a/src/test/compile-fail/issue-19521.rs b/src/test/compile-fail/issue-19521.rs index 58a95e9da2bf..93d95ca0b0f9 100644 --- a/src/test/compile-fail/issue-19521.rs +++ b/src/test/compile-fail/issue-19521.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - fn main() { "".homura()(); //~ ERROR no method named `homura` found } diff --git a/src/test/compile-fail/issue-19707.rs b/src/test/compile-fail/issue-19707.rs index 9affb44b7445..beeb7da6d389 100644 --- a/src/test/compile-fail/issue-19707.rs +++ b/src/test/compile-fail/issue-19707.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] #![allow(dead_code)] type foo = fn(&u8, &u8) -> &u8; //~ ERROR missing lifetime specifier diff --git a/src/test/compile-fail/issue-19991.rs b/src/test/compile-fail/issue-19991.rs index b368daaaf587..e07dfaf9fe59 100644 --- a/src/test/compile-fail/issue-19991.rs +++ b/src/test/compile-fail/issue-19991.rs @@ -14,7 +14,7 @@ fn main() { if let Some(homura) = Some("madoka") { //~ ERROR missing an else clause //~| expected type `()` - //~| found type `_` + //~| found type `{integer}` //~| expected (), found integral variable 765 }; diff --git a/src/test/compile-fail/issue-21332.rs b/src/test/compile-fail/issue-21332.rs index b36918149fa9..db3334834d44 100644 --- a/src/test/compile-fail/issue-21332.rs +++ b/src/test/compile-fail/issue-21332.rs @@ -14,8 +14,7 @@ impl Iterator for S { type Item = i32; fn next(&mut self) -> Result { Ok(7) } //~^ ERROR method `next` has an incompatible type for trait - //~| expected enum `std::option::Option` - //~| found enum `std::result::Result` [E0053] + //~| expected enum `std::option::Option`, found enum `std::result::Result` } fn main() {} diff --git a/src/test/compile-fail/issue-22933-2.rs b/src/test/compile-fail/issue-22933-2.rs index 7d619c270d32..54a240893546 100644 --- a/src/test/compile-fail/issue-22933-2.rs +++ b/src/test/compile-fail/issue-22933-2.rs @@ -12,10 +12,12 @@ enum Delicious { Pie = 0x1, Apple = 0x2, ApplePie = Delicious::Apple as isize | Delicious::PIE as isize, - //~^ ERROR constant evaluation error: unresolved path in constant expression + //~^ ERROR constant evaluation error + //~| unresolved path in constant expression } const FOO: [u32; u8::MIN as usize] = []; -//~^ ERROR array length constant evaluation error: unresolved path in constant expression +//~^ ERROR constant evaluation error +//~| unresolved path in constant expression fn main() {} diff --git a/src/test/compile-fail/issue-23217.rs b/src/test/compile-fail/issue-23217.rs index 32cdd6b5ed9f..c2bcbb9d54a9 100644 --- a/src/test/compile-fail/issue-23217.rs +++ b/src/test/compile-fail/issue-23217.rs @@ -10,7 +10,8 @@ pub enum SomeEnum { B = SomeEnum::A, - //~^ ERROR constant evaluation error: unresolved path in constant expression + //~^ ERROR constant evaluation error + //~| unresolved path in constant expression } fn main() {} diff --git a/src/test/compile-fail/issue-24356.rs b/src/test/compile-fail/issue-24356.rs index 27d46be40fbe..ede81bea32ae 100644 --- a/src/test/compile-fail/issue-24356.rs +++ b/src/test/compile-fail/issue-24356.rs @@ -30,9 +30,6 @@ fn main() { impl Deref for Thing { //~^ ERROR not all trait items implemented, missing: `Target` [E0046] fn deref(&self) -> i8 { self.0 } - //~^ ERROR method `deref` has an incompatible type for trait - //~| expected &-ptr - //~| found i8 [E0053] } let thing = Thing(72); diff --git a/src/test/compile-fail/issue-25145.rs b/src/test/compile-fail/issue-25145.rs index e8a9c8d2ea34..93f75e9bfed0 100644 --- a/src/test/compile-fail/issue-25145.rs +++ b/src/test/compile-fail/issue-25145.rs @@ -17,6 +17,7 @@ impl S { } static STUFF: [u8; S::N] = [0; S::N]; -//~^ ERROR array length constant evaluation error: unresolved path in constant expression +//~^ ERROR constant evaluation error +//~| unresolved path in constant expression fn main() {} diff --git a/src/test/compile-fail/issue-26237.rs b/src/test/compile-fail/issue-26237.rs index 11e236d22126..22772e596b19 100644 --- a/src/test/compile-fail/issue-26237.rs +++ b/src/test/compile-fail/issue-26237.rs @@ -11,7 +11,7 @@ macro_rules! macro_panic { ($not_a_function:expr, $some_argument:ident) => { $not_a_function($some_argument) - //~^ ERROR expected function, found `_` + //~^ ERROR expected function, found `{integer}` } } diff --git a/src/test/compile-fail/issue-27008.rs b/src/test/compile-fail/issue-27008.rs index bdcbaf09177f..ee6ec5276126 100644 --- a/src/test/compile-fail/issue-27008.rs +++ b/src/test/compile-fail/issue-27008.rs @@ -16,5 +16,5 @@ fn main() { //~| expected type `usize` //~| found type `S` //~| expected usize, found struct `S` - //~| ERROR expected positive integer for repeat count, found struct + //~| ERROR expected usize for repeat count, found struct } diff --git a/src/test/compile-fail/issue-27895.rs b/src/test/compile-fail/issue-27895.rs index 3b3abc94a490..ca8d5a1f7047 100644 --- a/src/test/compile-fail/issue-27895.rs +++ b/src/test/compile-fail/issue-27895.rs @@ -14,7 +14,8 @@ fn main() { match i { 0...index => println!("winner"), - //~^ ERROR non-constant path in constant expression + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression _ => println!("hello"), } } diff --git a/src/test/compile-fail/issue-28568.rs b/src/test/compile-fail/issue-28568.rs index 7c051784f61a..f03daafc6375 100644 --- a/src/test/compile-fail/issue-28568.rs +++ b/src/test/compile-fail/issue-28568.rs @@ -11,12 +11,13 @@ struct MyStruct; impl Drop for MyStruct { -//~^ NOTE conflicting implementation is here +//~^ NOTE first implementation here fn drop(&mut self) { } } impl Drop for MyStruct { //~^ ERROR conflicting implementations of trait +//~| NOTE conflicting implementation for `MyStruct` fn drop(&mut self) { } } diff --git a/src/test/compile-fail/issue-28586.rs b/src/test/compile-fail/issue-28586.rs index c8a1e424da2e..1dfd146985ff 100644 --- a/src/test/compile-fail/issue-28586.rs +++ b/src/test/compile-fail/issue-28586.rs @@ -11,6 +11,6 @@ // Regression test for issue #28586 pub trait Foo {} -impl Foo for [u8; usize::BYTES] {} //~ ERROR E0250 +impl Foo for [u8; usize::BYTES] {} //~ ERROR E0080 fn main() { } diff --git a/src/test/compile-fail/issue-3044.rs b/src/test/compile-fail/issue-3044.rs index 68046056fb31..d19e3b2c7b0a 100644 --- a/src/test/compile-fail/issue-3044.rs +++ b/src/test/compile-fail/issue-3044.rs @@ -14,7 +14,7 @@ fn main() { needlesArr.iter().fold(|x, y| { }); //~^^ ERROR this function takes 2 parameters but 1 parameter was supplied - //~^^^ NOTE the following parameter types were expected - // + //~| NOTE the following parameter types were expected + //~| NOTE expected 2 parameters // the first error is, um, non-ideal. } diff --git a/src/test/compile-fail/issue-31173.rs b/src/test/compile-fail/issue-31173.rs new file mode 100644 index 000000000000..fb1e3cc87e88 --- /dev/null +++ b/src/test/compile-fail/issue-31173.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::vec::IntoIter; + +pub fn get_tok(it: &mut IntoIter) { + let mut found_e = false; + + let temp: Vec = it.take_while(|&x| { + found_e = true; + false + }) + .cloned() + //~^ ERROR type mismatch resolving + //~| expected type `u8` + //~| found type `&_` + .collect(); //~ ERROR no method named `collect` +} + +fn main() {} diff --git a/src/test/compile-fail/issue-31221.rs b/src/test/compile-fail/issue-31221.rs index 2b3df9ad1d83..4997a6fee195 100644 --- a/src/test/compile-fail/issue-31221.rs +++ b/src/test/compile-fail/issue-31221.rs @@ -22,6 +22,7 @@ fn main() { //~^ NOTE this pattern matches any value Var2 => (), //~^ ERROR unreachable pattern + //~^^ NOTE this is an unreachable pattern }; match &s { &Var1 => (), @@ -29,6 +30,7 @@ fn main() { //~^ NOTE this pattern matches any value &Var2 => (), //~^ ERROR unreachable pattern + //~^^ NOTE this is an unreachable pattern }; let t = (Var1, Var1); match t { @@ -37,6 +39,7 @@ fn main() { //~^ NOTE this pattern matches any value anything => () //~^ ERROR unreachable pattern + //~^^ NOTE this is an unreachable pattern }; // `_` need not emit a note, it is pretty obvious already. let t = (Var1, Var1); @@ -45,5 +48,6 @@ fn main() { _ => (), anything => () //~^ ERROR unreachable pattern + //~^^ NOTE this is an unreachable pattern }; } diff --git a/src/test/compile-fail/issue-34349.rs b/src/test/compile-fail/issue-34349.rs new file mode 100644 index 000000000000..591753181db1 --- /dev/null +++ b/src/test/compile-fail/issue-34349.rs @@ -0,0 +1,32 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is a regression test for a problem encountered around upvar +// inference and trait caching: in particular, we were entering a +// temporary closure kind during inference, and then caching results +// based on that temporary kind, which led to no error being reported +// in this particular test. + +fn main() { + let inc = || {}; + inc(); + + fn apply(f: F) where F: Fn() { + f() + } + + let mut farewell = "goodbye".to_owned(); + let diary = || { //~ ERROR E0525 + farewell.push_str("!!!"); + println!("Then I screamed {}.", farewell); + }; + + apply(diary); +} diff --git a/src/test/compile-fail/issue-35075.rs b/src/test/compile-fail/issue-35075.rs new file mode 100644 index 000000000000..a70452dcbd09 --- /dev/null +++ b/src/test/compile-fail/issue-35075.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Bar { + inner: Foo //~ ERROR type name `Foo` is undefined or not in scope +} + +enum Baz { + Foo(Foo) //~ ERROR type name `Foo` is undefined or not in scope +} + +fn main() {} diff --git a/src/test/compile-fail/issue-35139.rs b/src/test/compile-fail/issue-35139.rs new file mode 100644 index 000000000000..67f0e7aaf971 --- /dev/null +++ b/src/test/compile-fail/issue-35139.rs @@ -0,0 +1,36 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; + +pub trait MethodType { + type GetProp: ?Sized; +} + +pub struct MTFn; + +impl<'a> MethodType for MTFn { //~ ERROR E0207 + type GetProp = fmt::Debug + 'a; +} + +fn bad(a: Box<::GetProp>) -> Box { + a +} + +fn dangling(a: &str) -> Box { + bad(Box::new(a)) +} + +fn main() { + let mut s = "hello".to_string(); + let x = dangling(&s); + s = String::new(); + println!("{:?}", x); +} diff --git a/src/test/compile-fail/issue-3521.rs b/src/test/compile-fail/issue-3521.rs index 52375ef281ac..1b6e4b1d289e 100644 --- a/src/test/compile-fail/issue-3521.rs +++ b/src/test/compile-fail/issue-3521.rs @@ -15,7 +15,8 @@ fn main() { enum Stuff { Bar = foo //~^ ERROR attempt to use a non-constant value in a constant - //~^^ ERROR constant evaluation error: non-constant path in constant expression + //~^^ ERROR constant evaluation error + //~| non-constant path in constant expression } println!("{}", Stuff::Bar); diff --git a/src/test/compile-fail/issue-3907.rs b/src/test/compile-fail/issue-3907.rs index c99ff1813e0d..93556577ad34 100644 --- a/src/test/compile-fail/issue-3907.rs +++ b/src/test/compile-fail/issue-3907.rs @@ -11,14 +11,15 @@ // aux-build:issue_3907.rs extern crate issue_3907; -type Foo = issue_3907::Foo; //~ NOTE: type aliases cannot be used for traits +type Foo = issue_3907::Foo; struct S { name: isize } impl Foo for S { //~ ERROR: `Foo` is not a trait - //~| `Foo` is not a trait + //~| NOTE: not a trait + //~| NOTE: type aliases cannot be used for traits fn bar() { } } diff --git a/src/test/compile-fail/issue-4201.rs b/src/test/compile-fail/issue-4201.rs index 58423341cc6f..b1f668d9c5e2 100644 --- a/src/test/compile-fail/issue-4201.rs +++ b/src/test/compile-fail/issue-4201.rs @@ -14,7 +14,7 @@ fn main() { } else if false { //~^ ERROR if may be missing an else clause //~| expected type `()` -//~| found type `_` +//~| found type `{integer}` //~| expected (), found integral variable 1 }; diff --git a/src/test/compile-fail/issue-4335.rs b/src/test/compile-fail/issue-4335.rs index 0089bff3e8fd..9a1b5d9b83d2 100644 --- a/src/test/compile-fail/issue-4335.rs +++ b/src/test/compile-fail/issue-4335.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - fn id(t: T) -> T { t } fn f<'r, T>(v: &'r T) -> Box T + 'r> { diff --git a/src/test/compile-fail/issue-4935.rs b/src/test/compile-fail/issue-4935.rs index 438d238b6fe6..58a84f3490b3 100644 --- a/src/test/compile-fail/issue-4935.rs +++ b/src/test/compile-fail/issue-4935.rs @@ -11,5 +11,7 @@ // Regression test for issue #4935 fn foo(a: usize) {} -fn main() { foo(5, 6) } //~ ERROR this function takes 1 parameter but 2 parameters were supplied -//~^ NOTE the following parameter type was expected +fn main() { foo(5, 6) } +//~^ ERROR this function takes 1 parameter but 2 parameters were supplied +//~| NOTE the following parameter type was expected +//~| NOTE expected 1 parameter diff --git a/src/test/compile-fail/issue-4968.rs b/src/test/compile-fail/issue-4968.rs index 7c0905873df8..77588e5c221f 100644 --- a/src/test/compile-fail/issue-4968.rs +++ b/src/test/compile-fail/issue-4968.rs @@ -14,7 +14,7 @@ const A: (isize,isize) = (4,2); fn main() { match 42 { A => () } //~^ ERROR mismatched types - //~| expected type `_` + //~| expected type `{integer}` //~| found type `(isize, isize)` //~| expected integral variable, found tuple } diff --git a/src/test/compile-fail/issue-5035.rs b/src/test/compile-fail/issue-5035.rs index a186a399a112..c2154e8a6c0b 100644 --- a/src/test/compile-fail/issue-5035.rs +++ b/src/test/compile-fail/issue-5035.rs @@ -10,7 +10,11 @@ trait I {} type K = I; -//~^ NOTE: aliases cannot be used for traits impl K for isize {} //~ ERROR: `K` is not a trait -//~| is not a trait + //~| NOTE: not a trait + //~| NOTE: aliases cannot be used for traits + +use ImportError; //~ ERROR unresolved +impl ImportError for () {} // check that this is not an additional error (c.f. #35142) + fn main() {} diff --git a/src/test/compile-fail/issue-5239-1.rs b/src/test/compile-fail/issue-5239-1.rs index 1ebef06008ff..06e3c9a207b7 100644 --- a/src/test/compile-fail/issue-5239-1.rs +++ b/src/test/compile-fail/issue-5239-1.rs @@ -13,4 +13,5 @@ fn main() { let x = |ref x: isize| -> isize { x += 1; }; //~^ ERROR E0368 + //~| NOTE cannot use `+=` on type `&isize` } diff --git a/src/test/compile-fail/issue-7867.rs b/src/test/compile-fail/issue-7867.rs index e0de860b0eac..ed465117344d 100644 --- a/src/test/compile-fail/issue-7867.rs +++ b/src/test/compile-fail/issue-7867.rs @@ -25,12 +25,12 @@ fn main() { match &Some(42) { Some(x) => (), //~^ ERROR mismatched types - //~| expected type `&std::option::Option<_>` + //~| expected type `&std::option::Option<{integer}>` //~| found type `std::option::Option<_>` //~| expected &-ptr, found enum `std::option::Option` None => () //~^ ERROR mismatched types - //~| expected type `&std::option::Option<_>` + //~| expected type `&std::option::Option<{integer}>` //~| found type `std::option::Option<_>` //~| expected &-ptr, found enum `std::option::Option` } diff --git a/src/test/compile-fail/issue-8460-const.rs b/src/test/compile-fail/issue-8460-const.rs index fe51d0b69987..d8ab48d1ec3e 100644 --- a/src/test/compile-fail/issue-8460-const.rs +++ b/src/test/compile-fail/issue-8460-const.rs @@ -15,43 +15,43 @@ use std::thread; fn main() { assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow + //~^ ERROR attempt to divide with overflow assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow + //~^ ERROR attempt to divide with overflow assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow + //~^ ERROR attempt to divide with overflow assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow + //~^ ERROR attempt to divide with overflow assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - //~^ ERROR attempted to divide with overflow + //~^ ERROR attempt to divide with overflow assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero + //~^ ERROR attempt to divide by zero assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero + //~^ ERROR attempt to divide by zero assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero + //~^ ERROR attempt to divide by zero assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero + //~^ ERROR attempt to divide by zero assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - //~^ ERROR attempted to divide by zero + //~^ ERROR attempt to divide by zero assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with overflow + //~^ ERROR attempt to calculate the remainder with overflow assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with overflow + //~^ ERROR attempt to calculate the remainder with overflow assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with overflow + //~^ ERROR attempt to calculate the remainder with overflow assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with overflow + //~^ ERROR attempt to calculate the remainder with overflow assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with overflow + //~^ ERROR attempt to calculate the remainder with overflow assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with a divisor of zero + //~^ ERROR attempt to calculate the remainder with a divisor of zero assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with a divisor of zero + //~^ ERROR attempt to calculate the remainder with a divisor of zero assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with a divisor of zero + //~^ ERROR attempt to calculate the remainder with a divisor of zero assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with a divisor of zero + //~^ ERROR attempt to calculate the remainder with a divisor of zero assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - //~^ ERROR attempted to calculate the remainder with a divisor of zero + //~^ ERROR attempt to calculate the remainder with a divisor of zero } diff --git a/src/test/compile-fail/issue-8761.rs b/src/test/compile-fail/issue-8761.rs index 1c98abce0304..91a07dd9ba6d 100644 --- a/src/test/compile-fail/issue-8761.rs +++ b/src/test/compile-fail/issue-8761.rs @@ -10,13 +10,11 @@ enum Foo { A = 1i64, - //~^ ERROR mismatched types: - //~| expected `isize`, - //~| found `i64` [E0080] + //~^ ERROR constant evaluation error + //~| expected isize, found i64 B = 2u8 - //~^ ERROR mismatched types: - //~| expected `isize`, - //~| found `u8` [E0080] + //~^ ERROR constant evaluation error + //~| expected isize, found u8 } fn main() {} diff --git a/src/test/compile-fail/kindck-impl-type-params-2.rs b/src/test/compile-fail/kindck-impl-type-params-2.rs index 1cf970e150d7..a455a7b2d5d0 100644 --- a/src/test/compile-fail/kindck-impl-type-params-2.rs +++ b/src/test/compile-fail/kindck-impl-type-params-2.rs @@ -21,5 +21,5 @@ fn take_param(foo: &T) { } fn main() { let x: Box<_> = box 3; take_param(&x); - //~^ ERROR `Box<_>: std::marker::Copy` is not satisfied + //~^ ERROR `Box<{integer}>: std::marker::Copy` is not satisfied } diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs index e34a3c4569d0..6da87fca3f35 100644 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs +++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs @@ -49,7 +49,8 @@ struct Baz<'x> { impl<'a> Baz<'a> { fn baz2<'b>(&self, x: &isize) -> (&'b isize, &'b isize) { - //~^ HELP consider using an explicit lifetime parameter as shown: fn baz2<'b>(&self, x: &'a isize) -> (&'a isize, &'a isize) + //~^ HELP consider using an explicit lifetime parameter as shown: fn baz2<'b>(&self, x: &' + // FIXME #35038: The above suggestion is different on Linux and Mac. (self.bar, x) //~ ERROR E0312 //~^ ERROR E0312 } diff --git a/src/test/compile-fail/lint-exceeding-bitshifts.rs b/src/test/compile-fail/lint-exceeding-bitshifts.rs index 6d5abc944e78..3e51550d1fa0 100644 --- a/src/test/compile-fail/lint-exceeding-bitshifts.rs +++ b/src/test/compile-fail/lint-exceeding-bitshifts.rs @@ -53,7 +53,7 @@ fn main() { let n = n << 8; //~ ERROR: bitshift exceeds the type's number of bits let n = 1u8 << -8; //~ ERROR: bitshift exceeds the type's number of bits - //~^ WARN: attempted to shift by a negative amount + //~^ WARN: attempt to shift by a negative amount let n = 1u8 << (4+3); let n = 1u8 << (4+4); //~ ERROR: bitshift exceeds the type's number of bits diff --git a/src/test/compile-fail/lint-forbid-attr.rs b/src/test/compile-fail/lint-forbid-attr.rs index fcc8fb6f933b..fd2513c5a066 100644 --- a/src/test/compile-fail/lint-forbid-attr.rs +++ b/src/test/compile-fail/lint-forbid-attr.rs @@ -9,6 +9,7 @@ // except according to those terms. #![forbid(deprecated)] +//~^ NOTE `forbid` lint level set here #[allow(deprecated)] //~ ERROR allow(deprecated) overruled by outer forbid(deprecated) fn main() { diff --git a/src/test/compile-fail/lint-type-overflow2.rs b/src/test/compile-fail/lint-type-overflow2.rs index e99dfb9aa0f0..a2971f23a79e 100644 --- a/src/test/compile-fail/lint-type-overflow2.rs +++ b/src/test/compile-fail/lint-type-overflow2.rs @@ -15,7 +15,7 @@ #[allow(unused_variables)] fn main() { let x2: i8 = --128; //~ error: literal out of range for i8 - //~^ error: attempted to negate with overflow + //~^ error: attempt to negate with overflow let x = -3.40282348e+38_f32; //~ error: literal out of range for f32 let x = 3.40282348e+38_f32; //~ error: literal out of range for f32 diff --git a/src/test/compile-fail/macro-tt-matchers.rs b/src/test/compile-fail/macro-tt-matchers.rs new file mode 100644 index 000000000000..f41da77ee989 --- /dev/null +++ b/src/test/compile-fail/macro-tt-matchers.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] + +macro_rules! foo { + ($x:tt) => (type Alias = $x;) +} + +foo!(Box); + +#[rustc_error] +fn main() {} //~ ERROR compilation successful diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index 526aa83dec7f..f89b3e39390d 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -20,13 +20,14 @@ fn main() { 10 ... "what" => () }; //~^^ ERROR only char and numeric types are allowed in range - //~| start type: _ + //~| start type: {integer} //~| end type: &'static str match 5 { 'c' ... 100 => { } _ => { } }; - //~^^^ ERROR mismatched types in range - //~| expected char, found integral variable + //~^^^ ERROR mismatched types + //~| expected type `{integer}` + //~| found type `char` } diff --git a/src/test/compile-fail/match-vec-mismatch.rs b/src/test/compile-fail/match-vec-mismatch.rs index 3ac4958e7db0..596cec167c21 100644 --- a/src/test/compile-fail/match-vec-mismatch.rs +++ b/src/test/compile-fail/match-vec-mismatch.rs @@ -18,7 +18,7 @@ fn main() { }; match &[0, 1, 2] { - [..] => {} //~ ERROR expected an array or slice, found `&[_; 3]` + [..] => {} //~ ERROR expected an array or slice, found `&[{integer}; 3]` }; match &[0, 1, 2] { diff --git a/src/test/compile-fail/method-call-err-msg.rs b/src/test/compile-fail/method-call-err-msg.rs index 212c09364cf4..bcf676dbede6 100644 --- a/src/test/compile-fail/method-call-err-msg.rs +++ b/src/test/compile-fail/method-call-err-msg.rs @@ -20,10 +20,13 @@ impl Foo { fn main() { let x = Foo; x.zero(0) //~ ERROR this function takes 0 parameters but 1 parameter was supplied + //~^ NOTE expected 0 parameters .one() //~ ERROR this function takes 1 parameter but 0 parameters were supplied //~^ NOTE the following parameter type was expected + //~| NOTE expected 1 parameter .two(0); //~ ERROR this function takes 2 parameters but 1 parameter was supplied //~^ NOTE the following parameter types were expected + //~| NOTE expected 2 parameters let y = Foo; y.zero() diff --git a/src/test/compile-fail/method-self-arg-1.rs b/src/test/compile-fail/method-self-arg-1.rs index ffa5287d4b2c..03816362d46c 100644 --- a/src/test/compile-fail/method-self-arg-1.rs +++ b/src/test/compile-fail/method-self-arg-1.rs @@ -24,6 +24,6 @@ fn main() { //~| expected &-ptr, found struct `Foo` Foo::bar(&42); //~ ERROR mismatched types //~| expected type `&Foo` - //~| found type `&_` + //~| found type `&{integer}` //~| expected struct `Foo`, found integral variable } diff --git a/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs b/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs index 5af326b42984..df9a3519d5d6 100644 --- a/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs +++ b/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs @@ -12,8 +12,6 @@ // bound must be noncopyable. For details see // http://smallcultfollowing.com/babysteps/blog/2013/04/30/the-case-of-the-recurring-closure/ -#![feature(unboxed_closures)] - struct R<'a> { // This struct is needed to create the // otherwise infinite type of a fn that diff --git a/src/test/compile-fail/mut-pattern-mismatched.rs b/src/test/compile-fail/mut-pattern-mismatched.rs index 63e7dbd30def..318d121e4c2d 100644 --- a/src/test/compile-fail/mut-pattern-mismatched.rs +++ b/src/test/compile-fail/mut-pattern-mismatched.rs @@ -14,7 +14,7 @@ fn main() { // (separate lines to ensure the spans are accurate) let &_ //~ ERROR mismatched types - //~| expected type `&mut _` + //~| expected type `&mut {integer}` //~| found type `&_` //~| values differ in mutability = foo; @@ -23,7 +23,7 @@ fn main() { let bar = &1; let &_ = bar; let &mut _ //~ ERROR mismatched types - //~| expected type `&_` + //~| expected type `&{integer}` //~| found type `&mut _` //~| values differ in mutability = bar; diff --git a/src/test/compile-fail/no-patterns-in-args.rs b/src/test/compile-fail/no-patterns-in-args.rs new file mode 100644 index 000000000000..3edbdf4ebc95 --- /dev/null +++ b/src/test/compile-fail/no-patterns-in-args.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern { + fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in foreign function declarations + //~^ NOTE this is a recent error + fn f2(&arg: u8); //~ ERROR patterns aren't allowed in foreign function declarations + fn f3(arg @ _: u8); //~ ERROR patterns aren't allowed in foreign function declarations + //~^ NOTE this is a recent error + fn g1(arg: u8); // OK + fn g2(_: u8); // OK + // fn g3(u8); // Not yet +} + +type A1 = fn(mut arg: u8); //~ ERROR patterns aren't allowed in function pointer types + //~^ NOTE this is a recent error +type A2 = fn(&arg: u8); //~ ERROR patterns aren't allowed in function pointer types + //~^ NOTE this is a recent error +type B1 = fn(arg: u8); // OK +type B2 = fn(_: u8); // OK +type B3 = fn(u8); // OK + +fn main() {} diff --git a/src/test/compile-fail/no_send-rc.rs b/src/test/compile-fail/no_send-rc.rs index 69f6fcdc4afa..f31d37873349 100644 --- a/src/test/compile-fail/no_send-rc.rs +++ b/src/test/compile-fail/no_send-rc.rs @@ -15,5 +15,5 @@ fn bar(_: T) {} fn main() { let x = Rc::new(5); bar(x); - //~^ ERROR `std::rc::Rc<_>: std::marker::Send` is not satisfied + //~^ ERROR `std::rc::Rc<{integer}>: std::marker::Send` is not satisfied } diff --git a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs index 9564a080b8ee..cadfec5a38d3 100644 --- a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs +++ b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs @@ -15,5 +15,6 @@ enum State { ST_NULL, ST_WHITESPACE } fn main() { [State::ST_NULL; (State::ST_WHITESPACE as usize)]; - //~^ ERROR expected constant integer for repeat count, but unimplemented constant expression + //~^ ERROR constant evaluation error + //~| unimplemented constant expression: enum variants } diff --git a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs index 3ce206ff7fb2..a6f88a57b912 100644 --- a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs +++ b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs @@ -13,6 +13,8 @@ fn main() { fn bar(n: usize) { let _x = [0; n]; - //~^ ERROR expected constant integer for repeat count, found variable + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression + //~| NOTE `n` is a variable } } diff --git a/src/test/compile-fail/non-constant-in-const-path.rs b/src/test/compile-fail/non-constant-in-const-path.rs index ee88168515d3..737f80372deb 100644 --- a/src/test/compile-fail/non-constant-in-const-path.rs +++ b/src/test/compile-fail/non-constant-in-const-path.rs @@ -12,6 +12,7 @@ fn main() { let x = 0; match 1 { 0 ... x => {} - //~^ ERROR non-constant path in constant expression + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression }; } diff --git a/src/test/compile-fail/not-enough-arguments.rs b/src/test/compile-fail/not-enough-arguments.rs index 1f5a54477dd6..f2f61fcaeec1 100644 --- a/src/test/compile-fail/not-enough-arguments.rs +++ b/src/test/compile-fail/not-enough-arguments.rs @@ -19,5 +19,6 @@ fn foo(a: isize, b: isize, c: isize, d:isize) { fn main() { foo(1, 2, 3); //~^ ERROR this function takes 4 parameters but 3 - //~^^ NOTE the following parameter types were expected + //~| NOTE the following parameter types were expected + //~| NOTE expected 4 parameters } diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs index 8763fb0913a8..5865d93e1282 100644 --- a/src/test/compile-fail/overloaded-calls-bad.rs +++ b/src/test/compile-fail/overloaded-calls-bad.rs @@ -42,7 +42,9 @@ fn main() { let ans = s(); //~^ ERROR this function takes 1 parameter but 0 parameters were supplied //~| NOTE the following parameter type was expected + //~| NOTE expected 1 parameter let ans = s("burma", "shave"); //~^ ERROR this function takes 1 parameter but 2 parameters were supplied //~| NOTE the following parameter type was expected + //~| NOTE expected 1 parameter } diff --git a/src/test/compile-fail/privacy-ns2.rs b/src/test/compile-fail/privacy-ns2.rs index bf296220d2a2..7accf0ca8201 100644 --- a/src/test/compile-fail/privacy-ns2.rs +++ b/src/test/compile-fail/privacy-ns2.rs @@ -25,15 +25,15 @@ pub mod foo1 { } fn test_single1() { - use foo1::Bar; //~ ERROR function `Bar` is private + use foo1::Bar; - Bar(); + Bar(); //~ ERROR unresolved name `Bar` } fn test_list1() { - use foo1::{Bar,Baz}; //~ ERROR `Bar` is private + use foo1::{Bar,Baz}; - Bar(); + Bar(); //~ ERROR unresolved name `Bar` } // private type, public value @@ -46,15 +46,15 @@ pub mod foo2 { } fn test_single2() { - use foo2::Bar; //~ ERROR trait `Bar` is private + use foo2::Bar; - let _x : Box; + let _x : Box; //~ ERROR type name `Bar` is undefined } fn test_list2() { - use foo2::{Bar,Baz}; //~ ERROR `Bar` is private + use foo2::{Bar,Baz}; - let _x: Box; + let _x: Box; //~ ERROR type name `Bar` is undefined } // neither public diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index c00be91a2d74..dc6833163a47 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -23,5 +23,5 @@ pub fn main() { // Unsized type. let arr: &[_] = &[1, 2, 3]; let range = *arr..; - //~^ ERROR `[_]: std::marker::Sized` is not satisfied + //~^ ERROR `[{integer}]: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs b/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs index 5db9a01c0128..8ec6036762f4 100644 --- a/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs +++ b/src/test/compile-fail/regionck-unboxed-closure-lifetimes.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures, overloaded_calls)] - use std::ops::FnMut; fn main() { diff --git a/src/test/compile-fail/regions-escape-unboxed-closure.rs b/src/test/compile-fail/regions-escape-unboxed-closure.rs index abbefd254888..cf41fad27083 100644 --- a/src/test/compile-fail/regions-escape-unboxed-closure.rs +++ b/src/test/compile-fail/regions-escape-unboxed-closure.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - fn with_int(f: &mut FnMut(&isize)) { } diff --git a/src/test/compile-fail/regions-return-ref-to-upvar-issue-17403.rs b/src/test/compile-fail/regions-return-ref-to-upvar-issue-17403.rs index 1e2224eafaeb..99e5cc031538 100644 --- a/src/test/compile-fail/regions-return-ref-to-upvar-issue-17403.rs +++ b/src/test/compile-fail/regions-return-ref-to-upvar-issue-17403.rs @@ -10,8 +10,6 @@ // Test that closures cannot subvert aliasing restrictions -#![feature(overloaded_calls, unboxed_closures)] - fn main() { // Unboxed closure case { diff --git a/src/test/compile-fail/regions-steal-closure.rs b/src/test/compile-fail/regions-steal-closure.rs index a30d8471a317..8ade8b239b3b 100644 --- a/src/test/compile-fail/regions-steal-closure.rs +++ b/src/test/compile-fail/regions-steal-closure.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - struct closure_box<'a> { cl: Box, } diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs index ab5af64d95c1..1758b28a3248 100644 --- a/src/test/compile-fail/repeat_count.rs +++ b/src/test/compile-fail/repeat_count.rs @@ -13,39 +13,38 @@ fn main() { let n = 1; let a = [0; n]; - //~^ ERROR expected constant integer for repeat count, found variable [E0307] + //~^ ERROR constant evaluation error + //~| non-constant path in constant expression let b = [0; ()]; //~^ ERROR mismatched types //~| expected type `usize` //~| found type `()` //~| expected usize, found () - //~| ERROR expected positive integer for repeat count, found tuple [E0306] + //~| ERROR expected usize for repeat count, found tuple [E0306] let c = [0; true]; //~^ ERROR mismatched types //~| expected usize, found bool - //~| ERROR expected positive integer for repeat count, found boolean [E0306] + //~| ERROR expected usize for repeat count, found boolean [E0306] let d = [0; 0.5]; //~^ ERROR mismatched types //~| expected type `usize` - //~| found type `_` + //~| found type `{float}` //~| expected usize, found floating-point variable - //~| ERROR expected positive integer for repeat count, found float [E0306] + //~| ERROR expected usize for repeat count, found float [E0306] let e = [0; "foo"]; //~^ ERROR mismatched types //~| expected type `usize` //~| found type `&'static str` //~| expected usize, found &-ptr - //~| ERROR expected positive integer for repeat count, found string literal [E0306] + //~| ERROR expected usize for repeat count, found string literal [E0306] let f = [0; -4_isize]; - //~^ ERROR mismatched types - //~| expected `usize` - //~| found `isize` - //~| ERROR mismatched types: + //~^ ERROR constant evaluation error + //~| expected usize, found isize + //~| ERROR mismatched types //~| expected usize, found isize let f = [0_usize; -1_isize]; - //~^ ERROR mismatched types - //~| expected `usize` - //~| found `isize` + //~^ ERROR constant evaluation error + //~| expected usize, found isize //~| ERROR mismatched types //~| expected usize, found isize struct G { @@ -56,5 +55,5 @@ fn main() { //~| expected type `usize` //~| found type `main::G` //~| expected usize, found struct `main::G` - //~| ERROR expected positive integer for repeat count, found struct [E0306] + //~| ERROR expected usize for repeat count, found struct [E0306] } diff --git a/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs b/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs index 30ff1ed0e26f..a1572b856664 100644 --- a/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs +++ b/src/test/compile-fail/resolve-type-param-in-item-in-trait.rs @@ -13,9 +13,8 @@ // scope (in this case, the enum). trait TraitA { - fn outer(self) { + fn outer(&self) { enum Foo { - //~^ ERROR parameter `B` is never used Variance(A) //~^ ERROR can't use type parameters from outer function } @@ -23,23 +22,21 @@ trait TraitA { } trait TraitB { - fn outer(self) { + fn outer(&self) { struct Foo(A); //~^ ERROR can't use type parameters from outer function - //~^^ ERROR parameter `B` is never used } } trait TraitC { - fn outer(self) { + fn outer(&self) { struct Foo { a: A } //~^ ERROR can't use type parameters from outer function - //~^^ ERROR parameter `B` is never used } } trait TraitD { - fn outer(self) { + fn outer(&self) { fn foo(a: A) { } //~^ ERROR can't use type parameters from outer function } diff --git a/src/test/compile-fail/slightly-nice-generic-literal-messages.rs b/src/test/compile-fail/slightly-nice-generic-literal-messages.rs index 3140bb6e5731..2eba7c2e534e 100644 --- a/src/test/compile-fail/slightly-nice-generic-literal-messages.rs +++ b/src/test/compile-fail/slightly-nice-generic-literal-messages.rs @@ -16,8 +16,8 @@ fn main() { match Foo(1.1, marker::PhantomData) { 1 => {} //~^ ERROR mismatched types - //~| expected type `Foo<_, _>` - //~| found type `_` + //~| expected type `Foo<{float}, _>` + //~| found type `{integer}` //~| expected struct `Foo`, found integral variable } diff --git a/src/test/compile-fail/str-idx.rs b/src/test/compile-fail/str-idx.rs index b972a09b5c49..2b2c23a3ce4e 100644 --- a/src/test/compile-fail/str-idx.rs +++ b/src/test/compile-fail/str-idx.rs @@ -10,5 +10,5 @@ pub fn main() { let s: &str = "hello"; - let c: u8 = s[4]; //~ ERROR `str: std::ops::Index<_>` is not satisfied + let c: u8 = s[4]; //~ ERROR `str: std::ops::Index<{integer}>` is not satisfied } diff --git a/src/test/compile-fail/struct-base-wrong-type-2.rs b/src/test/compile-fail/struct-base-wrong-type-2.rs index 1250d0dabcd9..7e5510edb2c3 100644 --- a/src/test/compile-fail/struct-base-wrong-type-2.rs +++ b/src/test/compile-fail/struct-base-wrong-type-2.rs @@ -24,6 +24,6 @@ fn main() { //~| expected struct `Foo`, found struct `Bar` let f__isize = Foo { a: 2, ..4 }; //~ ERROR mismatched types //~| expected type `Foo` - //~| found type `_` + //~| found type `{integer}` //~| expected struct `Foo`, found integral variable } diff --git a/src/test/compile-fail/struct-base-wrong-type.rs b/src/test/compile-fail/struct-base-wrong-type.rs index 4503e465840f..3703b15d4db8 100644 --- a/src/test/compile-fail/struct-base-wrong-type.rs +++ b/src/test/compile-fail/struct-base-wrong-type.rs @@ -23,7 +23,7 @@ static foo: Foo = Foo { a: 2, ..bar }; //~ ERROR mismatched types //~| expected struct `Foo`, found struct `Bar` static foo_i: Foo = Foo { a: 2, ..4 }; //~ ERROR mismatched types //~| expected type `Foo` - //~| found type `_` + //~| found type `{integer}` //~| expected struct `Foo`, found integral variable fn main() { diff --git a/src/test/compile-fail/struct-fields-decl-dupe.rs b/src/test/compile-fail/struct-fields-decl-dupe.rs index 049569e8a184..dd9d7d294688 100644 --- a/src/test/compile-fail/struct-fields-decl-dupe.rs +++ b/src/test/compile-fail/struct-fields-decl-dupe.rs @@ -9,8 +9,10 @@ // except according to those terms. struct BuildData { + foo: isize, //~ NOTE `foo` first declared here foo: isize, - foo: isize, //~ ERROR field `foo` is already declared + //~^ ERROR field `foo` is already declared [E0124] + //~| NOTE field already declared } fn main() { diff --git a/src/test/compile-fail/trait-as-struct-constructor.rs b/src/test/compile-fail/trait-as-struct-constructor.rs index 13fdaa302f70..c78eebddbfdb 100644 --- a/src/test/compile-fail/trait-as-struct-constructor.rs +++ b/src/test/compile-fail/trait-as-struct-constructor.rs @@ -13,4 +13,5 @@ trait TraitNotAStruct {} fn main() { TraitNotAStruct{ value: 0 }; //~^ ERROR: `TraitNotAStruct` does not name a struct or a struct variant [E0071] + //~| NOTE not a struct } diff --git a/src/test/compile-fail/trait-impl-method-mismatch.rs b/src/test/compile-fail/trait-impl-method-mismatch.rs index f86d9b7648bb..a05e007d6b73 100644 --- a/src/test/compile-fail/trait-impl-method-mismatch.rs +++ b/src/test/compile-fail/trait-impl-method-mismatch.rs @@ -17,8 +17,8 @@ impl Mumbo for usize { // Cannot have a larger effect than the trait: unsafe fn jumbo(&self, x: &usize) { *self + *x; } //~^ ERROR method `jumbo` has an incompatible type for trait - //~| expected normal fn, - //~| found unsafe fn + //~| expected type `fn + //~| found type `unsafe fn } fn main() {} diff --git a/src/test/compile-fail/traits-inductive-overflow-simultaneous.rs b/src/test/compile-fail/traits-inductive-overflow-simultaneous.rs index 2968e8a7ca99..777746a189c5 100644 --- a/src/test/compile-fail/traits-inductive-overflow-simultaneous.rs +++ b/src/test/compile-fail/traits-inductive-overflow-simultaneous.rs @@ -26,5 +26,5 @@ fn is_ee(t: T) { fn main() { is_ee(4); - //~^ ERROR overflow evaluating the requirement `_: Tweedle + //~^ ERROR overflow evaluating the requirement `{integer}: Tweedle } diff --git a/src/test/compile-fail/tuple-arity-mismatch.rs b/src/test/compile-fail/tuple-arity-mismatch.rs index e62255a4e77d..a71f44102947 100644 --- a/src/test/compile-fail/tuple-arity-mismatch.rs +++ b/src/test/compile-fail/tuple-arity-mismatch.rs @@ -16,7 +16,7 @@ fn main() { let y = first ((1,2.0,3)); //~^ ERROR mismatched types //~| expected type `(isize, f64)` - //~| found type `(isize, f64, _)` + //~| found type `(isize, f64, {integer})` //~| expected a tuple with 2 elements, found one with 3 elements let y = first ((1,)); diff --git a/src/test/compile-fail/tuple-index-out-of-bounds.rs b/src/test/compile-fail/tuple-index-out-of-bounds.rs index c2c41fbbb2aa..4597cf3d350c 100644 --- a/src/test/compile-fail/tuple-index-out-of-bounds.rs +++ b/src/test/compile-fail/tuple-index-out-of-bounds.rs @@ -20,5 +20,5 @@ fn main() { tuple.0; tuple.1; tuple.2; - //~^ ERROR attempted out-of-bounds tuple index `2` on type `(_, _)` + //~^ ERROR attempted out-of-bounds tuple index `2` on type `({integer}, {integer})` } diff --git a/src/test/compile-fail/type-mismatch-multiple.rs b/src/test/compile-fail/type-mismatch-multiple.rs index 0f174d99fefc..9359c0359566 100644 --- a/src/test/compile-fail/type-mismatch-multiple.rs +++ b/src/test/compile-fail/type-mismatch-multiple.rs @@ -13,7 +13,7 @@ fn main() { let a: bool = 1; let b: i32 = true; } //~^ ERROR mismatched types //~| expected type `bool` -//~| found type `_` +//~| found type `{integer}` //~| expected bool, found integral variable //~| ERROR mismatched types //~| expected i32, found bool diff --git a/src/test/compile-fail/typeck-unsafe-always-share.rs b/src/test/compile-fail/typeck-unsafe-always-share.rs index 6047f6770a7b..f0172777cdab 100644 --- a/src/test/compile-fail/typeck-unsafe-always-share.rs +++ b/src/test/compile-fail/typeck-unsafe-always-share.rs @@ -27,7 +27,7 @@ fn test(s: T) {} fn main() { let us = UnsafeCell::new(MySync{u: UnsafeCell::new(0)}); test(us); - //~^ ERROR `std::cell::UnsafeCell>: std::marker::Sync` is not satisfied + //~^ ERROR `std::cell::UnsafeCell>: std::marker::Sync` is not satisfied let uns = UnsafeCell::new(NoSync); test(uns); diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs index f14a3505cdeb..a98b7cd43090 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -41,14 +41,14 @@ trait SomeTrait { impl<'a, T> SomeTrait for &'a Bar { fn dummy1(self: &&'a Bar) { } - fn dummy2(self: &Bar) {} //~ ERROR mismatched types - //~^ ERROR mismatched types + fn dummy2(self: &Bar) {} //~ ERROR mismatched method receiver + //~^ ERROR mismatched method receiver fn dummy3(self: &&Bar) {} - //~^ ERROR mismatched types + //~^ ERROR mismatched method receiver //~| expected type `&&'a Bar` //~| found type `&&Bar` //~| lifetime mismatch - //~| ERROR mismatched types + //~| ERROR mismatched method receiver //~| expected type `&&'a Bar` //~| found type `&&Bar` //~| lifetime mismatch diff --git a/src/test/compile-fail/unboxed-closure-immutable-capture.rs b/src/test/compile-fail/unboxed-closure-immutable-capture.rs index 5be2738b47ef..2d9983742295 100644 --- a/src/test/compile-fail/unboxed-closure-immutable-capture.rs +++ b/src/test/compile-fail/unboxed-closure-immutable-capture.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - // Test that even unboxed closures that are capable of mutating their // environment cannot mutate captured variables that have not been // declared mutable (#18335) diff --git a/src/test/compile-fail/unboxed-closure-region.rs b/src/test/compile-fail/unboxed-closure-region.rs index eee1b6ce30b5..1c86dda3378a 100644 --- a/src/test/compile-fail/unboxed-closure-region.rs +++ b/src/test/compile-fail/unboxed-closure-region.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - // Test that an unboxed closure that captures a free variable by // reference cannot escape the region of that variable. fn main() { diff --git a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs index 21450856ae6c..465bddd060d7 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-nonexistent-trait.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - fn f isize>(x: F) {} //~ ERROR trait `Nonexist` is not in scope type Typedef = isize; diff --git a/src/test/compile-fail/unboxed-closures-borrow-conflict.rs b/src/test/compile-fail/unboxed-closures-borrow-conflict.rs index 372f3277931e..ad7e6784a0a4 100644 --- a/src/test/compile-fail/unboxed-closures-borrow-conflict.rs +++ b/src/test/compile-fail/unboxed-closures-borrow-conflict.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - // Test that an unboxed closure that mutates a free variable will // cause borrow conflicts. diff --git a/src/test/compile-fail/unboxed-closures-infer-argument-types-two-region-pointers.rs b/src/test/compile-fail/unboxed-closures-infer-argument-types-two-region-pointers.rs index 1e2b01856e71..5436a855ee78 100644 --- a/src/test/compile-fail/unboxed-closures-infer-argument-types-two-region-pointers.rs +++ b/src/test/compile-fail/unboxed-closures-infer-argument-types-two-region-pointers.rs @@ -11,8 +11,6 @@ // That a closure whose expected argument types include two distinct // bound regions. -#![feature(unboxed_closures)] - use std::cell::Cell; fn doit(val: T, f: &F) diff --git a/src/test/compile-fail/unboxed-closures-infer-explicit-call-too-early.rs b/src/test/compile-fail/unboxed-closures-infer-explicit-call-too-early.rs index 226b516e09db..62f6ee56ca5d 100644 --- a/src/test/compile-fail/unboxed-closures-infer-explicit-call-too-early.rs +++ b/src/test/compile-fail/unboxed-closures-infer-explicit-call-too-early.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - fn main() { let mut zero = || {}; let () = zero.call_mut(()); diff --git a/src/test/compile-fail/unboxed-closures-type-mismatch.rs b/src/test/compile-fail/unboxed-closures-type-mismatch.rs index 91182393ac8e..dba4c8cc2e9e 100644 --- a/src/test/compile-fail/unboxed-closures-type-mismatch.rs +++ b/src/test/compile-fail/unboxed-closures-type-mismatch.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::ops::FnMut; pub fn main() { diff --git a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs index cba7ad82ee16..2b0a8baf4f23 100644 --- a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs @@ -10,8 +10,6 @@ // Tests that unsafe extern fn pointers do not implement any Fn traits. -#![feature(unboxed_closures)] - use std::ops::{Fn,FnMut,FnOnce}; unsafe fn square(x: &isize) -> isize { (*x) * (*x) } diff --git a/src/test/compile-fail/unboxed-closures-wrong-abi.rs b/src/test/compile-fail/unboxed-closures-wrong-abi.rs index dd891bc473ce..f6ba25f43685 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-abi.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-abi.rs @@ -10,8 +10,6 @@ // Tests that unsafe extern fn pointers do not implement any Fn traits. -#![feature(unboxed_closures)] - use std::ops::{Fn,FnMut,FnOnce}; extern "C" fn square(x: &isize) -> isize { (*x) * (*x) } diff --git a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs index f9edd5df6739..9d907ffc17f2 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs @@ -10,8 +10,6 @@ // Tests that unsafe extern fn pointers do not implement any Fn traits. -#![feature(unboxed_closures)] - use std::ops::{Fn,FnMut,FnOnce}; unsafe fn square(x: isize) -> isize { x * x } diff --git a/src/test/compile-fail/unresolved-import-recovery.rs b/src/test/compile-fail/unresolved-import-recovery.rs new file mode 100644 index 000000000000..8173f69191da --- /dev/null +++ b/src/test/compile-fail/unresolved-import-recovery.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that unresolved imports do not create additional errors and ICEs + +mod m { + pub use unresolved; //~ ERROR unresolved import `unresolved` + + fn f() { + let unresolved = 0; // OK + } +} + +fn main() { + match 0u8 { + m::unresolved => {} // OK + m::unresolved(..) => {} // OK + m::unresolved{..} => {} // OK + } +} diff --git a/src/test/compile-fail/unsafe-trait-impl.rs b/src/test/compile-fail/unsafe-trait-impl.rs index 51f876661f65..fb4652affd0d 100644 --- a/src/test/compile-fail/unsafe-trait-impl.rs +++ b/src/test/compile-fail/unsafe-trait-impl.rs @@ -17,8 +17,8 @@ trait Foo { impl Foo for u32 { fn len(&self) -> u32 { *self } //~^ ERROR method `len` has an incompatible type for trait - //~| expected unsafe fn, - //~| found normal fn + //~| expected type `unsafe fn(&u32) -> u32` + //~| found type `fn(&u32) -> u32` } fn main() { } diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs index d8620ead8363..cc9a7c84eded 100644 --- a/src/test/compile-fail/variadic-ffi-3.rs +++ b/src/test/compile-fail/variadic-ffi-3.rs @@ -18,8 +18,10 @@ fn main() { unsafe { foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied //~^ NOTE the following parameter types were expected + //~| NOTE expected at least 2 parameters foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied //~^ NOTE the following parameter types were expected + //~| NOTE expected at least 2 parameters let x: unsafe extern "C" fn(f: isize, x: u8) = foo; //~^ ERROR: mismatched types diff --git a/src/test/compile-fail/vtable-res-trait-param.rs b/src/test/compile-fail/vtable-res-trait-param.rs index eb0baff0005d..8b3e9369ece4 100644 --- a/src/test/compile-fail/vtable-res-trait-param.rs +++ b/src/test/compile-fail/vtable-res-trait-param.rs @@ -24,7 +24,7 @@ impl TraitB for isize { fn call_it(b: B) -> isize { let y = 4; - b.gimme_an_a(y) //~ ERROR `_: TraitA` is not satisfied + b.gimme_an_a(y) //~ ERROR `{integer}: TraitA` is not satisfied } fn main() { diff --git a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs deleted file mode 100644 index b5b6ca757270..000000000000 --- a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-android: FIXME(#10381) -// min-lldb-version: 310 - -// This test case checks if function arguments already have the correct value -// when breaking at the beginning of a function. Functions with the -// #[no_stack_check] attribute have the same prologue as regular C functions -// compiled with GCC or Clang and therefore are better handled by GDB. As a -// consequence, and as opposed to regular Rust functions, we can set the -// breakpoints via the function name (and don't have to fall back on using line -// numbers). For LLDB this shouldn't make a difference because it can handle -// both cases. - -// compile-flags:-g - -// === GDB TESTS =================================================================================== - -// gdb-command:rbreak immediate_args -// gdb-command:rbreak binding -// gdb-command:rbreak assignment -// gdb-command:rbreak function_call -// gdb-command:rbreak identifier -// gdb-command:rbreak return_expr -// gdb-command:rbreak arithmetic_expr -// gdb-command:rbreak if_expr -// gdb-command:rbreak while_expr -// gdb-command:rbreak loop_expr -// gdb-command:run - -// IMMEDIATE ARGS -// gdb-command:print a -// gdb-check:$1 = 1 -// gdb-command:print b -// gdb-check:$2 = true -// gdb-command:print c -// gdb-check:$3 = 2.5 -// gdb-command:continue - -// NON IMMEDIATE ARGS -// gdb-command:print a -// gdb-check:$4 = {a = 3, b = 4, c = 5, d = 6, e = 7, f = 8, g = 9, h = 10} -// gdb-command:print b -// gdb-check:$5 = {a = 11, b = 12, c = 13, d = 14, e = 15, f = 16, g = 17, h = 18} -// gdb-command:continue - -// BINDING -// gdb-command:print a -// gdb-check:$6 = 19 -// gdb-command:print b -// gdb-check:$7 = 20 -// gdb-command:print c -// gdb-check:$8 = 21.5 -// gdb-command:continue - -// ASSIGNMENT -// gdb-command:print a -// gdb-check:$9 = 22 -// gdb-command:print b -// gdb-check:$10 = 23 -// gdb-command:print c -// gdb-check:$11 = 24.5 -// gdb-command:continue - -// FUNCTION CALL -// gdb-command:print x -// gdb-check:$12 = 25 -// gdb-command:print y -// gdb-check:$13 = 26 -// gdb-command:print z -// gdb-check:$14 = 27.5 -// gdb-command:continue - -// EXPR -// gdb-command:print x -// gdb-check:$15 = 28 -// gdb-command:print y -// gdb-check:$16 = 29 -// gdb-command:print z -// gdb-check:$17 = 30.5 -// gdb-command:continue - -// RETURN EXPR -// gdb-command:print x -// gdb-check:$18 = 31 -// gdb-command:print y -// gdb-check:$19 = 32 -// gdb-command:print z -// gdb-check:$20 = 33.5 -// gdb-command:continue - -// ARITHMETIC EXPR -// gdb-command:print x -// gdb-check:$21 = 34 -// gdb-command:print y -// gdb-check:$22 = 35 -// gdb-command:print z -// gdb-check:$23 = 36.5 -// gdb-command:continue - -// IF EXPR -// gdb-command:print x -// gdb-check:$24 = 37 -// gdb-command:print y -// gdb-check:$25 = 38 -// gdb-command:print z -// gdb-check:$26 = 39.5 -// gdb-command:continue - -// WHILE EXPR -// gdb-command:print x -// gdb-check:$27 = 40 -// gdb-command:print y -// gdb-check:$28 = 41 -// gdb-command:print z -// gdb-check:$29 = 42 -// gdb-command:continue - -// LOOP EXPR -// gdb-command:print x -// gdb-check:$30 = 43 -// gdb-command:print y -// gdb-check:$31 = 44 -// gdb-command:print z -// gdb-check:$32 = 45 -// gdb-command:continue - - -// === LLDB TESTS ================================================================================== - -// lldb-command:breakpoint set --name immediate_args -// lldb-command:breakpoint set --name non_immediate_args -// lldb-command:breakpoint set --name binding -// lldb-command:breakpoint set --name assignment -// lldb-command:breakpoint set --name function_call -// lldb-command:breakpoint set --name identifier -// lldb-command:breakpoint set --name return_expr -// lldb-command:breakpoint set --name arithmetic_expr -// lldb-command:breakpoint set --name if_expr -// lldb-command:breakpoint set --name while_expr -// lldb-command:breakpoint set --name loop_expr -// lldb-command:run - -// IMMEDIATE ARGS -// lldb-command:print a -// lldb-check:[...]$0 = 1 -// lldb-command:print b -// lldb-check:[...]$1 = true -// lldb-command:print c -// lldb-check:[...]$2 = 2.5 -// lldb-command:continue - -// NON IMMEDIATE ARGS -// lldb-command:print a -// lldb-check:[...]$3 = BigStruct { a: 3, b: 4, c: 5, d: 6, e: 7, f: 8, g: 9, h: 10 } -// lldb-command:print b -// lldb-check:[...]$4 = BigStruct { a: 11, b: 12, c: 13, d: 14, e: 15, f: 16, g: 17, h: 18 } -// lldb-command:continue - -// BINDING -// lldb-command:print a -// lldb-check:[...]$5 = 19 -// lldb-command:print b -// lldb-check:[...]$6 = 20 -// lldb-command:print c -// lldb-check:[...]$7 = 21.5 -// lldb-command:continue - -// ASSIGNMENT -// lldb-command:print a -// lldb-check:[...]$8 = 22 -// lldb-command:print b -// lldb-check:[...]$9 = 23 -// lldb-command:print c -// lldb-check:[...]$10 = 24.5 -// lldb-command:continue - -// FUNCTION CALL -// lldb-command:print x -// lldb-check:[...]$11 = 25 -// lldb-command:print y -// lldb-check:[...]$12 = 26 -// lldb-command:print z -// lldb-check:[...]$13 = 27.5 -// lldb-command:continue - -// EXPR -// lldb-command:print x -// lldb-check:[...]$14 = 28 -// lldb-command:print y -// lldb-check:[...]$15 = 29 -// lldb-command:print z -// lldb-check:[...]$16 = 30.5 -// lldb-command:continue - -// RETURN EXPR -// lldb-command:print x -// lldb-check:[...]$17 = 31 -// lldb-command:print y -// lldb-check:[...]$18 = 32 -// lldb-command:print z -// lldb-check:[...]$19 = 33.5 -// lldb-command:continue - -// ARITHMETIC EXPR -// lldb-command:print x -// lldb-check:[...]$20 = 34 -// lldb-command:print y -// lldb-check:[...]$21 = 35 -// lldb-command:print z -// lldb-check:[...]$22 = 36.5 -// lldb-command:continue - -// IF EXPR -// lldb-command:print x -// lldb-check:[...]$23 = 37 -// lldb-command:print y -// lldb-check:[...]$24 = 38 -// lldb-command:print z -// lldb-check:[...]$25 = 39.5 -// lldb-command:continue - -// WHILE EXPR -// lldb-command:print x -// lldb-check:[...]$26 = 40 -// lldb-command:print y -// lldb-check:[...]$27 = 41 -// lldb-command:print z -// lldb-check:[...]$28 = 42 -// lldb-command:continue - -// LOOP EXPR -// lldb-command:print x -// lldb-check:[...]$29 = 43 -// lldb-command:print y -// lldb-check:[...]$30 = 44 -// lldb-command:print z -// lldb-check:[...]$31 = 45 -// lldb-command:continue - -#![allow(dead_code, unused_assignments, unused_variables)] -#![feature(omit_gdb_pretty_printer_section)] -#![omit_gdb_pretty_printer_section] - -#[no_stack_check] -fn immediate_args(a: isize, b: bool, c: f64) { - println!(""); -} - -struct BigStruct { - a: u64, - b: u64, - c: u64, - d: u64, - e: u64, - f: u64, - g: u64, - h: u64 -} - -#[no_stack_check] -fn non_immediate_args(a: BigStruct, b: BigStruct) { - println!(""); -} - -#[no_stack_check] -fn binding(a: i64, b: u64, c: f64) { - let x = 0; - println!(""); -} - -#[no_stack_check] -fn assignment(mut a: u64, b: u64, c: f64) { - a = b; - println!(""); -} - -#[no_stack_check] -fn function_call(x: u64, y: u64, z: f64) { - println!("Hi!") -} - -#[no_stack_check] -fn identifier(x: u64, y: u64, z: f64) -> u64 { - x -} - -#[no_stack_check] -fn return_expr(x: u64, y: u64, z: f64) -> u64 { - return x; -} - -#[no_stack_check] -fn arithmetic_expr(x: u64, y: u64, z: f64) -> u64 { - x + y -} - -#[no_stack_check] -fn if_expr(x: u64, y: u64, z: f64) -> u64 { - if x + y < 1000 { - x - } else { - y - } -} - -#[no_stack_check] -fn while_expr(mut x: u64, y: u64, z: u64) -> u64 { - while x + y < 1000 { - x += z - } - return x; -} - -#[no_stack_check] -fn loop_expr(mut x: u64, y: u64, z: u64) -> u64 { - loop { - x += z; - - if x + y > 1000 { - return x; - } - } -} - -fn main() { - immediate_args(1, true, 2.5); - - non_immediate_args( - BigStruct { - a: 3, - b: 4, - c: 5, - d: 6, - e: 7, - f: 8, - g: 9, - h: 10 - }, - BigStruct { - a: 11, - b: 12, - c: 13, - d: 14, - e: 15, - f: 16, - g: 17, - h: 18 - } - ); - - binding(19, 20, 21.5); - assignment(22, 23, 24.5); - function_call(25, 26, 27.5); - identifier(28, 29, 30.5); - return_expr(31, 32, 33.5); - arithmetic_expr(34, 35, 36.5); - if_expr(37, 38, 39.5); - while_expr(40, 41, 42); - loop_expr(43, 44, 45); -} diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index a74369ed3c3a..2419625cbd37 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -11,6 +11,8 @@ // ignore-tidy-linelength // ignore-lldb // ignore-android: FIXME(#24958) +// ignore-arm: FIXME(#24958) +// ignore-aarch64: FIXME(#24958) // compile-flags:-g diff --git a/src/test/debuginfo/var-captured-in-sendable-closure.rs b/src/test/debuginfo/var-captured-in-sendable-closure.rs index aa269edadd8f..b415546faeac 100644 --- a/src/test/debuginfo/var-captured-in-sendable-closure.rs +++ b/src/test/debuginfo/var-captured-in-sendable-closure.rs @@ -40,7 +40,7 @@ // lldb-check:[...]$2 = 5 #![allow(unused_variables)] -#![feature(unboxed_closures, box_syntax)] +#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] diff --git a/src/test/debuginfo/var-captured-in-stack-closure.rs b/src/test/debuginfo/var-captured-in-stack-closure.rs index 6def5cf28593..e60f964dd095 100644 --- a/src/test/debuginfo/var-captured-in-stack-closure.rs +++ b/src/test/debuginfo/var-captured-in-stack-closure.rs @@ -69,7 +69,7 @@ // lldb-command:print *owned // lldb-check:[...]$9 = 6 -#![feature(unboxed_closures, box_syntax)] +#![feature(box_syntax)] #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] diff --git a/src/test/compile-fail/feature-gate-rust-call.rs b/src/test/incremental/rlib_cross_crate/auxiliary/a.rs similarity index 66% rename from src/test/compile-fail/feature-gate-rust-call.rs rename to src/test/incremental/rlib_cross_crate/auxiliary/a.rs index 029a9cad65fc..ff5fd6347144 100644 --- a/src/test/compile-fail/feature-gate-rust-call.rs +++ b/src/test/incremental/rlib_cross_crate/auxiliary/a.rs @@ -8,14 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern "rust-call" fn foo() { } //~ ERROR rust-call ABI is subject to change +// no-prefer-dynamic -trait Foo { - extern "rust-call" fn foo(); -} +#![crate_type="rlib"] -impl Foo for i32 { - extern "rust-call" fn foo() { } //~ ERROR rust-call ABI is subject to change -} +#[cfg(rpass1)] +pub type X = u32; -fn main() { } +#[cfg(rpass2)] +pub type X = i32; + +// this version doesn't actually change anything: +#[cfg(rpass3)] +pub type X = i32; + +pub type Y = char; diff --git a/src/test/incremental/rlib_cross_crate/b.rs b/src/test/incremental/rlib_cross_crate/b.rs new file mode 100644 index 000000000000..55398370425a --- /dev/null +++ b/src/test/incremental/rlib_cross_crate/b.rs @@ -0,0 +1,38 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Same test as `type_alias_cross_crate`, but with +// `no-prefer-dynamic`, ensuring that we test what happens when we +// build rlibs (before we were only testing dylibs, which meant we +// didn't realize we had to preserve a `bc` file as well). + +// aux-build:a.rs +// revisions:rpass1 rpass2 rpass3 +// no-prefer-dynamic + + +#![feature(rustc_attrs)] + +extern crate a; + +#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] +#[rustc_clean(label="TypeckItemBody", cfg="rpass3")] +pub fn use_X() -> u32 { + let x: a::X = 22; + x as u32 +} + +#[rustc_clean(label="TypeckItemBody", cfg="rpass2")] +#[rustc_clean(label="TypeckItemBody", cfg="rpass3")] +pub fn use_Y() { + let x: a::Y = 'c'; +} + +pub fn main() { } diff --git a/src/test/incremental/spike-neg1.rs b/src/test/incremental/spike-neg1.rs new file mode 100644 index 000000000000..b00c68a184ed --- /dev/null +++ b/src/test/incremental/spike-neg1.rs @@ -0,0 +1,62 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// A variant of the first "spike" test that serves to test the +// `rustc_partition_reused` and `rustc_partition_translated` tests. +// Here we change and say that the `x` module will be reused (when in +// fact it will not), and then indicate that the test itself +// should-fail (because an error will be reported, and hence the +// revision rpass2 will not compile, despite being named rpass). + +// revisions:rpass1 rpass2 +// should-fail + +#![feature(rustc_attrs)] + +#![rustc_partition_reused(module="spike_neg1", cfg="rpass2")] +#![rustc_partition_reused(module="spike_neg1-x", cfg="rpass2")] // this is wrong! +#![rustc_partition_reused(module="spike_neg1-y", cfg="rpass2")] + +mod x { + pub struct X { + x: u32, y: u32, + } + + #[cfg(rpass1)] + fn make() -> X { + X { x: 22, y: 0 } + } + + #[cfg(rpass2)] + fn make() -> X { + X { x: 11, y: 11 } + } + + pub fn new() -> X { + make() + } + + pub fn sum(x: &X) -> u32 { + x.x + x.y + } +} + +mod y { + use x; + + pub fn assert_sum() -> bool { + let x = x::new(); + x::sum(&x) == 22 + } +} + +pub fn main() { + y::assert_sum(); +} diff --git a/src/test/incremental/spike-neg2.rs b/src/test/incremental/spike-neg2.rs new file mode 100644 index 000000000000..472d11d7f902 --- /dev/null +++ b/src/test/incremental/spike-neg2.rs @@ -0,0 +1,62 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// A variant of the first "spike" test that serves to test the +// `rustc_partition_reused` and `rustc_partition_translated` tests. +// Here we change and say that the `y` module will be translated (when +// in fact it will not), and then indicate that the test itself +// should-fail (because an error will be reported, and hence the +// revision rpass2 will not compile, despite being named rpass). + +// revisions:rpass1 rpass2 +// should-fail + +#![feature(rustc_attrs)] + +#![rustc_partition_reused(module="spike_neg2", cfg="rpass2")] +#![rustc_partition_translated(module="spike_neg2-x", cfg="rpass2")] +#![rustc_partition_translated(module="spike_neg2-y", cfg="rpass2")] // this is wrong! + +mod x { + pub struct X { + x: u32, y: u32, + } + + #[cfg(rpass1)] + fn make() -> X { + X { x: 22, y: 0 } + } + + #[cfg(rpass2)] + fn make() -> X { + X { x: 11, y: 11 } + } + + pub fn new() -> X { + make() + } + + pub fn sum(x: &X) -> u32 { + x.x + x.y + } +} + +mod y { + use x; + + pub fn assert_sum() -> bool { + let x = x::new(); + x::sum(&x) == 22 + } +} + +pub fn main() { + y::assert_sum(); +} diff --git a/src/test/incremental/spike.rs b/src/test/incremental/spike.rs new file mode 100644 index 000000000000..68af20d41915 --- /dev/null +++ b/src/test/incremental/spike.rs @@ -0,0 +1,63 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// A first "spike" for incremental compilation: here, we change the +// content of the `make` function, and we find that we can reuse the +// `y` module entirely (but not the `x` module). + +// revisions:rpass1 rpass2 + +#![feature(rustc_attrs)] + +#![rustc_partition_reused(module="spike", cfg="rpass2")] +#![rustc_partition_translated(module="spike-x", cfg="rpass2")] +#![rustc_partition_reused(module="spike-y", cfg="rpass2")] + +mod x { + pub struct X { + x: u32, y: u32, + } + + #[cfg(rpass1)] + fn make() -> X { + X { x: 22, y: 0 } + } + + #[cfg(rpass2)] + fn make() -> X { + X { x: 11, y: 11 } + } + + #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="ItemSignature", cfg="rpass2")] + pub fn new() -> X { + make() + } + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + #[rustc_clean(label="ItemSignature", cfg="rpass2")] + pub fn sum(x: &X) -> u32 { + x.x + x.y + } +} + +mod y { + use x; + + #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] + pub fn assert_sum() -> bool { + let x = x::new(); + x::sum(&x) == 22 + } +} + +pub fn main() { + y::assert_sum(); +} diff --git a/src/test/mir-opt/README.md b/src/test/mir-opt/README.md new file mode 100644 index 000000000000..9144e9757f6a --- /dev/null +++ b/src/test/mir-opt/README.md @@ -0,0 +1,44 @@ +This folder contains tests for MIR optimizations. + +The test format is: + +``` +(arbitrary rust code) +// END RUST SOURCE +// START $file_name_of_some_mir_dump_0 +// $expected_line_0 +// ... +// $expected_line_N +// END $file_name_of_some_mir_dump_0 +// ... +// START $file_name_of_some_mir_dump_N +// $expected_line_0 +// ... +// $expected_line_N +// END $file_name_of_some_mir_dump_N +``` + +All the test information is in comments so the test is runnable. + +For each $file_name, compiletest expects [$expected_line_0, ..., +$expected_line_N] to appear in the dumped MIR in order. Currently it allows +other non-matched lines before, after and in-between. + +Lines match ignoring whitespace, and the prefix "//" is removed. + +It also currently strips trailing comments -- partly because the full file path +in "scope comments" is unpredictable and partly because tidy complains about +the lines being too long. + +compiletest handles dumping the MIR before and after every pass for you. The +test writer only has to specify the file names of the dumped files (not the +full path to the file) and what lines to expect. I added an option to rustc +that tells it to dump the mir into some directly (rather then always dumping to +the current directory). + +Lines match ignoring whitespace, and the prefix "//" is removed of course. + +It also currently strips trailing comments -- partly because the full file path +in "scope comments" is unpredictable and partly because tidy complains about +the lines being too long. + diff --git a/src/test/mir-opt/deaggregator_test.rs b/src/test/mir-opt/deaggregator_test.rs new file mode 100644 index 000000000000..e57a9674cf68 --- /dev/null +++ b/src/test/mir-opt/deaggregator_test.rs @@ -0,0 +1,41 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Baz { + x: usize, + y: f32, + z: bool, +} + +fn bar(a: usize) -> Baz { + Baz { x: a, y: 0.0, z: false } +} + +fn main() {} + +// END RUST SOURCE +// START rustc.node13.Deaggregator.before.mir +// bb0: { +// var0 = arg0; // scope 0 at main.rs:8:8: 8:9 +// tmp0 = var0; // scope 1 at main.rs:9:14: 9:15 +// return = Baz { x: tmp0, y: const F32(0), z: const false }; // scope ... +// goto -> bb1; // scope 1 at main.rs:8:1: 10:2 +// } +// END rustc.node13.Deaggregator.before.mir +// START rustc.node13.Deaggregator.after.mir +// bb0: { +// var0 = arg0; // scope 0 at main.rs:8:8: 8:9 +// tmp0 = var0; // scope 1 at main.rs:9:14: 9:15 +// (return.0: usize) = tmp0; // scope 1 at main.rs:9:5: 9:34 +// (return.1: f32) = const F32(0); // scope 1 at main.rs:9:5: 9:34 +// (return.2: bool) = const false; // scope 1 at main.rs:9:5: 9:34 +// goto -> bb1; // scope 1 at main.rs:8:1: 10:2 +// } +// END rustc.node13.Deaggregator.after.mir \ No newline at end of file diff --git a/src/test/mir-opt/return_an_array.rs b/src/test/mir-opt/return_an_array.rs new file mode 100644 index 000000000000..4409f16b3f5f --- /dev/null +++ b/src/test/mir-opt/return_an_array.rs @@ -0,0 +1,18 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// this tests move up progration, which is not yet implemented + +fn foo() -> [u8; 1024] { + let x = [0; 1024]; + return x; +} + +fn main() { } \ No newline at end of file diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs new file mode 100644 index 000000000000..dd6a85796043 --- /dev/null +++ b/src/test/mir-opt/simplify_if.rs @@ -0,0 +1,27 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + if false { + println!("hello world!"); + } +} + +// END RUST SOURCE +// START rustc.node4.SimplifyBranches.initial-before.mir +// bb0: { +// if(const false) -> [true: bb1, false: bb2]; // scope 0 at simplify_if.rs:12:5: 14:6 +// } +// END rustc.node4.SimplifyBranches.initial-before.mir +// START rustc.node4.SimplifyBranches.initial-after.mir +// bb0: { +// goto -> bb2; // scope 0 at simplify_if.rs:12:5: 14:6 +// } +// END rustc.node4.SimplifyBranches.initial-after.mir \ No newline at end of file diff --git a/src/test/run-fail/divide-by-zero.rs b/src/test/run-fail/divide-by-zero.rs index 3d9bee3c86a5..c9c4a88c9b53 100644 --- a/src/test/run-fail/divide-by-zero.rs +++ b/src/test/run-fail/divide-by-zero.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:attempted to divide by zero +// error-pattern:attempt to divide by zero fn main() { let y = 0; diff --git a/src/test/run-fail/mod-zero.rs b/src/test/run-fail/mod-zero.rs index 686c3eb2f83b..d2b598a7933b 100644 --- a/src/test/run-fail/mod-zero.rs +++ b/src/test/run-fail/mod-zero.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:attempted to calculate the remainder with a divisor of zero +// error-pattern:attempt to calculate the remainder with a divisor of zero fn main() { let y = 0; diff --git a/src/test/run-fail/overflowing-add.rs b/src/test/run-fail/overflowing-add.rs index ecb8c676cf70..acc7676db457 100644 --- a/src/test/run-fail/overflowing-add.rs +++ b/src/test/run-fail/overflowing-add.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to add with overflow' +// error-pattern:thread 'main' panicked at 'attempt to add with overflow' // compile-flags: -C debug-assertions diff --git a/src/test/run-fail/overflowing-lsh-1.rs b/src/test/run-fail/overflowing-lsh-1.rs index e277886d003d..29ce3b0e6a16 100644 --- a/src/test/run-fail/overflowing-lsh-1.rs +++ b/src/test/run-fail/overflowing-lsh-1.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift left with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-lsh-2.rs b/src/test/run-fail/overflowing-lsh-2.rs index 42cb0f2d55bc..62fc9230f353 100644 --- a/src/test/run-fail/overflowing-lsh-2.rs +++ b/src/test/run-fail/overflowing-lsh-2.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift left with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-lsh-3.rs b/src/test/run-fail/overflowing-lsh-3.rs index 8c6623dcf50c..1bc1703a89ce 100644 --- a/src/test/run-fail/overflowing-lsh-3.rs +++ b/src/test/run-fail/overflowing-lsh-3.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift left with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-lsh-4.rs b/src/test/run-fail/overflowing-lsh-4.rs index 3b7a00a2c73c..8de44f25e048 100644 --- a/src/test/run-fail/overflowing-lsh-4.rs +++ b/src/test/run-fail/overflowing-lsh-4.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift left with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions // This function is checking that our automatic truncation does not diff --git a/src/test/run-fail/overflowing-mul.rs b/src/test/run-fail/overflowing-mul.rs index 0e168bf6ffbc..a09c0f06a5cc 100644 --- a/src/test/run-fail/overflowing-mul.rs +++ b/src/test/run-fail/overflowing-mul.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to multiply with overflow' +// error-pattern:thread 'main' panicked at 'attempt to multiply with overflow' // compile-flags: -C debug-assertions fn main() { diff --git a/src/test/run-fail/overflowing-neg.rs b/src/test/run-fail/overflowing-neg.rs index 84e41ea84880..96853fc565b7 100644 --- a/src/test/run-fail/overflowing-neg.rs +++ b/src/test/run-fail/overflowing-neg.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to negate with overflow' +// error-pattern:thread 'main' panicked at 'attempt to negate with overflow' // compile-flags: -C debug-assertions fn main() { diff --git a/src/test/run-fail/overflowing-pow.rs b/src/test/run-fail/overflowing-pow.rs index 9172374ec281..b0ff0df55770 100644 --- a/src/test/run-fail/overflowing-pow.rs +++ b/src/test/run-fail/overflowing-pow.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:thread 'main' panicked at 'attempted to multiply with overflow' +// error-pattern:thread 'main' panicked at 'attempt to multiply with overflow' // compile-flags: -C debug-assertions fn main() { diff --git a/src/test/run-fail/overflowing-rsh-1.rs b/src/test/run-fail/overflowing-rsh-1.rs index d275792485d5..ef4a503cfe42 100644 --- a/src/test/run-fail/overflowing-rsh-1.rs +++ b/src/test/run-fail/overflowing-rsh-1.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift right with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-rsh-2.rs b/src/test/run-fail/overflowing-rsh-2.rs index 1b888cddf644..da072b5a9a5a 100644 --- a/src/test/run-fail/overflowing-rsh-2.rs +++ b/src/test/run-fail/overflowing-rsh-2.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift right with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-rsh-3.rs b/src/test/run-fail/overflowing-rsh-3.rs index be5c213493d6..0b7809402e6d 100644 --- a/src/test/run-fail/overflowing-rsh-3.rs +++ b/src/test/run-fail/overflowing-rsh-3.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift right with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-rsh-4.rs b/src/test/run-fail/overflowing-rsh-4.rs index 820d9611d6ac..1e0cc18fbdcd 100644 --- a/src/test/run-fail/overflowing-rsh-4.rs +++ b/src/test/run-fail/overflowing-rsh-4.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift right with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions // This function is checking that our (type-based) automatic diff --git a/src/test/run-fail/overflowing-rsh-5.rs b/src/test/run-fail/overflowing-rsh-5.rs index b87be696fcb2..690901ff0c25 100644 --- a/src/test/run-fail/overflowing-rsh-5.rs +++ b/src/test/run-fail/overflowing-rsh-5.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift right with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-rsh-6.rs b/src/test/run-fail/overflowing-rsh-6.rs index 554675686b5e..6a6ed4f11f20 100644 --- a/src/test/run-fail/overflowing-rsh-6.rs +++ b/src/test/run-fail/overflowing-rsh-6.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to shift right with overflow' +// error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions #![warn(exceeding_bitshifts)] diff --git a/src/test/run-fail/overflowing-sub.rs b/src/test/run-fail/overflowing-sub.rs index 1cb207240ca4..083e8d24467f 100644 --- a/src/test/run-fail/overflowing-sub.rs +++ b/src/test/run-fail/overflowing-sub.rs @@ -10,7 +10,7 @@ // ignore-pretty : (#23623) problems when ending with // comments -// error-pattern:thread 'main' panicked at 'attempted to subtract with overflow' +// error-pattern:thread 'main' panicked at 'attempt to subtract with overflow' // compile-flags: -C debug-assertions fn main() { diff --git a/src/test/run-make/execution-engine/Makefile b/src/test/run-make/execution-engine/Makefile deleted file mode 100644 index 4c818cd99e2d..000000000000 --- a/src/test/run-make/execution-engine/Makefile +++ /dev/null @@ -1,21 +0,0 @@ --include ../tools.mk - -# FIXME: ignore freebsd -# This is a basic test of LLVM ExecutionEngine functionality using compiled -# Rust code built using the `rustc` crate. - -ifeq ($(filter executionengine,$(LLVM_COMPONENTS)),executionengine) - -ifneq ($(shell uname),FreeBSD) -all: - $(RUSTC) test.rs - $(call RUN,test $(RUSTC)) -else -all: - -endif - -else -all: - -endif diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs deleted file mode 100644 index 2e90b5184326..000000000000 --- a/src/test/run-make/execution-engine/test.rs +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(rustc_private)] -#![feature(libc)] - -extern crate libc; -extern crate rustc; -extern crate rustc_driver; -extern crate rustc_lint; -extern crate rustc_llvm as llvm; -extern crate rustc_metadata; -extern crate rustc_resolve; -extern crate rustc_errors; -extern crate rustc_errors as errors; -#[macro_use] extern crate syntax; - -use std::ffi::{CStr, CString}; -use std::mem::transmute; -use std::path::PathBuf; -use std::rc::Rc; -use std::thread::Builder; - -use rustc::dep_graph::DepGraph; -use rustc::hir::map as ast_map; -use rustc::middle::cstore::LinkagePreference; -use rustc::ty; -use rustc::session::config::{self, basic_options, build_configuration, Input, Options}; -use rustc::session::build_session; -use rustc_driver::{driver, abort_on_err}; -use rustc_resolve::MakeGlobMap; -use rustc_metadata::cstore::CStore; -use libc::c_void; - -use rustc_errors::registry::Registry; - -fn main() { - // Currently trips an assertion on i686-msvc, presumably because the support - // in LLVM is a little young. - if cfg!(target_env = "msvc") && cfg!(target_arch = "x86") { - return - } - - let program = r#" - #[no_mangle] - pub static TEST_STATIC: i32 = 42; - "#; - - let program2 = r#" - #[no_mangle] - pub fn test_add(a: i32, b: i32) -> i32 { a + b } - "#; - - let mut path = match std::env::args().nth(2) { - Some(path) => PathBuf::from(&path), - None => panic!("missing rustc path") - }; - - // Remove two segments from rustc path to get sysroot. - path.pop(); - path.pop(); - - let mut ee = ExecutionEngine::new(program, path); - - let test_static = match ee.get_global("TEST_STATIC") { - Some(g) => g as *const i32, - None => panic!("failed to get global") - }; - - assert_eq!(unsafe { *test_static }, 42); - - ee.add_module(program2); - - let test_add: fn(i32, i32) -> i32; - - test_add = match ee.get_function("test_add") { - Some(f) => unsafe { transmute(f) }, - None => panic!("failed to get function") - }; - - assert_eq!(test_add(1, 2), 3); -} - -struct ExecutionEngine { - ee: llvm::ExecutionEngineRef, - modules: Vec, - sysroot: PathBuf, -} - -impl ExecutionEngine { - pub fn new(program: &str, sysroot: PathBuf) -> ExecutionEngine { - let (llmod, deps) = compile_program(program, sysroot.clone()) - .expect("failed to compile program"); - - let ee = unsafe { llvm::LLVMBuildExecutionEngine(llmod) }; - - if ee.is_null() { - panic!("Failed to create ExecutionEngine: {}", llvm_error()); - } - - let ee = ExecutionEngine{ - ee: ee, - modules: vec![llmod], - sysroot: sysroot, - }; - - ee.load_deps(&deps); - ee - } - - pub fn add_module(&mut self, program: &str) { - let (llmod, deps) = compile_program(program, self.sysroot.clone()) - .expect("failed to compile program in add_module"); - - unsafe { llvm::LLVMExecutionEngineAddModule(self.ee, llmod); } - - self.modules.push(llmod); - self.load_deps(&deps); - } - - /// Returns a raw pointer to the named function. - pub fn get_function(&mut self, name: &str) -> Option<*const c_void> { - let s = CString::new(name.as_bytes()).unwrap(); - - for &m in &self.modules { - let fv = unsafe { llvm::LLVMGetNamedFunction(m, s.as_ptr()) }; - - if !fv.is_null() { - let fp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, fv) }; - - assert!(!fp.is_null()); - return Some(fp); - } - } - None - } - - /// Returns a raw pointer to the named global item. - pub fn get_global(&mut self, name: &str) -> Option<*const c_void> { - let s = CString::new(name.as_bytes()).unwrap(); - - for &m in &self.modules { - let gv = unsafe { llvm::LLVMGetNamedGlobal(m, s.as_ptr()) }; - - if !gv.is_null() { - let gp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, gv) }; - - assert!(!gp.is_null()); - return Some(gp); - } - } - None - } - - /// Loads all dependencies of compiled code. - /// Expects a series of paths to dynamic library files. - fn load_deps(&self, deps: &[PathBuf]) { - for path in deps { - let s = match path.as_os_str().to_str() { - Some(s) => s, - None => panic!( - "Could not convert crate path to UTF-8 string: {:?}", path) - }; - let cs = CString::new(s).unwrap(); - - let res = unsafe { llvm::LLVMRustLoadDynamicLibrary(cs.as_ptr()) }; - - if res == 0 { - panic!("Failed to load crate {:?}: {}", - path.display(), llvm_error()); - } - } - } -} - -impl Drop for ExecutionEngine { - fn drop(&mut self) { - unsafe { llvm::LLVMDisposeExecutionEngine(self.ee) }; - } -} - -/// Returns last error from LLVM wrapper code. -fn llvm_error() -> String { - String::from_utf8_lossy( - unsafe { CStr::from_ptr(llvm::LLVMRustGetLastError()).to_bytes() }) - .into_owned() -} - -fn build_exec_options(sysroot: PathBuf) -> Options { - let mut opts = basic_options(); - - // librustc derives sysroot from the executable name. - // Since we are not rustc, we must specify it. - opts.maybe_sysroot = Some(sysroot); - - // Prefer faster build time - opts.optimize = config::OptLevel::No; - - // Don't require a `main` function - opts.crate_types = vec![config::CrateTypeDylib]; - - opts -} - -/// Compiles input up to phase 4, translation to LLVM. -/// -/// Returns the LLVM `ModuleRef` and a series of paths to dynamic libraries -/// for crates used in the given input. -fn compile_program(input: &str, sysroot: PathBuf) - -> Option<(llvm::ModuleRef, Vec)> { - let input = Input::Str { - name: driver::anon_src(), - input: input.to_string(), - }; - let thread = Builder::new().name("compile_program".to_string()); - - let handle = thread.spawn(move || { - let opts = build_exec_options(sysroot); - let dep_graph = DepGraph::new(opts.build_dep_graph()); - let cstore = Rc::new(CStore::new(&dep_graph)); - let sess = build_session(opts, - &dep_graph, - None, - Registry::new(&rustc::DIAGNOSTICS), - cstore.clone()); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - - let cfg = build_configuration(&sess); - - let id = "input".to_string(); - - let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input)); - - let driver::ExpansionResult { defs, analysis, resolutions, mut hir_forest, .. } = { - driver::phase_2_configure_and_expand( - &sess, &cstore, krate, &id, None, MakeGlobMap::No, |_| Ok(()), - ).expect("phase_2 returned `None`") - }; - - let arenas = ty::CtxtArenas::new(); - let ast_map = ast_map::map_crate(&mut hir_forest, defs); - - abort_on_err(driver::phase_3_run_analysis_passes( - &sess, ast_map, analysis, resolutions, &arenas, &id, - |tcx, mir_map, analysis, _| { - - let trans = driver::phase_4_translate_to_llvm(tcx, mir_map.unwrap(), analysis); - - let crates = tcx.sess.cstore.used_crates(LinkagePreference::RequireDynamic); - - // Collect crates used in the session. - // Reverse order finds dependencies first. - let deps = crates.into_iter().rev() - .filter_map(|(_, p)| p).collect(); - - assert_eq!(trans.modules.len(), 1); - let llmod = trans.modules[0].llmod; - - // Workaround because raw pointers do not impl Send - let modp = llmod as usize; - - (modp, deps) - }), &sess) - }).unwrap(); - - match handle.join() { - Ok((llmod, deps)) => Some((llmod as llvm::ModuleRef, deps)), - Err(_) => None - } -} diff --git a/src/test/run-make/issue-33329/Makefile b/src/test/run-make/issue-33329/Makefile new file mode 100644 index 000000000000..c53f51d5bf58 --- /dev/null +++ b/src/test/run-make/issue-33329/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +all: + $(RUSTC) --target x86_64_unknown-linux-musl main.rs 2>&1 | \ + grep "error: Error loading target specification: Could not find specification for target" diff --git a/src/test/run-make/issue-33329/main.rs b/src/test/run-make/issue-33329/main.rs new file mode 100644 index 000000000000..e06c0a5ec2a4 --- /dev/null +++ b/src/test/run-make/issue-33329/main.rs @@ -0,0 +1,11 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() {} diff --git a/src/test/run-make/llvm-phase/test.rs b/src/test/run-make/llvm-phase/test.rs index 402b5ed83556..19e410fef538 100644 --- a/src/test/run-make/llvm-phase/test.rs +++ b/src/test/run-make/llvm-phase/test.rs @@ -13,11 +13,13 @@ extern crate rustc; extern crate rustc_driver; extern crate rustc_llvm; +extern crate rustc_trans; #[macro_use] extern crate syntax; extern crate getopts; use rustc_driver::{CompilerCalls, Compilation}; use rustc_driver::driver::CompileController; +use rustc_trans::ModuleSource; use rustc::session::Session; use syntax::codemap::FileLoader; use std::io; @@ -51,7 +53,10 @@ impl<'a> CompilerCalls<'a> for JitCalls { state.session.abort_if_errors(); let trans = state.trans.unwrap(); assert_eq!(trans.modules.len(), 1); - let rs_llmod = trans.modules[0].llmod; + let rs_llmod = match trans.modules[0].source { + ModuleSource::Preexisting(_) => unimplemented!(), + ModuleSource::Translated(llvm) => llvm.llmod, + }; unsafe { rustc_llvm::LLVMDumpModule(rs_llmod) }; }); cc diff --git a/src/test/run-pass/coerce-match-calls.rs b/src/test/run-pass-valgrind/coerce-match-calls.rs similarity index 100% rename from src/test/run-pass/coerce-match-calls.rs rename to src/test/run-pass-valgrind/coerce-match-calls.rs diff --git a/src/test/run-pass/coerce-match.rs b/src/test/run-pass-valgrind/coerce-match.rs similarity index 100% rename from src/test/run-pass/coerce-match.rs rename to src/test/run-pass-valgrind/coerce-match.rs diff --git a/src/test/run-pass/assignability-trait.rs b/src/test/run-pass/assignability-trait.rs index 0ee460052c73..c364240f4ad6 100644 --- a/src/test/run-pass/assignability-trait.rs +++ b/src/test/run-pass/assignability-trait.rs @@ -12,9 +12,6 @@ // making method calls, but only if there aren't any matches without // it. - -#![feature(unboxed_closures)] - trait iterable { fn iterate(&self, blk: F) -> bool where F: FnMut(&A) -> bool; } diff --git a/src/test/run-pass/associated-types-impl-redirect.rs b/src/test/run-pass/associated-types-impl-redirect.rs index 4082580a123f..3e34367a2158 100644 --- a/src/test/run-pass/associated-types-impl-redirect.rs +++ b/src/test/run-pass/associated-types-impl-redirect.rs @@ -14,7 +14,7 @@ // for `ByRef`. The right answer was to consider the result ambiguous // until more type information was available. -#![feature(lang_items, unboxed_closures)] +#![feature(lang_items)] #![no_implicit_prelude] use std::marker::Sized; diff --git a/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs b/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs index 082ad53d5593..ef1225d39a70 100644 --- a/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs +++ b/src/test/run-pass/associated-types-where-clause-impl-ambiguity.rs @@ -14,7 +14,7 @@ // for `ByRef`. The right answer was to consider the result ambiguous // until more type information was available. -#![feature(lang_items, unboxed_closures)] +#![feature(lang_items)] #![no_implicit_prelude] use std::marker::Sized; diff --git a/src/test/run-pass/auxiliary/issue-18711.rs b/src/test/run-pass/auxiliary/issue-18711.rs index a29dcc00cddf..c247c0223fcb 100644 --- a/src/test/run-pass/auxiliary/issue-18711.rs +++ b/src/test/run-pass/auxiliary/issue-18711.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] #![crate_type = "rlib"] pub fn inner(f: F) -> F { diff --git a/src/test/run-pass/auxiliary/unboxed-closures-cross-crate.rs b/src/test/run-pass/auxiliary/unboxed-closures-cross-crate.rs index dac20dd2f7a7..dc9798a21016 100644 --- a/src/test/run-pass/auxiliary/unboxed-closures-cross-crate.rs +++ b/src/test/run-pass/auxiliary/unboxed-closures-cross-crate.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::ops::Add; #[inline] diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index ad38dc8f4525..f1ce17c0736b 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -46,19 +46,7 @@ fn template(me: &str) -> Command { } fn expected(fn_name: &str) -> String { - // FIXME(#32481) - // - // On windows, we read the function name from debuginfo using some - // system APIs. For whatever reason, these APIs seem to use the - // "name" field, which is only the "relative" name, not the full - // name with namespace info, so we just see `foo` and not - // `backtrace::foo` as we see on linux (which uses the linkage - // name). - if cfg!(windows) && cfg!(target_env = "msvc") { - format!(" - {}", fn_name) - } else { - format!(" - backtrace::{}", fn_name) - } + format!(" - backtrace::{}", fn_name) } fn runtest(me: &str) { diff --git a/src/test/run-pass/bare-fn-implements-fn-mut.rs b/src/test/run-pass/bare-fn-implements-fn-mut.rs index e8118e90a9f3..30a11ca2536d 100644 --- a/src/test/run-pass/bare-fn-implements-fn-mut.rs +++ b/src/test/run-pass/bare-fn-implements-fn-mut.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::ops::FnMut; fn call_f(mut f: F) { diff --git a/src/test/run-pass/borrowck/borrowck-move-by-capture-ok.rs b/src/test/run-pass/borrowck/borrowck-move-by-capture-ok.rs index bbc668f5cabf..158594df8cac 100644 --- a/src/test/run-pass/borrowck/borrowck-move-by-capture-ok.rs +++ b/src/test/run-pass/borrowck/borrowck-move-by-capture-ok.rs @@ -11,7 +11,6 @@ #![allow(unknown_features)] #![feature(box_syntax)] -#![feature(unboxed_closures)] pub fn main() { let bar: Box<_> = box 3; diff --git a/src/test/run-pass/capture-clauses-unboxed-closures.rs b/src/test/run-pass/capture-clauses-unboxed-closures.rs index 5e7d5aacb8d0..e8a9dc7b8f36 100644 --- a/src/test/run-pass/capture-clauses-unboxed-closures.rs +++ b/src/test/run-pass/capture-clauses-unboxed-closures.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(unboxed_closures)] - fn each<'a,T,F:FnMut(&'a T)>(x: &'a [T], mut f: F) { for val in x { f(val) diff --git a/src/test/run-pass/closure-bounds-can-capture-chan.rs b/src/test/run-pass/closure-bounds-can-capture-chan.rs index dbbac8a16333..5268e855d5fd 100644 --- a/src/test/run-pass/closure-bounds-can-capture-chan.rs +++ b/src/test/run-pass/closure-bounds-can-capture-chan.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - use std::sync::mpsc::channel; fn foo(blk: F) { diff --git a/src/test/run-pass/closure-reform.rs b/src/test/run-pass/closure-reform.rs index 0fa67e873f89..a37733bdc2df 100644 --- a/src/test/run-pass/closure-reform.rs +++ b/src/test/run-pass/closure-reform.rs @@ -11,8 +11,6 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -#![feature(unboxed_closures)] - fn call_it(f: F) where F : FnOnce(String) -> String { diff --git a/src/test/run-pass/const-byte-str-cast.rs b/src/test/run-pass/const-byte-str-cast.rs index 2f265b9112b9..7297c71a6d66 100644 --- a/src/test/run-pass/const-byte-str-cast.rs +++ b/src/test/run-pass/const-byte-str-cast.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -12,4 +12,7 @@ pub fn main() { let _ = b"x" as &[u8]; + let _ = b"y" as &[u8; 1]; + let _ = b"z" as *const u8; + let _ = "ä" as *const str; } diff --git a/src/test/run-pass/env-args-reverse-iterator.rs b/src/test/run-pass/env-args-reverse-iterator.rs new file mode 100644 index 000000000000..d22fa6494f03 --- /dev/null +++ b/src/test/run-pass/env-args-reverse-iterator.rs @@ -0,0 +1,44 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::env::args; +use std::process::Command; + +fn assert_reverse_iterator_for_program_arguments(program_name: &str) { + let args: Vec<_> = args().rev().collect(); + + assert!(args.len() == 4); + assert_eq!(args[0], "c"); + assert_eq!(args[1], "b"); + assert_eq!(args[2], "a"); + assert_eq!(args[3], program_name); + + println!("passed"); +} + +fn main() { + let mut args = args(); + let me = args.next().unwrap(); + + if let Some(_) = args.next() { + assert_reverse_iterator_for_program_arguments(&me); + return + } + + let output = Command::new(&me) + .arg("a") + .arg("b") + .arg("c") + .output() + .unwrap(); + assert!(output.status.success()); + assert!(output.stderr.is_empty()); + assert_eq!(output.stdout, b"passed\n"); +} diff --git a/src/test/run-pass/hashmap-memory.rs b/src/test/run-pass/hashmap-memory.rs index 4dae1131c6d9..3f6f1aa6b5fe 100644 --- a/src/test/run-pass/hashmap-memory.rs +++ b/src/test/run-pass/hashmap-memory.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(unknown_features)] -#![feature(unboxed_closures, std_misc)] +#![feature(std_misc)] /** A somewhat reduced test case to expose some Valgrind issues. diff --git a/src/test/run-pass/hrtb-parse.rs b/src/test/run-pass/hrtb-parse.rs index ecd0bc681c31..cdffaef66eb2 100644 --- a/src/test/run-pass/hrtb-parse.rs +++ b/src/test/run-pass/hrtb-parse.rs @@ -13,7 +13,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] #![allow(unused_variables)] #![allow(dead_code)] diff --git a/src/test/run-pass/hrtb-precedence-of-plus-where-clause.rs b/src/test/run-pass/hrtb-precedence-of-plus-where-clause.rs index bc00a0758f45..46ea25629619 100644 --- a/src/test/run-pass/hrtb-precedence-of-plus-where-clause.rs +++ b/src/test/run-pass/hrtb-precedence-of-plus-where-clause.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - // Test that `F : Fn(isize) -> isize + Send` is interpreted as two // distinct bounds on `F`. diff --git a/src/test/run-pass/hrtb-precedence-of-plus.rs b/src/test/run-pass/hrtb-precedence-of-plus.rs index 892f2f1ae9df..d93e52a8f5fb 100644 --- a/src/test/run-pass/hrtb-precedence-of-plus.rs +++ b/src/test/run-pass/hrtb-precedence-of-plus.rs @@ -11,7 +11,6 @@ // pretty-expanded FIXME #23616 #![allow(unknown_features)] -#![feature(unboxed_closures)] // Test that `Fn(isize) -> isize + 'static` parses as `(Fn(isize) -> isize) + // 'static` and not `Fn(isize) -> (isize + 'static)`. The latter would diff --git a/src/test/run-pass/hrtb-trait-object-paren-notation.rs b/src/test/run-pass/hrtb-trait-object-paren-notation.rs index fefbd0047668..5b9d4a834d87 100644 --- a/src/test/run-pass/hrtb-trait-object-paren-notation.rs +++ b/src/test/run-pass/hrtb-trait-object-paren-notation.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(unboxed_closures)] - // A basic test of using a higher-ranked trait bound. trait FnLike { diff --git a/src/test/run-pass/hrtb-unboxed-closure-trait.rs b/src/test/run-pass/hrtb-unboxed-closure-trait.rs index 008e7ddbc9c5..6666b61a4a72 100644 --- a/src/test/run-pass/hrtb-unboxed-closure-trait.rs +++ b/src/test/run-pass/hrtb-unboxed-closure-trait.rs @@ -10,8 +10,6 @@ // Test HRTB used with the `Fn` trait. -#![feature(unboxed_closures)] - fn foo(f: F) { let x = 22; f(&x); diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 0a69ccf47dd9..8b5536de12e4 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -70,15 +70,15 @@ pub fn main() { t!(format!("{}", '☃'), "☃"); t!(format!("{}", 10), "10"); t!(format!("{}", 10_usize), "10"); - t!(format!("{:?}", '☃'), "'\\u{2603}'"); + t!(format!("{:?}", '☃'), "'☃'"); t!(format!("{:?}", 10), "10"); t!(format!("{:?}", 10_usize), "10"); t!(format!("{:?}", "true"), "\"true\""); t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\""); t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#); - t!(format!("{:?}", "foo\0bar\x01baz\u{3b1}q\u{75}x"), - r#""foo\u{0}bar\u{1}baz\u{3b1}qux""#); + t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"), + r#""foo\u{0}bar\u{1}baz\u{7f}qux""#); t!(format!("{:o}", 10_usize), "12"); t!(format!("{:x}", 10_usize), "a"); t!(format!("{:X}", 10_usize), "A"); @@ -125,7 +125,7 @@ pub fn main() { t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), " aaaa"); t!(format!("{:2.4}", "aaaaa"), "aaaa"); t!(format!("{:2.4}", "aaaa"), "aaaa"); t!(format!("{:2.4}", "aaa"), "aaa"); @@ -140,6 +140,7 @@ pub fn main() { t!(format!("{:a$}", "a", a=4), "a "); t!(format!("{:-#}", "a"), "a"); t!(format!("{:+#}", "a"), "a"); + t!(format!("{:/^10.8}", "1234567890"), "/12345678/"); // Some float stuff t!(format!("{:}", 1.0f32), "1"); diff --git a/src/test/run-pass/issue-10718.rs b/src/test/run-pass/issue-10718.rs index 0a6e454e181a..fedd94e22e7b 100644 --- a/src/test/run-pass/issue-10718.rs +++ b/src/test/run-pass/issue-10718.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - fn f(p: F) { p(); } diff --git a/src/test/run-pass/issue-14936.rs b/src/test/run-pass/issue-14936.rs index 5f8e7cb8145e..428d4e4dbb12 100644 --- a/src/test/run-pass/issue-14936.rs +++ b/src/test/run-pass/issue-14936.rs @@ -28,7 +28,8 @@ macro_rules! demo { unsafe { asm!("mov ($1), $0" : $output_constraint (*wrap(&mut x, "out", &mut history)) - : "r"(&wrap(y, "in", &mut history))); + : "r"(&wrap(y, "in", &mut history)) + :: "volatile"); } assert_eq!((x,y), (1,1)); let b: &[_] = &["out", "in"]; diff --git a/src/test/run-pass/issue-16560.rs b/src/test/run-pass/issue-16560.rs index 596f0d20155d..e91569f8b245 100644 --- a/src/test/run-pass/issue-16560.rs +++ b/src/test/run-pass/issue-16560.rs @@ -10,8 +10,6 @@ // ignore-emscripten no threads support -#![feature(unboxed_closures)] - use std::thread; use std::mem; diff --git a/src/test/run-pass/issue-16668.rs b/src/test/run-pass/issue-16668.rs index 786c701a0427..0fd996502848 100644 --- a/src/test/run-pass/issue-16668.rs +++ b/src/test/run-pass/issue-16668.rs @@ -11,7 +11,6 @@ // ignore-pretty #![allow(unknown_features)] -#![feature(unboxed_closures)] struct Parser<'a, I, O> { parse: Box Result + 'a> diff --git a/src/test/run-pass/issue-16774.rs b/src/test/run-pass/issue-16774.rs index 627717ab1cd1..9ec5910c2f67 100644 --- a/src/test/run-pass/issue-16774.rs +++ b/src/test/run-pass/issue-16774.rs @@ -12,7 +12,6 @@ #![allow(unknown_features)] #![feature(box_syntax)] #![feature(box_patterns)] -#![feature(unboxed_closures)] use std::ops::{Deref, DerefMut}; diff --git a/src/test/run-pass/issue-17816.rs b/src/test/run-pass/issue-17816.rs index 8e3cb414566c..a9aa4cdd4f69 100644 --- a/src/test/run-pass/issue-17816.rs +++ b/src/test/run-pass/issue-17816.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::marker::PhantomData; fn main() { diff --git a/src/test/run-pass/issue-18652.rs b/src/test/run-pass/issue-18652.rs index 8ab645e54add..cea0beaf5f07 100644 --- a/src/test/run-pass/issue-18652.rs +++ b/src/test/run-pass/issue-18652.rs @@ -12,9 +12,6 @@ // once closure as an optimization by trans. This used to hit an // incorrect assert. - -#![feature(unboxed_closures)] - fn main() { let x = 2u8; let y = 3u8; diff --git a/src/test/run-pass/issue-18685.rs b/src/test/run-pass/issue-18685.rs index e4537e158d12..b569dbc8062e 100644 --- a/src/test/run-pass/issue-18685.rs +++ b/src/test/run-pass/issue-18685.rs @@ -13,8 +13,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - trait Tr { fn foo(&self); diff --git a/src/test/run-pass/issue-18711.rs b/src/test/run-pass/issue-18711.rs index 277ad3260c51..8239d74d6df1 100644 --- a/src/test/run-pass/issue-18711.rs +++ b/src/test/run-pass/issue-18711.rs @@ -13,8 +13,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - // aux-build:issue-18711.rs extern crate issue_18711 as issue; diff --git a/src/test/run-pass/issue-19127.rs b/src/test/run-pass/issue-19127.rs index c5eb50693280..8d169917cad9 100644 --- a/src/test/run-pass/issue-19127.rs +++ b/src/test/run-pass/issue-19127.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - fn foo T>(f: F) {} fn id<'a>(input: &'a u8) -> &'a u8 { input } diff --git a/src/test/run-pass/issue-19135.rs b/src/test/run-pass/issue-19135.rs index 5e6dd567d632..ca2098138ef0 100644 --- a/src/test/run-pass/issue-19135.rs +++ b/src/test/run-pass/issue-19135.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::marker::PhantomData; #[derive(Debug)] diff --git a/src/test/run-pass/issue-28950.rs b/src/test/run-pass/issue-28950.rs index f01ce46a891d..efce148ea51d 100644 --- a/src/test/run-pass/issue-28950.rs +++ b/src/test/run-pass/issue-28950.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z orbit=off +// (blows the stack with MIR trans and no optimizations) + // Tests that the `vec!` macro does not overflow the stack when it is // given data larger than the stack. diff --git a/src/test/run-pass/issue-34932.rs b/src/test/run-pass/issue-34932.rs new file mode 100644 index 000000000000..e83939e7aec6 --- /dev/null +++ b/src/test/run-pass/issue-34932.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:--test +// rustc-env:RUSTC_BOOTSTRAP_KEY= +// ignore-pretty : (#23623) problems when ending with // comments + +#![cfg(any())] // This test should be configured away +#![feature(rustc_attrs)] // Test that this is allowed on stable/beta +#![feature(iter_arith_traits)] // Test that this is not unused +#![deny(unused_features)] + +#[test] +fn dummy() { + let () = "this should not reach type-checking"; +} diff --git a/src/test/run-pass/macro-of-higher-order.rs b/src/test/run-pass/macro-of-higher-order.rs index 52e19b37d793..c982e8ac6f83 100644 --- a/src/test/run-pass/macro-of-higher-order.rs +++ b/src/test/run-pass/macro-of-higher-order.rs @@ -16,7 +16,16 @@ macro_rules! higher_order { }); } +macro_rules! outer { + ($x:expr; $fragment:ident) => { + macro_rules! inner { ($y:$fragment) => { $x + $y } } + } +} + fn main() { let val = higher_order!(subst ($x:expr, $y:expr, $foo:expr) => (($x + $y, $foo))); assert_eq!(val, (3, "foo")); + + outer!(2; expr); + assert_eq!(inner!(3), 5); } diff --git a/src/test/run-pass/mir_cross_crate.rs b/src/test/run-pass/mir_cross_crate.rs new file mode 100644 index 000000000000..cc239d9f68b1 --- /dev/null +++ b/src/test/run-pass/mir_cross_crate.rs @@ -0,0 +1,28 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z orbit +// Tests that -Z orbit affects functions from other crates. + +#![feature(unsafe_no_drop_flag)] + +#[unsafe_no_drop_flag] +struct Foo; + +impl Drop for Foo { + fn drop(&mut self) { + panic!("MIR trans is not enabled for mem::forget"); + } +} + +fn main() { + let x = Foo; + std::mem::forget(x); +} diff --git a/src/test/run-pass/mir_overflow_off.rs b/src/test/run-pass/mir_overflow_off.rs new file mode 100644 index 000000000000..04ac606a8a9a --- /dev/null +++ b/src/test/run-pass/mir_overflow_off.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z force-overflow-checks=off -Z orbit + +// Test that with MIR trans, overflow checks can be +// turned off, even when they're from core::ops::*. + +use std::ops::*; + +fn main() { + assert_eq!(i8::neg(-0x80), -0x80); + + assert_eq!(u8::add(0xff, 1), 0_u8); + assert_eq!(u8::sub(0, 1), 0xff_u8); + assert_eq!(u8::mul(0xff, 2), 0xfe_u8); + assert_eq!(u8::shl(1, 9), 2_u8); + assert_eq!(u8::shr(2, 9), 1_u8); +} diff --git a/src/test/run-pass/mir_trans_calls.rs b/src/test/run-pass/mir_trans_calls.rs index ca3294a87adb..7ff684a5ef39 100644 --- a/src/test/run-pass/mir_trans_calls.rs +++ b/src/test/run-pass/mir_trans_calls.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs, unboxed_closures, fn_traits)] +#![feature(rustc_attrs, fn_traits)] #[rustc_mir] fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) { diff --git a/src/test/run-pass/myriad-closures.rs b/src/test/run-pass/myriad-closures.rs new file mode 100644 index 000000000000..d2c9a5d562b0 --- /dev/null +++ b/src/test/run-pass/myriad-closures.rs @@ -0,0 +1,48 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This test case tests whether we can handle code bases that contain a high +// number of closures, something that needs special handling in the MingGW +// toolchain. +// See https://github.com/rust-lang/rust/issues/34793 for more information. + +// Expand something exponentially +macro_rules! go_bacterial { + ($mac:ident) => ($mac!()); + ($mac:ident 1 $($t:tt)*) => ( + go_bacterial!($mac $($t)*); + go_bacterial!($mac $($t)*); + ) +} + +macro_rules! mk_closure { + () => ({ + let c = |a: u32| a + 4; + let _ = c(2); + }) +} + +macro_rules! mk_fn { + () => { + { + fn function() { + // Make 16 closures + go_bacterial!(mk_closure 1 1 1 1); + } + let _ = function(); + } + } +} + +fn main() { + // Make 2^12 functions, each containing 16 closures, + // resulting in 2^16 closures overall. + go_bacterial!(mk_fn 1 1 1 1 1 1 1 1 1 1 1 1); +} diff --git a/src/test/run-pass/simd-upgraded.rs b/src/test/run-pass/simd-upgraded.rs new file mode 100644 index 000000000000..821a505c1384 --- /dev/null +++ b/src/test/run-pass/simd-upgraded.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that removed LLVM SIMD intrinsics continue +// to work via the "AutoUpgrade" mechanism. + +#![feature(cfg_target_feature, repr_simd)] +#![feature(platform_intrinsics, stmt_expr_attributes)] + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); + +fn main() { + #[cfg(target_feature = "sse2")] unsafe { + extern "platform-intrinsic" { + fn x86_mm_min_epi16(x: i16x8, y: i16x8) -> i16x8; + } + assert_eq!(x86_mm_min_epi16(i16x8(0, 1, 2, 3, 4, 5, 6, 7), + i16x8(7, 6, 5, 4, 3, 2, 1, 0)), + i16x8(0, 1, 2, 3, 3, 2, 1, 0)); + }; +} diff --git a/src/test/run-pass/sync-send-iterators-in-libcore.rs b/src/test/run-pass/sync-send-iterators-in-libcore.rs index 931789948159..d12bdf182fa4 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcore.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcore.rs @@ -67,7 +67,7 @@ macro_rules! is_sync_send { fn main() { // for char.rs - all_sync_send!("Я", escape_default, escape_unicode); + all_sync_send!("Я", escape_debug, escape_default, escape_unicode); // for iter.rs all_sync_send_mutable_ref!([1], iter); diff --git a/src/test/run-pass/tcp-stress.rs b/src/test/run-pass/tcp-stress.rs index dfc86497c965..0ba019c591c1 100644 --- a/src/test/run-pass/tcp-stress.rs +++ b/src/test/run-pass/tcp-stress.rs @@ -21,6 +21,8 @@ use std::sync::mpsc::channel; use std::time::Duration; use std::thread::{self, Builder}; +const TARGET_CNT: usize = 200; + fn main() { // This test has a chance to time out, try to not let it time out thread::spawn(move|| -> () { @@ -42,8 +44,9 @@ fn main() { }); let (tx, rx) = channel(); + let mut spawned_cnt = 0; - for _ in 0..1000 { + for _ in 0..TARGET_CNT { let tx = tx.clone(); let res = Builder::new().stack_size(64 * 1024).spawn(move|| { match TcpStream::connect(addr) { @@ -66,6 +69,6 @@ fn main() { for _ in 0..spawned_cnt { rx.recv().unwrap(); } - assert_eq!(spawned_cnt, 1000); + assert_eq!(spawned_cnt, TARGET_CNT); process::exit(0); } diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs index 24dc73d4a43d..0de6fbc91cc6 100644 --- a/src/test/run-pass/trait-bounds-in-arc.rs +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -16,7 +16,6 @@ #![allow(unknown_features)] #![feature(box_syntax, std_misc)] -#![feature(unboxed_closures)] use std::sync::Arc; use std::sync::mpsc::channel; diff --git a/src/test/run-pass/type-id-higher-rank.rs b/src/test/run-pass/type-id-higher-rank.rs index 3030833c7721..c29fb5e86f51 100644 --- a/src/test/run-pass/type-id-higher-rank.rs +++ b/src/test/run-pass/type-id-higher-rank.rs @@ -12,7 +12,7 @@ // Also acts as a regression test for an ICE (issue #19791) -#![feature(unboxed_closures, core)] +#![feature(core)] use std::any::{Any, TypeId}; diff --git a/src/test/run-pass/unboxed-closures-all-traits.rs b/src/test/run-pass/unboxed-closures-all-traits.rs index c28d4f463e57..201500d0c628 100644 --- a/src/test/run-pass/unboxed-closures-all-traits.rs +++ b/src/test/run-pass/unboxed-closures-all-traits.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(lang_items, unboxed_closures)] +#![feature(lang_items)] fn a isize>(f: F) -> isize { f(1, 2) diff --git a/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs index 54c92900c89b..23ec0cb5f60f 100644 --- a/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs +++ b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs @@ -10,8 +10,7 @@ // Test that you can supply `&F` where `F: FnMut()`. - -#![feature(lang_items, unboxed_closures)] +#![feature(lang_items)] fn a i32>(mut f: F) -> i32 { f() diff --git a/src/test/run-pass/unboxed-closures-blanket-fn.rs b/src/test/run-pass/unboxed-closures-blanket-fn.rs index eb474473094a..2aa48e7d2add 100644 --- a/src/test/run-pass/unboxed-closures-blanket-fn.rs +++ b/src/test/run-pass/unboxed-closures-blanket-fn.rs @@ -10,8 +10,7 @@ // Test that you can supply `&F` where `F: Fn()`. - -#![feature(lang_items, unboxed_closures)] +#![feature(lang_items)] fn a i32>(f: F) -> i32 { f() diff --git a/src/test/run-pass/unboxed-closures-boxed.rs b/src/test/run-pass/unboxed-closures-boxed.rs index 5dea6a7c6db3..069f26841d2c 100644 --- a/src/test/run-pass/unboxed-closures-boxed.rs +++ b/src/test/run-pass/unboxed-closures-boxed.rs @@ -10,7 +10,6 @@ #![allow(unknown_features)] #![feature(box_syntax)] -#![feature(unboxed_closures)] use std::ops::FnMut; diff --git a/src/test/run-pass/unboxed-closures-by-ref.rs b/src/test/run-pass/unboxed-closures-by-ref.rs index e3ddfdbac00f..b251215909a4 100644 --- a/src/test/run-pass/unboxed-closures-by-ref.rs +++ b/src/test/run-pass/unboxed-closures-by-ref.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(unboxed_closures)] - // Test by-ref capture of environment in unboxed closure types fn call_fn(f: F) { diff --git a/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs b/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs index 64236ce563b0..56c53bcafced 100644 --- a/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs +++ b/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs @@ -10,9 +10,6 @@ // Test that the call operator autoderefs when calling a bounded type parameter. - -#![feature(unboxed_closures)] - use std::ops::FnMut; fn call_with_2(x: &fn(isize) -> isize) -> isize diff --git a/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs b/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs index 67ab84f0276c..63667ec11d66 100644 --- a/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs +++ b/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs @@ -10,9 +10,6 @@ // Test that the call operator autoderefs when calling a bounded type parameter. - -#![feature(unboxed_closures)] - use std::ops::FnMut; fn call_with_2(x: &mut F) -> isize diff --git a/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs b/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs index c82026235c2a..a92fb05306f4 100644 --- a/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs +++ b/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs @@ -11,7 +11,6 @@ // Test that the call operator autoderefs when calling to an object type. #![allow(unknown_features)] -#![feature(unboxed_closures)] use std::ops::FnMut; diff --git a/src/test/run-pass/unboxed-closures-call-sugar-object.rs b/src/test/run-pass/unboxed-closures-call-sugar-object.rs index 629da1091ac5..5dd2343cfd1d 100644 --- a/src/test/run-pass/unboxed-closures-call-sugar-object.rs +++ b/src/test/run-pass/unboxed-closures-call-sugar-object.rs @@ -9,7 +9,6 @@ // except according to those terms. #![allow(unknown_features)] -#![feature(unboxed_closures)] use std::ops::FnMut; diff --git a/src/test/run-pass/unboxed-closures-counter-not-moved.rs b/src/test/run-pass/unboxed-closures-counter-not-moved.rs index cb5f190bcd73..0b85916d2241 100644 --- a/src/test/run-pass/unboxed-closures-counter-not-moved.rs +++ b/src/test/run-pass/unboxed-closures-counter-not-moved.rs @@ -10,7 +10,6 @@ // Test that we mutate a counter on the stack only when we expect to. - fn call(f: F) where F : FnOnce() { f(); } diff --git a/src/test/run-pass/unboxed-closures-direct-sugary-call.rs b/src/test/run-pass/unboxed-closures-direct-sugary-call.rs index c91aa6ed0d92..c8da4a6992a1 100644 --- a/src/test/run-pass/unboxed-closures-direct-sugary-call.rs +++ b/src/test/run-pass/unboxed-closures-direct-sugary-call.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - fn main() { let mut unboxed = || {}; unboxed(); diff --git a/src/test/run-pass/unboxed-closures-drop.rs b/src/test/run-pass/unboxed-closures-drop.rs index 78f4905aef97..57f2f87e2469 100644 --- a/src/test/run-pass/unboxed-closures-drop.rs +++ b/src/test/run-pass/unboxed-closures-drop.rs @@ -11,9 +11,6 @@ // A battery of tests to ensure destructors of unboxed closure environments // run at the right times. - -#![feature(unboxed_closures)] - static mut DROP_COUNT: usize = 0; fn drop_count() -> usize { diff --git a/src/test/run-pass/unboxed-closures-extern-fn.rs b/src/test/run-pass/unboxed-closures-extern-fn.rs index 57acbae4ce6d..eddb6080d17b 100644 --- a/src/test/run-pass/unboxed-closures-extern-fn.rs +++ b/src/test/run-pass/unboxed-closures-extern-fn.rs @@ -10,10 +10,6 @@ // Checks that extern fn pointers implement the full range of Fn traits. - -#![feature(unboxed_closures)] -#![feature(unboxed_closures)] - use std::ops::{Fn,FnMut,FnOnce}; fn square(x: isize) -> isize { x * x } diff --git a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs index 2e63c600a46c..f90aced3dbe3 100644 --- a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs @@ -11,7 +11,6 @@ // Checks that the Fn trait hierarchy rules permit // any Fn trait to be used where Fn is implemented. - #![feature(unboxed_closures, fn_traits)] use std::ops::{Fn,FnMut,FnOnce}; diff --git a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs index ce93fcafc9e7..0a977cef442e 100644 --- a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs @@ -11,7 +11,6 @@ // Checks that the Fn trait hierarchy rules permit // FnMut or FnOnce to be used where FnMut is implemented. - #![feature(unboxed_closures, fn_traits)] struct S; diff --git a/src/test/run-pass/unboxed-closures-generic.rs b/src/test/run-pass/unboxed-closures-generic.rs index 47936ba93828..01c81ef98d50 100644 --- a/src/test/run-pass/unboxed-closures-generic.rs +++ b/src/test/run-pass/unboxed-closures-generic.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::ops::FnMut; fn call_iti32>(y: i32, mut f: F) -> i32 { diff --git a/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs b/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs index 2da899ed95b5..17833033492d 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs @@ -11,7 +11,6 @@ // Test that we are able to infer a suitable kind for this closure // that is just called (`FnMut`). - fn main() { let mut counter = 0; diff --git a/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs b/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs index 32fc3433e847..794527249bff 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs @@ -11,7 +11,6 @@ // Test that we are able to infer a suitable kind for this `move` // closure that is just called (`FnMut`). - fn main() { let mut counter = 0; diff --git a/src/test/run-pass/unboxed-closures-infer-fnmut.rs b/src/test/run-pass/unboxed-closures-infer-fnmut.rs index a8469f4019ab..67f36b9a9203 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnmut.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnmut.rs @@ -11,7 +11,6 @@ // Test that we are able to infer a suitable kind for this closure // that is just called (`FnMut`). - fn main() { let mut counter = 0; diff --git a/src/test/run-pass/unboxed-closures-infer-kind.rs b/src/test/run-pass/unboxed-closures-infer-kind.rs index fa668475f587..c04df7ed5f87 100644 --- a/src/test/run-pass/unboxed-closures-infer-kind.rs +++ b/src/test/run-pass/unboxed-closures-infer-kind.rs @@ -11,9 +11,6 @@ // Test that we can infer the "kind" of an unboxed closure based on // the expected type. - -#![feature(unboxed_closures)] - // Test by-ref capture of environment in unboxed closure types fn call_fn(f: F) { diff --git a/src/test/run-pass/unboxed-closures-infer-upvar.rs b/src/test/run-pass/unboxed-closures-infer-upvar.rs index f2423145b197..1401fe7470b0 100644 --- a/src/test/run-pass/unboxed-closures-infer-upvar.rs +++ b/src/test/run-pass/unboxed-closures-infer-upvar.rs @@ -11,7 +11,6 @@ // Test that the type variable in the type(`Vec<_>`) of a closed over // variable does not interfere with type inference. - fn f(mut f: F) { f(); } diff --git a/src/test/run-pass/unboxed-closures-move-mutable.rs b/src/test/run-pass/unboxed-closures-move-mutable.rs index 1aca3174e1fe..a55b0a0185e6 100644 --- a/src/test/run-pass/unboxed-closures-move-mutable.rs +++ b/src/test/run-pass/unboxed-closures-move-mutable.rs @@ -10,7 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] #![deny(unused_mut)] // Test that mutating a mutable upvar in a capture-by-value unboxed diff --git a/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs b/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs index e2b286738e76..99663646254e 100644 --- a/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs +++ b/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs @@ -11,7 +11,6 @@ // Test that in a by-ref once closure we move some variables even as // we capture others by mutable reference. - fn call(f: F) where F : FnOnce() { f(); } diff --git a/src/test/run-pass/unboxed-closures-simple.rs b/src/test/run-pass/unboxed-closures-simple.rs index ec3419816693..429afb95248c 100644 --- a/src/test/run-pass/unboxed-closures-simple.rs +++ b/src/test/run-pass/unboxed-closures-simple.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(unboxed_closures)] - use std::ops::FnMut; pub fn main() { diff --git a/src/test/run-pass/unboxed-closures-single-word-env.rs b/src/test/run-pass/unboxed-closures-single-word-env.rs index 166054e88b7b..3ed055a7884e 100644 --- a/src/test/run-pass/unboxed-closures-single-word-env.rs +++ b/src/test/run-pass/unboxed-closures-single-word-env.rs @@ -11,9 +11,6 @@ // Ensures that single-word environments work right in unboxed closures. // These take a different path in codegen. - -#![feature(unboxed_closures)] - fn a isize>(f: F) -> isize { f(1, 2) } diff --git a/src/test/run-pass/unboxed-closures-static-call-fn-once.rs b/src/test/run-pass/unboxed-closures-static-call-fn-once.rs index e90a3443610c..c13e9513ce33 100644 --- a/src/test/run-pass/unboxed-closures-static-call-fn-once.rs +++ b/src/test/run-pass/unboxed-closures-static-call-fn-once.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - fn main() { let onetime = |x| x; onetime(0); diff --git a/src/test/run-pass/unboxed-closures-sugar-object.rs b/src/test/run-pass/unboxed-closures-sugar-object.rs index 49b9b7f061e7..b7d367f23538 100644 --- a/src/test/run-pass/unboxed-closures-sugar-object.rs +++ b/src/test/run-pass/unboxed-closures-sugar-object.rs @@ -10,9 +10,7 @@ // Test unboxed closure sugar used in object types. - #![allow(dead_code)] -#![feature(unboxed_closures)] struct Foo { t: T, u: U diff --git a/src/test/run-pass/unboxed-closures-unique-type-id.rs b/src/test/run-pass/unboxed-closures-unique-type-id.rs index 30c45fc766a1..40071ec9754e 100644 --- a/src/test/run-pass/unboxed-closures-unique-type-id.rs +++ b/src/test/run-pass/unboxed-closures-unique-type-id.rs @@ -19,9 +19,6 @@ // // compile-flags: -g - -#![feature(unboxed_closures)] - use std::ptr; pub fn replace_map<'a, T, F>(src: &mut T, prod: F) where F: FnOnce(T) -> T { diff --git a/src/test/run-pass/unboxed-closures-zero-args.rs b/src/test/run-pass/unboxed-closures-zero-args.rs index cb3a18a18c13..9e6a7cce1fd2 100644 --- a/src/test/run-pass/unboxed-closures-zero-args.rs +++ b/src/test/run-pass/unboxed-closures-zero-args.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - fn main() { let mut zero = || {}; let () = zero(); diff --git a/src/test/run-pass/where-clauses-unboxed-closures.rs b/src/test/run-pass/where-clauses-unboxed-closures.rs index c509cbe2a5e9..8a775caaac6d 100644 --- a/src/test/run-pass/where-clauses-unboxed-closures.rs +++ b/src/test/run-pass/where-clauses-unboxed-closures.rs @@ -10,8 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures)] - struct Bencher; // ICE diff --git a/src/test/rustdoc/issue-34928.rs b/src/test/rustdoc/issue-34928.rs new file mode 100644 index 000000000000..b2104a0c80f5 --- /dev/null +++ b/src/test/rustdoc/issue-34928.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +pub trait Bar {} + +// @has foo/struct.Foo.html '//pre' 'pub struct Foo(pub T) where T: Bar;' +pub struct Foo(pub T) where T: Bar; diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs index 91ec69d9a3cb..d8dc115abf91 100644 --- a/src/test/rustdoc/where.rs +++ b/src/test/rustdoc/where.rs @@ -12,7 +12,7 @@ pub trait MyTrait { fn dummy(&self) { } } -// @has foo/struct.Alpha.html '//pre' "pub struct Alpha where A: MyTrait" +// @has foo/struct.Alpha.html '//pre' "pub struct Alpha(_) where A: MyTrait" pub struct Alpha(A) where A: MyTrait; // @has foo/trait.Bravo.html '//pre' "pub trait Bravo where B: MyTrait" pub trait Bravo where B: MyTrait { fn get(&self, B: B); } diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr index 6c388cd69395..695601743461 100644 --- a/src/test/ui/codemap_tests/two_files.stderr +++ b/src/test/ui/codemap_tests/two_files.stderr @@ -2,12 +2,9 @@ error[E0404]: `Bar` is not a trait --> $DIR/two_files.rs:16:6 | 16 | impl Bar for Baz { } - | ^^^ `Bar` is not a trait - | - ::: $DIR/two_files_data.rs + | ^^^ not a trait | -15 | type Bar = Foo; - | --------------- type aliases cannot be used for traits + = note: type aliases cannot be used for traits error: cannot continue compilation due to previous error diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index ff6920d28ccf..45638a65915c 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -5,7 +5,7 @@ error[E0308]: mismatched types | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize $DIR/issue-26480.rs:38:5: 38:19 note: in this expansion of write! (defined in $DIR/issue-26480.rs) -error: non-scalar cast: `_` as `()` +error: non-scalar cast: `{integer}` as `()` --> $DIR/issue-26480.rs:33:19 | 33 | ($x:expr) => ($x as ()) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 5ec62e06e37a..2a35fab9676a 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -29,6 +29,7 @@ pub enum Mode { Incremental, RunMake, Ui, + MirOpt, } impl FromStr for Mode { @@ -49,6 +50,7 @@ impl FromStr for Mode { "incremental" => Ok(Incremental), "run-make" => Ok(RunMake), "ui" => Ok(Ui), + "mir-opt" => Ok(MirOpt), _ => Err(()), } } @@ -71,6 +73,7 @@ impl fmt::Display for Mode { Incremental => "incremental", RunMake => "run-make", Ui => "ui", + MirOpt => "mir-opt", }, f) } } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 6830f32bb2ce..cefcc11486fe 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -86,7 +86,7 @@ pub fn parse_config(args: Vec ) -> Config { reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET"), reqopt("", "mode", "which sort of compile tests to run", "(compile-fail|parse-fail|run-fail|run-pass|\ - run-pass-valgrind|pretty|debug-info|incremental)"), + run-pass-valgrind|pretty|debug-info|incremental|mir-opt)"), optflag("", "ignored", "run tests marked as ignored"), optopt("", "runtool", "supervisor program to run tests under \ (eg. emulator, valgrind)", "PROGRAM"), diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 577da5c5af11..6647a1a0a933 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -11,7 +11,7 @@ use common::Config; use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind}; use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits}; -use common::{Incremental, RunMake, Ui}; +use common::{Incremental, RunMake, Ui, MirOpt}; use errors::{self, ErrorKind, Error}; use json; use header::TestProps; @@ -117,6 +117,7 @@ impl<'test> TestCx<'test> { Incremental => self.run_incremental_test(), RunMake => self.run_rmake_test(), Ui => self.run_ui_test(), + MirOpt => self.run_mir_opt_test(), } } @@ -1336,7 +1337,24 @@ actual:\n\ .map(|s| s.to_string())); } } + MirOpt => { + args.extend(["-Z", + "dump-mir=all", + "-Z", + "mir-opt-level=3", + "-Z"] + .iter() + .map(|s| s.to_string())); + + let mir_dump_dir = self.get_mir_dump_dir(); + self.create_dir_racy(mir_dump_dir.as_path()); + let mut dir_opt = "dump-mir-dir=".to_string(); + dir_opt.push_str(mir_dump_dir.to_str().unwrap()); + debug!("dir_opt: {:?}", dir_opt); + + args.push(dir_opt); + } RunFail | RunPass | RunPassValgrind | @@ -2145,6 +2163,100 @@ actual:\n\ } } + fn run_mir_opt_test(&self) { + let proc_res = self.compile_test(); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + + let proc_res = self.exec_compiled_test(); + + if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); + } + self.check_mir_dump(); + } + + fn check_mir_dump(&self) { + let mut test_file_contents = String::new(); + fs::File::open(self.testpaths.file.clone()).unwrap() + .read_to_string(&mut test_file_contents) + .unwrap(); + if let Some(idx) = test_file_contents.find("// END RUST SOURCE") { + let (_, tests_text) = test_file_contents.split_at(idx + "// END_RUST SOURCE".len()); + let tests_text_str = String::from(tests_text); + let mut curr_test : Option<&str> = None; + let mut curr_test_contents = Vec::new(); + for l in tests_text_str.lines() { + debug!("line: {:?}", l); + if l.starts_with("// START ") { + let (_, t) = l.split_at("// START ".len()); + curr_test = Some(t); + } else if l.starts_with("// END") { + let (_, t) = l.split_at("// END ".len()); + if Some(t) != curr_test { + panic!("mismatched START END test name"); + } + self.compare_mir_test_output(curr_test.unwrap(), &curr_test_contents); + curr_test = None; + curr_test_contents.clear(); + } else if l.is_empty() { + // ignore + } else if l.starts_with("// ") { + let (_, test_content) = l.split_at("// ".len()); + curr_test_contents.push(test_content); + } + } + } + } + + fn compare_mir_test_output(&self, test_name: &str, expected_content: &Vec<&str>) { + let mut output_file = PathBuf::new(); + output_file.push(self.get_mir_dump_dir()); + output_file.push(test_name); + debug!("comparing the contests of: {:?}", output_file); + debug!("with: {:?}", expected_content); + + let mut dumped_file = fs::File::open(output_file.clone()).unwrap(); + let mut dumped_string = String::new(); + dumped_file.read_to_string(&mut dumped_string).unwrap(); + let mut dumped_lines = dumped_string.lines().filter(|l| !l.is_empty()); + let mut expected_lines = expected_content.iter().filter(|l| !l.is_empty()); + + // We expect each non-empty line from expected_content to appear + // in the dump in order, but there may be extra lines interleaved + while let Some(expected_line) = expected_lines.next() { + let e_norm = normalize_mir_line(expected_line); + if e_norm.is_empty() { + continue; + }; + let mut found = false; + while let Some(dumped_line) = dumped_lines.next() { + let d_norm = normalize_mir_line(dumped_line); + debug!("found: {:?}", d_norm); + debug!("expected: {:?}", e_norm); + if e_norm == d_norm { + found = true; + break; + }; + } + if !found { + panic!("ran out of mir dump output to match against"); + } + } + } + + fn get_mir_dump_dir(&self) -> PathBuf { + let mut mir_dump_dir = PathBuf::from(self.config.build_base + .as_path() + .to_str() + .unwrap()); + debug!("input_file: {:?}", self.testpaths.file); + mir_dump_dir.push(self.testpaths.file.file_stem().unwrap().to_str().unwrap()); + mir_dump_dir + } + fn normalize_output(&self, output: &str) -> String { let parent_dir = self.testpaths.file.parent().unwrap(); let parent_dir_str = parent_dir.display().to_string(); @@ -2274,3 +2386,12 @@ enum TargetLocation { ThisDirectory(PathBuf), } +fn normalize_mir_line(line: &str) -> String { + let no_comments = if let Some(idx) = line.find("//") { + let (l, _) = line.split_at(idx); + l + } else { + line + }; + no_comments.replace(char::is_whitespace, "") +}