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,
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,
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,
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=
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,
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=
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,
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 :=
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 :=
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=
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 :=
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=
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=
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=
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,
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,
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 :=
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 :=
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 :=
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 :=
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 :=
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 :=
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=
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_GCCISH_CFLAGS_x86_64-unknown-linux-musl := -g -fPIC -m64
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 :=
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 :=
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 :=
# 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)))
+# 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
-# 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)))
+ifeq ($$(findstring ios,$(1)),)
+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 windows-gnu,$(1)),windows-gnu)
-COMPRT_DIR_$(1) := windows
-COMPRT_LIB_NAME_$(1) := clang_rt.builtins-$$(COMPRT_ARCH_$(1))
+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 darwin,$(1)),darwin)
-COMPRT_DIR_$(1) := builtins
-COMPRT_LIB_NAME_$(1) := clang_rt.builtins_$$(patsubst i686,i386,$$(COMPRT_ARCH_$(1)))_osx
+
+ifeq ($$(findstring windows,$(1)),)
+COMPRT_OBJS_$(1) += emutls.o
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
+ifeq ($$(findstring msvc,$(1)),)
+COMPRT_OBJS_$(1) += gcc_personality_v0.o
+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
-COMPRT_DEFINES_$(1) := -DCOMPILER_RT_ENABLE_IOS=ON
+
+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
-ifndef COMPRT_DIR_$(1)
-# NB: FreeBSD and NetBSD output to "linux"...
-COMPRT_DIR_$(1) := linux
-COMPRT_ARCH_$(1) := $$(patsubst i586,i386,$$(COMPRT_ARCH_$(1)))
+else
-ifeq ($$(findstring android,$(1)),android)
-ifeq ($$(findstring arm,$$(COMPRT_ARCH_$(1))),arm)
-COMPRT_ARCH_$(1) := armhf
-endif
+ifeq ($$(findstring x86_64,$(1)),x86_64)
+COMPRT_OBJS_$(1) += \
+ x86_64/floatdidf.o \
+ x86_64/floatdisf.o \
+ x86_64/floatdixf.o
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))
+# 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
-
-ifeq ($$(findstring windows-gnu,$(1)),windows-gnu)
-COMPRT_LIB_FILE_$(1) := lib$$(COMPRT_LIB_NAME_$(1)).a
+# 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
-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
+# 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
-ifndef COMPRT_LIB_FILE_$(1)
-COMPRT_LIB_FILE_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$$(COMPRT_LIB_NAME_$(1)))
+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
-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) :=
+ifeq ($$(findstring msvc,$(1)),msvc)
+$$(COMPRT_BUILD_DIR_$(1))/%.o: CFLAGS += -Zl -D__func__=__FUNCTION__
else
-COMPRT_BUILD_ARGS_$(1) :=
-ifndef COMPRT_BUILD_TARGET_$(1)
-COMPRT_BUILD_TARGET_$(1) := $$(COMPRT_LIB_NAME_$(1))
+$$(COMPRT_BUILD_DIR_$(1))/%.o: CFLAGS += -fno-builtin -fvisibility=hidden \
+ -fomit-frame-pointer -ffreestanding
endif
-COMPRT_BUILD_CC_$(1) := -DCMAKE_C_COMPILER=$$(call FIND_COMPILER,$$(CC_$(1))) \
- -DCMAKE_CXX_COMPILER=$$(call FIND_COMPILER,$$(CXX_$(1)))
-ifeq ($$(findstring ios,$(1)),)
-COMPRT_BUILD_CC_$(1) := $$(COMPRT_BUILD_CC_$(1)) \
- -DCMAKE_C_FLAGS="$$(CFG_GCCISH_CFLAGS_$(1)) -Wno-error"
-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
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: \
$(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)
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
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
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
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), \
pretty-rfail-full \
pretty-rfail \
pretty-pretty \
+ mir-opt \
$(NULL)
define DEF_CHECK_FOR_STAGE_AND_TARGET_AND_HOST
"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)",
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]]
[[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]]
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"
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");
/// 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_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());
+ t!(fs::create_dir_all(&build_dir));
- 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)
+ let mut cfg = gcc::Config::new();
+ cfg.cargo_metadata(false)
+ .out_dir(&build_dir)
+ .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))
+ .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 {
- panic!("can't get os from target: {}", target)
- };
- let output = dst.join("build/lib").join(dir)
- .join(staticlib(&libname, target));
- build.compiler_rt_built.borrow_mut().insert(target.to_string(),
- output.clone());
- if fs::metadata(&output).is_ok() {
+ // 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 {
+ 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
(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> }),
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(),
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),
Source::CheckTidy { stage } => {
vec![self.tool_tidy(stage)]
}
+ Source::CheckMirOpt { compiler} |
Source::CheckPrettyRPass { compiler } |
Source::CheckPrettyRFail { compiler } |
Source::CheckRFail { compiler } |
/// 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 {
: "eax"
);
# } }
+# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+# fn main() {}
```
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
// 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
}
println!("eax is currently {}", result);
# }
+# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+# fn main() {}
```
## More Information
#### 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.
* `|` (`|โฆ| 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
[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
# 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();
}
# 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();
}
}
```
-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!
* includes a `PhantomData<T>`
* auto-derives Send/Sync as if T was contained
* marks the pointer as NonZero for the null-pointer optimization
-
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.
//!
//! 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;
/// by putting it inside `Mutex` and then share `Mutex` immutably
/// with `Arc<T>` 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;
///
}
/// 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
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,
_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<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>,
_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<K, V, I: Iterator<Item = (K, V)>> {
left: Peekable<I>,
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 {
/// 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<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
match self {
}
/// 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 {
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
/// 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;
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
/// 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
//! ## 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.
//!
//! ```
//! 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:
//! ```text
//! Hello, `1234.560` has 3 fractional digits
//! Hello, `123` has 3 characters
+//! Hello, ` 123` has 3 right-aligned characters
//! ```
//!
//! # Escaping
impl<T> LinkedList<T> {
/// Creates an empty `LinkedList`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::LinkedList;
+ ///
+ /// let list: LinkedList<u32> = LinkedList::new();
+ /// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> Self {
}
/// Provides a forward iterator.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::LinkedList;
+ ///
+ /// let mut list: LinkedList<u32> = 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<T> {
}
/// Provides a forward iterator with mutable references.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::LinkedList;
+ ///
+ /// let mut list: LinkedList<u32> = 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<T> {
///
/// dl.push_back(3);
/// assert_eq!(dl.len(), 3);
- ///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// dl.clear();
/// assert_eq!(dl.len(), 0);
/// assert_eq!(dl.front(), None);
- ///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// 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<u32> = 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
///
/// dl.push_front(1);
/// assert_eq!(dl.front(), Some(&1));
- ///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// Some(x) => *x = 5,
/// }
/// assert_eq!(dl.front(), Some(&5));
- ///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
///
/// dl.push_back(1);
/// assert_eq!(dl.back(), Some(&1));
- ///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// Some(x) => *x = 5,
/// }
/// assert_eq!(dl.back(), Some(&5));
- ///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
///
/// 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) {
/// 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<T> {
self.pop_front_node().map(Node::into_element)
///
/// # 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());
+ /// ```
+ ///
+ /// If the slice is shorter than `size`:
///
- /// ```rust
- /// let v = &[1, 2, 3, 4];
- /// for win in v.windows(2) {
- /// println!("{:?}", win);
- /// }
+ /// ```
+ /// let slice = ['f', 'o', 'o'];
+ /// let mut iter = slice.windows(4);
+ /// assert!(iter.next().is_none());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
///
/// # 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());
/// ```
- /// let v = [10, 40, 30, 20, 60, 50];
///
- /// for group in v.split(|num| *num % 3 == 0) {
- /// println!("{:?}", group);
- /// }
+ /// 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 slice = [10, 40, 33];
+ /// let mut iter = slice.split(|num| num % 3 == 0);
+ ///
+ /// 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]
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};
/// 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:
assert!(idx <= len);
assert!(self.is_char_boundary(idx));
let bits = ch.encode_utf8();
- let bits = bits.as_slice();
- let amt = bits.len();
+
+ unsafe {
+ 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 {
- 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, string.as_bytes());
}
}
}
}
+#[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<ops::Range<usize>> for String {
type Output = str;
///
/// * `ptr` needs to have been previously allocated via `String`/`Vec<T>`
/// (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<T>` 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
///
/// ```
}
}
- /// 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 {
/// 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] {
/// 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] {
/// # Examples
///
/// ```
- /// let mut v = vec![1, 2, 3, 4];
+ /// use std::ptr;
+ ///
+ /// let mut vec = vec!['r', 'u', 's', 't'];
+ ///
+ /// unsafe {
+ /// 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<char> = Vec::new();
+ ///
/// unsafe {
- /// v.set_len(1);
+ /// vec.set_len(4);
/// }
/// ```
#[inline]
impl<T> VecDeque<T> {
/// Creates an empty `VecDeque`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::VecDeque;
+ ///
+ /// let vector: VecDeque<u32> = VecDeque::new();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> VecDeque<T> {
VecDeque::with_capacity(INITIAL_CAPACITY)
}
/// Creates an empty `VecDeque` with space for at least `n` elements.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::VecDeque;
+ ///
+ /// let vector: VecDeque<u32> = VecDeque::with_capacity(10);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(n: usize) -> VecDeque<T> {
// +1 since the ringbuffer always leaves one space empty
/// Retrieves an element in the `VecDeque` by index.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Examples
///
/// ```
/// Retrieves an element in the `VecDeque` mutably by index.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Examples
///
/// ```
///
/// Fails if there is no element with either index.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Examples
///
/// ```
/// Returns a pair of slices which contain, in order, the contents of the
/// `VecDeque`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::VecDeque;
+ ///
+ /// let mut vector: VecDeque<u32> = 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]) {
/// Returns a pair of slices which contain, in order, the contents of the
/// `VecDeque`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::collections::VecDeque;
+ ///
+ /// let mut vector: VecDeque<u32> = 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]) {
///
/// ```
/// use std::collections::VecDeque;
-
+ ///
/// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
/// assert_eq!(vec![3].into_iter().collect::<VecDeque<_>>(), v.drain(2..).collect());
/// assert_eq!(vec![1, 2].into_iter().collect::<VecDeque<_>>(), v);
/// 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<u32> = 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
///
/// Returns `None` if `index` is out of bounds.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Examples
///
/// ```
///
/// Returns `None` if `index` is out of bounds.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Examples
///
/// ```
/// 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
/// 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;
///
///
/// Note that the capacity of `self` does not change.
///
+ /// Element at index 0 is the front of the queue.
+ ///
/// # Panics
///
/// Panics if `at > len`
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
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;
}
/// Moves a value out of scope without running drop glue.
pub fn forget<T>(_: 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
///
+ /// There are a few things that `transmute` is really useful for.
+ ///
+ /// Getting the bitpattern of a floating point type (or, more generally,
+ /// type punning, when `T` and `U` aren't pointers):
+ ///
/// ```
- /// use std::mem;
+ /// let bitpattern = unsafe {
+ /// std::mem::transmute::<f32, u32>(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<'b>, 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`:
///
- /// let array: &[u8] = unsafe { mem::transmute("Rust") };
- /// assert_eq!(array, [82, 117, 115, 116]);
+ /// 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<Option<&T>>`:
+ ///
+ /// ```
+ /// let store = [0, 1, 2, 3];
+ /// let mut v_orig = store.iter().collect::<Vec<&i32>>();
+ /// // Using transmute: this is Undefined Behavior, and a bad idea.
+ /// // However, it is no-copy.
+ /// let v_transmuted = unsafe {
+ /// std::mem::transmute::<Vec<&i32>, Vec<Option<&i32>>>(
+ /// 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::<Vec<Option<&i32>>>();
+ /// // 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<T>(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<T>(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<T>(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<T, U>(e: T) -> U;
/// ```
#[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
///
use self::Option::*;
use clone::Clone;
+use convert::From;
use default::Default;
use iter::ExactSizeIterator;
use iter::{Iterator, DoubleEndedIterator, FromIterator, IntoIterator};
}
}
+#[stable(since = "1.12.0", feature = "option_from")]
+impl<T> From<T> for Option<T> {
+ fn from(val: T) -> Option<T> {
+ Some(val)
+ }
+}
+
/////////////////////////////////////////////////////////////////////////////
// The Option Iterators
/////////////////////////////////////////////////////////////////////////////
/// Immutable slice iterator
///
+/// This struct is created by the [`iter`] method on [slices].
+///
/// # Examples
///
/// Basic usage:
/// 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,
/// Mutable slice iterator.
///
+/// This struct is created by the [`iter_mut`] method on [slices].
+///
/// # Examples
///
/// Basic usage:
/// // 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,
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<usize> {
+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;
let call_site_encoding = reader.read::<u8>();
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;
-
- 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;
+ let ip = context.ip;
+
+ 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 hapen... but it does: issie #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]
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!(),
};
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"))))]
+// All targets, except ARM which uses a slightly different ABI (however, iOS goes here as it uses
+// SjLj unwinding). Also, 64-bit Windows implementation lives in seh64_gnu.rs
+#[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))]
pub mod eabi {
use unwind as uw;
- use libc::c_int;
+ use libc::{c_int, uintptr_t};
+ use dwarf::eh::{EHContext, EHAction, find_eh_action};
- 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;
- }
+ // 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 <arch>RegisterInfo.td, search for "DwarfRegNum").
+ // See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
- #[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) }
- }
+ #[cfg(target_arch = "x86")]
+ const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX
- #[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 {
+ #[cfg(target_arch = "x86_64")]
+ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
- 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) }
- }
- }
-}
-
-// iOS on armv7 is using SjLj exceptions and therefore requires to use
-// a specialized personality routine: __gcc_personality_sj0
+ #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
-#[cfg(all(target_os = "ios", target_arch = "arm"))]
-pub mod eabi {
- use unwind as uw;
- use libc::c_int;
+ #[cfg(any(target_arch = "mips", target_arch = "mipsel"))]
+ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
- 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;
- }
+ #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
+ const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4
+ // 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
#[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) }
+ #[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;
+ }
+ 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),
+ };
+ let eh_action = find_eh_action(lsda, &eh_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,
+ }
+ }
}
+ #[cfg(stage0)]
#[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) }
- }
+ 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)
}
}
-
// ARM EHABI uses a slightly different personality routine signature,
// but otherwise works the same.
#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
// 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 (),
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:
// This is considered acceptable, because the behavior of throwing exceptions
// through a C ABI boundary is undefined.
+#[cfg(stage0)]
#[lang = "eh_personality_catch"]
#[cfg(not(test))]
unsafe extern "C" fn rust_eh_personality_catch(exceptionRecord: *mut c::EXCEPTION_RECORD,
}
unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
- 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(),
+ }
}
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;
}
}
- 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,
}
}
+ 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<ValuePairs<'tcx>>,
+ 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<T: fmt::Display + Resolvable<'tcx> + TypeFoldable<'tcx>>(
+ fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
&self,
exp_found: &ty::error::ExpectedFound<T>)
-> Option<(String, String)>
{
- let expected = exp_found.expected.resolve(self);
- if expected.references_error() {
- return None;
- }
-
- let found = exp_found.found.resolve(self);
- if found.references_error() {
+ let exp_found = self.resolve_type_vars_if_possible(exp_found);
+ if exp_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,
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"
- }
- };
-
- 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));
- }
+ 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*.
+
+ err.span_note(
+ trace.origin.span(),
+ &format!("...so that {}",
+ trace.origin.as_requirement_str()));
}
}
infer::Reborrow(span) => {
}
}
-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<hir::LifetimeDef> {
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};
// 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),
// `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",
&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",
+ }
}
}
// 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<M>(&self,
- sp: Span,
- mk_msg: M,
- actual_ty: String,
- err: Option<&TypeError<'tcx>>)
- where M: FnOnce(Option<String>, String) -> String,
- {
- self.type_error_message_str_with_expected(sp, mk_msg, None, actual_ty, err)
- }
-
- pub fn type_error_struct_str<M>(&self,
- sp: Span,
- mk_msg: M,
- actual_ty: String,
- err: Option<&TypeError<'tcx>>)
- -> DiagnosticBuilder<'tcx>
- where M: FnOnce(Option<String>, String) -> String,
- {
- self.type_error_struct_str_with_expected(sp, mk_msg, None, actual_ty, err)
- }
-
- pub fn type_error_message_str_with_expected<M>(&self,
- sp: Span,
- mk_msg: M,
- expected_ty: Option<Ty<'tcx>>,
- actual_ty: String,
- err: Option<&TypeError<'tcx>>)
- where M: FnOnce(Option<String>, 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<M>(&self,
- sp: Span,
- mk_msg: M,
- expected_ty: Option<Ty<'tcx>>,
- actual_ty: String,
- err: Option<&TypeError<'tcx>>)
- -> DiagnosticBuilder<'tcx>
- where M: FnOnce(Option<String>, 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<M>(&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<M>(&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<M>(&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,
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,
}
}
}
}
}
}
+
+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<V: TypeVisitor<'tcx>>(&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<V: TypeVisitor<'tcx>>(&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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ self.origin.visit_with(visitor) || self.values.visit_with(visitor)
+ }
+}
"set the MIR optimization level (0-3)"),
dump_mir: Option<String> = (None, parse_opt_string,
"dump MIR state at various points in translation"),
+ dump_mir_dir: Option<String> = (None, parse_opt_string,
+ "the directory the MIR is dumped into"),
orbit: bool = (false, parse_bool,
"get MIR where it belongs - everywhere; most importantly, in orbit"),
}
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<MultiSpan>>(&'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)
}
}
pub fn span_err<S: Into<MultiSpan>>(&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<S: Into<MultiSpan>>(&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)
}
}
-fn split_msg_into_multilines(msg: &str) -> Option<String> {
- // 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<PathBuf>,
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};
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,
+ 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,
- 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();
+ 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,
self.generics.visit_with(visitor) || self.ty.visit_with(visitor)
}
}
+
+impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound<T> {
+ 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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ self.expected.visit_with(visitor) || self.found.visit_with(visitor)
+ }
+}
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()
},
/// List of supported targets
pub const TARGETS: &'static [&'static str] = &[$($triple),*];
- // this would use a match if stringify! were allowed in pattern position
fn load_specific(target: &str) -> Option<Target> {
- 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);
- }
- )*
-
- None
+ match target {
+ $(
+ $triple => {
+ let mut t = $module::target();
+ t.options.is_builtin = true;
+ debug!("Got builtin target: {:?}", t);
+ Some(t)
+ },
+ )+
+ _ => None
+ }
}
)
}
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
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};
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 {
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();
}
}
}
}
}
-fn range_covered_by_constructor(ctor: &Constructor,
- from: &ConstVal, to: &ConstVal) -> Option<bool> {
+fn range_covered_by_constructor(tcx: TyCtxt, span: Span,
+ ctor: &Constructor,
+ from: &ConstVal, to: &ConstVal)
+ -> Result<bool, ErrorReported> {
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>,
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,
}
}
}
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,
}
}
See also https://github.com/rust-lang/rust/issues/14587
"##,
-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:
+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
-let x = [0i32; true]; // error: expected positive integer for repeat count,
- // found boolean
+enum Enum {
+ X = (1 << 500),
+ Y = (1 / 0)
+}
```
-Working example:
+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:
-```
-let x = [0i32; 2];
-```
+https://doc.rust-lang.org/reference.html#ffi-attributes
"##,
-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:
+
+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:
```compile_fail
- let len = 10;
- let x = [0i32; len]; // error: expected constant integer for repeat count,
- // found variable
+let x = [0i32; true]; // error: expected positive integer for repeat count,
+ // found boolean
```
Working example:
```
-let x = [0i32; 10];
+let x = [0i32; 2];
```
"##,
-
}
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)
}
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;
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) => {
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
},
}
}
IntermediateUnsignedNegative,
/// Expected, Got
TypeMismatch(String, ConstInt),
+
BadType(ConstVal),
ErroneousReferencedConstant(Box<ConstEvalErr>),
CharCast(ConstInt),
}
}
+#[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<str> {
+ 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(),
-
- MissingStructField => "nonexistent struct field".into_cow(),
- NonConstPath => "non-constant path in constant expression".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 => 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())
},
}
}
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),
})
}
-pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
- match (a, b) {
+pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
+ -> Result<Ordering, ErrorReported>
+{
+ 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)),
(&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<Ordering> {
+ b: &Expr) -> Result<Ordering, ErrorReported> {
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<usize, ErrorReported>
+{
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)
}
}
}
#[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
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);
}
}
}
+
+// 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();
+}
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();
}
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
_ => 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));
ALIGN,
comment(tcx, data.terminator().source_info))?;
- writeln!(w, "{}}}\n", INDENT)
+ writeln!(w, "{}}}", INDENT)
}
fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
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;
_ => 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| {
}
}
}
-
- 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> {
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)
Err(msg) => {
self.tcx.sess.add_lint(CONST_ERR, ex.id,
msg.span,
- msg.description().into_owned())
+ msg.description().into_oneline().into_owned())
}
}
}
#![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
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
}
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)
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;
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"),
}
}
}
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));
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))
}
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;
/// 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>) {
+fn internalize_symbols<'a, 'tcx>(ccxs: &CrateContextList<'a, 'tcx>,
+ symbol_map: &SymbolMap<'tcx>,
+ reachable: &FnvHashSet<&str>) {
+ let scx = ccxs.shared();
+ let tcx = scx.tcx();
+
+ // 'unsafe' because we are holding on to CStr's from the LLVM module within
+ // this block.
unsafe {
- let mut declared = HashSet::new();
+ let mut referenced_somewhere = FnvHashSet();
- // Collect all external declarations in all compilation units.
- for ccx in cx.iter() {
+ // 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() {
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)
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() {
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 {
+ if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage {
llvm::SetLinkage(val, llvm::InternalLinkage);
llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass);
llvm::UnsetComdat(val);
}
-
}
}
}
}));
}
- internalize_symbols(&crate_context_list,
- &reachable_symbols.iter().map(|x| &x[..]).collect());
+ time(shared_ccx.sess().time_passes(), "internalize symbols", || {
+ internalize_symbols(&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) {
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;
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};
Compiletime(e) => e,
}
}
- pub fn description(&self) -> Cow<str> {
+
+ 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,
}
}
}
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,
(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))
},
}
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 {
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;
// 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
+ let target = &bcx.sess().target.target;
+ let catch_pers = if target.arch == "arm" && target.target_os != "ios" {
+ // Only ARM still uses a separate catch personality (for now)
+ 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"),
}
- None => bug!("eh_personality_catch not defined"),
+ } else {
+ bcx.fcx.eh_personality()
};
let then = bcx.fcx.new_temp_block("then");
// 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]
}
Err(ConstEvalFailure::Runtime(err)) => {
span_bug!(constant.span,
- "MIR constant {:?} results in runtime panic: {}",
+ "MIR constant {:?} results in runtime panic: {:?}",
constant, err.description())
}
}
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};
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")
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;
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 => {
},
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")
}
//! 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;
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};
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) => {
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);
// 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);
_ => {
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;
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",
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();
}
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 {
traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span)
}
}
-
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;
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
}
// 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,
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();
}
});
}
}
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
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
- }
- }
}
//! 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};
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);
}
}
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) {
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;
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);
|t| {
format!("can't pass `{}` to variadic \
function, cast to `{}`", t, ptr_ty)
- }, arg_ty, None);
+ }, arg_ty);
}
_ => {}
}
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);
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![]);
}
actual)
}
},
- expr_t, None);
+ expr_t);
self.write_error(expr.id);
}
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());
self.type_error_message(expr.span, |actual| {
format!("type `{}` cannot be \
dereferenced", actual)
- }, oprnd_t, None);
+ }, oprnd_t);
oprnd_t = tcx.types.err;
}
}
}
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) => {
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;
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;
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
}
}
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};
}
}
- 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;
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) => {
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,
}
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,
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)
}
}
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};
},
// 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
}
```
"##,
-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,
[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:
}
```
"##,
+ */
E0214: r##"
A generic type was described using parentheses rather than angle brackets. For
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
```
"##,
+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! {
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
}
}
-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
})
}));
- 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,
}),
}));
- 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,
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.
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.
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() {
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;
}
/// }
///
/// for val in map.values() {
- /// print!("{}", val);
+ /// println!("{}", val);
/// }
/// ```
#[stable(feature = "map_values_mut", since = "1.10.0")]
}
/// 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.
),
}
+#[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<K>,
elem: FullBucket<K, V, &'a mut RawTable<K, V>>,
}
+#[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,
elem: VacantEntryState<K, V, &'a mut RawTable<K, V>>,
}
+#[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<K, V, M> {
/// The index is occupied, but the key to insert has precedence,
#[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(),
#[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<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
match self {
Occupied(entry) => entry.into_mut(),
}
/// 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 {
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();
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
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 {
/// 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 {
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")]
/// 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
///
/// ```
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<String> {
+ self.inner.next_back().map(|s| s.into_string().unwrap())
+ }
+}
+
#[stable(feature = "env", since = "1.0.0")]
impl Iterator for ArgsOs {
type Item = OsString;
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<OsString> { self.inner.next_back() }
+}
/// Constants associated with the current target
#[stable(feature = "env", since = "1.0.0")]
pub mod consts {
/// 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<DirEntry>`. Through a `DirEntry`
+/// This iterator is returned from the [`read_dir`] function of this module and
+/// will yield instances of `io::Result<DirEntry>`. 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
/// 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
///
/// 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);
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
///
/// 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
///
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
/// 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
///
/// 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<File> {
Ok(File {
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
///
/// 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<Metadata> {
self.0.metadata().map(Metadata)
/// 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<FileType> {
self.0.file_type().map(FileType)
/// 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()
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 {
/// 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;
}
}
+fn read_one_byte(reader: &mut Read) -> Option<Result<u8>> {
+ 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.
type Item = Result<u8>;
fn next(&mut self) -> Option<Result<u8>> {
- 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)
}
}
type Item = result::Result<char, CharsError>;
fn next(&mut self) -> Option<result::Result<char, CharsError>> {
- 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)) }
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))),
}
}
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.
///
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,
rx: &'a Receiver<T>
}
+/// 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<T>
+}
+
/// 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.
pub fn iter(&self) -> Iter<T> {
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<T> {
+ TryIter { rx: self }
+ }
+
}
impl<T> select::Packet for Receiver<T> {
fn next(&mut self) -> Option<T> { 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<T> { self.rx.try_recv().ok() }
+}
+
#[stable(feature = "receiver_into_iter", since = "1.1.0")]
impl<'a, T> IntoIterator for &'a Receiver<T> {
type Item = T;
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 = {
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;
}
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;
}
fn len(&self) -> usize { self.iter.len() }
}
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
+}
+
/// Returns the command line arguments
///
/// Returns a list of the command line arguments.
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<OsString> {
- 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<usize>) { self.range.size_hint() }
}
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> {
+ 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() }
}
fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P<ast::Expr> {
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)
}
pub tokens_consumed: usize,
pub restrictions: Restrictions,
pub quote_depth: usize, // not (yet) related to the quasiquoter
+ parsing_token_tree: bool,
pub reader: Box<Reader+'a>,
/// The set of seen errors about obsolete syntax. Used to suppress
/// extra detail when the same error is seen twice
tokens_consumed: 0,
restrictions: Restrictions::empty(),
quote_depth: 0,
+ parsing_token_tree: false,
obsolete_set: HashSet::new(),
mod_path_stack: Vec::new(),
filename: filename,
}
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(),
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;
_ => {}
}
+ self.parsing_token_tree = parsing_token_tree;
Ok(TokenTree::Delimited(span, Rc::new(Delimited {
delim: delim,
open_span: open_span,
Bracket,
/// A curly brace: `{` or `}`
Brace,
+ /// An empty delimiter
+ NoDelim,
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
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(),
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(()),
}
}
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");
}
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");
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 }`
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;
}
}
- _ => 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(),
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<Expr> {
+fn cs_clone(name: &str,
+ cx: &mut ExtCtxt,
+ trait_span: Span,
+ substr: &Substructure,
+ mode: Mode)
+ -> P<Expr> {
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
};
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))
}
}
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::<Vec<_>>();
+ 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::<Vec<_>>();
cx.expr_struct(trait_span, ctor_path, fields)
}
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),
}
}
}
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;
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<Expr> {
- cs_same_method(
- |cx, span, exprs| {
- // create `a.<method>(); b.<method>(); c.<method>(); ...`
- // (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.<method>(); b.<method>(); c.<method>(); ...`
+ // (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(),
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)
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;
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(),
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(),
};
pub fn ordering_collapsed(cx: &mut ExtCtxt,
span: Span,
- self_arg_tags: &[ast::Ident]) -> P<ast::Expr> {
+ self_arg_tags: &[ast::Ident])
+ -> P<ast::Expr> {
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<Expr> {
+pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
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)
}
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;
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<Expr> {
- 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<Expr> {
- 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 {
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;
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"));
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",
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
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 {
#[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<ast::Expr> {
+ self_arg_tags: &[ast::Ident])
+ -> P<ast::Expr> {
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<Expr> {
+pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
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:
-
- 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 args = vec![
+ // 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
+ // }
+
+ 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![
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)
- };
-
- 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_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));
+
+ 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<Expr> {
+fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
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`
-
- ```
- 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)`")
+ 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)`"),
+ };
+
+ 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,
};
-
- 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)
}
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));
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<Expr> {
+fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
// build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build()
// or fmt.debug_tuple(<name>).field(&<fieldval>)....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 {
}
} 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());
}
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::Expr>) -> ast::Stmt {
+fn stmt_let_undescore(cx: &mut ExtCtxt, sp: Span, expr: P<ast::Expr>) -> ast::Stmt {
let local = P(ast::Local {
pat: cx.pat_wild(sp),
ty: None,
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;
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")
}
span: Span,
mitem: &MetaItem,
item: &Annotatable,
- push: &mut FnMut(Annotatable))
-{
+ push: &mut FnMut(Annotatable)) {
expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
}
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");
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<Expr> {
+ krate: &str)
+ -> P<Expr> {
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");
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");
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)"),
};
}
outer_pat_path: ast::Path,
fields: &StaticFields,
mut getarg: F)
- -> P<Expr> where
- F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P<Expr>,
+ -> P<Expr>
+ where F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P<Expr>
{
match *fields {
Unnamed(ref fields) => {
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)
}
}
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;
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(),
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)
}
}
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)`"),
};
}
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;
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")
}
span: Span,
mitem: &MetaItem,
item: &Annotatable,
- push: &mut FnMut(Annotatable))
-{
+ push: &mut FnMut(Annotatable)) {
expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize")
}
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;
}
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,
trait_def.expand(cx, mitem, item, push)
}
-fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
- substr: &Substructure, krate: &'static str) -> P<Expr> {
+fn encodable_substructure(cx: &mut ExtCtxt,
+ trait_span: Span,
+ substr: &Substructure,
+ krate: &'static str)
+ -> P<Expr> {
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;
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) => {
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 {
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)"),
};
}
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};
pub self_args: &'a [P<Expr>],
/// verbatim access to any other arguments
pub nonself_args: &'a [P<Expr>],
- pub fields: &'a SubstructureFields<'a>
+ pub fields: &'a SubstructureFields<'a>,
}
/// Summary of the relevant parts of a struct/enum field.
Box<FnMut(&mut ExtCtxt, Span, (&[Ident], &[Ident]), &[P<Expr>]) -> P<Expr> + 'a>;
pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>)
- -> RefCell<CombineSubstructureFunc<'a>> {
+ -> RefCell<CombineSubstructureFunc<'a>> {
RefCell::new(f)
}
/// This method helps to extract all the type parameters referenced from a
/// type. For a type parameter `<T>`, 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<P<ast::Ty>> {
use syntax::visit;
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,
// 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");
}
}
}
type_ident: Ident,
generics: &Generics,
field_tys: Vec<P<ast::Ty>>,
- methods: Vec<ast::ImplItem>) -> P<ast::Item> {
+ methods: Vec<ast::ImplItem>)
+ -> P<ast::Item> {
let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
// Transform associated types from `deriving::ty::Ty` into `ast::ImplItem`
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
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
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) => {
id: ast::DUMMY_NODE_ID,
span: self.span,
path: we.path.clone(),
- ty: we.ty.clone()
+ ty: we.ty.clone(),
})
}
}
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()));
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<ast::Lifetime> =
- generics.lifetimes
+ let self_lifetimes: Vec<ast::Lifetime> = 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 attr = cx.attribute(
- self.span,
- cx.meta_word(self.span,
- InternedString::new("automatically_derived")));
+ 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")));
// 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());
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<ast::Item> {
- let field_tys: Vec<P<ast::Ty>> = struct_def.fields().iter()
+ generics: &Generics)
+ -> P<ast::Item> {
+ let field_tys: Vec<P<ast::Ty>> = 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 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();
+ 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[..])
+ };
+
+ 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)
}
enum_def: &'a EnumDef,
type_attrs: &[ast::Attribute],
type_ident: Ident,
- generics: &Generics) -> P<ast::Item> {
+ generics: &Generics)
+ -> P<ast::Item> {
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 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();
+ 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[..])
+ };
+
+ 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) {
self_args: &[P<Expr>],
nonself_args: &[P<Expr>],
fields: &SubstructureFields)
- -> P<Expr> {
+ -> P<Expr> {
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;
self.explicit_self.is_none()
}
- fn split_self_nonself_args(&self,
- cx: &mut ExtCtxt,
- trait_: &TraitDef,
- type_ident: Ident,
- generics: &Generics)
- -> (Option<ast::ExplicitSelf>, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
+ fn split_self_nonself_args
+ (&self,
+ cx: &mut ExtCtxt,
+ trait_: &TraitDef,
+ type_ident: Ident,
+ generics: &Generics)
+ -> (Option<ast::ExplicitSelf>, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
let mut self_args = Vec::new();
let mut nonself_args = Vec::new();
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 => {
generics: &Generics,
abi: Abi,
explicit_self: Option<ast::ExplicitSelf>,
- arg_types: Vec<(Ident, P<ast::Ty>)> ,
- body: P<Expr>) -> ast::ImplItem {
+ arg_types: Vec<(Ident, P<ast::Ty>)>,
+ body: P<Expr>)
+ -> 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()
};
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),
}
}
/// }
/// ```
fn expand_struct_method_body<'b>(&self,
- cx: &mut ExtCtxt,
- trait_: &TraitDef<'b>,
- struct_def: &'b VariantData,
- type_ident: Ident,
- self_args: &[P<Expr>],
- nonself_args: &[P<Expr>])
- -> P<Expr> {
+ cx: &mut ExtCtxt,
+ trait_: &TraitDef<'b>,
+ struct_def: &'b VariantData,
+ type_ident: Ident,
+ self_args: &[P<Expr>],
+ nonself_args: &[P<Expr>])
+ -> P<Expr> {
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);
}
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<vec::IntoIter<_>>
- = raw_fields.collect();
+ let mut other_fields: Vec<vec::IntoIter<_>> = 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 \
};
// 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
type_ident: Ident,
self_args: &[P<Expr>],
nonself_args: &[P<Expr>])
- -> P<Expr> {
+ -> P<Expr> {
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))
}
/// 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<P<Expr>>,
- nonself_args: &[P<Expr>])
- -> P<Expr> {
- 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<P<Expr>>,
+ nonself_args: &[P<Expr>])
+ -> P<Expr> {
+ self.build_enum_match_tuple(cx,
+ trait_,
+ enum_def,
+ type_attrs,
+ type_ident,
+ self_args,
+ nonself_args)
}
/// ... // 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<P<Expr>>,
- nonself_args: &[P<Expr>]) -> P<Expr> {
+ 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<P<Expr>>,
+ nonself_args: &[P<Expr>])
+ -> P<Expr> {
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()
.collect::<Vec<String>>();
let self_arg_idents = self_arg_names.iter()
- .map(|name|cx.ident_of(&name[..]))
+ .map(|name| cx.ident_of(&name[..]))
.collect::<Vec<ast::Ident>>();
// 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<ast::Ident> = 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::<Vec<ast::Ident>>();
// 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());
// (Variant2, Variant2, ...) => Body2
// ...
// where each tuple has length = self_args.len()
- let mut match_arms: Vec<ast::Arm> = variants.iter().enumerate()
+ let mut match_arms: Vec<ast::Arm> = 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)
};
// 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
// 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));
// ```
let mut index_let_stmts: Vec<ast::Stmt> = 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);
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);
}
}
- 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
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
// 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
type_ident: Ident,
self_args: &[P<Expr>],
nonself_args: &[P<Expr>])
- -> P<Expr> {
- 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<Expr> {
+ 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)),
}
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
fn create_subpatterns(&self,
cx: &mut ExtCtxt,
- field_paths: Vec<ast::SpannedIdent> ,
+ field_paths: Vec<ast::SpannedIdent>,
mutbl: ast::Mutability)
-> Vec<P<ast::Pat>> {
- 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<ast::Pat>, Vec<(Span, Option<Ident>,
- P<Expr>,
- &'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<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'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)
(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<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'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<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'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`).
cx: &mut ExtCtxt,
trait_span: Span,
substructure: &Substructure)
- -> P<Expr> where
- F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
+ -> P<Expr>
+ where F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>
{
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`"),
}
}
cx: &mut ExtCtxt,
trait_span: Span,
substructure: &Substructure)
- -> P<Expr> where
- F: FnOnce(&mut ExtCtxt, Span, Vec<P<Expr>>) -> P<Expr>,
+ -> P<Expr>
+ where F: FnOnce(&mut ExtCtxt, Span, Vec<P<Expr>>) -> P<Expr>
{
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`"),
}
}
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
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;
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");
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(),
};
fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
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 = {
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();
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 {
//! The compiler code necessary to implement the `#[derive]` extensions.
-use syntax::ast::{MetaItem, MetaItemKind, self};
+use syntax::ast::{self, MetaItem, MetaItemKind};
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;
span: Some(titem.span),
allow_internal_unstable: true,
},
- }), ..titem.span
+ }),
+ ..titem.span
};
if &tname[..] == "Eq" {
}
// #[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)
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
}
"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));
}
}
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());
}
fn call_intrinsic(cx: &ExtCtxt,
span: Span,
intrinsic: &str,
- args: Vec<P<ast::Expr>>) -> P<ast::Expr> {
+ args: Vec<P<ast::Expr>>)
+ -> P<ast::Expr> {
let path = cx.std_path(&["intrinsics", intrinsic]);
let call = cx.expr_call_global(span, path, args);
stmts: vec![cx.stmt_expr(call)],
id: ast::DUMMY_NODE_ID,
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
- span: span }))
+ span: span,
+ }))
}
-
}
}
- pub fn from_span(primary_span: Span) -> MultiSpan {
- MultiSpan {
- primary_spans: vec![primary_span],
- span_labels: vec![]
- }
- }
-
- pub fn from_spans(vec: Vec<Span>) -> MultiSpan {
- MultiSpan {
- primary_spans: vec,
- span_labels: vec![]
- }
- }
-
pub fn push_span_label(&mut self, span: Span, label: String) {
self.span_labels.push((span, label));
}
impl From<Span> for MultiSpan {
fn from(span: Span) -> MultiSpan {
- MultiSpan::from_span(span)
+ MultiSpan {
+ primary_spans: vec![span],
+ span_labels: vec![]
+ }
}
}
pub type _Unwind_Exception_Class = u64;
pub type _Unwind_Word = libc::uintptr_t;
+pub type _Unwind_Ptr = libc::uintptr_t;
pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut libc::c_void)
-> _Unwind_Reason_Code;
ip_before_insn: *mut libc::c_int)
-> libc::uintptr_t;
+ pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
+ 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;
+ pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: libc::c_int, value: _Unwind_Ptr);
+ pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Ptr);
+
#[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;
"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",
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
+}
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;
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;
const ID: usize;
}
-const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0250
+const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0080
fn main() {
assert_eq!(1, X);
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() {}
}
pub fn test<A: Foo, B: Foo>() {
- let _array = [4; <A as Foo>::Y]; //~ error: expected constant integer
+ let _array = [4; <A as Foo>::Y]; //~ ERROR E0080
+ //~| non-constant path in constant
}
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`
}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T> Mirror for T {
+ type Image = T;
+}
+
+#[cfg(bad)]
+fn foo<U, T>(_t: T)
+ where for<'a> &'a T: Mirror<Image=U>
+{}
+
+#[cfg(good)]
+fn foo<U, T>(_t: T)
+ where for<'a> &'a T: Mirror<Image=&'a U>
+{}
+
+#[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
+}
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;
}
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
}
// 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
+ //~| attempted 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
+ //~| attempted to add with overflow
+ //~^^^ WARN this expression will panic at run-time
+ //~| attempted to add with overflow
let c = 200u8 * 4;
- //~^ WARN attempted to multiply with overflow
+ //~^ WARN this expression will panic at run-time
+ //~| attempted to multiply with overflow
let d = 42u8 - (42u8 + 1);
- //~^ WARN attempted to subtract with overflow
+ //~^ WARN this expression will panic at run-time
+ //~| attempted 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);
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
+//~| attempted to negate with overflow
+//~| ERROR constant evaluation error
+//~| attempted to negate with overflow
+//~| ERROR constant evaluation error
+//~| attempted 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"),
}
}
// 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: attempted to add with overflow
#![allow(unused_imports)]
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];
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() {}
const VALS_I8: (i8, i8, i8, i8) =
(-i8::MIN,
- //~^ ERROR attempted to negate with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to negate with overflow
i8::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
i8::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
i8::MIN * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_I16: (i16, i16, i16, i16) =
(-i16::MIN,
- //~^ ERROR attempted to negate with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to negate with overflow
i16::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
i16::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
i16::MIN * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_I32: (i32, i32, i32, i32) =
(-i32::MIN,
- //~^ ERROR attempted to negate with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to negate with overflow
i32::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
i32::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
i32::MIN * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
const VALS_I64: (i64, i64, i64, i64) =
(-i64::MIN,
- //~^ ERROR attempted to negate with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to negate with overflow
i64::MIN - 1,
- //~^ ERROR attempted to subtract with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to subtract with overflow
i64::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
i64::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted 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
+ //~| attempted to subtract with overflow
u8::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
u8::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted 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
+ //~| attempted to subtract with overflow
u16::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
u16::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted 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
+ //~| attempted to subtract with overflow
u32::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
u32::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted 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
+ //~| attempted to subtract with overflow
u64::MAX + 1,
- //~^ ERROR attempted to add with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to add with overflow
u64::MAX * 2,
- //~^ ERROR attempted to multiply with overflow
+ //~^ ERROR constant evaluation error
+ //~| attempted to multiply with overflow
);
fn main() {
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,
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
}
// 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() {
}
// 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;
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
+//~| attempted to subtract with overflow
fn main() {
let a: [i8; LEN] = unimplemented!();
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]
+ //~| attempted to subtract with overflow
}
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"),
}
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;
// Test spans of errors
const TUP: (usize,) = 5 << 64;
-//~^ ERROR: attempted to shift left with overflow [E0250]
+//~^ ERROR E0080
+//~| attempted to shift left with overflow
const ARR: [i32; TUP.0] = [];
fn main() {
Ok = i8::MAX - 1,
Ok2,
OhNo = 0_u8,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected i8, found u8
}
let x = A::Ok;
Ok = u8::MAX - 1,
Ok2,
OhNo = 0_i8,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected u8, found i8
}
let x = A::Ok;
Ok = i16::MAX - 1,
Ok2,
OhNo = 0_u16,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected i16, found u16
}
let x = A::Ok;
Ok = u16::MAX - 1,
Ok2,
OhNo = 0_i16,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected u16, found i16
}
let x = A::Ok;
Ok = i32::MAX - 1,
Ok2,
OhNo = 0_u32,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected i32, found u32
}
let x = A::Ok;
Ok = u32::MAX - 1,
Ok2,
OhNo = 0_i32,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected u32, found i32
}
let x = A::Ok;
Ok = i64::MAX - 1,
Ok2,
OhNo = 0_u64,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected i64, found u64
}
let x = A::Ok;
Ok = u64::MAX - 1,
Ok2,
OhNo = 0_i64,
- //~^ ERROR mismatched types
+ //~^ ERROR E0080
+ //~| expected u64, found i64
}
let x = A::Ok;
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
// 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
+ //~| attempted to divide by zero
rem_zero = 1%0,
-//~^ ERROR constant evaluation error: attempted to calculate the remainder with a divisor of zero
+ //~^ ERROR E0080
+ //~| attempted to calculate the remainder with a divisor of zero
}
fn main() {}
}
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() {}
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
}
fn main() {
fn f(a: [u8; u32::DOESNOTEXIST]) {}
- //~^ ERROR unresolved path in constant expression
+ //~^ ERROR constant evaluation error
+ //~| unresolved path in constant expression
}
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() {}
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);
}
}
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
type Item = i32;
fn next(&mut self) -> Result<i32, i32> { 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() {}
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() {}
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() {}
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);
}
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() {}
//~| 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
}
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"),
}
}
// 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() { }
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<u8>) {
+ let mut found_e = false;
+
+ let temp: Vec<u8> = 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() {}
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);
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() {}
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
}
'c' ... 100 => { }
_ => { }
};
- //~^^^ ERROR mismatched types in range
- //~| expected char, found integral variable
+ //~^^^ ERROR mismatched types
+ //~| expected type `_`
+ //~| found type `char`
}
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
}
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
}
}
let x = 0;
match 1 {
0 ... x => {}
- //~^ ERROR non-constant path in constant expression
+ //~^ ERROR constant evaluation error
+ //~| non-constant path in constant expression
};
}
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 `_`
//~| 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 {
//~| 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]
}
// 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() {}
impl<'a, T> SomeTrait for &'a Bar<T> {
fn dummy1(self: &&'a Bar<T>) { }
- fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched types
- //~^ ERROR mismatched types
+ fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched method receiver
+ //~^ ERROR mismatched method receiver
fn dummy3(self: &&Bar<T>) {}
- //~^ ERROR mismatched types
+ //~^ ERROR mismatched method receiver
//~| expected type `&&'a Bar<T>`
//~| found type `&&Bar<T>`
//~| lifetime mismatch
- //~| ERROR mismatched types
+ //~| ERROR mismatched method receiver
//~| expected type `&&'a Bar<T>`
//~| found type `&&Bar<T>`
//~| lifetime mismatch
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() { }
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
-}
// ignore-tidy-linelength
// ignore-lldb
// ignore-android: FIXME(#24958)
+// ignore-arm: FIXME(#24958)
+// ignore-aarch64: FIXME(#24958)
// compile-flags:-g
--- /dev/null
+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.
+
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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
--- /dev/null
+-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"
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {}
-// 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.
//
pub fn main() {
let _ = b"x" as &[u8];
+ let _ = b"y" as &[u8; 1];
+ let _ = b"z" as *const u8;
+ let _ = "รค" as *const str;
}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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");
+}
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");
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");
});
}
+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);
}
Incremental,
RunMake,
Ui,
+ MirOpt,
}
impl FromStr for Mode {
"incremental" => Ok(Incremental),
"run-make" => Ok(RunMake),
"ui" => Ok(Ui),
+ "mir-opt" => Ok(MirOpt),
_ => Err(()),
}
}
Incremental => "incremental",
RunMake => "run-make",
Ui => "ui",
+ MirOpt => "mir-opt",
}, f)
}
}
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"),
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;
Incremental => self.run_incremental_test(),
RunMake => self.run_rmake_test(),
Ui => self.run_ui_test(),
+ MirOpt => self.run_mir_opt_test(),
}
}
.map(|s| s.to_string()));
}
}
+ MirOpt => {
+ args.extend(["-Z",
+ "dump-mir=all",
+ "-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 |
}
}
+ 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();
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, "")
+}