valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
valopt android-cross-path "/opt/ndk_standalone" "Android NDK standalone path"
valopt release-channel "dev" "the name of the release channel to build"
+valopt musl-root "/usr/local" "MUSL root installation directory"
# Many of these are saved below during the "writing configuration" step
# (others are conditionally saved).
fi
;;
+
+ *-musl)
+ if [ ! -f $CFG_MUSL_ROOT/lib/libc.a ]
+ then
+ err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found"
+ fi
+ ;;
*)
;;
esac
make_dir $h/test/run-pass-valgrind
make_dir $h/test/run-pass-fulldeps
make_dir $h/test/run-fail
+ make_dir $h/test/run-fail-fulldeps
make_dir $h/test/compile-fail
make_dir $h/test/parse-fail
make_dir $h/test/compile-fail-fulldeps
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_GCCISH_PRE_LIB_FLAGS_aarch64-apple-ios :=
-CFG_GCCISH_POST_LIB_FLAGS_aarch64-apple-ios :=
-CFG_DEF_SUFFIX_aarch64-apple-ios := .darwin.def
CFG_LLC_FLAGS_aarch64-apple-ios := -mattr=+neon,+cyclone,+fp-armv8
CFG_INSTALL_NAME_aarch64-apple-ios = -Wl,-install_name,@rpath/$(1)
CFG_LIBUV_LINK_FLAGS_aarch64-apple-ios =
CFG_EXE_SUFFIX_aarch64-apple-ios :=
CFG_WINDOWSY_aarch64-apple-ios :=
CFG_UNIXY_aarch64-apple-ios := 1
-CFG_PATH_MUNGE_aarch64-apple-ios := true
CFG_LDPATH_aarch64-apple-ios :=
CFG_RUN_aarch64-apple-ios = $(2)
CFG_RUN_TARG_aarch64-apple-ios = $(call CFG_RUN_aarch64-apple-ios,,$(2))
CFG_GCCISH_CXXFLAGS_aarch64-linux-android := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_aarch64-linux-android := -shared -fPIC -ldl -g -lm -lsupc++
CFG_GCCISH_DEF_FLAG_aarch64-linux-android := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_aarch64-linux-android := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_aarch64-linux-android := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_aarch64-linux-android := .android.def
CFG_LLC_FLAGS_aarch64-linux-android :=
CFG_INSTALL_NAME_aarch64-linux-android =
CFG_EXE_SUFFIX_aarch64-linux-android :=
CFG_WINDOWSY_aarch64-linux-android :=
CFG_UNIXY_aarch64-linux-android := 1
-CFG_PATH_MUNGE_aarch64-linux-android := true
CFG_LDPATH_aarch64-linux-android :=
CFG_RUN_aarch64-linux-android=
CFG_RUN_TARG_aarch64-linux-android=
CFG_GCCISH_CXXFLAGS_aarch64-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_aarch64-unknown-linux-gnu := -shared -fPIC -g
CFG_GCCISH_DEF_FLAG_aarch64-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_aarch64-unknown-linux-gnu := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_aarch64-unknown-linux-gnu := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_aarch64-unknown-linux-gnu := .linux.def
CFG_LLC_FLAGS_aarch64-unknown-linux-gnu :=
CFG_INSTALL_NAME_aarch64-unknown-linux-gnu =
CFG_EXE_SUFFIX_aarch64-unknown-linux-gnu :=
CFG_WINDOWSY_aarch64-unknown-linux-gnu :=
CFG_UNIXY_aarch64-unknown-linux-gnu := 1
-CFG_PATH_MUNGE_aarch64-unknown-linux-gnu := true
CFG_LDPATH_aarch64-unknown-linux-gnu :=
CFG_RUN_aarch64-unknown-linux-gnu=$(2)
CFG_RUN_TARG_aarch64-unknown-linux-gnu=$(call CFG_RUN_aarch64-unknown-linux-gnu,,$(2))
CFG_GCCISH_CXXFLAGS_arm-linux-androideabi := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_arm-linux-androideabi := -shared -fPIC -ldl -g -lm -lsupc++
CFG_GCCISH_DEF_FLAG_arm-linux-androideabi := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_arm-linux-androideabi := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_arm-linux-androideabi := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_arm-linux-androideabi := .android.def
CFG_LLC_FLAGS_arm-linux-androideabi :=
CFG_INSTALL_NAME_arm-linux-androideabi =
CFG_EXE_SUFFIX_arm-linux-androideabi :=
CFG_WINDOWSY_arm-linux-androideabi :=
CFG_UNIXY_arm-linux-androideabi := 1
-CFG_PATH_MUNGE_arm-linux-androideabi := true
CFG_LDPATH_arm-linux-androideabi :=
CFG_RUN_arm-linux-androideabi=
CFG_RUN_TARG_arm-linux-androideabi=
CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabi := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabi := -shared -fPIC -g
CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabi := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_arm-unknown-linux-gnueabi := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_arm-unknown-linux-gnueabi := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_arm-unknown-linux-gnueabi := .linux.def
CFG_LLC_FLAGS_arm-unknown-linux-gnueabi :=
CFG_INSTALL_NAME_arm-unknown-linux-gnueabi =
CFG_EXE_SUFFIX_arm-unknown-linux-gnueabi :=
CFG_WINDOWSY_arm-unknown-linux-gnueabi :=
CFG_UNIXY_arm-unknown-linux-gnueabi := 1
-CFG_PATH_MUNGE_arm-unknown-linux-gnueabi := true
CFG_LDPATH_arm-unknown-linux-gnueabi :=
CFG_RUN_arm-unknown-linux-gnueabi=$(2)
CFG_RUN_TARG_arm-unknown-linux-gnueabi=$(call CFG_RUN_arm-unknown-linux-gnueabi,,$(2))
CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabihf := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabihf := -shared -fPIC -g
CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabihf := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_arm-unknown-linux-gnueabihf := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_arm-unknown-linux-gnueabihf := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_arm-unknown-linux-gnueabihf := .linux.def
CFG_LLC_FLAGS_arm-unknown-linux-gnueabihf :=
CFG_INSTALL_NAME_ar,-unknown-linux-gnueabihf =
CFG_EXE_SUFFIX_arm-unknown-linux-gnueabihf :=
CFG_WINDOWSY_arm-unknown-linux-gnueabihf :=
CFG_UNIXY_arm-unknown-linux-gnueabihf := 1
-CFG_PATH_MUNGE_arm-unknown-linux-gnueabihf := true
CFG_LDPATH_arm-unknown-linux-gnueabihf :=
CFG_RUN_arm-unknown-linux-gnueabihf=$(2)
CFG_RUN_TARG_arm-unknown-linux-gnueabihf=$(call CFG_RUN_arm-unknown-linux-gnueabihf,,$(2))
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_GCCISH_PRE_LIB_FLAGS_armv7-apple-ios :=
-CFG_GCCISH_POST_LIB_FLAGS_armv7-apple-ios :=
-CFG_DEF_SUFFIX_armv7-apple-ios := .darwin.def
CFG_LLC_FLAGS_armv7-apple-ios := -mattr=+vfp3,+v7,+neon -march=arm
CFG_INSTALL_NAME_armv7-apple-ios = -Wl,-install_name,@rpath/$(1)
CFG_EXE_SUFFIX_armv7-apple-ios :=
CFG_WINDOWSY_armv7-apple-ios :=
CFG_UNIXY_armv7-apple-ios := 1
-CFG_PATH_MUNGE_armv7-apple-ios := true
CFG_LDPATH_armv7-apple-ios :=
CFG_RUN_armv7-apple-ios = $(2)
CFG_RUN_TARG_armv7-apple-ios = $(call CFG_RUN_armv7-apple-ios,,$(2))
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_GCCISH_PRE_LIB_FLAGS_armv7s-apple-ios :=
-CFG_GCCISH_POST_LIB_FLAGS_armv7s-apple-ios :=
-CFG_DEF_SUFFIX_armv7s-apple-ios := .darwin.def
CFG_LLC_FLAGS_armv7s-apple-ios := -mattr=+vfp4,+v7,+neon
CFG_INSTALL_NAME_armv7s-apple-ios = -Wl,-install_name,@rpath/$(1)
CFG_EXE_SUFFIX_armv7s-apple-ios :=
CFG_WINDOWSY_armv7s-apple-ios :=
CFG_UNIXY_armv7s-apple-ios := 1
-CFG_PATH_MUNGE_armv7s-apple-ios := true
CFG_LDPATH_armv7s-apple-ios :=
CFG_RUN_armv7s-apple-ios = $(2)
CFG_RUN_TARG_armv7s-apple-ios = $(call CFG_RUN_armv7s-apple-ios,,$(2))
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_GCCISH_PRE_LIB_FLAGS_i386-apple-ios :=
-CFG_GCCISH_POST_LIB_FLAGS_i386-apple-ios :=
-CFG_DEF_SUFFIX_i386-apple-ios := .darwin.def
CFG_LLC_FLAGS_i386-apple-ios =
CFG_INSTALL_NAME_i386-apple-ios = -Wl,-install_name,@rpath/$(1)
CFG_EXE_SUFFIX_i386-apple-ios :=
CFG_WINDOWSY_i386-apple-ios :=
CFG_UNIXY_i386-apple-ios := 1
-CFG_PATH_MUNGE_i386-apple-ios = :true
CFG_LDPATH_i386-apple-ios =
CFG_RUN_i386-apple-ios = $(2)
CFG_RUN_TARG_i386-apple-ios = $(call CFG_RUN_i386-apple-ios,,$(2))
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_GCCISH_PRE_LIB_FLAGS_i686-apple-darwin :=
-CFG_GCCISH_POST_LIB_FLAGS_i686-apple-darwin :=
-CFG_DEF_SUFFIX_i686-apple-darwin := .darwin.def
CFG_LLC_FLAGS_i686-apple-darwin :=
CFG_INSTALL_NAME_i686-apple-darwin = -Wl,-install_name,@rpath/$(1)
CFG_EXE_SUFFIX_i686-apple-darwin :=
CFG_WINDOWSY_i686-apple-darwin :=
CFG_UNIXY_i686-apple-darwin := 1
-CFG_PATH_MUNGE_i686-apple-darwin := true
CFG_LDPATH_i686-apple-darwin :=
CFG_RUN_i686-apple-darwin=$(2)
CFG_RUN_TARG_i686-apple-darwin=$(call CFG_RUN_i686-apple-darwin,,$(2))
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_GCCISH_PRE_LIB_FLAGS_i686-pc-windows-gnu :=
-CFG_GCCISH_POST_LIB_FLAGS_i686-pc-windows-gnu :=
-CFG_DEF_SUFFIX_i686-pc-windows-gnu := .windows.def
CFG_LLC_FLAGS_i686-pc-windows-gnu :=
CFG_INSTALL_NAME_i686-pc-windows-gnu =
CFG_EXE_SUFFIX_i686-pc-windows-gnu := .exe
CFG_WINDOWSY_i686-pc-windows-gnu := 1
CFG_UNIXY_i686-pc-windows-gnu :=
-CFG_PATH_MUNGE_i686-pc-windows-gnu :=
CFG_LDPATH_i686-pc-windows-gnu :=
CFG_RUN_i686-pc-windows-gnu=$(2)
CFG_RUN_TARG_i686-pc-windows-gnu=$(call CFG_RUN_i686-pc-windows-gnu,,$(2))
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_GCCISH_PRE_LIB_FLAGS_i686-unknown-linux-gnu := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_i686-unknown-linux-gnu := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_i686-unknown-linux-gnu := .linux.def
CFG_LLC_FLAGS_i686-unknown-linux-gnu :=
CFG_INSTALL_NAME_i686-unknown-linux-gnu =
CFG_EXE_SUFFIX_i686-unknown-linux-gnu =
CFG_WINDOWSY_i686-unknown-linux-gnu :=
CFG_UNIXY_i686-unknown-linux-gnu := 1
-CFG_PATH_MUNGE_i686-unknown-linux-gnu := true
CFG_LDPATH_i686-unknown-linux-gnu :=
CFG_RUN_i686-unknown-linux-gnu=$(2)
CFG_RUN_TARG_i686-unknown-linux-gnu=$(call CFG_RUN_i686-unknown-linux-gnu,,$(2))
CFG_GCCISH_CXXFLAGS_mips-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-gnu := -shared -fPIC -g -mips32r2 -msoft-float -mabi=32
CFG_GCCISH_DEF_FLAG_mips-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_mips-unknown-linux-gnu := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_mips-unknown-linux-gnu := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_mips-unknown-linux-gnu := .linux.def
CFG_LLC_FLAGS_mips-unknown-linux-gnu :=
CFG_INSTALL_NAME_mips-unknown-linux-gnu =
CFG_EXE_SUFFIX_mips-unknown-linux-gnu :=
CFG_WINDOWSY_mips-unknown-linux-gnu :=
CFG_UNIXY_mips-unknown-linux-gnu := 1
-CFG_PATH_MUNGE_mips-unknown-linux-gnu := true
CFG_LDPATH_mips-unknown-linux-gnu :=
CFG_RUN_mips-unknown-linux-gnu=
CFG_RUN_TARG_mips-unknown-linux-gnu=
CFG_GCCISH_CXXFLAGS_mipsel-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_mipsel-unknown-linux-gnu := -shared -fPIC -g -mips32
CFG_GCCISH_DEF_FLAG_mipsel-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
-CFG_GCCISH_PRE_LIB_FLAGS_mipsel-unknown-linux-gnu := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_mipsel-unknown-linux-gnu := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_mipsel-unknown-linux-gnu := .linux.def
CFG_LLC_FLAGS_mipsel-unknown-linux-gnu :=
CFG_INSTALL_NAME_mipsel-unknown-linux-gnu =
CFG_EXE_SUFFIX_mipsel-unknown-linux-gnu :=
CFG_WINDOWSY_mipsel-unknown-linux-gnu :=
CFG_UNIXY_mipsel-unknown-linux-gnu := 1
-CFG_PATH_MUNGE_mipsel-unknown-linux-gnu := true
CFG_LDPATH_mipsel-unknown-linux-gnu :=
CFG_RUN_mipsel-unknown-linux-gnu=
CFG_RUN_TARG_mipsel-unknown-linux-gnu=
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_GCCISH_PRE_LIB_FLAGS_powerpc-unknown-linux-gnu := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_powerpc-unknown-linux-gnu := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_powerpc-unknown-linux-gnu := .linux.def
CFG_LLC_FLAGS_powerpc-unknown-linux-gnu :=
CFG_INSTALL_NAME_powerpc-unknown-linux-gnu =
CFG_EXE_SUFFIX_powerpc-unknown-linux-gnu =
CFG_WINDOWSY_powerpc-unknown-linux-gnu :=
CFG_UNIXY_powerpc-unknown-linux-gnu := 1
-CFG_PATH_MUNGE_powerpc-unknown-linux-gnu := true
CFG_LDPATH_powerpc-unknown-linux-gnu :=
CFG_RUN_powerpc-unknown-linux-gnu=$(2)
CFG_RUN_TARG_powerpc-unknown-linux-gnu=$(call CFG_RUN_powerpc-unknown-linux-gnu,,$(2))
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_GCCISH_PRE_LIB_FLAGS_x86_64-apple-darwin :=
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-apple-darwin :=
-CFG_DEF_SUFFIX_x86_64-apple-darwin := .darwin.def
CFG_LLC_FLAGS_x86_64-apple-darwin :=
CFG_INSTALL_NAME_x86_64-apple-darwin = -Wl,-install_name,@rpath/$(1)
CFG_EXE_SUFFIX_x86_64-apple-darwin :=
CFG_WINDOWSY_x86_64-apple-darwin :=
CFG_UNIXY_x86_64-apple-darwin := 1
-CFG_PATH_MUNGE_x86_64-apple-darwin := true
CFG_LDPATH_x86_64-apple-darwin :=
CFG_RUN_x86_64-apple-darwin=$(2)
CFG_RUN_TARG_x86_64-apple-darwin=$(call CFG_RUN_x86_64-apple-darwin,,$(2))
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_GCCISH_PRE_LIB_FLAGS_x86_64-apple-ios :=
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-apple-ios :=
-CFG_DEF_SUFFIX_x86_64-apple-ios := .darwin.def
CFG_LLC_FLAGS_x86_64-apple-ios :=
CFG_INSTALL_NAME_x86_64-apple-ios = -Wl,-install_name,@rpath/$(1)
CFG_LIBUV_LINK_FLAGS_x86_64-apple-ios :=
CFG_EXE_SUFFIX_x86_64-apple-ios :=
CFG_WINDOWSY_x86_64-apple-ios :=
CFG_UNIXY_x86_64-apple-ios := 1
-CFG_PATH_MUNGE_x86_64-apple-ios := true
CFG_LDPATH_x86_64-apple-ios :=
CFG_RUN_x86_64-apple-ios = $(2)
CFG_RUN_TARG_x86_64-apple-ios = $(call CFG_RUN_x86_64-apple-ios,,$(2))
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_GCCISH_PRE_LIB_FLAGS_x86_64-pc-windows-gnu :=
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-pc-windows-gnu :=
-CFG_DEF_SUFFIX_x86_64-pc-windows-gnu := .windows.def
CFG_LLC_FLAGS_x86_64-pc-windows-gnu :=
CFG_INSTALL_NAME_x86_64-pc-windows-gnu =
CFG_EXE_SUFFIX_x86_64-pc-windows-gnu := .exe
CFG_WINDOWSY_x86_64-pc-windows-gnu := 1
CFG_UNIXY_x86_64-pc-windows-gnu :=
-CFG_PATH_MUNGE_x86_64-pc-windows-gnu :=
CFG_LDPATH_x86_64-pc-windows-gnu :=
CFG_RUN_x86_64-pc-windows-gnu=$(2)
CFG_RUN_TARG_x86_64-pc-windows-gnu=$(call CFG_RUN_x86_64-pc-windows-gnu,,$(2))
CFG_GCCISH_CFLAGS_x86_64-unknown-bitrig := -Wall -Werror -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_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-bitrig := -Wl,-pic -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-bitrig := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_x86_64-unknown-bitrig := .bsd.def
CFG_LLC_FLAGS_x86_64-unknown-bitrig :=
CFG_INSTALL_NAME_x86_64-unknown-bitrig =
CFG_EXE_SUFFIX_x86_64-unknown-bitrig :=
CFG_WINDOWSY_x86_64-unknown-bitrig :=
CFG_UNIXY_x86_64-unknown-bitrig := 1
-CFG_PATH_MUNGE_x86_64-unknown-bitrig :=
CFG_LDPATH_x86_64-unknown-bitrig :=
CFG_RUN_x86_64-unknown-bitrig=$(2)
CFG_RUN_TARG_x86_64-unknown-bitrig=$(call CFG_RUN_x86_64-unknown-bitrig,,$(2))
CFG_GCCISH_CFLAGS_x86_64-unknown-dragonfly := -Wall -Werror -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_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-dragonfly := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-dragonfly := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_x86_64-unknown-dragonfly := .bsd.def
CFG_LLC_FLAGS_x86_64-unknown-dragonfly :=
CFG_INSTALL_NAME_x86_64-unknown-dragonfly =
CFG_EXE_SUFFIX_x86_64-unknown-dragonfly :=
CFG_WINDOWSY_x86_64-unknown-dragonfly :=
CFG_UNIXY_x86_64-unknown-dragonfly := 1
-CFG_PATH_MUNGE_x86_64-unknown-dragonfly :=
CFG_LDPATH_x86_64-unknown-dragonfly :=
CFG_RUN_x86_64-unknown-dragonfly=$(2)
CFG_RUN_TARG_x86_64-unknown-dragonfly=$(call CFG_RUN_x86_64-unknown-dragonfly,,$(2))
CFG_GCCISH_CFLAGS_x86_64-unknown-freebsd := -Wall -Werror -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_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-freebsd := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-freebsd := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_x86_64-unknown-freebsd := .bsd.def
CFG_LLC_FLAGS_x86_64-unknown-freebsd :=
CFG_INSTALL_NAME_x86_64-unknown-freebsd =
CFG_EXE_SUFFIX_x86_64-unknown-freebsd :=
CFG_WINDOWSY_x86_64-unknown-freebsd :=
CFG_UNIXY_x86_64-unknown-freebsd := 1
-CFG_PATH_MUNGE_x86_64-unknown-freebsd :=
CFG_LDPATH_x86_64-unknown-freebsd :=
CFG_RUN_x86_64-unknown-freebsd=$(2)
CFG_RUN_TARG_x86_64-unknown-freebsd=$(call CFG_RUN_x86_64-unknown-freebsd,,$(2))
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_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-linux-gnu := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-linux-gnu := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_x86_64-unknown-linux-gnu := .linux.def
CFG_LLC_FLAGS_x86_64-unknown-linux-gnu :=
CFG_INSTALL_NAME_x86_64-unknown-linux-gnu =
CFG_EXE_SUFFIX_x86_64-unknown-linux-gnu =
CFG_WINDOWSY_x86_64-unknown-linux-gnu :=
CFG_UNIXY_x86_64-unknown-linux-gnu := 1
-CFG_PATH_MUNGE_x86_64-unknown-linux-gnu := true
CFG_LDPATH_x86_64-unknown-linux-gnu :=
CFG_RUN_x86_64-unknown-linux-gnu=$(2)
CFG_RUN_TARG_x86_64-unknown-linux-gnu=$(call CFG_RUN_x86_64-unknown-linux-gnu,,$(2))
--- /dev/null
+# x86_64-unknown-linux-musl configuration
+CC_x86_64-unknown-linux-musl=$(CFG_MUSL_ROOT)/bin/musl-gcc
+CXX_x86_64-unknown-linux-musl=notaprogram
+CPP_x86_64-unknown-linux-musl=$(CFG_MUSL_ROOT)/bin/musl-gcc -E
+AR_x86_64-unknown-linux-musl=$(AR)
+CFG_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).so
+CFG_STATIC_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).a
+CFG_LIB_GLOB_x86_64-unknown-linux-musl=lib$(1)-*.so
+CFG_JEMALLOC_CFLAGS_x86_64-unknown-linux-musl := -m64
+CFG_GCCISH_CFLAGS_x86_64-unknown-linux-musl := -Wall -Werror -g -fPIC -m64
+CFG_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_LLC_FLAGS_x86_64-unknown-linux-musl :=
+CFG_INSTALL_NAME_x86_64-unknown-linux-musl =
+CFG_EXE_SUFFIX_x86_64-unknown-linux-musl =
+CFG_WINDOWSY_x86_64-unknown-linux-musl :=
+CFG_UNIXY_x86_64-unknown-linux-musl := 1
+CFG_LDPATH_x86_64-unknown-linux-musl :=
+CFG_RUN_x86_64-unknown-linux-musl=$(2)
+CFG_RUN_TARG_x86_64-unknown-linux-musl=$(call CFG_RUN_x86_64-unknown-linux-musl,,$(2))
+CFG_GNU_TRIPLE_x86_64-unknown-linux-musl := x86_64-unknown-linux-musl
+
+NATIVE_DEPS_libc_T_x86_64-unknown-linux-musl += libc.a
+NATIVE_DEPS_std_T_x86_64-unknown-linux-musl += libunwind.a \
+ crt1.o crti.o crtn.o
+INSTALLED_OBJECTS_x86_64-unknown-linux-musl += crt1.o crti.o crtn.o
CFG_GCCISH_CFLAGS_x86_64-unknown-openbsd := -Wall -Werror -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_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-openbsd := -Wl,-whole-archive
-CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-openbsd := -Wl,-no-whole-archive
-CFG_DEF_SUFFIX_x86_64-unknown-openbsd := .bsd.def
CFG_LLC_FLAGS_x86_64-unknown-openbsd :=
CFG_INSTALL_NAME_x86_64-unknown-openbsd =
CFG_EXE_SUFFIX_x86_64-unknown-openbsd :=
CFG_WINDOWSY_x86_64-unknown-openbsd :=
CFG_UNIXY_x86_64-unknown-openbsd := 1
-CFG_PATH_MUNGE_x86_64-unknown-openbsd :=
CFG_LDPATH_x86_64-unknown-openbsd :=
CFG_RUN_x86_64-unknown-openbsd=$(2)
CFG_RUN_TARG_x86_64-unknown-openbsd=$(call CFG_RUN_x86_64-unknown-openbsd,,$(2))
# Documented-by-default crates
DOC_CRATES := std alloc collections core libc rustc_unicode
+# Installed objects/libraries by default
+INSTALLED_OBJECTS := libmorestack.a libcompiler-rt.a
+
################################################################################
# You should not need to edit below this line
################################################################################
# Prerequisites for using the stageN compiler to build target artifacts
TSREQ$(1)_T_$(2)_H_$(3) = \
$$(HSREQ$(1)_H_$(3)) \
- $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a \
- $$(TLIB$(1)_T_$(2)_H_$(3))/libcompiler-rt.a
+ $$(foreach obj,$$(INSTALLED_OBJECTS),\
+ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \
+ $$(foreach obj,$$(INSTALLED_OBJECTS_$(2)),\
+ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj))
# Prerequisites for a working stageN compiler and libraries, for a specific
# target
$$(if $$(findstring $(2),$$(CFG_HOST)), \
$$(foreach crate,$$(HOST_CRATES), \
$$(call PREPARE_LIB,$$(call CFG_LIB_GLOB_$(2),$$(crate)))),) \
- $$(call PREPARE_LIB,libmorestack.a) \
- $$(call PREPARE_LIB,libcompiler-rt.a),),),)
+ $$(foreach object,$$(INSTALLED_OBJECTS) $$(INSTALLED_OBJECTS_$(2)),\
+ $$(call PREPARE_LIB,$$(object))),),),)
endef
define INSTALL_GDB_DEBUGGER_SCRIPTS_COMMANDS
@mkdir -p $$(@D)
@$$(call E, compile: $$@)
$$(Q)$$(LLC_$$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) \
- -filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) -relocation-model=pic -o $$@ $$<
+ -filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) \
+ -relocation-model=pic -o $$@ $$<
$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS)
@mkdir -p $$(@D)
@$$(call E, link: $$@)
$$(Q)$$(AR_$(1)) rcs $$@ $$^
+ifeq ($$(findstring windows,$(1)),windows)
+$$(RT_OUTPUT_DIR_$(1))/lib$(2).a: $$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1))
+ $$(Q)cp $$^ $$@
+endif
+
endef
$(foreach target,$(CFG_TARGET), \
$(S)src/compiler-rt/*/*/*/*)
endif
-COMPRT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
+COMPRT_NAME_$(1) := libcompiler-rt.a
COMPRT_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(COMPRT_NAME_$(1))
COMPRT_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/compiler-rt
endif # endif for ios
endif # endif for darwin
+################################################################################
+# libc/libunwind for musl
+#
+# When we're building a musl-like target we're going to link libc/libunwind
+# statically into the standard library and liblibc, so we need to make sure
+# they're in a location that we can find
+################################################################################
+
+ifeq ($$(findstring musl,$(1)),musl)
+$$(RT_OUTPUT_DIR_$(1))/%: $$(CFG_MUSL_ROOT)/lib/%
+ cp $$^ $$@
+endif
+
endef
# Instantiate template for all stages/targets
RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, \
ExecutionEngineWrapper.cpp RustWrapper.cpp PassWrapper.cpp)
-RUSTLLVM_DEF_$(1) := $(1)/rustllvm/rustllvm$(CFG_DEF_SUFFIX_$(1))
-
RUSTLLVM_INCS_$(1) = $$(LLVM_EXTRA_INCDIRS_$(1)) \
-iquote $$(LLVM_INCDIR_$(1)) \
-iquote $$(S)src/rustllvm/include
$$(foreach dep,$$(RUST_DEPS_$(4)), \
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
$$(foreach dep,$$(NATIVE_DEPS_$(4)), \
- $$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),$$(dep)))
+ $$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),$$(dep))) \
+ $$(foreach dep,$$(NATIVE_DEPS_$(4)_T_$(2)), \
+ $$(RT_OUTPUT_DIR_$(2))/$$(dep))
endef
$(foreach host,$(CFG_HOST), \
$$(TLIB$(1)_T_$(2)_H_$(3))/:
mkdir -p $$@
-$$(TLIB$(1)_T_$(2)_H_$(3))/libcompiler-rt.a: \
- $$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),compiler-rt) \
- | $$(TLIB$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP)
- @$$(call E, cp: $$@)
- $$(Q)cp $$< $$@
-
-$$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a: \
- $$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),morestack) \
+$$(TLIB$(1)_T_$(2)_H_$(3))/%: $$(RT_OUTPUT_DIR_$(2))/% \
| $$(TLIB$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP)
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
check-stage$(1)-T-$(2)-H-$(3)-pfail-exec \
check-stage$(1)-T-$(2)-H-$(3)-rpass-valgrind-exec \
check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \
+ check-stage$(1)-T-$(2)-H-$(3)-rfail-full-exec \
check-stage$(1)-T-$(2)-H-$(3)-cfail-full-exec \
check-stage$(1)-T-$(2)-H-$(3)-rmake-exec \
check-stage$(1)-T-$(2)-H-$(3)-rustdocck-exec \
check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-valgrind-exec \
check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-full-exec \
check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-exec \
+ check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-full-exec \
check-stage$(1)-T-$(2)-H-$(3)-pretty-bench-exec \
check-stage$(1)-T-$(2)-H-$(3)-pretty-pretty-exec
RPASS_RS := $(wildcard $(S)src/test/run-pass/*.rs)
RPASS_VALGRIND_RS := $(wildcard $(S)src/test/run-pass-valgrind/*.rs)
RPASS_FULL_RS := $(wildcard $(S)src/test/run-pass-fulldeps/*.rs)
+RFAIL_FULL_RS := $(wildcard $(S)src/test/run-fail-fulldeps/*.rs)
CFAIL_FULL_RS := $(wildcard $(S)src/test/compile-fail-fulldeps/*.rs)
RFAIL_RS := $(wildcard $(S)src/test/run-fail/*.rs)
CFAIL_RS := $(wildcard $(S)src/test/compile-fail/*.rs)
RPASS_TESTS := $(RPASS_RS)
RPASS_VALGRIND_TESTS := $(RPASS_VALGRIND_RS)
RPASS_FULL_TESTS := $(RPASS_FULL_RS)
+RFAIL_FULL_TESTS := $(RFAIL_FULL_RS)
CFAIL_FULL_TESTS := $(CFAIL_FULL_RS)
RFAIL_TESTS := $(RFAIL_RS)
CFAIL_TESTS := $(CFAIL_RS)
CTEST_MODE_rpass-full = run-pass
CTEST_RUNTOOL_rpass-full = $(CTEST_RUNTOOL)
+CTEST_SRC_BASE_rfail-full = run-fail-fulldeps
+CTEST_BUILD_BASE_rfail-full = run-fail-fulldeps
+CTEST_MODE_rfail-full = run-fail
+CTEST_RUNTOOL_rfail-full = $(CTEST_RUNTOOL)
+
CTEST_SRC_BASE_cfail-full = compile-fail-fulldeps
CTEST_BUILD_BASE_cfail-full = compile-fail-fulldeps
CTEST_MODE_cfail-full = compile-fail
CTEST_DEPS_rpass_$(1)-T-$(2)-H-$(3) = $$(RPASS_TESTS)
CTEST_DEPS_rpass-valgrind_$(1)-T-$(2)-H-$(3) = $$(RPASS_VALGRIND_TESTS)
CTEST_DEPS_rpass-full_$(1)-T-$(2)-H-$(3) = $$(RPASS_FULL_TESTS) $$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3))
+CTEST_DEPS_rfail-full_$(1)-T-$(2)-H-$(3) = $$(RFAIL_FULL_TESTS) $$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3))
CTEST_DEPS_cfail-full_$(1)-T-$(2)-H-$(3) = $$(CFAIL_FULL_TESTS) $$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3))
CTEST_DEPS_rfail_$(1)-T-$(2)-H-$(3) = $$(RFAIL_TESTS)
CTEST_DEPS_cfail_$(1)-T-$(2)-H-$(3) = $$(CFAIL_TESTS)
endef
-CTEST_NAMES = rpass rpass-valgrind rpass-full cfail-full rfail cfail pfail \
+CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \
bench perf debuginfo-gdb debuginfo-lldb codegen rustdocck
$(foreach host,$(CFG_HOST), \
$(eval $(foreach name,$(CTEST_NAMES), \
$(eval $(call DEF_RUN_COMPILETEST,$(stage),$(target),$(host),$(name))))))))))
-PRETTY_NAMES = pretty-rpass pretty-rpass-valgrind pretty-rpass-full pretty-rfail pretty-bench pretty-pretty
+PRETTY_NAMES = pretty-rpass pretty-rpass-valgrind pretty-rpass-full pretty-rfail-full pretty-rfail \
+ pretty-bench pretty-pretty
PRETTY_DEPS_pretty-rpass = $(RPASS_TESTS)
PRETTY_DEPS_pretty-rpass-valgrind = $(RPASS_VALGRIND_TESTS)
PRETTY_DEPS_pretty-rpass-full = $(RPASS_FULL_TESTS)
+PRETTY_DEPS_pretty-rfail-full = $(RFAIL_FULL_TESTS)
PRETTY_DEPS_pretty-rfail = $(RFAIL_TESTS)
PRETTY_DEPS_pretty-bench = $(BENCH_TESTS)
PRETTY_DEPS_pretty-pretty = $(PRETTY_TESTS)
PRETTY_DIRNAME_pretty-rpass = run-pass
PRETTY_DIRNAME_pretty-rpass-valgrind = run-pass-valgrind
PRETTY_DIRNAME_pretty-rpass-full = run-pass-fulldeps
+PRETTY_DIRNAME_pretty-rfail-full = run-fail-fulldeps
PRETTY_DIRNAME_pretty-rfail = run-fail
PRETTY_DIRNAME_pretty-bench = bench
PRETTY_DIRNAME_pretty-pretty = pretty
define DEF_PRETTY_FULLDEPS
PRETTY_DEPS$(1)_T_$(2)_H_$(3)_pretty-rpass-full = $$(CSREQ$(1)_T_$(3)_H_$(3))
+PRETTY_DEPS$(1)_T_$(2)_H_$(3)_pretty-rfail-full = $$(CSREQ$(1)_T_$(3)_H_$(3))
endef
$(foreach host,$(CFG_HOST), \
rpass \
rpass-valgrind \
rpass-full \
+ rfail-full \
cfail-full \
rfail \
cfail \
pretty-rpass \
pretty-rpass-valgrind \
pretty-rpass-full \
+ pretty-rfail-full \
pretty-rfail \
pretty-bench \
pretty-pretty \
format!("ignore-{}",
config.stage_id.split('-').next().unwrap())
}
+ fn ignore_env(config: &Config) -> String {
+ format!("ignore-{}", util::get_env(&config.target).unwrap_or("<unknown>"))
+ }
fn ignore_gdb(config: &Config, line: &str) -> bool {
if config.mode != common::DebugInfoGdb {
return false;
!parse_name_directive(ln, &ignore_target(config)) &&
!parse_name_directive(ln, &ignore_architecture(config)) &&
!parse_name_directive(ln, &ignore_stage(config)) &&
+ !parse_name_directive(ln, &ignore_env(config)) &&
!(config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) &&
!(config.target != config.host && parse_name_directive(ln, "ignore-cross-compile")) &&
!ignore_gdb(config, ln) &&
let mut crate_type = if aux_props.no_prefer_dynamic {
Vec::new()
} else {
- vec!("--crate-type=dylib".to_string())
+ // We primarily compile all auxiliary libraries as dynamic libraries
+ // to avoid code size bloat and large binaries as much as possible
+ // for the test suite (otherwise including libstd statically in all
+ // executables takes up quite a bit of space).
+ //
+ // For targets like MUSL, however, there is no support for dynamic
+ // libraries so we just go back to building a normal library. Note,
+ // however, that if the library is built with `force_host` then it's
+ // ok to be a dylib as the host should always support dylibs.
+ if config.target.contains("musl") && !aux_props.force_host {
+ vec!("--crate-type=lib".to_string())
+ } else {
+ vec!("--crate-type=dylib".to_string())
+ }
};
crate_type.extend(extra_link_args.clone().into_iter());
let aux_args =
panic!("Cannot determine Architecture from triple");
}
+pub fn get_env(triple: &str) -> Option<&str> {
+ triple.split('-').nth(3)
+}
+
pub fn make_new_path(path: &str) -> String {
assert!(cfg!(windows));
// Windows just uses PATH as the library search path, so we have to
## Comments
Comments in Rust code follow the general C++ style of line (`//`) and
-block-comment (`/* ... */`) forms. Nested block comments are supported.
+block (`/* ... */`) comment forms. Nested block comments are supported.
Line comments beginning with exactly _three_ slashes (`///`), and block
comments beginning with exactly one repeated asterisk in the block-open
A _string literal_ is a sequence of any Unicode characters enclosed within two
`U+0022` (double-quote) characters, with the exception of `U+0022` itself,
-which must be _escaped_ by a preceding `U+005C` character (`\`), or a _raw
-string literal_.
+which must be _escaped_ by a preceding `U+005C` character (`\`).
-A multi-line string literal may be defined by terminating each line with a
-`U+005C` character (`\`) immediately before the newline. This causes the
-`U+005C` character, the newline, and all whitespace at the beginning of the
-next line to be ignored.
+Line-break characters are allowed in string literals. Normally they represent
+themselves (i.e. no translation), but as a special exception, when a `U+005C`
+character (`\`) occurs immediately before the newline, the `U+005C` character,
+the newline, and all whitespace at the beginning of the next line are ignored.
+Thus `a` and `b` are equal:
```rust
let a = "foobar";
optionally followed by another decimal literal, with an optional _exponent_.
* A single _decimal literal_ followed by an _exponent_.
-By default, a floating-point literal has a generic type, and, like integer
-literals, the type must be uniquely determined from the context. There are two valid
+Like integer literals, a floating-point literal may be followed by a
+suffix, so long as the pre-suffix part does not end with `U+002E` (`.`).
+The suffix forcibly sets the type of the literal. There are two valid
_floating-point suffixes_, `f32` and `f64` (the 32-bit and 64-bit floating point
types), which explicitly determine the type of the literal.
+The type of an _unsuffixed_ floating-point literal is determined by type
+inference. If a floating-point type can be _uniquely_ determined from the
+surrounding program context, the unsuffixed floating-point literal has that type.
+If the program context underconstrains the type, it defaults to double-precision `f64`;
+if the program context overconstrains the type, it is considered a static type
+error.
+
Examples of floating-point literals of various forms:
```
semantics are likely to change, so this macro usage must be opted
into.
-* `associated_types` - Allows type aliases in traits. Experimental.
+* `associated_consts` - Allows constants to be defined in `impl` and `trait`
+ blocks, so that they can be associated with a type or
+ trait in a similar manner to methods and associated
+ types.
* `box_patterns` - Allows `box` patterns, the exact semantics of which
is subject to change.
$ mv main.rs src/main.rs
```
+Note that since we're creating an executable, we used `main.rs`. If we
+want to make a library instead, we should use `lib.rs`.
+Custom file locations for the entry point can be specified
+with a [`[[lib]]` or `[[bin]]`][crates-custom] key in the TOML file described below.
+
+[crates-custom]: http://doc.crates.io/manifest.html#configuring-a-target
+
Cargo expects your source files to live inside a `src` directory. That leaves
the top level for other things, like READMEs, license information, and anything
not related to your code. Cargo helps us keep our projects nice and tidy. A
The form of UFCS we just talked about:
```rust,ignore
-Type::method(args);
+Trait::method(args);
```
Is a short-hand. There’s an expanded form of this that’s needed in some
% Vectors
A ‘vector’ is a dynamic or ‘growable’ array, implemented as the standard
-library type [`Vec<T>`][vec]. That `<T>` is a [generic][generic], meaning we
-can have vectors of any type. Vectors always allocate their data on the heap.
+library type [`Vec<T>`][vec]. The `T` means that we can have vectors
+of any type (see the chapter on [generics][generic] for more).
+Vectors always allocate their data on the heap.
You can create them with the `vec!` macro:
```rust
;
trait_item
-: trait_type
+: trait_const
+| trait_type
| trait_method
;
+trait_const
+: maybe_outer_attrs CONST ident maybe_const_default ';' { $$ = mk_node("ConstTraitItem", 3, $1, $3, $4); }
+;
+
+maybe_const_default
+: '=' expr { $$ = mk_node("ConstDefault", 1, $2); }
+| %empty { $$ = mk_none(); }
+;
+
trait_type
: maybe_outer_attrs TYPE ty_param ';' { $$ = mk_node("TypeTraitItem", 2, $1, $3); }
;
impl_item
: impl_method
| item_macro
-| trait_type
+| impl_const
+| impl_type
+;
+
+impl_const
+: attrs_and_vis item_const { $$ = mk_node("ImplConst", 1, $1, $2); }
+;
+
+impl_type
+: attrs_and_vis TYPE ident generic_params '=' ty_sum ';' { $$ = mk_node("ImplType", 4, $1, $3, $4, $6); }
;
item_fn
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Arc<T> {
/// Drops the `Arc<T>`.
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Weak<T> {
/// Drops the `Weak<T>`.
}
// -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
- #[cfg(all(not(windows), not(target_os = "android")))]
+ #[cfg(all(not(windows),
+ not(target_os = "android"),
+ not(target_env = "musl")))]
#[link(name = "pthread")]
extern {}
#![feature(allocator)]
#![feature(custom_attribute)]
#![feature(fundamental)]
-#![feature(lang_items, unsafe_destructor)]
+#![feature(lang_items)]
#![feature(box_syntax)]
#![feature(optin_builtin_traits)]
#![feature(unboxed_closures)]
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Rc<T> {
/// Drops the `Rc<T>`.
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Weak<T> {
/// Drops the `Weak<T>`.
#![feature(core)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
-#![feature(unsafe_destructor)]
#![cfg_attr(test, feature(test))]
extern crate alloc;
}
}
-#[unsafe_destructor]
impl<'longer_than_self> Drop for Arena<'longer_than_self> {
fn drop(&mut self) {
unsafe {
}
}
-#[unsafe_destructor]
impl<T> Drop for TypedArena<T> {
fn drop(&mut self) {
unsafe {
#[unstable(feature = "collections",
reason = "matches collection reform specification, waiting for dust to settle")]
pub fn drain(&mut self) -> Drain<T> {
- Drain { iter: self.data.drain() }
+ Drain { iter: self.data.drain(..) }
}
/// Drops all items from the binary heap.
}
}
-#[unsafe_destructor]
impl<T> Drop for RawItems<T> {
fn drop(&mut self) {
for _ in self.by_ref() {}
}
}
-#[unsafe_destructor]
impl<K, V> Drop for Node<K, V> {
fn drop(&mut self) {
if self.keys.is_null() ||
}
}
-#[unsafe_destructor]
impl<K, V> Drop for MoveTraversalImpl<K, V> {
fn drop(&mut self) {
// We need to cleanup the stored values manually, as the RawItems destructor would run
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(unicode)]
-#![feature(unsafe_destructor)]
#![feature(unique)]
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(step_by)]
#![feature(slice_patterns)]
#![feature(debug_builders)]
#![feature(utf8_error)]
-#![cfg_attr(test, feature(rand, rustc_private, test, hash, collections))]
+#![cfg_attr(test, feature(rand, rustc_private, test, hash, collections,
+ collections_drain, collections_range))]
#![cfg_attr(test, allow(deprecated))] // rand
#![feature(no_std)]
pub mod enum_set;
pub mod fmt;
pub mod linked_list;
+pub mod range;
pub mod slice;
pub mod str;
pub mod string;
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for LinkedList<T> {
fn drop(&mut self) {
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+#![unstable(feature = "collections_range", reason = "was just added")]
+
+//! Range syntax.
+
+use core::option::Option::{self, None, Some};
+use core::ops::{RangeFull, Range, RangeTo, RangeFrom};
+
+/// **RangeArgument** is implemented by Rust's built-in range types, produced
+/// by range syntax like `..`, `a..`, `..b` or `c..d`.
+pub trait RangeArgument<T> {
+ /// Start index (inclusive)
+ ///
+ /// Return start value if present, else `None`.
+ fn start(&self) -> Option<&T> { None }
+
+ /// End index (exclusive)
+ ///
+ /// Return end value if present, else `None`.
+ fn end(&self) -> Option<&T> { None }
+}
+
+
+impl<T> RangeArgument<T> for RangeFull {}
+
+impl<T> RangeArgument<T> for RangeFrom<T> {
+ fn start(&self) -> Option<&T> { Some(&self.start) }
+}
+
+impl<T> RangeArgument<T> for RangeTo<T> {
+ fn end(&self) -> Option<&T> { Some(&self.end) }
+}
+
+impl<T> RangeArgument<T> for Range<T> {
+ fn start(&self) -> Option<&T> { Some(&self.start) }
+ fn end(&self) -> Option<&T> { Some(&self.end) }
+}
/// # #![feature(collections)]
/// use std::string::as_string;
///
-/// fn string_consumer(s: String) {
-/// assert_eq!(s, "foo".to_string());
+/// // Let's pretend we have a function that requires `&String`
+/// fn string_consumer(s: &String) {
+/// assert_eq!(s, "foo");
/// }
///
-/// let string = as_string("foo").clone();
-/// string_consumer(string);
+/// // Provide a `&String` from a `&str` without allocating
+/// string_consumer(&as_string("foo"));
/// ```
#[unstable(feature = "collections")]
pub fn as_string<'a>(x: &'a str) -> DerefString<'a> {
use borrow::{Cow, IntoCow};
+use super::range::RangeArgument;
+
// FIXME- fix places which assume the max vector allowed has memory usize::MAX.
static MAX_MEMORY_SIZE: usize = isize::MAX as usize;
///
/// # Panics
///
- /// Panics if `i` is out of bounds.
+ /// Panics if `index` is out of bounds.
///
/// # Examples
///
unsafe { other.set_len(0); }
}
- /// Creates a draining iterator that clears the `Vec` and iterates over
- /// the removed items from start to end.
+ /// Create a draining iterator that removes the specified range in the vector
+ /// and yields the removed items from start to end. The element range is
+ /// removed even if the iterator is not consumed until the end.
+ ///
+ /// Note: It is unspecified how many elements are removed from the vector,
+ /// if the `Drain` value is leaked.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the starting point is greater than the end point or if
+ /// the end point is greater than the length of the vector.
///
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let mut v = vec!["a".to_string(), "b".to_string()];
- /// for s in v.drain() {
- /// // s has type String, not &String
- /// println!("{}", s);
- /// }
- /// assert!(v.is_empty());
+ /// # #![feature(collections_drain, collections_range)]
+ ///
+ /// // Draining using `..` clears the whole vector.
+ /// let mut v = vec![1, 2, 3];
+ /// let u: Vec<_> = v.drain(..).collect();
+ /// assert_eq!(v, &[]);
+ /// assert_eq!(u, &[1, 2, 3]);
/// ```
- #[inline]
- #[unstable(feature = "collections",
- reason = "matches collection reform specification, waiting for dust to settle")]
- pub fn drain(&mut self) -> Drain<T> {
+ #[unstable(feature = "collections_drain",
+ reason = "recently added, matches RFC")]
+ pub fn drain<R>(&mut self, range: R) -> Drain<T> where R: RangeArgument<usize> {
+ // Memory safety
+ //
+ // When the Drain is first created, it shortens the length of
+ // the source vector to make sure no uninitalized or moved-from elements
+ // are accessible at all if the Drain's destructor never gets to run.
+ //
+ // Drain will ptr::read out the values to remove.
+ // When finished, remaining tail of the vec is copied back to cover
+ // the hole, and the vector length is restored to the new length.
+ //
+ let len = self.len();
+ let start = *range.start().unwrap_or(&0);
+ let end = *range.end().unwrap_or(&len);
+ assert!(start <= end);
+ assert!(end <= len);
+
unsafe {
- let begin = *self.ptr as *const T;
- let end = if mem::size_of::<T>() == 0 {
- (*self.ptr as usize + self.len()) as *const T
- } else {
- (*self.ptr).offset(self.len() as isize) as *const T
- };
- self.set_len(0);
+ // set self.vec length's to start, to be safe in case Drain is leaked
+ self.set_len(start);
+ // Use the borrow in the IterMut to indicate borrowing behavior of the
+ // whole Drain iterator (like &mut T).
+ let range_slice = slice::from_raw_parts_mut(
+ self.as_mut_ptr().offset(start as isize),
+ end - start);
Drain {
- ptr: begin,
- end: end,
- marker: PhantomData,
+ tail_start: end,
+ tail_len: len - end,
+ iter: range_slice.iter_mut(),
+ vec: self as *mut _,
}
}
}
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Vec<T> {
fn drop(&mut self) {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ExactSizeIterator for IntoIter<T> {}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for IntoIter<T> {
fn drop(&mut self) {
}
}
-/// An iterator that drains a vector.
-#[unsafe_no_drop_flag]
-#[unstable(feature = "collections",
- reason = "recently added as part of collections reform 2")]
-pub struct Drain<'a, T:'a> {
- ptr: *const T,
- end: *const T,
- marker: PhantomData<&'a T>,
+/// A draining iterator for `Vec<T>`.
+#[unstable(feature = "collections_drain", reason = "recently added")]
+pub struct Drain<'a, T: 'a> {
+ /// Index of tail to preserve
+ tail_start: usize,
+ /// Length of tail
+ tail_len: usize,
+ /// Current remaining range to remove
+ iter: slice::IterMut<'a, T>,
+ vec: *mut Vec<T>,
}
unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
#[inline]
fn next(&mut self) -> Option<T> {
- unsafe {
- if self.ptr == self.end {
- None
- } else {
- if mem::size_of::<T>() == 0 {
- // purposefully don't use 'ptr.offset' because for
- // vectors with 0-size elements this would return the
- // same pointer.
- self.ptr = mem::transmute(self.ptr as usize + 1);
-
- // Use a non-null pointer value
- Some(ptr::read(EMPTY as *mut T))
- } else {
- let old = self.ptr;
- self.ptr = self.ptr.offset(1);
-
- Some(ptr::read(old))
- }
+ self.iter.next().map(|elt|
+ unsafe {
+ ptr::read(elt as *const _)
}
- }
+ )
}
- #[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- let diff = (self.end as usize) - (self.ptr as usize);
- let size = mem::size_of::<T>();
- let exact = diff / (if size == 0 {1} else {size});
- (exact, Some(exact))
+ self.iter.size_hint()
}
}
impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<T> {
- unsafe {
- if self.end == self.ptr {
- None
- } else {
- if mem::size_of::<T>() == 0 {
- // See above for why 'ptr.offset' isn't used
- self.end = mem::transmute(self.end as usize - 1);
-
- // Use a non-null pointer value
- Some(ptr::read(EMPTY as *mut T))
- } else {
- self.end = self.end.offset(-1);
-
- Some(ptr::read(self.end))
- }
+ self.iter.next_back().map(|elt|
+ unsafe {
+ ptr::read(elt as *const _)
}
- }
+ )
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
-
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Drop for Drain<'a, T> {
fn drop(&mut self) {
- // self.ptr == self.end == mem::POST_DROP_USIZE if drop has already been called,
- // so we can use #[unsafe_no_drop_flag].
+ // exhaust self first
+ while let Some(_) = self.next() { }
- // destroy the remaining elements
- for _x in self.by_ref() {}
+ if self.tail_len > 0 {
+ unsafe {
+ let source_vec = &mut *self.vec;
+ // memmove back untouched tail, update to new length
+ let start = source_vec.len();
+ let tail = self.tail_start;
+ let src = source_vec.as_ptr().offset(tail as isize);
+ let dst = source_vec.as_mut_ptr().offset(start as isize);
+ ptr::copy(src, dst, self.tail_len);
+ source_vec.set_len(start + self.tail_len);
+ }
+ }
}
}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
+
////////////////////////////////////////////////////////////////////////////////
// Conversion from &[T] to &Vec<T>
////////////////////////////////////////////////////////////////////////////////
}
// Prevent the inner `Vec<T>` from attempting to deallocate memory.
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Drop for DerefVec<'a, T> {
fn drop(&mut self) {
}
/// Converts a slice to a wrapper type providing a `&Vec<T>` reference.
+///
+/// # Examples
+///
+/// ```
+/// # #![feature(collections)]
+/// use std::vec::as_vec;
+///
+/// // Let's pretend we have a function that requires `&Vec<i32>`
+/// fn vec_consumer(s: &Vec<i32>) {
+/// assert_eq!(s, &[1, 2, 3]);
+/// }
+///
+/// // Provide a `&Vec<i32>` from a `&[i32]` without allocating
+/// let values = [1, 2, 3];
+/// vec_consumer(&as_vec(&values));
+/// ```
#[unstable(feature = "collections")]
pub fn as_vec<'a, T>(x: &'a [T]) -> DerefVec<'a, T> {
unsafe {
marker: PhantomData<::core::cell::Cell<(T,U)>>,
}
-#[unsafe_destructor]
impl<T,U> Drop for PartialVecNonZeroSized<T,U> {
fn drop(&mut self) {
unsafe {
}
}
-#[unsafe_destructor]
impl<T,U> Drop for PartialVecZeroSized<T,U> {
fn drop(&mut self) {
unsafe {
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for VecDeque<T> {
fn drop(&mut self) {
inner: &'a mut VecDeque<T>,
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: 'a> Drop for Drain<'a, T> {
fn drop(&mut self) {
}
let filter: fn((usize, Option<V>)) -> Option<(usize, V)> = filter; // coerce to fn ptr
- Drain { iter: self.v.drain().enumerate().filter_map(filter) }
+ Drain { iter: self.v.drain(..).enumerate().filter_map(filter) }
}
/// Returns the number of elements in the map.
#![feature(box_syntax)]
#![feature(collections)]
+#![feature(collections_drain)]
#![feature(core)]
#![feature(hash)]
#![feature(rand)]
#![feature(test)]
#![feature(unboxed_closures)]
#![feature(unicode)]
-#![feature(unsafe_destructor)]
#![feature(into_cow)]
#![feature(step_by)]
#![cfg_attr(test, feature(str_char))]
count: &'a mut u32
}
-#[unsafe_destructor]
impl<'a> Drop for DropCounter<'a> {
fn drop(&mut self) {
*self.count += 1;
fn test_drain_items() {
let mut vec = vec![1, 2, 3];
let mut vec2 = vec![];
- for i in vec.drain() {
+ for i in vec.drain(..) {
vec2.push(i);
}
assert_eq!(vec, []);
fn test_drain_items_reverse() {
let mut vec = vec![1, 2, 3];
let mut vec2 = vec![];
- for i in vec.drain().rev() {
+ for i in vec.drain(..).rev() {
vec2.push(i);
}
assert_eq!(vec, []);
fn test_drain_items_zero_sized() {
let mut vec = vec![(), (), ()];
let mut vec2 = vec![];
- for i in vec.drain() {
+ for i in vec.drain(..) {
vec2.push(i);
}
assert_eq!(vec, []);
assert_eq!(vec2, [(), (), ()]);
}
+#[test]
+#[should_panic]
+fn test_drain_out_of_bounds() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ v.drain(5..6);
+}
+
+#[test]
+fn test_drain_range() {
+ let mut v = vec![1, 2, 3, 4, 5];
+ for _ in v.drain(4..) {
+ }
+ assert_eq!(v, &[1, 2, 3, 4]);
+
+ let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect();
+ for _ in v.drain(1..4) {
+ }
+ assert_eq!(v, &[1.to_string(), 5.to_string()]);
+
+ let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect();
+ for _ in v.drain(1..4).rev() {
+ }
+ assert_eq!(v, &[1.to_string(), 5.to_string()]);
+
+ let mut v: Vec<_> = vec![(); 5];
+ for _ in v.drain(1..4).rev() {
+ }
+ assert_eq!(v, &[(), ()]);
+}
+
#[test]
fn test_into_boxed_slice() {
let xs = vec![1, 2, 3];
}
}
-#[unsafe_destructor]
impl<'b> Drop for BorrowRef<'b> {
#[inline]
fn drop(&mut self) {
_borrow: &'b Cell<BorrowFlag>,
}
-#[unsafe_destructor]
impl<'b> Drop for BorrowRefMut<'b> {
#[inline]
fn drop(&mut self) {
/// `String` implements `From<&str>`:
///
/// ```
-/// let s = "hello";
/// let string = "hello".to_string();
-///
-/// let other_string: String = From::from(s);
+/// let other_string = String::from("hello");
///
/// assert_eq!(string, other_string);
/// ```
mod float;
mod builders;
-#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
-#[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
+#[unstable(feature = "core", reason = "internal to format_args!")]
#[doc(hidden)]
pub mod rt {
pub mod v1;
/// compile time it is ensured that the function and the value have the correct
/// types, and then this struct is used to canonicalize arguments to one type.
#[derive(Copy)]
-#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
-#[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
+#[unstable(feature = "core", reason = "internal to format_args!")]
#[doc(hidden)]
pub struct ArgumentV1<'a> {
value: &'a Void,
}
#[doc(hidden)]
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
- #[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
+ #[unstable(feature = "core", reason = "internal to format_args!")]
pub fn new<'b, T>(x: &'b T,
f: fn(&T, &mut Formatter) -> Result) -> ArgumentV1<'b> {
unsafe {
}
#[doc(hidden)]
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
- #[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
+ #[unstable(feature = "core", reason = "internal to format_args!")]
pub fn from_usize(x: &usize) -> ArgumentV1 {
ArgumentV1::new(x, ArgumentV1::show_usize)
}
/// When using the format_args!() macro, this function is used to generate the
/// Arguments structure.
#[doc(hidden)] #[inline]
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
- #[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
+ #[unstable(feature = "core", reason = "internal to format_args!")]
pub fn new_v1(pieces: &'a [&'a str],
args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
Arguments {
/// created with `argumentusize`. However, failing to do so doesn't cause
/// unsafety, but will ignore invalid .
#[doc(hidden)] #[inline]
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
- #[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
+ #[unstable(feature = "core", reason = "internal to format_args!")]
pub fn new_v1_formatted(pieces: &'a [&'a str],
args: &'a [ArgumentV1<'a>],
fmt: &'a [rt::v1::Argument]) -> Arguments<'a> {
//! These definitions are similar to their `ct` equivalents, but differ in that
//! these can be statically allocated and are slightly optimized for the runtime
-#![cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
-#![cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))]
+#![unstable(feature = "core", reason = "internal to format_args!")]
#[derive(Copy, Clone)]
-#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub struct Argument {
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub position: Position,
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub format: FormatSpec,
}
#[derive(Copy, Clone)]
-#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub struct FormatSpec {
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub fill: char,
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub align: Alignment,
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub flags: u32,
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub precision: Count,
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub width: Count,
}
/// Possible alignments that can be requested as part of a formatting directive.
#[derive(Copy, Clone, PartialEq)]
-#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub enum Alignment {
/// Indication that contents should be left-aligned.
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Left,
/// Indication that contents should be right-aligned.
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Right,
/// Indication that contents should be center-aligned.
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Center,
/// No alignment was requested.
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Unknown,
}
#[derive(Copy, Clone)]
-#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub enum Count {
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Is(usize),
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Param(usize),
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
NextParam,
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Implied,
}
#[derive(Copy, Clone)]
-#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
pub enum Position {
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
Next,
- #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))]
At(usize)
}
/// Returns `true` if a type is managed (will be allocated on the local heap)
pub fn owns_managed<T>() -> bool;
- /// Calculates the offset from a pointer. The offset *must* be in-bounds of
- /// the object, or one-byte-past-the-end. An arithmetic overflow is also
- /// undefined behaviour.
+ /// Calculates the offset from a pointer.
///
/// This is implemented as an intrinsic to avoid converting to and from an
/// integer, since the conversion would throw away aliasing information.
+ ///
+ /// # Safety
+ ///
+ /// Both the starting and resulting pointer must be either in bounds or one
+ /// byte past the end of an allocated object. If either pointer is out of
+ /// bounds or arithmetic overflow occurs then any further use of the
+ /// returned value will result in undefined behavior.
pub fn offset<T>(dst: *const T, offset: isize) -> *const T;
/// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(not(stage0))]
pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
- /// dox
- #[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(stage0)]
- pub fn copy_nonoverlapping<T>(dst: *mut T, src: *const T, count: usize);
-
/// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
/// and destination may overlap.
///
/// ```
///
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(not(stage0))]
pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
- /// dox
- #[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(stage0)]
- pub fn copy<T>(dst: *mut T, src: *const T, count: usize);
-
/// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
/// bytes of memory starting at `dst` to `c`.
#[stable(feature = "rust1", since = "1.0.0")]
/// Returns the value of the discriminant for the variant in 'v',
/// cast to a `u64`; if `T` has no discriminant, returns 0.
- // SNAP 5520801
- #[cfg(not(stage0))]
pub fn discriminant_value<T>(v: &T) -> u64;
}
/// `start` should always be less than `end`, so the result should never
/// be negative.
///
+ /// `by` must be > 0.
+ ///
/// Returns `None` if it is not possible to calculate steps_between
/// without overflow.
fn steps_between(start: &Self, end: &Self, by: &Self) -> Option<usize>;
}
-macro_rules! step_impl {
+macro_rules! step_impl_unsigned {
($($t:ty)*) => ($(
impl Step for $t {
#[inline]
#[allow(trivial_numeric_casts)]
fn steps_between(start: &$t, end: &$t, by: &$t) -> Option<usize> {
if *start <= *end {
- Some(((*end - *start) / *by) as usize)
+ // Note: We assume $t <= usize here
+ Some((*end - *start) as usize / (*by as usize))
+ } else {
+ Some(0)
+ }
+ }
+ }
+ )*)
+}
+macro_rules! step_impl_signed {
+ ($($t:ty)*) => ($(
+ impl Step for $t {
+ #[inline]
+ fn step(&self, by: &$t) -> Option<$t> {
+ (*self).checked_add(*by)
+ }
+ #[inline]
+ #[allow(trivial_numeric_casts)]
+ fn steps_between(start: &$t, end: &$t, by: &$t) -> Option<usize> {
+ if *start <= *end {
+ // Note: We assume $t <= isize here
+ // Use .wrapping_sub and cast to usize to compute the
+ // difference that may not fit inside the range of isize.
+ Some(
+ ((*end as isize).wrapping_sub(*start as isize) as usize
+ / (*by as usize))
+ )
} else {
Some(0)
}
)*)
}
-step_impl!(usize u8 u16 u32 isize i8 i16 i32);
+step_impl_unsigned!(usize u8 u16 u32);
+step_impl_signed!(isize i8 i16 i32);
+#[cfg(target_pointer_width = "64")]
+step_impl_unsigned!(u64);
#[cfg(target_pointer_width = "64")]
-step_impl!(u64 i64);
+step_impl_signed!(i64);
#[cfg(target_pointer_width = "32")]
step_impl_no_between!(u64 i64);
#![feature(intrinsics, lang_items)]
#![feature(on_unimplemented)]
-#![feature(simd, unsafe_destructor)]
+#![feature(simd)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(rustc_attrs)]
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="send"]
#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
-#[cfg(not(stage0))]
pub unsafe trait Send {
// empty.
}
-/// Types able to be transferred across thread boundaries.
-#[stable(feature = "rust1", since = "1.0.0")]
-#[lang="send"]
-#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
-#[cfg(stage0)]
-pub unsafe trait Send : MarkerTrait {
- // empty.
-}
-
unsafe impl Send for .. { }
impl<T> !Send for *const T { }
#[lang="sized"]
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
-#[cfg(not(stage0))]
pub trait Sized {
// Empty.
}
-/// Types with a constant size known at compile-time.
-#[stable(feature = "rust1", since = "1.0.0")]
-#[lang="sized"]
-#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
-#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
-#[cfg(stage0)]
-pub trait Sized : MarkerTrait {
- // Empty.
-}
-
/// Types that can be copied by simply copying bits (i.e. `memcpy`).
///
/// By default, variable bindings have 'move semantics.' In other
/// wrapper around the value(s) which can be mutated when behind a `&`
/// reference; not doing this is undefined behaviour (for example,
/// `transmute`-ing from `&T` to `&mut T` is illegal).
-#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
#[lang="sync"]
#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
// Empty
}
-/// dox
-#[cfg(stage0)]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[lang="sync"]
-#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
-pub unsafe trait Sync : MarkerTrait {
- // Empty
-}
-
unsafe impl Sync for .. { }
impl<T> !Sync for *const T { }
)
}
-/// dox
-#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg(stage0)]
-pub trait MarkerTrait : PhantomFn<Self,Self> { }
-
-#[cfg(stage0)]
-impl<T: ?Sized> MarkerTrait for T {}
-
-/// dox
-#[lang="phantom_fn"]
-#[cfg(stage0)]
-pub trait PhantomFn<A:?Sized,R:?Sized=()> {
-}
-
/// `PhantomData<T>` allows you to describe that a type acts as if it stores a value of type `T`,
/// even though it does not. This allows you to inform the compiler about certain safety properties
/// of your code.
#[rustc_reflect_like]
#[unstable(feature = "core", reason = "requires RFC and more experience")]
#[allow(deprecated)]
-#[cfg(not(stage0))]
pub trait Reflect {}
-/// dox
-#[rustc_reflect_like]
-#[unstable(feature = "core", reason = "requires RFC and more experience")]
-#[cfg(stage0)]
-pub trait Reflect: MarkerTrait {}
-
impl Reflect for .. { }
-
use marker::Sized;
use ops::Deref;
-#[cfg(stage0)] use marker::MarkerTrait;
/// Unsafe trait to indicate what types are usable with the NonZero struct
-#[cfg(not(stage0))]
pub unsafe trait Zeroable {}
-/// Unsafe trait to indicate what types are usable with the NonZero struct
-#[cfg(stage0)]
-pub unsafe trait Zeroable: MarkerTrait {}
-
unsafe impl<T:?Sized> Zeroable for *const T {}
unsafe impl<T:?Sized> Zeroable for *mut T {}
unsafe impl Zeroable for isize {}
macro_rules! neg_impl_unsigned {
($($t:ty)*) => {
neg_impl_core!{ x => {
- #[cfg(stage0)]
- use ::num::wrapping::WrappingOps;
!x.wrapping_add(1)
}, $($t)*} }
}
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
-#[cfg(not(stage0))]
mod impls {
use marker::Sized;
use super::{Fn, FnMut, FnOnce};
// FIXME #19649: intrinsic docs don't render, so these have no docs :(
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg(not(stage0))]
pub use intrinsics::copy_nonoverlapping;
-/// dox
-#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
- intrinsics::copy_nonoverlapping(dst, src, count)
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg(not(stage0))]
pub use intrinsics::copy;
-/// dox
-#[cfg(stage0)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
- intrinsics::copy(dst, src, count)
-}
-
-
#[stable(feature = "rust1", since = "1.0.0")]
pub use intrinsics::write_bytes;
///
/// # Safety
///
- /// The offset must be in-bounds of the object, or one-byte-past-the-end.
- /// Otherwise `offset` invokes Undefined Behaviour, regardless of whether
- /// the pointer is used.
+ /// Both the starting and resulting pointer must be either in bounds or one
+ /// byte past the end of an allocated object. If either pointer is out of
+ /// bounds or arithmetic overflow occurs then
+ /// any further use of the returned value will result in undefined behavior.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub unsafe fn offset(self, count: isize) -> *const T where T: Sized {
}
}
+#[inline(always)]
+fn size_from_ptr<T>(_: *const T) -> usize {
+ mem::size_of::<T>()
+}
+
+
+// Use macro to be generic over const/mut
+macro_rules! slice_offset {
+ ($ptr:expr, $by:expr) => {{
+ let ptr = $ptr;
+ if size_from_ptr(ptr) == 0 {
+ transmute(ptr as usize + $by)
+ } else {
+ ptr.offset($by)
+ }
+ }};
+}
+
+macro_rules! slice_ref {
+ ($ptr:expr) => {{
+ let ptr = $ptr;
+ if size_from_ptr(ptr) == 0 {
+ // Use a non-null pointer value
+ &mut *(1 as *mut _)
+ } else {
+ transmute(ptr)
+ }
+ }};
+}
+
// The shared definition of the `Iter` and `IterMut` iterators
macro_rules! iterator {
(struct $name:ident -> $ptr:ty, $elem:ty) => {
if self.ptr == self.end {
None
} else {
- if mem::size_of::<T>() == 0 {
- // purposefully don't use 'ptr.offset' because for
- // vectors with 0-size elements this would return the
- // same pointer.
- self.ptr = transmute(self.ptr as usize + 1);
-
- // Use a non-null pointer value
- Some(&mut *(1 as *mut _))
- } else {
- let old = self.ptr;
- self.ptr = self.ptr.offset(1);
-
- Some(transmute(old))
- }
+ let old = self.ptr;
+ self.ptr = slice_offset!(self.ptr, 1);
+ Some(slice_ref!(old))
}
}
}
let exact = diff / (if size == 0 {1} else {size});
(exact, Some(exact))
}
+
+ #[inline]
+ fn count(self) -> usize {
+ self.size_hint().0
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<$elem> {
+ // Call helper method. Can't put the definition here because mut versus const.
+ self.iter_nth(n)
+ }
+
+ #[inline]
+ fn last(mut self) -> Option<$elem> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
if self.end == self.ptr {
None
} else {
- if mem::size_of::<T>() == 0 {
- // See above for why 'ptr.offset' isn't used
- self.end = transmute(self.end as usize - 1);
-
- // Use a non-null pointer value
- Some(&mut *(1 as *mut _))
- } else {
- self.end = self.end.offset(-1);
-
- Some(transmute(self.end))
- }
+ self.end = slice_offset!(self.end, -1);
+ Some(slice_ref!(self.end))
}
}
}
pub fn as_slice(&self) -> &'a [T] {
make_slice!(T => &'a [T]: self.ptr, self.end)
}
+
+ // Helper function for Iter::nth
+ fn iter_nth(&mut self, n: usize) -> Option<&'a T> {
+ match self.as_slice().get(n) {
+ Some(elem_ref) => unsafe {
+ self.ptr = slice_offset!(elem_ref as *const _, 1);
+ Some(slice_ref!(elem_ref))
+ },
+ None => {
+ self.ptr = self.end;
+ None
+ }
+ }
+ }
}
iterator!{struct Iter -> *const T, &'a T}
pub fn into_slice(self) -> &'a mut [T] {
make_mut_slice!(T => &'a mut [T]: self.ptr, self.end)
}
+
+ // Helper function for IterMut::nth
+ fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> {
+ match make_mut_slice!(T => &'a mut [T]: self.ptr, self.end).get_mut(n) {
+ Some(elem_ref) => unsafe {
+ self.ptr = slice_offset!(elem_ref as *mut _, 1);
+ Some(slice_ref!(elem_ref))
+ },
+ None => {
+ self.ptr = self.end;
+ None
+ }
+ }
+ }
}
iterator!{struct IterMut -> *mut T, &'a mut T}
use core::iter::*;
use core::iter::order::*;
use core::iter::MinMaxResult::*;
+use core::isize;
use core::usize;
use core::cmp;
assert_eq!((usize::MAX - 1..usize::MAX).size_hint(), (1, Some(1)));
assert_eq!((-10..-1).size_hint(), (9, Some(9)));
assert_eq!((-1..-10).size_hint(), (0, Some(0)));
+
+ assert_eq!((-70..58i8).size_hint(), (128, Some(128)));
+ assert_eq!((-128..127i8).size_hint(), (255, Some(255)));
+ assert_eq!((-2..isize::MAX).size_hint(),
+ (isize::MAX as usize + 2, Some(isize::MAX as usize + 2)));
}
#[test]
#![feature(box_syntax)]
#![feature(unboxed_closures)]
-#![feature(unsafe_destructor)]
#![feature(core)]
#![feature(test)]
#![feature(rand)]
i: Rc<RefCell<isize>>,
}
- #[unsafe_destructor]
- impl Drop for R {
+ impl Drop for R {
fn drop(&mut self) {
let ii = &*self.i;
let i = *ii.borrow();
test!([1u8,2,3]);
test!([(),(),()]);
}
+
+#[test]
+fn test_iterator_nth() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+ for i in 0..v.len() {
+ assert_eq!(v.iter().nth(i).unwrap(), &v[i]);
+ }
+ assert_eq!(v.iter().nth(v.len()), None);
+
+ let mut iter = v.iter();
+ assert_eq!(iter.nth(2).unwrap(), &v[2]);
+ assert_eq!(iter.nth(1).unwrap(), &v[4]);
+}
+
+#[test]
+fn test_iterator_last() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+ assert_eq!(v.iter().last().unwrap(), &4);
+ assert_eq!(v[..1].iter().last().unwrap(), &0);
+}
+
+#[test]
+fn test_iterator_count() {
+ let v: &[_] = &[0, 1, 2, 3, 4];
+ assert_eq!(v.iter().count(), 5);
+
+ let mut iter2 = v.iter();
+ iter2.next();
+ iter2.next();
+ assert_eq!(iter2.count(), 3);
+}
// On NaCl, these libraries are static. Thus it would be a Bad Idea to link them
// in when creating a test crate.
-#[cfg(not(any(windows, all(target_os = "nacl", test))))]
+#[cfg(not(any(windows, target_env = "musl", all(target_os = "nacl", test))))]
#[link(name = "c")]
#[link(name = "m")]
extern {}
+#[cfg(all(target_env = "musl", not(test)))]
+#[link(name = "c", kind = "static")]
+extern {}
+
// libnacl provides functions that require a trip through the IRT to work.
// ie: _exit, mmap, nanosleep, etc. Anything that would otherwise require a trip
// to the kernel.
```
"##,
+E0013: r##"
+Static and const variables can refer to other const variables. But a const
+variable cannot refer to a static variable. For example, `Y` cannot refer to `X`
+here:
+
+```
+static X: i32 = 42;
+const Y: i32 = X;
+```
+
+To fix this, the value can be extracted as a const and then used:
+
+```
+const A: i32 = 42;
+static X: i32 = A;
+const Y: i32 = A;
+```
+"##,
+
E0015: r##"
The only function calls allowed in static or constant expressions are enum
variant constructors or struct constructors (for unit or tuple structs). This
E0010,
E0011,
E0012,
- E0013,
E0014,
E0016,
E0017,
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
-#![feature(unsafe_destructor)]
#![feature(staged_api)]
#![feature(std_misc)]
#![feature(path_ext)]
.into_inner()
.map_in_place(|mbc|
codemap::MultiByteChar {
- pos: mbc.pos + start_pos,
+ pos: mbc.pos - start_pos,
bytes: mbc.bytes
});
decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.node, tcx)
}
+pub fn get_associated_consts<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
+ -> Vec<Rc<ty::AssociatedConst<'tcx>>> {
+ let cstore = &tcx.sess.cstore;
+ let cdata = cstore.get_crate_data(def.krate);
+ decoder::get_associated_consts(cstore.intr.clone(), &*cdata, def.node, tcx)
+}
+
pub fn get_type_name_if_impl(cstore: &cstore::CStore, def: ast::DefId)
-> Option<ast::Name> {
let cdata = cstore.get_crate_data(def.krate);
-> DefLike {
let fam = item_family(item);
match fam {
- Constant => DlDef(def::DefConst(did)),
+ Constant => {
+ // Check whether we have an associated const item.
+ if item_sort(item) == Some('C') {
+ // Check whether the associated const is from a trait or impl.
+ // See the comment for methods below.
+ let provenance = if reader::maybe_get_doc(
+ item, tag_item_trait_parent_sort).is_some() {
+ def::FromTrait(item_reqd_and_translated_parent_item(cnum,
+ item))
+ } else {
+ def::FromImpl(item_reqd_and_translated_parent_item(cnum,
+ item))
+ };
+ DlDef(def::DefAssociatedConst(did, provenance))
+ } else {
+ // Regular const item.
+ DlDef(def::DefConst(did))
+ }
+ }
ImmStatic => DlDef(def::DefStatic(did, false)),
MutStatic => DlDef(def::DefStatic(did, true)),
Struct => DlDef(def::DefStruct(did)),
tag_item_impl_item, |doc| {
let def_id = item_def_id(doc, cdata);
match item_sort(doc) {
+ Some('C') => impl_items.push(ty::ConstTraitItemId(def_id)),
Some('r') | Some('p') => {
impl_items.push(ty::MethodTraitItemId(def_id))
}
let vis = item_visibility(method_doc);
match item_sort(method_doc) {
+ Some('C') => {
+ let ty = doc_type(method_doc, tcx, cdata);
+ let default = get_provided_source(method_doc, cdata);
+ ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
+ name: name,
+ ty: ty,
+ vis: vis,
+ def_id: def_id,
+ container: container,
+ default: default,
+ }))
+ }
Some('r') | Some('p') => {
let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics);
let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics);
reader::tagged_docs(item, tag_item_trait_item, |mth| {
let def_id = item_def_id(mth, cdata);
match item_sort(mth) {
+ Some('C') => result.push(ty::ConstTraitItemId(def_id)),
Some('r') | Some('p') => {
result.push(ty::MethodTraitItemId(def_id));
}
cdata,
did.node,
tcx);
- match trait_item {
- ty::MethodTraitItem(ref method) => {
- result.push((*method).clone())
- }
- ty::TypeTraitItem(_) => {}
+ if let ty::MethodTraitItem(ref method) = trait_item {
+ result.push((*method).clone())
}
}
true
return result;
}
+pub fn get_associated_consts<'tcx>(intr: Rc<IdentInterner>,
+ cdata: Cmd,
+ id: ast::NodeId,
+ tcx: &ty::ctxt<'tcx>)
+ -> Vec<Rc<ty::AssociatedConst<'tcx>>> {
+ let data = cdata.data();
+ let item = lookup_item(id, data);
+ let mut result = Vec::new();
+
+ for &tag in &[tag_item_trait_item, tag_item_impl_item] {
+ reader::tagged_docs(item, tag, |ac_id| {
+ let did = item_def_id(ac_id, cdata);
+ let ac_doc = lookup_item(did.node, data);
+
+ if item_sort(ac_doc) == Some('C') {
+ let trait_item = get_impl_or_trait_item(intr.clone(),
+ cdata,
+ did.node,
+ tcx);
+ if let ty::ConstTraitItem(ref ac) = trait_item {
+ result.push((*ac).clone())
+ }
+ }
+ true
+ });
+ }
+
+ return result;
+}
+
pub fn get_type_name_if_impl(cdata: Cmd,
node_id: ast::NodeId) -> Option<ast::Name> {
let item = lookup_item(node_id, cdata.data());
let impl_item = ty::impl_or_trait_item(
ecx.tcx,
method_did.def_id());
- match impl_item {
- ty::MethodTraitItem(ref m) => {
- encode_reexported_static_method(rbml_w,
- exp,
- m.def_id,
- m.name);
- }
- ty::TypeTraitItem(_) => {}
+ if let ty::MethodTraitItem(ref m) = impl_item {
+ encode_reexported_static_method(rbml_w,
+ exp,
+ m.def_id,
+ m.name);
}
}
}
encode_provided_source(rbml_w, method_ty.provided_source);
}
+fn encode_info_for_associated_const(ecx: &EncodeContext,
+ rbml_w: &mut Encoder,
+ associated_const: &ty::AssociatedConst,
+ impl_path: PathElems,
+ parent_id: NodeId,
+ impl_item_opt: Option<&ast::ImplItem>) {
+ debug!("encode_info_for_associated_const({:?},{:?})",
+ associated_const.def_id,
+ token::get_name(associated_const.name));
+
+ rbml_w.start_tag(tag_items_data_item);
+
+ encode_def_id(rbml_w, associated_const.def_id);
+ encode_name(rbml_w, associated_const.name);
+ encode_visibility(rbml_w, associated_const.vis);
+ encode_family(rbml_w, 'C');
+ encode_provided_source(rbml_w, associated_const.default);
+
+ encode_parent_item(rbml_w, local_def(parent_id));
+ encode_item_sort(rbml_w, 'C');
+
+ encode_bounds_and_type_for_item(rbml_w, ecx, associated_const.def_id.local_id());
+
+ let stab = stability::lookup(ecx.tcx, associated_const.def_id);
+ encode_stability(rbml_w, stab);
+
+ let elem = ast_map::PathName(associated_const.name);
+ encode_path(rbml_w, impl_path.chain(Some(elem).into_iter()));
+
+ if let Some(ii) = impl_item_opt {
+ encode_attributes(rbml_w, &ii.attrs);
+ encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id), ii));
+ }
+
+ rbml_w.end_tag();
+}
+
fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
m: &ty::Method<'tcx>,
for &item_def_id in items {
rbml_w.start_tag(tag_item_impl_item);
match item_def_id {
+ ty::ConstTraitItemId(item_def_id) => {
+ encode_def_id(rbml_w, item_def_id);
+ encode_item_sort(rbml_w, 'C');
+ }
ty::MethodTraitItemId(item_def_id) => {
encode_def_id(rbml_w, item_def_id);
encode_item_sort(rbml_w, 'r');
});
match ty::impl_or_trait_item(tcx, trait_item_def_id.def_id()) {
+ ty::ConstTraitItem(ref associated_const) => {
+ encode_info_for_associated_const(ecx,
+ rbml_w,
+ &*associated_const,
+ path.clone(),
+ item.id,
+ ast_item)
+ }
ty::MethodTraitItem(ref method_type) => {
encode_info_for_method(ecx,
rbml_w,
for &method_def_id in &*ty::trait_item_def_ids(tcx, def_id) {
rbml_w.start_tag(tag_item_trait_item);
match method_def_id {
+ ty::ConstTraitItemId(const_def_id) => {
+ encode_def_id(rbml_w, const_def_id);
+ encode_item_sort(rbml_w, 'C');
+ }
ty::MethodTraitItemId(method_def_id) => {
encode_def_id(rbml_w, method_def_id);
encode_item_sort(rbml_w, 'r');
ty::impl_or_trait_item(tcx, item_def_id.def_id());
let is_nonstatic_method;
match trait_item_type {
+ ty::ConstTraitItem(associated_const) => {
+ encode_name(rbml_w, associated_const.name);
+ encode_def_id(rbml_w, associated_const.def_id);
+ encode_visibility(rbml_w, associated_const.vis);
+
+ encode_provided_source(rbml_w, associated_const.default);
+
+ let elem = ast_map::PathName(associated_const.name);
+ encode_path(rbml_w,
+ path.clone().chain(Some(elem).into_iter()));
+
+ encode_item_sort(rbml_w, 'C');
+ encode_family(rbml_w, 'C');
+
+ encode_bounds_and_type_for_item(rbml_w, ecx,
+ associated_const.def_id.local_id());
+
+ is_nonstatic_method = false;
+ }
ty::MethodTraitItem(method_ty) => {
let method_def_id = item_def_id.def_id();
let trait_item = &*ms[i];
encode_attributes(rbml_w, &trait_item.attrs);
match trait_item.node {
+ ast::ConstTraitItem(_, _) => {
+ encode_inlined_item(ecx, rbml_w,
+ IITraitItemRef(def_id, trait_item));
+ }
ast::MethodTraitItem(ref sig, ref body) => {
// If this is a static method, we've already
// encoded this.
encode_method_argument_names(rbml_w, &sig.decl);
}
- ast::TypeTraitItem(..) => {
- encode_item_sort(rbml_w, 't');
- }
+ ast::TypeTraitItem(..) => {}
}
rbml_w.end_tag();
def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) }
def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) }
def::DefConst(did) => { def::DefConst(did.tr(dcx)) }
+ def::DefAssociatedConst(did, p) => {
+ def::DefAssociatedConst(did.tr(dcx), p.map(|did2| did2.tr(dcx)))
+ }
def::DefLocal(nid) => { def::DefLocal(dcx.tr_id(nid)) }
def::DefVariant(e_did, v_did, is_s) => {
def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s)
match pat.node {
ast::PatIdent(_, _, None) |
ast::PatEnum(_, None) |
+ ast::PatQPath(..) |
ast::PatLit(..) |
ast::PatRange(..) |
ast::PatWild(_) => {
}
}
+ fn visit_trait_item(&mut self, t: &'v ast::TraitItem) {
+ match t.node {
+ ast::ConstTraitItem(_, ref default) => {
+ if let Some(ref expr) = *default {
+ self.global_expr(Mode::Const, &*expr);
+ } else {
+ visit::walk_trait_item(self, t);
+ }
+ }
+ _ => self.with_mode(Mode::Var, |v| visit::walk_trait_item(v, t)),
+ }
+ }
+
+ fn visit_impl_item(&mut self, i: &'v ast::ImplItem) {
+ match i.node {
+ ast::ConstImplItem(_, ref expr) => {
+ self.global_expr(Mode::Const, &*expr);
+ }
+ _ => self.with_mode(Mode::Var, |v| visit::walk_impl_item(v, i)),
+ }
+ }
+
fn visit_fn(&mut self,
fk: visit::FnKind<'v>,
fd: &'v ast::FnDecl,
Mode::Var => v.add_qualif(NOT_CONST)
}
}
- Some(def::DefConst(did)) => {
- if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did) {
+ Some(def::DefConst(did)) |
+ Some(def::DefAssociatedConst(did, _)) => {
+ if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
+ Some(e.id)) {
let inner = v.global_expr(Mode::Const, expr);
v.add_qualif(inner);
} else {
- v.tcx.sess.span_bug(e.span, "DefConst doesn't point \
- to an ItemConst");
+ v.tcx.sess.span_bug(e.span,
+ "DefConst or DefAssociatedConst \
+ doesn't point to a constant");
}
}
def => {
impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
return match pat.node {
- ast::PatIdent(..) | ast::PatEnum(..) => {
+ ast::PatIdent(..) | ast::PatEnum(..) | ast::PatQPath(..) => {
let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
match def {
- Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did) {
+ Some(DefAssociatedConst(did, _)) |
+ Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did, Some(pat.id)) {
Some(const_expr) => {
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
match pat.node {
ast::PatIdent(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) =>
+ Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
Some(DefStruct(_)) => vec!(Single),
},
ast::PatEnum(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) =>
+ Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
Some(DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!(Single)
},
+ ast::PatQPath(..) =>
+ cx.tcx.sess.span_bug(pat.span, "const pattern should've \
+ been rewritten"),
ast::PatStruct(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) =>
+ Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
Some(DefVariant(_, id, _)) => vec!(Variant(id)),
ast::PatIdent(_, _, _) => {
let opt_def = cx.tcx.def_map.borrow().get(&pat_id).map(|d| d.full_def());
match opt_def {
- Some(DefConst(..)) =>
+ Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
ast::PatEnum(_, ref args) => {
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
match def {
- DefConst(..) =>
+ DefConst(..) | DefAssociatedConst(..) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
DefVariant(_, id, _) if *constructor != Variant(id) => None,
}
}
+ ast::PatQPath(_, _) => {
+ cx.tcx.sess.span_bug(pat_span, "const pattern should've \
+ been rewritten")
+ }
+
ast::PatStruct(_, ref pattern_fields, _) => {
// Is this a struct or an enum variant?
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
let class_id = match def {
- DefConst(..) =>
+ DefConst(..) | DefAssociatedConst(..) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) {
// recursively.
use session::Session;
-use middle::def::{DefStatic, DefConst, DefMap};
+use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefMap};
use syntax::ast;
use syntax::{ast_util, ast_map};
+use syntax::codemap::Span;
use syntax::visit::Visitor;
use syntax::visit;
}
impl<'v, 'a, 'ast> Visitor<'v> for CheckCrateVisitor<'a, 'ast> {
- fn visit_item(&mut self, i: &ast::Item) {
- check_item(self, i);
+ fn visit_item(&mut self, it: &ast::Item) {
+ match it.node {
+ ast::ItemStatic(_, _, ref expr) |
+ ast::ItemConst(_, ref expr) => {
+ let mut recursion_visitor =
+ CheckItemRecursionVisitor::new(self, &it.span);
+ recursion_visitor.visit_item(it);
+ visit::walk_expr(self, &*expr)
+ },
+ _ => visit::walk_item(self, it)
+ }
+ }
+
+ fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
+ match ti.node {
+ ast::ConstTraitItem(_, ref default) => {
+ if let Some(ref expr) = *default {
+ let mut recursion_visitor =
+ CheckItemRecursionVisitor::new(self, &ti.span);
+ recursion_visitor.visit_trait_item(ti);
+ visit::walk_expr(self, &*expr)
+ }
+ }
+ _ => visit::walk_trait_item(self, ti)
+ }
+ }
+
+ fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
+ match ii.node {
+ ast::ConstImplItem(_, ref expr) => {
+ let mut recursion_visitor =
+ CheckItemRecursionVisitor::new(self, &ii.span);
+ recursion_visitor.visit_impl_item(ii);
+ visit::walk_expr(self, &*expr)
+ }
+ _ => visit::walk_impl_item(self, ii)
+ }
}
}
sess.abort_if_errors();
}
-fn check_item(v: &mut CheckCrateVisitor, it: &ast::Item) {
- match it.node {
- ast::ItemStatic(_, _, ref ex) |
- ast::ItemConst(_, ref ex) => {
- check_item_recursion(v.sess, v.ast_map, v.def_map, it);
- visit::walk_expr(v, &**ex)
- },
- _ => visit::walk_item(v, it)
- }
-}
-
struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
- root_it: &'a ast::Item,
+ root_span: &'a Span,
sess: &'a Session,
ast_map: &'a ast_map::Map<'ast>,
def_map: &'a DefMap,
idstack: Vec<ast::NodeId>
}
-// Make sure a const item doesn't recursively refer to itself
-// FIXME: Should use the dependency graph when it's available (#1356)
-pub fn check_item_recursion<'a>(sess: &'a Session,
- ast_map: &'a ast_map::Map,
- def_map: &'a DefMap,
- it: &'a ast::Item) {
-
- let mut visitor = CheckItemRecursionVisitor {
- root_it: it,
- sess: sess,
- ast_map: ast_map,
- def_map: def_map,
- idstack: Vec::new()
- };
- visitor.visit_item(it);
+impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
+ fn new(v: &CheckCrateVisitor<'a, 'ast>, span: &'a Span)
+ -> CheckItemRecursionVisitor<'a, 'ast> {
+ CheckItemRecursionVisitor {
+ root_span: span,
+ sess: v.sess,
+ ast_map: v.ast_map,
+ def_map: v.def_map,
+ idstack: Vec::new()
+ }
+ }
+ fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F)
+ where F: Fn(&mut Self) {
+ if self.idstack.iter().any(|x| x == &(id)) {
+ span_err!(self.sess, *self.root_span, E0265, "recursive constant");
+ return;
+ }
+ self.idstack.push(id);
+ f(self);
+ self.idstack.pop();
+ }
}
impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
fn visit_item(&mut self, it: &ast::Item) {
- if self.idstack.iter().any(|x| x == &(it.id)) {
- span_err!(self.sess, self.root_it.span, E0265, "recursive constant");
- return;
- }
- self.idstack.push(it.id);
- visit::walk_item(self, it);
- self.idstack.pop();
+ self.with_item_id_pushed(it.id, |v| visit::walk_item(v, it));
+ }
+
+ fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
+ self.with_item_id_pushed(ti.id, |v| visit::walk_trait_item(v, ti));
+ }
+
+ fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
+ self.with_item_id_pushed(ii.id, |v| visit::walk_impl_item(v, ii));
}
fn visit_expr(&mut self, e: &ast::Expr) {
ast::ExprPath(..) => {
match self.def_map.borrow().get(&e.id).map(|d| d.base_def) {
Some(DefStatic(def_id, _)) |
+ Some(DefAssociatedConst(def_id, _)) |
Some(DefConst(def_id)) if
ast_util::is_local(def_id) => {
match self.ast_map.get(def_id.node) {
ast_map::NodeItem(item) =>
self.visit_item(item),
+ ast_map::NodeTraitItem(item) =>
+ self.visit_trait_item(item),
+ ast_map::NodeImplItem(item) =>
+ self.visit_impl_item(item),
ast_map::NodeForeignItem(_) => {},
_ => {
span_err!(self.sess, e.span, E0266,
use self::ErrKind::*;
use metadata::csearch;
-use middle::{astencode, def};
+use middle::{astencode, def, infer, subst, traits};
use middle::pat_util::def_to_path;
use middle::ty::{self, Ty};
use middle::astconv_util::ast_ty_to_prim_ty;
use util::num::ToPrimitive;
+use util::ppaux::Repr;
use syntax::ast::{self, Expr};
use syntax::codemap::Span;
fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> {
let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
match opt_def {
- Some(def::DefConst(def_id)) => {
- lookup_const_by_id(tcx, def_id)
+ Some(def::DefConst(def_id)) |
+ Some(def::DefAssociatedConst(def_id, _)) => {
+ lookup_const_by_id(tcx, def_id, Some(e.id))
}
Some(def::DefVariant(enum_def, variant_def, _)) => {
lookup_variant_by_id(tcx, enum_def, variant_def)
}
}
-pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
- -> Option<&'a Expr> {
+pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
+ def_id: ast::DefId,
+ maybe_ref_id: Option<ast::NodeId>)
+ -> Option<&'tcx Expr> {
if ast_util::is_local(def_id) {
match tcx.map.find(def_id.node) {
None => None,
Some(ast_map::NodeItem(it)) => match it.node {
ast::ItemConst(_, ref const_expr) => {
- Some(&**const_expr)
+ Some(&*const_expr)
+ }
+ _ => None
+ },
+ Some(ast_map::NodeTraitItem(ti)) => match ti.node {
+ ast::ConstTraitItem(_, _) => {
+ match maybe_ref_id {
+ // If we have a trait item, and we know the expression
+ // that's the source of the obligation to resolve it,
+ // `resolve_trait_associated_const` will select an impl
+ // or the default.
+ Some(ref_id) => {
+ let trait_id = ty::trait_of_item(tcx, def_id)
+ .unwrap();
+ resolve_trait_associated_const(tcx, ti, trait_id,
+ ref_id)
+ }
+ // Technically, without knowing anything about the
+ // expression that generates the obligation, we could
+ // still return the default if there is one. However,
+ // it's safer to return `None` than to return some value
+ // that may differ from what you would get from
+ // correctly selecting an impl.
+ None => None
+ }
+ }
+ _ => None
+ },
+ Some(ast_map::NodeImplItem(ii)) => match ii.node {
+ ast::ConstImplItem(_, ref expr) => {
+ Some(&*expr)
}
_ => None
},
}
None => {}
}
+ let mut used_ref_id = false;
let expr_id = match csearch::maybe_get_item_ast(tcx, def_id,
Box::new(|a, b, c, d| astencode::decode_inlined_item(a, b, c, d))) {
csearch::FoundAst::Found(&ast::IIItem(ref item)) => match item.node {
ast::ItemConst(_, ref const_expr) => Some(const_expr.id),
_ => None
},
+ csearch::FoundAst::Found(&ast::IITraitItem(trait_id, ref ti)) => match ti.node {
+ ast::ConstTraitItem(_, _) => {
+ used_ref_id = true;
+ match maybe_ref_id {
+ // As mentioned in the comments above for in-crate
+ // constants, we only try to find the expression for
+ // a trait-associated const if the caller gives us
+ // the expression that refers to it.
+ Some(ref_id) => {
+ resolve_trait_associated_const(tcx, ti, trait_id,
+ ref_id).map(|e| e.id)
+ }
+ None => None
+ }
+ }
+ _ => None
+ },
+ csearch::FoundAst::Found(&ast::IIImplItem(_, ref ii)) => match ii.node {
+ ast::ConstImplItem(_, ref expr) => Some(expr.id),
+ _ => None
+ },
_ => None
};
- tcx.extern_const_statics.borrow_mut().insert(def_id,
- expr_id.unwrap_or(ast::DUMMY_NODE_ID));
+ // If we used the reference expression, particularly to choose an impl
+ // of a trait-associated const, don't cache that, because the next
+ // lookup with the same def_id may yield a different result.
+ if !used_ref_id {
+ tcx.extern_const_statics
+ .borrow_mut().insert(def_id,
+ expr_id.unwrap_or(ast::DUMMY_NODE_ID));
+ }
expr_id.map(|id| tcx.map.expect_expr(id))
}
}
_ => (None, None)
}
} else {
- (lookup_const_by_id(tcx, def_id), None)
+ (lookup_const_by_id(tcx, def_id, Some(e.id)), None)
+ }
+ }
+ Some(def::DefAssociatedConst(def_id, provenance)) => {
+ if ast_util::is_local(def_id) {
+ match provenance {
+ def::FromTrait(trait_id) => match tcx.map.find(def_id.node) {
+ Some(ast_map::NodeTraitItem(ti)) => match ti.node {
+ ast::ConstTraitItem(ref ty, _) => {
+ (resolve_trait_associated_const(tcx, ti,
+ trait_id, e.id),
+ Some(&**ty))
+ }
+ _ => (None, None)
+ },
+ _ => (None, None)
+ },
+ def::FromImpl(_) => match tcx.map.find(def_id.node) {
+ Some(ast_map::NodeImplItem(ii)) => match ii.node {
+ ast::ConstImplItem(ref ty, ref expr) => {
+ (Some(&**expr), Some(&**ty))
+ }
+ _ => (None, None)
+ },
+ _ => (None, None)
+ },
+ }
+ } else {
+ (lookup_const_by_id(tcx, def_id, Some(e.id)), None)
}
}
Some(def::DefVariant(enum_def, variant_def, _)) => {
Ok(result)
}
+fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
+ ti: &'tcx ast::TraitItem,
+ trait_id: ast::DefId,
+ ref_id: ast::NodeId)
+ -> Option<&'tcx Expr>
+{
+ let rcvr_substs = ty::node_id_item_substs(tcx, ref_id).substs;
+ let subst::SeparateVecsPerParamSpace {
+ types: rcvr_type,
+ selfs: rcvr_self,
+ fns: _,
+ } = rcvr_substs.types.split();
+ let trait_substs =
+ subst::Substs::erased(subst::VecPerParamSpace::new(rcvr_type,
+ rcvr_self,
+ Vec::new()));
+ let trait_substs = tcx.mk_substs(trait_substs);
+ debug!("resolve_trait_associated_const: trait_substs={}",
+ trait_substs.repr(tcx));
+ let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id,
+ substs: trait_substs }));
+
+ ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id());
+ let infcx = infer::new_infer_ctxt(tcx);
+
+ let param_env = ty::empty_parameter_environment(tcx);
+ let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env);
+ let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
+ trait_ref.to_poly_trait_predicate());
+ let selection = match selcx.select(&obligation) {
+ Ok(Some(vtable)) => vtable,
+ // Still ambiguous, so give up and let the caller decide whether this
+ // expression is really needed yet. Some associated constant values
+ // can't be evaluated until monomorphization is done in trans.
+ Ok(None) => {
+ return None
+ }
+ Err(e) => {
+ tcx.sess.span_bug(ti.span,
+ &format!("Encountered error `{}` when trying \
+ to select an implementation for \
+ constant trait item reference.",
+ e.repr(tcx)))
+ }
+ };
+
+ match selection {
+ traits::VtableImpl(ref impl_data) => {
+ match ty::associated_consts(tcx, impl_data.impl_def_id)
+ .iter().find(|ic| ic.name == ti.ident.name) {
+ Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
+ None => match ti.node {
+ ast::ConstTraitItem(_, Some(ref expr)) => Some(&*expr),
+ _ => None,
+ },
+ }
+ }
+ _ => {
+ tcx.sess.span_bug(
+ ti.span,
+ &format!("resolve_trait_associated_const: unexpected vtable type"))
+ }
+ }
+}
+
fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: const_val, ty: Ty) -> CastResult {
macro_rules! convert_val {
($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {
fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) {
self.tcx.def_map.borrow().get(id).map(|def| {
match def.full_def() {
- def::DefConst(_) => {
+ def::DefConst(_) | def::DefAssociatedConst(..) => {
self.check_def_id(def.def_id())
}
_ if self.ignore_non_const_paths => (),
let trait_item = ty::trait_item(self.tcx,
trait_ref.def_id,
index);
- match trait_item {
- ty::MethodTraitItem(method) => {
- self.check_def_id(method.def_id);
- }
- ty::TypeTraitItem(typedef) => {
- self.check_def_id(typedef.def_id);
- }
- }
+ self.check_def_id(trait_item.def_id());
}
}
}
ast::ItemTrait(_, _, _, ref trait_items) => {
for trait_item in trait_items {
match trait_item.node {
+ ast::ConstTraitItem(_, Some(_)) |
ast::MethodTraitItem(_, Some(_)) => {
if has_allow_dead_code_or_lang_attr(&trait_item.attrs) {
self.worklist.push(trait_item.id);
ast::ItemImpl(_, _, _, ref opt_trait, _, ref impl_items) => {
for impl_item in impl_items {
match impl_item.node {
+ ast::ConstImplItem(..) |
ast::MethodImplItem(..) => {
if opt_trait.is_some() ||
has_allow_dead_code_or_lang_attr(&impl_item.attrs) {
None => ()
}
- // Seed implemented trait methods
+ // Seed implemented trait items
let mut life_seeder = LifeSeeder {
worklist: worklist
};
|ctor| self.live_symbols.contains(&ctor)) {
return true;
}
- // If it's a type whose methods are live, then it's live, too.
+ // If it's a type whose items are live, then it's live, too.
// This is done to handle the case where, for example, the static
// method of a private type is used, but the type itself is never
// called directly.
visit::walk_foreign_item(self, fi);
}
- fn visit_fn(&mut self, fk: visit::FnKind<'v>,
- _: &'v ast::FnDecl, block: &'v ast::Block,
- span: codemap::Span, id: ast::NodeId) {
- // Have to warn method here because methods are not ast::Item
- match fk {
- visit::FkMethod(name, _, _) => {
- if !self.symbol_is_live(id, None) {
- self.warn_dead_code(id, span, name.name, "method");
- }
- }
- _ => ()
- }
- visit::walk_block(self, block);
- }
-
fn visit_struct_field(&mut self, field: &ast::StructField) {
if self.should_warn_about_field(&field.node) {
self.warn_dead_code(field.node.id, field.span,
visit::walk_struct_field(self, field);
}
- // Overwrite so that we don't warn the trait method itself.
- fn visit_trait_item(&mut self, trait_method: &ast::TraitItem) {
- match trait_method.node {
+ fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
+ match impl_item.node {
+ ast::ConstImplItem(_, ref expr) => {
+ if !self.symbol_is_live(impl_item.id, None) {
+ self.warn_dead_code(impl_item.id, impl_item.span,
+ impl_item.ident.name, "associated const");
+ }
+ visit::walk_expr(self, expr)
+ }
+ ast::MethodImplItem(_, ref body) => {
+ if !self.symbol_is_live(impl_item.id, None) {
+ self.warn_dead_code(impl_item.id, impl_item.span,
+ impl_item.ident.name, "method");
+ }
+ visit::walk_block(self, body)
+ }
+ ast::TypeImplItem(..) |
+ ast::MacImplItem(..) => {}
+ }
+ }
+
+ // Overwrite so that we don't warn the trait item itself.
+ fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
+ match trait_item.node {
+ ast::ConstTraitItem(_, Some(ref expr)) => {
+ visit::walk_expr(self, expr)
+ }
ast::MethodTraitItem(_, Some(ref body)) => {
visit::walk_block(self, body)
}
+ ast::ConstTraitItem(_, None) |
ast::MethodTraitItem(_, None) |
ast::TypeTraitItem(..) => {}
}
DefForeignMod(ast::DefId),
DefStatic(ast::DefId, bool /* is_mutbl */),
DefConst(ast::DefId),
+ DefAssociatedConst(ast::DefId /* const */, MethodProvenance),
DefLocal(ast::NodeId),
DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */),
DefTy(ast::DefId, bool /* is_enum */),
DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) |
DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
- DefMethod(id, _) | DefConst(id) | DefSelfTy(Some(id), None)=> {
+ DefMethod(id, _) | DefConst(id) | DefAssociatedConst(id, _) |
+ DefSelfTy(Some(id), None)=> {
id
}
DefLocal(id) |
ty::MethodTraitItem(ref method_descriptor) => {
(*method_descriptor).clone()
}
- ty::TypeTraitItem(_) => {
+ _ => {
tcx.sess.bug("overloaded call method wasn't in method map")
}
};
let tcx = typer.tcx();
match pat.node {
- ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => {
+ ast::PatEnum(_, _) | ast::PatQPath(..) |
+ ast::PatIdent(_, _, None) | ast::PatStruct(..) => {
match def_map.get(&pat.id).map(|d| d.full_def()) {
None => {
// no definition found: pat is not a
}
Some(def::DefConst(..)) |
+ Some(def::DefAssociatedConst(..)) |
Some(def::DefLocal(..)) => {
// This is a leaf (i.e. identifier binding
// or constant value to match); thus no
Some(&sig.explicit_self.node),
item.span))
}
- ast::TypeImplItem(_) => None,
- ast::MacImplItem(_) => self.tcx.sess.bug("unexpanded macro")
+ ast::MacImplItem(_) => self.tcx.sess.bug("unexpanded macro"),
+ _ => None,
}
},
ast_map::NodeTraitItem(item) => {
taken.push_all(&sig.generics.lifetimes);
Some(ii.id)
}
- ast::TypeImplItem(_) => None,
- ast::MacImplItem(_) => tcx.sess.bug("unexpanded macro")
+ ast::MacImplItem(_) => tcx.sess.bug("unexpanded macro"),
+ _ => None,
}
}
_ => None
match def {
def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) |
- def::DefFn(..) | def::DefMethod(..) => {
+ def::DefAssociatedConst(..) | def::DefFn(..) | def::DefMethod(..) => {
Ok(self.cat_rvalue_node(id, span, expr_ty))
}
def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
try!(self.cat_pattern_(cmt_field, &**subpat, op));
}
}
- Some(def::DefConst(..)) => {
+ Some(def::DefConst(..)) | Some(def::DefAssociatedConst(..)) => {
for subpat in subpats {
try!(self.cat_pattern_(cmt.clone(), &**subpat, op));
}
}
}
+ ast::PatQPath(..) => {
+ // Lone constant: ignore
+ }
+
ast::PatIdent(_, _, Some(ref subpat)) => {
try!(self.cat_pattern_(cmt, &**subpat, op));
}
pub fn pat_is_refutable(dm: &DefMap, pat: &ast::Pat) -> bool {
match pat.node {
- ast::PatLit(_) | ast::PatRange(_, _) => true,
+ ast::PatLit(_) | ast::PatRange(_, _) | ast::PatQPath(..) => true,
ast::PatEnum(_, _) |
ast::PatIdent(_, _, None) |
ast::PatStruct(..) => {
pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool {
match pat.node {
- ast::PatIdent(_, _, None) | ast::PatEnum(..) => {
+ ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => {
match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) => true,
+ Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
+ _ => false
+ }
+ }
+ _ => false
+ }
+}
+
+// Same as above, except that partially-resolved defs cause `false` to be
+// returned instead of a panic.
+pub fn pat_is_resolved_const(dm: &DefMap, pat: &ast::Pat) -> bool {
+ match pat.node {
+ ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => {
+ match dm.borrow().get(&pat.id)
+ .and_then(|d| if d.depth == 0 { Some(d.base_def) }
+ else { None } ) {
+ Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
_ => false
}
}
// If this path leads to a constant, then we need to
// recurse into the constant to continue finding
// items that are reachable.
- def::DefConst(..) => {
+ def::DefConst(..) | def::DefAssociatedConst(..) => {
self.worklist.push(def_id.node);
}
}
Some(ast_map::NodeTraitItem(trait_method)) => {
match trait_method.node {
+ ast::ConstTraitItem(_, ref default) => default.is_some(),
ast::MethodTraitItem(_, ref body) => body.is_some(),
ast::TypeTraitItem(..) => false,
}
}
Some(ast_map::NodeImplItem(impl_item)) => {
match impl_item.node {
+ ast::ConstImplItem(..) => true,
ast::MethodImplItem(ref sig, _) => {
if generics_require_inlining(&sig.generics) ||
attr::requests_inline(&impl_item.attrs) {
}
ast_map::NodeTraitItem(trait_method) => {
match trait_method.node {
+ ast::ConstTraitItem(_, None) |
ast::MethodTraitItem(_, None) => {
// Keep going, nothing to get exported
}
+ ast::ConstTraitItem(_, Some(ref expr)) => {
+ self.visit_expr(&*expr);
+ }
ast::MethodTraitItem(_, Some(ref body)) => {
visit::walk_block(self, body);
}
}
ast_map::NodeImplItem(impl_item) => {
match impl_item.node {
+ ast::ConstImplItem(_, ref expr) => {
+ self.visit_expr(&*expr);
+ }
ast::MethodImplItem(ref sig, ref body) => {
let did = self.tcx.map.get_parent_did(search_item);
if method_might_be_inlined(self.tcx, sig, impl_item, did) {
.map(|code| ObjectSafetyViolation::Method(m.clone(), code))
.into_iter()
}
- ty::TypeTraitItem(_) => {
- None.into_iter()
- }
+ _ => None.into_iter(),
}
})
.collect();
for impl_item in impl_items {
let assoc_type = match *impl_or_trait_items_map.get(&impl_item.def_id()).unwrap() {
ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
- ty::MethodTraitItem(..) => { continue; }
+ ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => { continue; }
};
if assoc_type.name != obligation.predicate.item_name {
for trait_item in &**trait_items {
match *trait_item {
ty::MethodTraitItem(_) => method_count += 1,
- ty::TypeTraitItem(_) => {}
+ _ => {}
}
}
}
for trait_item in trait_items.iter().take(method_offset_in_trait) {
match *trait_item {
ty::MethodTraitItem(_) => method_count += 1,
- ty::TypeTraitItem(_) => {}
+ _ => {}
}
}
// the item at the offset we were given really ought to be a method
assert!(match trait_items[method_offset_in_trait] {
ty::MethodTraitItem(_) => true,
- ty::TypeTraitItem(_) => false
+ _ => false
});
method_count
use collections::enum_set::{EnumSet, CLike};
use std::collections::{HashMap, HashSet};
use syntax::abi;
-use syntax::ast::{CrateNum, DefId, ItemTrait, LOCAL_CRATE};
+use syntax::ast::{CrateNum, DefId, ItemImpl, ItemTrait, LOCAL_CRATE};
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility};
use syntax::ast_util::{self, is_local, lit_is_str, local_def};
#[derive(Clone, Debug)]
pub enum ImplOrTraitItem<'tcx> {
+ ConstTraitItem(Rc<AssociatedConst<'tcx>>),
MethodTraitItem(Rc<Method<'tcx>>),
TypeTraitItem(Rc<AssociatedType>),
}
impl<'tcx> ImplOrTraitItem<'tcx> {
fn id(&self) -> ImplOrTraitItemId {
match *self {
+ ConstTraitItem(ref associated_const) => {
+ ConstTraitItemId(associated_const.def_id)
+ }
MethodTraitItem(ref method) => MethodTraitItemId(method.def_id),
TypeTraitItem(ref associated_type) => {
TypeTraitItemId(associated_type.def_id)
pub fn def_id(&self) -> ast::DefId {
match *self {
+ ConstTraitItem(ref associated_const) => associated_const.def_id,
MethodTraitItem(ref method) => method.def_id,
TypeTraitItem(ref associated_type) => associated_type.def_id,
}
pub fn name(&self) -> ast::Name {
match *self {
+ ConstTraitItem(ref associated_const) => associated_const.name,
MethodTraitItem(ref method) => method.name,
TypeTraitItem(ref associated_type) => associated_type.name,
}
}
+ pub fn vis(&self) -> ast::Visibility {
+ match *self {
+ ConstTraitItem(ref associated_const) => associated_const.vis,
+ MethodTraitItem(ref method) => method.vis,
+ TypeTraitItem(ref associated_type) => associated_type.vis,
+ }
+ }
+
pub fn container(&self) -> ImplOrTraitItemContainer {
match *self {
+ ConstTraitItem(ref associated_const) => associated_const.container,
MethodTraitItem(ref method) => method.container,
TypeTraitItem(ref associated_type) => associated_type.container,
}
pub fn as_opt_method(&self) -> Option<Rc<Method<'tcx>>> {
match *self {
MethodTraitItem(ref m) => Some((*m).clone()),
- TypeTraitItem(_) => None
+ _ => None,
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum ImplOrTraitItemId {
+ ConstTraitItemId(ast::DefId),
MethodTraitItemId(ast::DefId),
TypeTraitItemId(ast::DefId),
}
impl ImplOrTraitItemId {
pub fn def_id(&self) -> ast::DefId {
match *self {
+ ConstTraitItemId(def_id) => def_id,
MethodTraitItemId(def_id) => def_id,
TypeTraitItemId(def_id) => def_id,
}
}
}
+#[derive(Clone, Copy, Debug)]
+pub struct AssociatedConst<'tcx> {
+ pub name: ast::Name,
+ pub ty: Ty<'tcx>,
+ pub vis: ast::Visibility,
+ pub def_id: ast::DefId,
+ pub container: ImplOrTraitItemContainer,
+ pub default: Option<ast::DefId>,
+}
+
#[derive(Clone, Copy, Debug)]
pub struct AssociatedType {
pub name: ast::Name,
match cx.map.find(id) {
Some(ast_map::NodeImplItem(ref impl_item)) => {
match impl_item.node {
+ ast::ConstImplItem(_, _) => {
+ let def_id = ast_util::local_def(id);
+ let scheme = lookup_item_type(cx, def_id);
+ let predicates = lookup_predicates(cx, def_id);
+ construct_parameter_environment(cx,
+ impl_item.span,
+ &scheme.generics,
+ &predicates,
+ id)
+ }
ast::MethodImplItem(_, ref body) => {
let method_def_id = ast_util::local_def(id);
match ty::impl_or_trait_item(cx, method_def_id) {
method_bounds,
body.id)
}
- TypeTraitItem(_) => {
+ _ => {
cx.sess
.bug("ParameterEnvironment::for_item(): \
- can't create a parameter environment \
- for type trait items")
+ got non-method item from impl method?!")
}
}
}
}
Some(ast_map::NodeTraitItem(trait_item)) => {
match trait_item.node {
+ ast::ConstTraitItem(_, ref default) => {
+ match *default {
+ Some(_) => {
+ let def_id = ast_util::local_def(id);
+ let scheme = lookup_item_type(cx, def_id);
+ let predicates = lookup_predicates(cx, def_id);
+ construct_parameter_environment(cx,
+ trait_item.span,
+ &scheme.generics,
+ &predicates,
+ id)
+ }
+ None => {
+ cx.sess.bug("ParameterEnvironment::from_item(): \
+ can't create a parameter environment \
+ for const trait items without defaults")
+ }
+ }
+ }
ast::MethodTraitItem(_, None) => {
cx.sess.span_bug(trait_item.span,
"ParameterEnvironment::for_item():
method_bounds,
body.id)
}
- TypeTraitItem(_) => {
+ _ => {
cx.sess
.bug("ParameterEnvironment::for_item(): \
- can't create a parameter environment \
- for type trait items")
+ got non-method item from provided \
+ method?!")
}
}
}
def::DefUpvar(..) |
def::DefLocal(..) => LvalueExpr,
- def::DefConst(..) => RvalueDatumExpr,
+ def::DefConst(..) |
+ def::DefAssociatedConst(..) => RvalueDatumExpr,
def => {
tcx.sess.span_bug(
if let ast::MethodTraitItem(_, Some(_)) = ti.node {
match impl_or_trait_item(cx, ast_util::local_def(ti.id)) {
MethodTraitItem(m) => Some(m),
- TypeTraitItem(_) => {
+ _ => {
cx.sess.bug("provided_trait_methods(): \
- associated type found from \
- looking up ProvidedMethod?!")
+ non-method item found from \
+ looking up provided method?!")
}
}
} else {
}
}
+pub fn associated_consts<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
+ -> Vec<Rc<AssociatedConst<'tcx>>> {
+ if is_local(id) {
+ match cx.map.expect_item(id.node).node {
+ ItemTrait(_, _, _, ref tis) => {
+ tis.iter().filter_map(|ti| {
+ if let ast::ConstTraitItem(_, _) = ti.node {
+ match impl_or_trait_item(cx, ast_util::local_def(ti.id)) {
+ ConstTraitItem(ac) => Some(ac),
+ _ => {
+ cx.sess.bug("associated_consts(): \
+ non-const item found from \
+ looking up a constant?!")
+ }
+ }
+ } else {
+ None
+ }
+ }).collect()
+ }
+ ItemImpl(_, _, _, _, _, ref iis) => {
+ iis.iter().filter_map(|ii| {
+ if let ast::ConstImplItem(_, _) = ii.node {
+ match impl_or_trait_item(cx, ast_util::local_def(ii.id)) {
+ ConstTraitItem(ac) => Some(ac),
+ _ => {
+ cx.sess.bug("associated_consts(): \
+ non-const item found from \
+ looking up a constant?!")
+ }
+ }
+ } else {
+ None
+ }
+ }).collect()
+ }
+ _ => {
+ cx.sess.bug(&format!("associated_consts: `{:?}` is not a trait \
+ or impl", id))
+ }
+ }
+ } else {
+ csearch::get_associated_consts(cx, id)
+ }
+}
+
/// Helper for looking things up in the various maps that are populated during
/// typeck::collect (e.g., `cx.impl_or_trait_items`, `cx.tcache`, etc). All of
/// these share the pattern that if the id is local, it should have been loaded
Some(ref item) => {
match **item {
TypeTraitItem(_) => true,
- MethodTraitItem(_) => false,
+ _ => false,
}
}
None => false,
.insert(method_def_id, source);
}
}
- TypeTraitItem(_) => {}
+ _ => {}
}
}
.insert(method_def_id, source);
}
}
- TypeTraitItem(_) => {}
+ _ => {}
}
}
let arch = &sess.target.target.arch;
let wordsz = &sess.target.target.target_pointer_width;
let os = &sess.target.target.target_os;
+ let env = &sess.target.target.target_env;
let fam = match sess.target.target.options.is_like_windows {
true => InternedString::new("windows"),
mk(InternedString::new("target_family"), fam),
mk(InternedString::new("target_arch"), intern(arch)),
mk(InternedString::new("target_endian"), intern(end)),
- mk(InternedString::new("target_pointer_width"),
- intern(wordsz))
+ mk(InternedString::new("target_pointer_width"), intern(wordsz)),
+ mk(InternedString::new("target_env"), intern(env)),
];
if sess.opts.debug_assertions {
ret.push(attr::mk_word_item(InternedString::new("debug_assertions")));
impl<'tcx> Repr<'tcx> for ast::TraitItem {
fn repr(&self, _tcx: &ctxt) -> String {
let kind = match self.node {
+ ast::ConstTraitItem(..) => "ConstTraitItem",
ast::MethodTraitItem(..) => "MethodTraitItem",
ast::TypeTraitItem(..) => "TypeTraitItem",
};
}
}
+impl<'tcx> Repr<'tcx> for ty::ImplOrTraitItem<'tcx> {
+ fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+ format!("ImplOrTraitItem({})",
+ match *self {
+ ty::ImplOrTraitItem::MethodTraitItem(ref i) => i.repr(tcx),
+ ty::ImplOrTraitItem::ConstTraitItem(ref i) => i.repr(tcx),
+ ty::ImplOrTraitItem::TypeTraitItem(ref i) => i.repr(tcx),
+ })
+ }
+}
+
+impl<'tcx> Repr<'tcx> for ty::AssociatedConst<'tcx> {
+ fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+ format!("AssociatedConst(name: {}, ty: {}, vis: {}, def_id: {})",
+ self.name.repr(tcx),
+ self.ty.repr(tcx),
+ self.vis.repr(tcx),
+ self.def_id.repr(tcx))
+ }
+}
+
+impl<'tcx> Repr<'tcx> for ty::AssociatedType {
+ fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+ format!("AssociatedType(name: {}, vis: {}, def_id: {})",
+ self.name.repr(tcx),
+ self.vis.repr(tcx),
+ self.def_id.repr(tcx))
+ }
+}
+
impl<'tcx> Repr<'tcx> for ty::Method<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("method(name: {}, generics: {}, predicates: {}, fty: {}, \
+ format!("Method(name: {}, generics: {}, predicates: {}, fty: {}, \
explicit_self: {}, vis: {}, def_id: {})",
self.name.repr(tcx),
self.generics.repr(tcx),
target_pointer_width: "64".to_string(),
arch: "aarch64".to_string(),
target_os: "ios".to_string(),
+ target_env: "".to_string(),
options: TargetOptions {
features: "+neon,+fp-armv8,+cyclone".to_string(),
eliminate_frame_pointer: false,
target_pointer_width: "64".to_string(),
arch: "aarch64".to_string(),
target_os: "android".to_string(),
+ target_env: "".to_string(),
options: base,
}
}
llvm_target: "aarch64-unknown-linux-gnu".to_string(),
target_endian: "little".to_string(),
target_pointer_width: "64".to_string(),
+ target_env: "gnu".to_string(),
arch: "aarch64".to_string(),
target_os: "linux".to_string(),
options: base,
target_pointer_width: "32".to_string(),
arch: "arm".to_string(),
target_os: "android".to_string(),
+ target_env: "gnu".to_string(),
options: base,
}
}
target_pointer_width: "32".to_string(),
arch: "arm".to_string(),
target_os: "linux".to_string(),
+ target_env: "gnueabi".to_string(),
options: TargetOptions {
features: "+v6".to_string(),
target_pointer_width: "32".to_string(),
arch: "arm".to_string(),
target_os: "linux".to_string(),
+ target_env: "gnueabihf".to_string(),
options: TargetOptions {
features: "+v6,+vfp2".to_string(),
target_pointer_width: "32".to_string(),
arch: "arm".to_string(),
target_os: "ios".to_string(),
+ target_env: "".to_string(),
options: TargetOptions {
features: "+v7,+vfp3,+neon".to_string(),
.. opts(Arch::Armv7)
target_pointer_width: "32".to_string(),
arch: "arm".to_string(),
target_os: "ios".to_string(),
+ target_env: "".to_string(),
options: TargetOptions {
features: "+v7,+vfp4,+neon".to_string(),
.. opts(Arch::Armv7s)
target_pointer_width: "32".to_string(),
arch: "x86".to_string(),
target_os: "ios".to_string(),
+ target_env: "".to_string(),
options: opts(Arch::I386)
}
}
target_pointer_width: "32".to_string(),
arch: "x86".to_string(),
target_os: "macos".to_string(),
+ target_env: "".to_string(),
options: base,
}
}
target_pointer_width: "32".to_string(),
arch: "x86".to_string(),
target_os: "windows".to_string(),
+ target_env: "gnu".to_string(),
options: options,
}
}
target_pointer_width: "32".to_string(),
arch: "x86".to_string(),
target_os: "dragonfly".to_string(),
+ target_env: "".to_string(),
options: base,
}
}
target_pointer_width: "32".to_string(),
arch: "x86".to_string(),
target_os: "linux".to_string(),
+ target_env: "gnu".to_string(),
options: base,
}
}
morestack: true,
linker_is_gnu: true,
has_rpath: true,
- pre_link_args: vec!(
- // GNU-style linkers will use this to omit linking to libraries which
- // don't actually fulfill any relocations, but only for libraries which
- // follow this flag. Thus, use it before specifying libraries to link to.
+ pre_link_args: vec![
+ // We want to be able to strip as much executable code as possible
+ // from the linker command line, and this flag indicates to the
+ // linker that it can avoid linking in dynamic libraries that don't
+ // actually satisfy any symbols up to that point (as with many other
+ // resolutions the linker does). This option only applies to all
+ // following libraries so we're sure to pass it as one of the first
+ // arguments.
"-Wl,--as-needed".to_string(),
- ),
+ ],
position_independent_executables: true,
.. Default::default()
}
target_pointer_width: "32".to_string(),
arch: "mips".to_string(),
target_os: "linux".to_string(),
+ target_env: "gnu".to_string(),
options: super::linux_base::opts()
}
}
target_pointer_width: "32".to_string(),
arch: "mips".to_string(),
target_os: "linux".to_string(),
+ target_env: "gnu".to_string(),
options: super::linux_base::opts()
}
mod bitrig_base;
mod openbsd_base;
-mod armv7_apple_ios;
-mod armv7s_apple_ios;
-mod i386_apple_ios;
-
-mod arm_linux_androideabi;
-mod arm_unknown_linux_gnueabi;
-mod arm_unknown_linux_gnueabihf;
-mod aarch64_apple_ios;
-mod aarch64_linux_android;
-mod aarch64_unknown_linux_gnu;
-mod i686_apple_darwin;
-mod i686_pc_windows_gnu;
-mod i686_unknown_dragonfly;
-mod i686_unknown_linux_gnu;
-mod mips_unknown_linux_gnu;
-mod mipsel_unknown_linux_gnu;
-mod powerpc_unknown_linux_gnu;
-mod x86_64_apple_darwin;
-mod x86_64_apple_ios;
-mod x86_64_pc_windows_gnu;
-mod x86_64_unknown_freebsd;
-mod x86_64_unknown_dragonfly;
-mod x86_64_unknown_bitrig;
-mod x86_64_unknown_linux_gnu;
-mod x86_64_unknown_openbsd;
-
/// Everything `rustc` knows about how to compile for a specific target.
///
/// Every field here must be specified, and has no default value.
pub target_pointer_width: String,
/// OS name to use for conditional compilation.
pub target_os: String,
+ /// Environment name to use for conditional compilation.
+ pub target_env: String,
/// Architecture to use for ABI considerations. Valid options: "x86", "x86_64", "arm",
/// "aarch64", "mips", and "powerpc". "mips" includes "mipsel".
pub arch: String,
pub struct TargetOptions {
/// Linker to invoke. Defaults to "cc".
pub linker: String,
- /// Linker arguments that are unconditionally passed *before* any user-defined libraries.
+ /// Linker arguments that are unconditionally passed *before* any
+ /// user-defined libraries.
pub pre_link_args: Vec<String>,
- /// Linker arguments that are unconditionally passed *after* any user-defined libraries.
+ /// Linker arguments that are unconditionally passed *after* any
+ /// user-defined libraries.
pub post_link_args: Vec<String>,
- /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults to "default".
+ /// Objects to link before and after all others, always found within the
+ /// sysroot folder.
+ pub pre_link_objects: Vec<String>,
+ pub post_link_objects: Vec<String>,
+ /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults
+ /// to "default".
pub cpu: String,
- /// Default target features to pass to LLVM. These features will *always* be passed, and cannot
- /// be disabled even via `-C`. Corresponds to `llc -mattr=$features`.
+ /// Default target features to pass to LLVM. These features will *always* be
+ /// passed, and cannot be disabled even via `-C`. Corresponds to `llc
+ /// -mattr=$features`.
pub features: String,
/// Whether dynamic linking is available on this target. Defaults to false.
pub dynamic_linking: bool,
has_rpath: false,
no_compiler_rt: false,
position_independent_executables: false,
+ pre_link_objects: Vec::new(),
+ post_link_objects: Vec::new(),
}
}
}
target_pointer_width: get_req_field("target-pointer-width"),
arch: get_req_field("arch"),
target_os: get_req_field("os"),
+ target_env: obj.find("env").and_then(|s| s.as_string())
+ .map(|s| s.to_string()).unwrap_or(String::new()),
options: Default::default(),
};
macro_rules! load_specific {
( $($name:ident),+ ) => (
{
+ $(mod $name;)*
let target = target.replace("-", "_");
if false { }
$(
arm_unknown_linux_gnueabi,
arm_unknown_linux_gnueabihf,
aarch64_unknown_linux_gnu,
+ x86_64_unknown_linux_musl,
arm_linux_androideabi,
aarch64_linux_android,
target_pointer_width: "32".to_string(),
arch: "powerpc".to_string(),
target_os: "linux".to_string(),
+ target_env: "gnu".to_string(),
options: base,
}
}
target_pointer_width: "64".to_string(),
arch: "x86_64".to_string(),
target_os: "macos".to_string(),
+ target_env: "".to_string(),
options: base,
}
}
target_pointer_width: "64".to_string(),
arch: "x86_64".to_string(),
target_os: "ios".to_string(),
+ target_env: "".to_string(),
options: opts(Arch::X86_64)
}
}
target_pointer_width: "64".to_string(),
arch: "x86_64".to_string(),
target_os: "windows".to_string(),
+ target_env: "gnu".to_string(),
options: base,
}
}
target_pointer_width: "64".to_string(),
arch: "x86_64".to_string(),
target_os: "bitrig".to_string(),
+ target_env: "".to_string(),
options: base,
}
}
target_pointer_width: "64".to_string(),
arch: "x86_64".to_string(),
target_os: "dragonfly".to_string(),
+ target_env: "".to_string(),
options: base,
}
}
target_pointer_width: "64".to_string(),
arch: "x86_64".to_string(),
target_os: "freebsd".to_string(),
+ target_env: "".to_string(),
options: base,
}
}
target_pointer_width: "64".to_string(),
arch: "x86_64".to_string(),
target_os: "linux".to_string(),
+ target_env: "gnu".to_string(),
options: base,
}
}
--- /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 target::Target;
+
+pub fn target() -> Target {
+ let mut base = super::linux_base::opts();
+ base.cpu = "x86-64".to_string();
+ base.pre_link_args.push("-m64".to_string());
+
+ // Make sure that the linker/gcc really don't pull in anything, including
+ // default objects, libs, etc.
+ base.pre_link_args.push("-nostdlib".to_string());
+ base.pre_link_args.push("-static".to_string());
+
+ // At least when this was tested, the linker would not add the
+ // `GNU_EH_FRAME` program header to executables generated, which is required
+ // when unwinding to locate the unwinding information. I'm not sure why this
+ // argument is *not* necessary for normal builds, but it can't hurt!
+ base.pre_link_args.push("-Wl,--eh-frame-hdr".to_string());
+
+ // There's a whole bunch of circular dependencies when dealing with MUSL
+ // unfortunately. To put this in perspective libc is statically linked to
+ // liblibc and libunwind is statically linked to libstd:
+ //
+ // * libcore depends on `fmod` which is in libc (transitively in liblibc).
+ // liblibc, however, depends on libcore.
+ // * compiler-rt has personality symbols that depend on libunwind, but
+ // libunwind is in libstd which depends on compiler-rt.
+ //
+ // Recall that linkers discard libraries and object files as much as
+ // possible, and with all the static linking and archives flying around with
+ // MUSL the linker is super aggressively stripping out objects. For example
+ // the first case has fmod stripped from liblibc (it's in its own object
+ // file) so it's not there when libcore needs it. In the second example all
+ // the unused symbols from libunwind are stripped (each is in its own object
+ // file in libstd) before we end up linking compiler-rt which depends on
+ // those symbols.
+ //
+ // To deal with these circular dependencies we just force the compiler to
+ // link everything as a group, not stripping anything out until everything
+ // is processed. The linker will still perform a pass to strip out object
+ // files but it won't do so until all objects/archives have been processed.
+ base.pre_link_args.push("-Wl,-(".to_string());
+ base.post_link_args.push("-Wl,-)".to_string());
+
+ // When generating a statically linked executable there's generally some
+ // small setup needed which is listed in these files. These are provided by
+ // a musl toolchain and are linked by default by the `musl-gcc` script. Note
+ // that `gcc` also does this by default, it just uses some different files.
+ //
+ // Each target directory for musl has these object files included in it so
+ // they'll be included from there.
+ base.pre_link_objects.push("crt1.o".to_string());
+ base.pre_link_objects.push("crti.o".to_string());
+ base.post_link_objects.push("crtn.o".to_string());
+
+ // MUSL support doesn't currently include dynamic linking, so there's no
+ // need for dylibs or rpath business. Additionally `-pie` is incompatible
+ // with `-static`, so we can't pass `-pie`.
+ base.dynamic_linking = false;
+ base.has_rpath = false;
+ base.position_independent_executables = false;
+
+ Target {
+ data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
+ f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
+ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),
+ llvm_target: "x86_64-unknown-linux-musl".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "64".to_string(),
+ arch: "x86_64".to_string(),
+ target_os: "linux".to_string(),
+ target_env: "musl".to_string(),
+ options: base,
+ }
+}
target_pointer_width: "64".to_string(),
arch: "x86_64".to_string(),
target_os: "openbsd".to_string(),
+ target_env: "".to_string(),
options: base,
}
}
fn visit_item(&mut self, item: &ast::Item) {
borrowck_item(self, item);
}
+
+ fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
+ if let ast::ConstTraitItem(_, Some(ref expr)) = ti.node {
+ gather_loans::gather_loans_in_static_initializer(self, &*expr);
+ }
+ visit::walk_trait_item(self, ti);
+ }
+
+ fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
+ if let ast::ConstImplItem(_, ref expr) = ii.node {
+ gather_loans::gather_loans_in_static_initializer(self, &*expr);
+ }
+ visit::walk_impl_item(self, ii);
+ }
}
pub fn check_crate(tcx: &ty::ctxt) {
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
-#![feature(unsafe_destructor)]
#![feature(into_cow)]
#[macro_use] extern crate log;
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
-#![feature(unsafe_destructor)]
#![feature(staged_api)]
#![feature(exit_status)]
#![feature(set_stdio)]
use syntax::fold::{self, Folder};
use syntax::print::{pp, pprust};
use syntax::ptr::P;
+use syntax::util::small_vector::SmallVector;
use graphviz as dot;
}
}
+ fn fold_trait_item(&mut self, i: P<ast::TraitItem>) -> SmallVector<P<ast::TraitItem>> {
+ match i.node {
+ ast::ConstTraitItem(..) => {
+ self.within_static_or_const = true;
+ let ret = fold::noop_fold_trait_item(i, self);
+ self.within_static_or_const = false;
+ return ret;
+ }
+ _ => fold::noop_fold_trait_item(i, self),
+ }
+ }
+
+ fn fold_impl_item(&mut self, i: P<ast::ImplItem>) -> SmallVector<P<ast::ImplItem>> {
+ match i.node {
+ ast::ConstImplItem(..) => {
+ self.within_static_or_const = true;
+ let ret = fold::noop_fold_impl_item(i, self);
+ self.within_static_or_const = false;
+ return ret;
+ }
+ _ => fold::noop_fold_impl_item(i, self),
+ }
+ }
fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
fn expr_to_block(rules: ast::BlockCheckMode,
}
}
+ fn check_trait_item(&mut self, cx: &Context, ti: &ast::TraitItem) {
+ match ti.node {
+ ast::ConstTraitItem(..) => {
+ NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
+ ti.ident, ti.span);
+ }
+ _ => {}
+ }
+ }
+
+ fn check_impl_item(&mut self, cx: &Context, ii: &ast::ImplItem) {
+ match ii.node {
+ ast::ConstImplItem(..) => {
+ NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
+ ii.ident, ii.span);
+ }
+ _ => {}
+ }
+ }
+
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
// Lint for constants that look like binding identifiers (#7526)
match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) {
if self.private_traits.contains(&trait_item.id) { return }
let desc = match trait_item.node {
+ ast::ConstTraitItem(..) => "an associated constant",
ast::MethodTraitItem(..) => "a trait method",
- ast::TypeTraitItem(..) => "an associated type"
+ ast::TypeTraitItem(..) => "an associated type",
};
self.check_missing_docs_attrs(cx, Some(trait_item.id),
}
let desc = match impl_item.node {
+ ast::ConstImplItem(..) => "an associated constant",
ast::MethodImplItem(..) => "a method",
ast::TypeImplItem(_) => "an associated type",
- ast::MacImplItem(_) => "an impl item macro"
+ ast::MacImplItem(_) => "an impl item macro",
};
self.check_missing_docs_attrs(cx, Some(impl_item.id),
&impl_item.attrs,
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
-#![feature(unsafe_destructor)]
#![feature(staged_api)]
#![feature(str_char)]
#![cfg_attr(test, feature(test))]
}
}
-#[unsafe_destructor]
impl<'a> Drop for Iter<'a> {
fn drop(&mut self) {
unsafe {
#![feature(libc)]
#![feature(link_args)]
#![feature(staged_api)]
-#![feature(unsafe_destructor)]
extern crate libc;
#[macro_use] #[no_link] extern crate rustc_bitflags;
visit::walk_fn(self, a, b, c, d);
}
+ fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
+ // visit_fn handles methods, but associated consts have to be handled
+ // here.
+ if !self.parents.contains_key(&ii.id) {
+ self.parents.insert(ii.id, self.curparent);
+ }
+ visit::walk_impl_item(self, ii);
+ }
+
fn visit_struct_def(&mut self, s: &ast::StructDef, _: ast::Ident,
_: &'v ast::Generics, n: ast::NodeId) {
// Struct constructors are parented to their struct definitions because
if public_ty || public_trait {
for impl_item in impl_items {
match impl_item.node {
+ ast::ConstImplItem(..) => {
+ if (public_ty && impl_item.vis == ast::Public)
+ || tr.is_some() {
+ self.exported_items.insert(impl_item.id);
+ }
+ }
ast::MethodImplItem(ref sig, _) => {
let meth_public = match sig.explicit_self.node {
ast::SelfStatic => public_ty,
debug!("privacy - is {:?} a public method", did);
return match self.tcx.impl_or_trait_items.borrow().get(&did) {
+ Some(&ty::ConstTraitItem(ref ac)) => {
+ debug!("privacy - it's a const: {:?}", *ac);
+ match ac.container {
+ ty::TraitContainer(id) => {
+ debug!("privacy - recursing on trait {:?}", id);
+ self.def_privacy(id)
+ }
+ ty::ImplContainer(id) => {
+ match ty::impl_trait_ref(self.tcx, id) {
+ Some(t) => {
+ debug!("privacy - impl of trait {:?}", id);
+ self.def_privacy(t.def_id)
+ }
+ None => {
+ debug!("privacy - found inherent \
+ associated constant {:?}",
+ ac.vis);
+ if ac.vis == ast::Public {
+ Allowable
+ } else {
+ ExternallyDenied
+ }
+ }
+ }
+ }
+ }
+ }
Some(&ty::MethodTraitItem(ref meth)) => {
debug!("privacy - well at least it's a method: {:?}",
*meth);
// where the method was defined?
Some(ast_map::NodeImplItem(ii)) => {
match ii.node {
+ ast::ConstImplItem(..) |
ast::MethodImplItem(..) => {
let imp = self.tcx.map
.get_parent_did(closest_private_id);
ty::MethodTraitItem(method_type) => {
method_type.provided_source.unwrap_or(method_id)
}
- ty::TypeTraitItem(_) => method_id,
+ _ => {
+ self.tcx.sess
+ .span_bug(span,
+ "got non-method item in check_static_method")
+ }
};
let string = token::get_name(name);
def::DefFn(..) => ck("function"),
def::DefStatic(..) => ck("static"),
def::DefConst(..) => ck("const"),
+ def::DefAssociatedConst(..) => ck("associated const"),
def::DefVariant(..) => ck("variant"),
def::DefTy(_, false) => ck("type"),
def::DefTy(_, true) => ck("enum"),
ast::MethodImplItem(..) => {
check_inherited(tcx, impl_item.span, impl_item.vis);
}
- ast::TypeImplItem(_) |
- ast::MacImplItem(_) => {}
+ _ => {}
}
}
}
impl_items.iter()
.any(|impl_item| {
match impl_item.node {
+ ast::ConstImplItem(..) |
ast::MethodImplItem(..) => {
self.exported_items.contains(&impl_item.id)
}
// don't erroneously report errors for private
// types in private items.
match impl_item.node {
+ ast::ConstImplItem(..) |
ast::MethodImplItem(..)
if self.item_is_public(&impl_item.id, impl_item.vis) =>
{
// Those in 3. are warned with this call.
for impl_item in impl_items {
- match impl_item.node {
- ast::TypeImplItem(ref ty) => {
- self.visit_ty(ty);
- }
- ast::MethodImplItem(..) |
- ast::MacImplItem(_) => {},
+ if let ast::TypeImplItem(ref ty) = impl_item.node {
+ self.visit_ty(ty);
}
}
}
let mut found_pub_static = false;
for impl_item in impl_items {
match impl_item.node {
+ ast::ConstImplItem(..) => {
+ if self.item_is_public(&impl_item.id, impl_item.vis) {
+ found_pub_static = true;
+ visit::walk_impl_item(self, impl_item);
+ }
+ }
ast::MethodImplItem(ref sig, _) => {
if sig.explicit_self.node == ast::SelfStatic &&
- self.item_is_public(&impl_item.id, impl_item.vis) {
+ self.item_is_public(&impl_item.id, impl_item.vis) {
found_pub_static = true;
visit::walk_impl_item(self, impl_item);
}
}
- ast::TypeImplItem(_) |
- ast::MacImplItem(_) => {}
+ _ => {}
}
}
if found_pub_static {
trait_item.span);
match trait_item.node {
+ ast::ConstTraitItem(..) => {
+ let def = DefAssociatedConst(local_def(trait_item.id),
+ FromTrait(local_def(item.id)));
+ // NB: not IMPORTABLE
+ name_bindings.define_value(def, trait_item.span, PUBLIC);
+ }
ast::MethodTraitItem(..) => {
let def = DefMethod(local_def(trait_item.id),
FromTrait(local_def(item.id)));
csearch::get_tuple_struct_definition_if_ctor(&self.session.cstore, ctor_id)
.map_or(def, |_| DefStruct(ctor_id)), DUMMY_SP, modifiers);
}
- DefFn(..) | DefStatic(..) | DefConst(..) | DefMethod(..) => {
+ DefFn(..) | DefStatic(..) | DefConst(..) | DefAssociatedConst(..) |
+ DefMethod(..) => {
debug!("(building reduced graph for external \
crate) building value (fn/static) {}", final_ident);
// impl methods have already been defined with the correct importability modifier
use self::RibKind::*;
use self::UseLexicalScopeFlag::*;
use self::ModulePrefixResult::*;
+use self::AssocItemResolveResult::*;
use self::NameSearchType::*;
use self::BareIdentifierPatternResolution::*;
use self::ParentLink::*;
use rustc::util::nodemap::{NodeMap, NodeSet, DefIdSet, FnvHashMap};
use rustc::util::lev_distance::lev_distance;
-use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum};
+use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block};
+use syntax::ast::{ConstImplItem, Crate, CrateNum};
use syntax::ast::{DefId, Expr, ExprAgain, ExprBreak, ExprField};
use syntax::ast::{ExprLoop, ExprWhile, ExprMethodCall};
use syntax::ast::{ExprPath, ExprStruct, FnDecl};
use syntax::ast::{ItemFn, ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl};
use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse};
use syntax::ast::{Local, MethodImplItem, Name, NodeId};
-use syntax::ast::{Pat, PatEnum, PatIdent, PatLit};
+use syntax::ast::{Pat, PatEnum, PatIdent, PatLit, PatQPath};
use syntax::ast::{PatRange, PatStruct, Path, PrimTy};
use syntax::ast::{TraitRef, Ty, TyBool, TyChar, TyF32};
use syntax::ast::{TyF64, TyFloat, TyIs, TyI8, TyI16, TyI32, TyI64, TyInt};
PrefixFound(Rc<Module>, usize)
}
+#[derive(Copy, Clone)]
+enum AssocItemResolveResult {
+ /// Syntax such as `<T>::item`, which can't be resolved until type
+ /// checking.
+ TypecheckRequired,
+ /// We should have been able to resolve the associated item.
+ ResolveAttempt(Option<PathResolution>),
+}
+
#[derive(Copy, Clone, PartialEq)]
enum NameSearchType {
/// We're doing a name search in order to resolve a `use` directive.
//
// FIXME #4951: Do we need a node ID here?
- let type_parameters = match trait_item.node {
+ match trait_item.node {
+ ast::ConstTraitItem(_, ref default) => {
+ // Only impose the restrictions of
+ // ConstRibKind if there's an actual constant
+ // expression in a provided default.
+ if default.is_some() {
+ this.with_constant_rib(|this| {
+ visit::walk_trait_item(this, trait_item)
+ });
+ } else {
+ visit::walk_trait_item(this, trait_item)
+ }
+ }
ast::MethodTraitItem(ref sig, _) => {
- HasTypeParameters(&sig.generics,
- FnSpace,
- MethodRibKind)
+ let type_parameters =
+ HasTypeParameters(&sig.generics,
+ FnSpace,
+ MethodRibKind);
+ this.with_type_parameter_rib(type_parameters, |this| {
+ visit::walk_trait_item(this, trait_item)
+ });
}
ast::TypeTraitItem(..) => {
this.check_if_primitive_type_name(trait_item.ident.name,
trait_item.span);
- NoTypeParameters
+ this.with_type_parameter_rib(NoTypeParameters, |this| {
+ visit::walk_trait_item(this, trait_item)
+ });
}
};
- this.with_type_parameter_rib(type_parameters, |this| {
- visit::walk_trait_item(this, trait_item)
- });
}
});
});
this.with_current_self_type(self_type, |this| {
for impl_item in impl_items {
match impl_item.node {
+ ConstImplItem(..) => {
+ // If this is a trait impl, ensure the method
+ // exists in trait
+ this.check_trait_item(impl_item.ident.name,
+ impl_item.span);
+ this.with_constant_rib(|this| {
+ visit::walk_impl_item(this, impl_item);
+ });
+ }
MethodImplItem(ref sig, _) => {
// If this is a trait impl, ensure the method
// exists in trait
fn resolve_type(&mut self, ty: &Ty) {
match ty.node {
- // `<T>::a::b::c` is resolved by typeck alone.
- TyPath(Some(ast::QSelf { position: 0, .. }), _) => {}
-
TyPath(ref maybe_qself, ref path) => {
- let max_assoc_types = if let Some(ref qself) = *maybe_qself {
- // Make sure the trait is valid.
- let _ = self.resolve_trait_reference(ty.id, path, 1);
- path.segments.len() - qself.position
- } else {
- path.segments.len()
- };
-
- let mut resolution = None;
- for depth in 0..max_assoc_types {
- self.with_no_errors(|this| {
- resolution = this.resolve_path(ty.id, path, depth, TypeNS, true);
- });
- if resolution.is_some() {
- break;
- }
- }
- if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
- // A module is not a valid type.
- resolution = None;
- }
+ let resolution =
+ match self.resolve_possibly_assoc_item(ty.id,
+ maybe_qself.as_ref(),
+ path,
+ TypeNS,
+ true) {
+ // `<T>::a::b::c` is resolved by typeck alone.
+ TypecheckRequired => {
+ // Resolve embedded types.
+ visit::walk_ty(self, ty);
+ return;
+ }
+ ResolveAttempt(resolution) => resolution,
+ };
// This is a path in the type namespace. Walk through scopes
// looking for it.
PatEnum(ref path, _) => {
// This must be an enum variant, struct or const.
- if let Some(path_res) = self.resolve_path(pat_id, path, 0, ValueNS, false) {
+ let resolution =
+ match self.resolve_possibly_assoc_item(pat_id, None,
+ path, ValueNS,
+ false) {
+ // The below shouldn't happen because all
+ // qualified paths should be in PatQPath.
+ TypecheckRequired =>
+ self.session.span_bug(
+ path.span,
+ "resolve_possibly_assoc_item claimed
+ that a path in PatEnum requires typecheck
+ to resolve, but qualified paths should be
+ PatQPath"),
+ ResolveAttempt(resolution) => resolution,
+ };
+ if let Some(path_res) = resolution {
match path_res.base_def {
DefVariant(..) | DefStruct(..) | DefConst(..) => {
self.record_def(pattern.id, path_res);
referenced in a pattern, \
use a `const` instead");
}
+ _ => {
+ // If anything ends up here entirely resolved,
+ // it's an error. If anything ends up here
+ // partially resolved, that's OK, because it may
+ // be a `T::CONST` that typeck will resolve to
+ // an inherent impl.
+ if path_res.depth == 0 {
+ self.resolve_error(
+ path.span,
+ &format!("`{}` is not an enum variant, struct or const",
+ token::get_ident(
+ path.segments.last().unwrap().identifier)));
+ } else {
+ self.record_def(pattern.id, path_res);
+ }
+ }
+ }
+ } else {
+ self.resolve_error(path.span,
+ &format!("unresolved enum variant, struct or const `{}`",
+ token::get_ident(path.segments.last().unwrap().identifier)));
+ }
+ visit::walk_path(self, path);
+ }
+
+ PatQPath(ref qself, ref path) => {
+ // Associated constants only.
+ let resolution =
+ match self.resolve_possibly_assoc_item(pat_id, Some(qself),
+ path, ValueNS,
+ false) {
+ TypecheckRequired => {
+ // All `<T>::CONST` should end up here, and will
+ // require use of the trait map to resolve
+ // during typechecking.
+ let const_name = path.segments.last().unwrap()
+ .identifier.name;
+ let traits = self.get_traits_containing_item(const_name);
+ self.trait_map.insert(pattern.id, traits);
+ visit::walk_pat(self, pattern);
+ return true;
+ }
+ ResolveAttempt(resolution) => resolution,
+ };
+ if let Some(path_res) = resolution {
+ match path_res.base_def {
+ // All `<T as Trait>::CONST` should end up here, and
+ // have the trait already selected.
+ DefAssociatedConst(..) => {
+ self.record_def(pattern.id, path_res);
+ }
_ => {
self.resolve_error(path.span,
- &format!("`{}` is not an enum variant, struct or const",
+ &format!("`{}` is not an associated const",
token::get_ident(
path.segments.last().unwrap().identifier)));
}
}
} else {
self.resolve_error(path.span,
- &format!("unresolved enum variant, struct or const `{}`",
+ &format!("unresolved associated const `{}`",
token::get_ident(path.segments.last().unwrap().identifier)));
}
- visit::walk_path(self, path);
+ visit::walk_pat(self, pattern);
}
PatStruct(ref path, _, _) => {
def @ DefVariant(..) | def @ DefStruct(..) => {
return FoundStructOrEnumVariant(def, LastMod(AllPublic));
}
- def @ DefConst(..) => {
+ def @ DefConst(..) | def @ DefAssociatedConst(..) => {
return FoundConst(def, LastMod(AllPublic));
}
DefStatic(..) => {
}
}
+ /// Handles paths that may refer to associated items
+ fn resolve_possibly_assoc_item(&mut self,
+ id: NodeId,
+ maybe_qself: Option<&ast::QSelf>,
+ path: &Path,
+ namespace: Namespace,
+ check_ribs: bool)
+ -> AssocItemResolveResult
+ {
+ match maybe_qself {
+ Some(&ast::QSelf { position: 0, .. }) =>
+ return TypecheckRequired,
+ _ => {}
+ }
+ let max_assoc_types = if let Some(qself) = maybe_qself {
+ // Make sure the trait is valid.
+ let _ = self.resolve_trait_reference(id, path, 1);
+ path.segments.len() - qself.position
+ } else {
+ path.segments.len()
+ };
+
+ let mut resolution = self.with_no_errors(|this| {
+ this.resolve_path(id, path, 0, namespace, check_ribs)
+ });
+ for depth in 1..max_assoc_types {
+ if resolution.is_some() {
+ break;
+ }
+ self.with_no_errors(|this| {
+ resolution = this.resolve_path(id, path, depth,
+ TypeNS, true);
+ });
+ }
+ if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
+ // A module is not a valid type or value.
+ resolution = None;
+ }
+ ResolveAttempt(resolution)
+ }
+
/// If `check_ribs` is true, checks the local definitions first; i.e.
/// doesn't skip straight to the containing module.
/// Skips `path_depth` trailing segments, which is also reflected in the
// Next, resolve the node.
match expr.node {
- // `<T>::a::b::c` is resolved by typeck alone.
- ExprPath(Some(ast::QSelf { position: 0, .. }), ref path) => {
- let method_name = path.segments.last().unwrap().identifier.name;
- let traits = self.search_for_traits_containing_method(method_name);
- self.trait_map.insert(expr.id, traits);
- visit::walk_expr(self, expr);
- }
-
ExprPath(ref maybe_qself, ref path) => {
- let max_assoc_types = if let Some(ref qself) = *maybe_qself {
- // Make sure the trait is valid.
- let _ = self.resolve_trait_reference(expr.id, path, 1);
- path.segments.len() - qself.position
- } else {
- path.segments.len()
- };
-
- let mut resolution = self.with_no_errors(|this| {
- this.resolve_path(expr.id, path, 0, ValueNS, true)
- });
- for depth in 1..max_assoc_types {
- if resolution.is_some() {
- break;
- }
- self.with_no_errors(|this| {
- resolution = this.resolve_path(expr.id, path, depth, TypeNS, true);
- });
- }
- if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
- // A module is not a valid type or value.
- resolution = None;
- }
+ let resolution =
+ match self.resolve_possibly_assoc_item(expr.id,
+ maybe_qself.as_ref(),
+ path,
+ ValueNS,
+ true) {
+ // `<T>::a::b::c` is resolved by typeck alone.
+ TypecheckRequired => {
+ let method_name = path.segments.last().unwrap().identifier.name;
+ let traits = self.get_traits_containing_item(method_name);
+ self.trait_map.insert(expr.id, traits);
+ visit::walk_expr(self, expr);
+ return;
+ }
+ ResolveAttempt(resolution) => resolution,
+ };
// This is a local path in the value namespace. Walk through
// scopes looking for it.
// so they can be completed during typeck.
if path_res.depth != 0 {
let method_name = path.segments.last().unwrap().identifier.name;
- let traits = self.search_for_traits_containing_method(method_name);
+ let traits = self.get_traits_containing_item(method_name);
self.trait_map.insert(expr.id, traits);
}
// field, we need to add any trait methods we find that match
// the field name so that we can do some nice error reporting
// later on in typeck.
- let traits = self.search_for_traits_containing_method(ident.node.name);
+ let traits = self.get_traits_containing_item(ident.node.name);
self.trait_map.insert(expr.id, traits);
}
ExprMethodCall(ident, _, _) => {
debug!("(recording candidate traits for expr) recording \
traits for {}",
expr.id);
- let traits = self.search_for_traits_containing_method(ident.node.name);
+ let traits = self.get_traits_containing_item(ident.node.name);
self.trait_map.insert(expr.id, traits);
}
_ => {
}
}
- fn search_for_traits_containing_method(&mut self, name: Name) -> Vec<DefId> {
- debug!("(searching for traits containing method) looking for '{}'",
+ fn get_traits_containing_item(&mut self, name: Name) -> Vec<DefId> {
+ debug!("(getting traits containing item) looking for '{}'",
token::get_name(name));
fn add_trait_info(found_traits: &mut Vec<DefId>,
let pname = get_cc_prog(sess);
let mut cmd = Command::new(&pname[..]);
+ let root = sess.target_filesearch(PathKind::Native).get_lib_path();
cmd.args(&sess.target.target.options.pre_link_args);
+ for obj in &sess.target.target.options.pre_link_objects {
+ cmd.arg(root.join(obj));
+ }
+
link_args(&mut cmd, sess, dylib, tmpdir.path(),
trans, obj_filename, out_filename);
- cmd.args(&sess.target.target.options.post_link_args);
if !sess.target.target.options.no_compiler_rt {
cmd.arg("-lcompiler-rt");
}
+ for obj in &sess.target.target.options.post_link_objects {
+ cmd.arg(root.join(obj));
+ }
+ cmd.args(&sess.target.target.options.post_link_args);
if sess.opts.debugging_opts.print_link_args {
println!("{:?}", &cmd);
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
-#![feature(unsafe_destructor)]
#![feature(staged_api)]
#![feature(unicode)]
#![feature(path_ext)]
def::DefTrait(_) => Some(recorder::TypeRef),
def::DefStatic(_, _) |
def::DefConst(_) |
+ def::DefAssociatedConst(..) |
def::DefLocal(_) |
def::DefVariant(_, _, _) |
def::DefUpvar(..) => Some(recorder::VarRef),
// record the decl for this def (if it has one)
let decl_id = ty::trait_item_of_item(&self.analysis.ty_cx,
ast_util::local_def(id))
- .and_then(|def_id| {
- if match def_id {
- ty::MethodTraitItemId(def_id) => {
- def_id.node != 0 && def_id != ast_util::local_def(id)
- }
- ty::TypeTraitItemId(_) => false,
- } {
- Some(def_id.def_id())
+ .and_then(|new_id| {
+ let def_id = new_id.def_id();
+ if def_id.node != 0 && def_id != ast_util::local_def(id) {
+ Some(def_id)
} else {
None
}
}
fn process_const(&mut self,
- item: &ast::Item,
- typ: &ast::Ty,
- expr: &ast::Expr)
+ id: ast::NodeId,
+ ident: &ast::Ident,
+ span: Span,
+ typ: &ast::Ty,
+ expr: &ast::Expr)
{
- let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+ let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(id));
- let sub_span = self.span.sub_span_after_keyword(item.span,
+ let sub_span = self.span.sub_span_after_keyword(span,
keywords::Const);
- self.fmt.static_str(item.span,
+ self.fmt.static_str(span,
sub_span,
- item.id,
- &get_ident(item.ident),
+ id,
+ &get_ident((*ident).clone()),
&qualname[..],
"",
&ty_to_string(&*typ),
self.cur_scope);
// walk type and init value
- self.visit_ty(&*typ);
+ self.visit_ty(typ);
self.visit_expr(expr);
}
def::DefLocal(..) |
def::DefStatic(..) |
def::DefConst(..) |
+ def::DefAssociatedConst(..) |
def::DefVariant(..) => self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef),
span,
sub_span,
def::DefLocal(_) |
def::DefStatic(_,_) |
def::DefConst(..) |
+ def::DefAssociatedConst(..) |
def::DefStruct(_) |
def::DefVariant(..) |
def::DefFn(..) => self.write_sub_paths_truncated(path, false),
ty::MethodTraitItem(method) => {
method.provided_source.unwrap_or(def_id)
}
- ty::TypeTraitItem(_) => def_id,
+ _ => self.sess
+ .span_bug(ex.span,
+ "save::process_method_call: non-method \
+ DefId in MethodStatic or MethodStaticClosure"),
};
(Some(def_id), decl_id)
}
let def = self.analysis.ty_cx.def_map.borrow().get(&p.id).unwrap().full_def();
let struct_def = match def {
- def::DefConst(..) => None,
+ def::DefConst(..) | def::DefAssociatedConst(..) => None,
def::DefVariant(_, variant_id, _) => Some(variant_id),
_ => {
match ty::ty_to_def_id(ty::node_id_to_type(&self.analysis.ty_cx, p.id)) {
}
}
}
- ast::PatEnum(ref path, _) => {
+ ast::PatEnum(ref path, _) |
+ ast::PatQPath(_, ref path) => {
self.collected_paths.push((p.id, path.clone(), false, recorder::VarRef));
visit::walk_pat(self, p);
}
ast::ItemStatic(ref typ, mt, ref expr) =>
self.process_static(item, &**typ, mt, &**expr),
ast::ItemConst(ref typ, ref expr) =>
- self.process_const(item, &**typ, &**expr),
+ self.process_const(item.id, &item.ident, item.span, &*typ, &*expr),
ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, &**def, ty_params),
ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
ast::ItemImpl(_, _,
fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
match trait_item.node {
+ ast::ConstTraitItem(ref ty, Some(ref expr)) => {
+ self.process_const(trait_item.id, &trait_item.ident,
+ trait_item.span, &*ty, &*expr);
+ }
ast::MethodTraitItem(ref sig, ref body) => {
self.process_method(sig, body.as_ref().map(|x| &**x),
trait_item.id, trait_item.ident.name, trait_item.span);
}
+ ast::ConstTraitItem(_, None) |
ast::TypeTraitItem(..) => {}
}
}
fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
match impl_item.node {
+ ast::ConstImplItem(ref ty, ref expr) => {
+ self.process_const(impl_item.id, &impl_item.ident,
+ impl_item.span, &*ty, &*expr);
+ }
ast::MethodImplItem(ref sig, ref body) => {
self.process_method(sig, Some(body), impl_item.id,
impl_item.ident.name, impl_item.span);
paths_to_process.push((id, p.clone(), Some(ref_kind)))
}
// FIXME(nrc) what are these doing here?
- def::DefStatic(_, _) => {}
- def::DefConst(..) => {}
+ def::DefStatic(_, _) |
+ def::DefConst(..) |
+ def::DefAssociatedConst(..) => {}
_ => error!("unexpected definition kind when processing collected paths: {:?}",
def)
}
let datum = Datum::new(llval, binding_info.ty, Lvalue);
if let Some(cs) = cs {
- bcx.fcx.schedule_drop_and_zero_mem(cs, llval, binding_info.ty);
bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch);
+ bcx.fcx.schedule_drop_and_fill_mem(cs, llval, binding_info.ty);
}
debug!("binding {} to {}", binding_info.id, bcx.val_to_string(llval));
ast::PatMac(..) => {
bcx.sess().span_bug(pat.span, "unexpanded macro");
}
- ast::PatWild(_) | ast::PatLit(_) | ast::PatRange(_, _) => ()
+ ast::PatQPath(..) | ast::PatWild(_) | ast::PatLit(_) |
+ ast::PatRange(_, _) => ()
}
return bcx;
}
(_match::Switch, Some(trans_get_discr(bcx, r, scrutinee, None)))
}
Univariant(..) => {
+ // N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
(_match::Single, None)
}
}
));
bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {
let ptr = struct_field_ptr(variant_cx, st, value, (st.fields.len() - 1), false);
- datum::Datum::new(ptr, ptr_ty, datum::Rvalue::new(datum::ByRef))
+ datum::Datum::new(ptr, ptr_ty, datum::Lvalue)
.store_to(variant_cx, scratch.val)
});
let expr_datum = scratch.to_expr_datum();
_cannot_construct_outside_of_this_module: ()
}
-#[unsafe_destructor]
impl Drop for _InsnCtxt {
fn drop(&mut self) {
TASK_LOCAL_INSN_KEY.with(|slot| {
}
}
-#[unsafe_destructor]
impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> {
fn drop(&mut self) {
if self.ccx.sess().trans_stats() {
match adt::trans_switch(cx, &*repr, av) {
(_match::Single, None) => {
- cx = iter_variant(cx, &*repr, av, &*(*variants)[0],
- substs, &mut f);
+ if n_variants != 0 {
+ assert!(n_variants == 1);
+ cx = iter_variant(cx, &*repr, av, &*(*variants)[0],
+ substs, &mut f);
+ }
}
(_match::Switch, Some(lldiscrim_a)) => {
cx = f(cx, lldiscrim_a, cx.tcx().types.isize);
Some(ast_map::NodeTraitItem(trait_item)) => {
match trait_item.node {
ast::MethodTraitItem(_, Some(ref body)) => body,
- ast::MethodTraitItem(_, None) => {
- tcx.sess.bug("unexpected variant: required trait method \
- in has_nested_returns")
- }
- ast::TypeTraitItem(..) => {
- tcx.sess.bug("unexpected variant: associated type trait item in \
- has_nested_returns")
+ _ => {
+ tcx.sess.bug("unexpected variant: trait item other than a \
+ provided method in has_nested_returns")
}
}
}
Some(ast_map::NodeImplItem(impl_item)) => {
match impl_item.node {
ast::MethodImplItem(_, ref body) => body,
- ast::TypeImplItem(_) => {
- tcx.sess.bug("unexpected variant: associated type impl item in \
- has_nested_returns")
- }
- ast::MacImplItem(_) => {
- tcx.sess.bug("unexpected variant: unexpanded macro impl item in \
+ _ => {
+ tcx.sess.bug("unexpected variant: non-method impl item in \
has_nested_returns")
}
}
ast_map::NodeTraitItem(trait_item) => {
debug!("get_item_val(): processing a NodeTraitItem");
match trait_item.node {
- ast::MethodTraitItem(_, None) | ast::TypeTraitItem(..) => {
- ccx.sess().span_bug(trait_item.span,
- "unexpected variant: required trait method in get_item_val()");
- }
ast::MethodTraitItem(_, Some(_)) => {
register_method(ccx, id, &trait_item.attrs, trait_item.span)
}
+ _ => {
+ ccx.sess().span_bug(trait_item.span,
+ "unexpected variant: trait item other than a provided \
+ method in get_item_val()");
+ }
}
}
ast::MethodImplItem(..) => {
register_method(ccx, id, &impl_item.attrs, impl_item.span)
}
- ast::TypeImplItem(_) => {
- ccx.sess().span_bug(impl_item.span,
- "unexpected variant: associated type in get_item_val()")
- }
- ast::MacImplItem(_) => {
+ _ => {
ccx.sess().span_bug(impl_item.span,
- "unexpected variant: unexpanded macro in get_item_val()")
+ "unexpected variant: non-method impl item in \
+ get_item_val()");
}
}
}
}
def::DefStatic(..) |
def::DefConst(..) |
+ def::DefAssociatedConst(..) |
def::DefLocal(..) |
def::DefUpvar(..) => {
datum_callee(bcx, ref_expr)
(true, source_id, new_substs)
}
- ty::TypeTraitItem(_) => {
+ _ => {
tcx.sess.bug("trans_fn_ref_with_vtables() tried \
- to translate an associated type?!")
+ to translate a non-method?!")
}
}
}
must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
val: val,
ty: ty,
- zero: false
+ fill_on_drop: false,
+ skip_dtor: false,
};
- debug!("schedule_drop_mem({:?}, val={}, ty={})",
+ debug!("schedule_drop_mem({:?}, val={}, ty={}) fill_on_drop={} skip_dtor={}",
cleanup_scope,
self.ccx.tn().val_to_string(val),
- ty.repr(self.ccx.tcx()));
+ ty.repr(self.ccx.tcx()),
+ drop.fill_on_drop,
+ drop.skip_dtor);
self.schedule_clean(cleanup_scope, drop as CleanupObj);
}
- /// Schedules a (deep) drop and zero-ing of `val`, which is a pointer to an instance of `ty`
- fn schedule_drop_and_zero_mem(&self,
+ /// Schedules a (deep) drop and filling of `val`, which is a pointer to an instance of `ty`
+ fn schedule_drop_and_fill_mem(&self,
cleanup_scope: ScopeId,
val: ValueRef,
ty: Ty<'tcx>) {
must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
val: val,
ty: ty,
- zero: true
+ fill_on_drop: true,
+ skip_dtor: false,
+ };
+
+ debug!("schedule_drop_and_fill_mem({:?}, val={}, ty={}, fill_on_drop={}, skip_dtor={})",
+ cleanup_scope,
+ self.ccx.tn().val_to_string(val),
+ ty.repr(self.ccx.tcx()),
+ drop.fill_on_drop,
+ drop.skip_dtor);
+
+ self.schedule_clean(cleanup_scope, drop as CleanupObj);
+ }
+
+ /// Issue #23611: Schedules a (deep) drop of the contents of
+ /// `val`, which is a pointer to an instance of struct/enum type
+ /// `ty`. The scheduled code handles extracting the discriminant
+ /// and dropping the contents associated with that variant
+ /// *without* executing any associated drop implementation.
+ fn schedule_drop_enum_contents(&self,
+ cleanup_scope: ScopeId,
+ val: ValueRef,
+ ty: Ty<'tcx>) {
+ // `if` below could be "!contents_needs_drop"; skipping drop
+ // is just an optimization, so sound to be conservative.
+ if !self.type_needs_drop(ty) { return; }
+
+ let drop = box DropValue {
+ is_immediate: false,
+ must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
+ val: val,
+ ty: ty,
+ fill_on_drop: false,
+ skip_dtor: true,
};
- debug!("schedule_drop_and_zero_mem({:?}, val={}, ty={}, zero={})",
+ debug!("schedule_drop_enum_contents({:?}, val={}, ty={}) fill_on_drop={} skip_dtor={}",
cleanup_scope,
self.ccx.tn().val_to_string(val),
ty.repr(self.ccx.tcx()),
- true);
+ drop.fill_on_drop,
+ drop.skip_dtor);
self.schedule_clean(cleanup_scope, drop as CleanupObj);
}
must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
val: val,
ty: ty,
- zero: false
+ fill_on_drop: false,
+ skip_dtor: false,
};
- debug!("schedule_drop_immediate({:?}, val={}, ty={:?})",
+ debug!("schedule_drop_immediate({:?}, val={}, ty={:?}) fill_on_drop={} skip_dtor={}",
cleanup_scope,
self.ccx.tn().val_to_string(val),
- ty.repr(self.ccx.tcx()));
+ ty.repr(self.ccx.tcx()),
+ drop.fill_on_drop,
+ drop.skip_dtor);
self.schedule_clean(cleanup_scope, drop as CleanupObj);
}
must_unwind: bool,
val: ValueRef,
ty: Ty<'tcx>,
- zero: bool
+ fill_on_drop: bool,
+ skip_dtor: bool,
}
impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> {
bcx: Block<'blk, 'tcx>,
debug_loc: DebugLoc)
-> Block<'blk, 'tcx> {
- let _icx = base::push_ctxt("<DropValue as Cleanup>::trans");
+ let skip_dtor = self.skip_dtor;
+ let _icx = if skip_dtor {
+ base::push_ctxt("<DropValue as Cleanup>::trans skip_dtor=true")
+ } else {
+ base::push_ctxt("<DropValue as Cleanup>::trans skip_dtor=false")
+ };
let bcx = if self.is_immediate {
- glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc)
+ glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc, self.skip_dtor)
} else {
- glue::drop_ty(bcx, self.val, self.ty, debug_loc)
+ glue::drop_ty_core(bcx, self.val, self.ty, debug_loc, self.skip_dtor)
};
- if self.zero {
+ if self.fill_on_drop {
base::drop_done_fill_mem(bcx, self.val, self.ty);
}
bcx
cleanup_scope: ScopeId,
val: ValueRef,
ty: Ty<'tcx>);
- fn schedule_drop_and_zero_mem(&self,
+ fn schedule_drop_and_fill_mem(&self,
cleanup_scope: ScopeId,
val: ValueRef,
ty: Ty<'tcx>);
+ fn schedule_drop_enum_contents(&self,
+ cleanup_scope: ScopeId,
+ val: ValueRef,
+ ty: Ty<'tcx>);
fn schedule_drop_immediate(&self,
cleanup_scope: ScopeId,
val: ValueRef,
"cross crate constant could not be inlined");
}
- let item = ccx.tcx().map.expect_item(def_id.node);
- if let ast::ItemConst(_, ref expr) = item.node {
- &**expr
- } else {
- ccx.sess().span_bug(ref_expr.span,
- &format!("get_const_expr given non-constant item {}",
- item.repr(ccx.tcx())));
+ match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id)) {
+ Some(ref expr) => expr,
+ None => {
+ ccx.sess().span_bug(ref_expr.span, "constant item not found")
+ }
}
}
ast::ExprPath(..) => {
let def = ccx.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
match def {
- def::DefConst(def_id) => {
+ def::DefConst(def_id) | def::DefAssociatedConst(def_id, _) => {
if !ccx.tcx().adjustments.borrow().contains_key(&expr.id) {
return get_const_val(ccx, def_id, expr);
}
def::DefFn(..) | def::DefMethod(..) => {
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
}
- def::DefConst(def_id) => {
+ def::DefConst(def_id) | def::DefAssociatedConst(def_id, _) => {
const_deref_ptr(cx, get_const_val(cx, def_id, e))
}
def::DefVariant(enum_did, variant_did, _) => {
use trans::common::{ExternMap,BuilderRef_res};
use trans::debuginfo;
use trans::declare;
+use trans::glue::DropGlueKind;
use trans::monomorphize::MonoId;
use trans::type_::{Type, TypeNames};
use middle::subst::Substs;
check_drop_flag_for_sanity: bool,
available_monomorphizations: RefCell<FnvHashSet<String>>,
- available_drop_glues: RefCell<FnvHashMap<Ty<'tcx>, String>>,
+ available_drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, String>>,
}
/// The local portion of a `CrateContext`. There is one `LocalCrateContext`
item_vals: RefCell<NodeMap<ValueRef>>,
needs_unwind_cleanup_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
fn_pointer_shims: RefCell<FnvHashMap<Ty<'tcx>, ValueRef>>,
- drop_glues: RefCell<FnvHashMap<Ty<'tcx>, ValueRef>>,
+ drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, ValueRef>>,
/// Track mapping of external ids to local items imported for inlining
external: RefCell<DefIdMap<Option<ast::NodeId>>>,
/// Backwards version of the `external` map (inlined items to where they
&self.local.fn_pointer_shims
}
- pub fn drop_glues<'a>(&'a self) -> &'a RefCell<FnvHashMap<Ty<'tcx>, ValueRef>> {
+ pub fn drop_glues<'a>(&'a self) -> &'a RefCell<FnvHashMap<DropGlueKind<'tcx>, ValueRef>> {
&self.local.drop_glues
}
&self.shared.available_monomorphizations
}
- pub fn available_drop_glues<'a>(&'a self) -> &'a RefCell<FnvHashMap<Ty<'tcx>, String>> {
+ pub fn available_drop_glues(&self) -> &RefCell<FnvHashMap<DropGlueKind<'tcx>, String>> {
&self.shared.available_drop_glues
}
impl_item.span,
true)
}
- ast::TypeImplItem(_) => {
- cx.sess().span_bug(impl_item.span,
- "create_function_debug_context() \
- called on associated type?!")
- }
- ast::MacImplItem(_) => {
+ _ => {
cx.sess().span_bug(impl_item.span,
"create_function_debug_context() \
- called on unexpanded macro?!")
+ called on non-method impl item?!")
}
}
}
}
}
+ ast::PatQPath(..) => {
+ scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
+ }
+
ast::PatStruct(_, ref field_pats, _) => {
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
use trans::cleanup;
use trans::cleanup::CleanupMethods;
use trans::common::*;
-use trans::datum;
use trans::debuginfo::DebugLoc;
use trans::declare;
use trans::expr;
pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
v: ValueRef,
t: Ty<'tcx>,
- debug_loc: DebugLoc)
- -> Block<'blk, 'tcx> {
+ debug_loc: DebugLoc) -> Block<'blk, 'tcx> {
+ drop_ty_core(bcx, v, t, debug_loc, false)
+}
+
+pub fn drop_ty_core<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ v: ValueRef,
+ t: Ty<'tcx>,
+ debug_loc: DebugLoc,
+ skip_dtor: bool) -> Block<'blk, 'tcx> {
// NB: v is an *alias* of type t here, not a direct value.
- debug!("drop_ty(t={})", t.repr(bcx.tcx()));
+ debug!("drop_ty_core(t={}, skip_dtor={})", t.repr(bcx.tcx()), skip_dtor);
let _icx = push_ctxt("drop_ty");
if bcx.fcx.type_needs_drop(t) {
let ccx = bcx.ccx();
- let glue = get_drop_glue(ccx, t);
+ let g = if skip_dtor {
+ DropGlueKind::TyContents(t)
+ } else {
+ DropGlueKind::Ty(t)
+ };
+ let glue = get_drop_glue_core(ccx, g);
let glue_type = get_drop_glue_type(ccx, t);
let ptr = if glue_type != t {
PointerCast(bcx, v, type_of(ccx, glue_type).ptr_to())
pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
v: ValueRef,
t: Ty<'tcx>,
- debug_loc: DebugLoc)
+ debug_loc: DebugLoc,
+ skip_dtor: bool)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("drop_ty_immediate");
let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
store_ty(bcx, v, vp, t);
- drop_ty(bcx, vp, t, debug_loc)
+ drop_ty_core(bcx, vp, t, debug_loc, skip_dtor)
}
pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ValueRef {
- debug!("make drop glue for {}", ppaux::ty_to_string(ccx.tcx(), t));
- let t = get_drop_glue_type(ccx, t);
- debug!("drop glue type {}", ppaux::ty_to_string(ccx.tcx(), t));
- match ccx.drop_glues().borrow().get(&t) {
+ get_drop_glue_core(ccx, DropGlueKind::Ty(t))
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub enum DropGlueKind<'tcx> {
+ /// The normal path; runs the dtor, and then recurs on the contents
+ Ty(Ty<'tcx>),
+ /// Skips the dtor, if any, for ty; drops the contents directly.
+ /// Note that the dtor is only skipped at the most *shallow*
+ /// level, namely, an `impl Drop for Ty` itself. So, for example,
+ /// if Ty is Newtype(S) then only the Drop impl for for Newtype
+ /// itself will be skipped, while the Drop impl for S, if any,
+ /// will be invoked.
+ TyContents(Ty<'tcx>),
+}
+
+impl<'tcx> DropGlueKind<'tcx> {
+ fn ty(&self) -> Ty<'tcx> {
+ match *self { DropGlueKind::Ty(t) | DropGlueKind::TyContents(t) => t }
+ }
+
+ fn map_ty<F>(&self, mut f: F) -> DropGlueKind<'tcx> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>
+ {
+ match *self {
+ DropGlueKind::Ty(t) => DropGlueKind::Ty(f(t)),
+ DropGlueKind::TyContents(t) => DropGlueKind::TyContents(f(t)),
+ }
+ }
+
+ fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
+ let t_str = ppaux::ty_to_string(ccx.tcx(), self.ty());
+ match *self {
+ DropGlueKind::Ty(_) => format!("DropGlueKind::Ty({})", t_str),
+ DropGlueKind::TyContents(_) => format!("DropGlueKind::TyContents({})", t_str),
+ }
+ }
+}
+
+fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ g: DropGlueKind<'tcx>) -> ValueRef {
+ debug!("make drop glue for {}", g.to_string(ccx));
+ let g = g.map_ty(|t| get_drop_glue_type(ccx, t));
+ debug!("drop glue type {}", g.to_string(ccx));
+ match ccx.drop_glues().borrow().get(&g) {
Some(&glue) => return glue,
_ => { }
}
+ let t = g.ty();
let llty = if type_is_sized(ccx.tcx(), t) {
type_of(ccx, t).ptr_to()
// To avoid infinite recursion, don't `make_drop_glue` until after we've
// added the entry to the `drop_glues` cache.
- if let Some(old_sym) = ccx.available_drop_glues().borrow().get(&t) {
+ if let Some(old_sym) = ccx.available_drop_glues().borrow().get(&g) {
let llfn = declare::declare_cfn(ccx, &old_sym, llfnty, ty::mk_nil(ccx.tcx()));
- ccx.drop_glues().borrow_mut().insert(t, llfn);
+ ccx.drop_glues().borrow_mut().insert(g, llfn);
return llfn;
};
let llfn = declare::define_cfn(ccx, &fn_nm, llfnty, ty::mk_nil(ccx.tcx())).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` already defined", fn_nm));
});
- ccx.available_drop_glues().borrow_mut().insert(t, fn_nm);
+ ccx.available_drop_glues().borrow_mut().insert(g, fn_nm);
let _s = StatRecorder::new(ccx, format!("drop {}", ty_to_short_str(ccx.tcx(), t)));
// type, so we don't need to explicitly cast the function parameter.
let llrawptr0 = get_param(llfn, fcx.arg_pos(0) as c_uint);
- let bcx = make_drop_glue(bcx, llrawptr0, t);
+ let bcx = make_drop_glue(bcx, llrawptr0, g);
finish_fn(&fcx, bcx, ty::FnConverging(ty::mk_nil(ccx.tcx())), DebugLoc::None);
llfn
substs: &subst::Substs<'tcx>)
-> Block<'blk, 'tcx>
{
- let repr = adt::represent_type(bcx.ccx(), t);
+ debug!("trans_struct_drop t: {}", bcx.ty_to_string(t));
// Find and call the actual destructor
- let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t,
- class_did, substs);
+ let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t, class_did, substs);
- // The first argument is the "self" argument for drop
+ // Class dtors have no explicit args, so the params should
+ // just consist of the environment (self).
let params = unsafe {
let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr));
ty.element_type().func_params()
};
+ assert_eq!(params.len(), 1);
- let fty = ty::lookup_item_type(bcx.tcx(), dtor_did).ty.subst(bcx.tcx(), substs);
- let self_ty = match fty.sty {
- ty::ty_bare_fn(_, ref f) => {
- let sig = ty::erase_late_bound_regions(bcx.tcx(), &f.sig);
- assert!(sig.inputs.len() == 1);
- sig.inputs[0]
- }
- _ => bcx.sess().bug(&format!("Expected function type, found {}",
- bcx.ty_to_string(fty)))
- };
-
- let (struct_data, info) = if type_is_sized(bcx.tcx(), t) {
- (v0, None)
- } else {
- let data = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
- let info = GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]);
- (Load(bcx, data), Some(Load(bcx, info)))
- };
-
- adt::fold_variants(bcx, &*repr, struct_data, |variant_cx, st, value| {
- // Be sure to put all of the fields into a scope so we can use an invoke
- // instruction to call the user destructor but still call the field
- // destructors if the user destructor panics.
- let field_scope = variant_cx.fcx.push_custom_cleanup_scope();
-
- // Class dtors have no explicit args, so the params should
- // just consist of the environment (self).
- assert_eq!(params.len(), 1);
- let self_arg = if type_is_fat_ptr(bcx.tcx(), self_ty) {
- // The dtor expects a fat pointer, so make one, even if we have to fake it.
- let scratch = datum::rvalue_scratch_datum(bcx, t, "__fat_ptr_drop_self");
- Store(bcx, value, GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_ADDR]));
- Store(bcx,
- // If we just had a thin pointer, make a fat pointer by sticking
- // null where we put the unsizing info. This works because t
- // is a sized type, so we will only unpack the fat pointer, never
- // use the fake info.
- info.unwrap_or(C_null(Type::i8p(bcx.ccx()))),
- GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_EXTRA]));
- PointerCast(variant_cx, scratch.val, params[0])
- } else {
- PointerCast(variant_cx, value, params[0])
- };
- let args = vec!(self_arg);
+ // Be sure to put the contents into a scope so we can use an invoke
+ // instruction to call the user destructor but still call the field
+ // destructors if the user destructor panics.
+ //
+ // FIXME (#14875) panic-in-drop semantics might be unsupported; we
+ // might well consider changing below to more direct code.
+ let contents_scope = bcx.fcx.push_custom_cleanup_scope();
- // Add all the fields as a value which needs to be cleaned at the end of
- // this scope. Iterate in reverse order so a Drop impl doesn't reverse
- // the order in which fields get dropped.
- for (i, &ty) in st.fields.iter().enumerate().rev() {
- let llfld_a = adt::struct_field_ptr(variant_cx, &*st, value, i, false);
+ // Issue #23611: schedule cleanup of contents, re-inspecting the
+ // discriminant (if any) in case of variant swap in drop code.
+ bcx.fcx.schedule_drop_enum_contents(cleanup::CustomScope(contents_scope), v0, t);
- let val = if type_is_sized(bcx.tcx(), ty) {
- llfld_a
- } else {
- let scratch = datum::rvalue_scratch_datum(bcx, ty, "__fat_ptr_drop_field");
- Store(bcx, llfld_a, GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_ADDR]));
- Store(bcx, info.unwrap(), GEPi(bcx, scratch.val, &[0, abi::FAT_PTR_EXTRA]));
- scratch.val
- };
- variant_cx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope), val, ty);
- }
-
- let dtor_ty = ty::mk_ctor_fn(bcx.tcx(),
- class_did,
- &[get_drop_glue_type(bcx.ccx(), t)],
- ty::mk_nil(bcx.tcx()));
- let (_, variant_cx) = invoke(variant_cx, dtor_addr, &args[..], dtor_ty, DebugLoc::None);
+ let glue_type = get_drop_glue_type(bcx.ccx(), t);
+ let dtor_ty = ty::mk_ctor_fn(bcx.tcx(), class_did, &[glue_type], ty::mk_nil(bcx.tcx()));
+ let (_, bcx) = invoke(bcx, dtor_addr, &[v0], dtor_ty, DebugLoc::None);
- variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope)
- })
+ bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope)
}
fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef)
}
}
-fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
+fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueKind<'tcx>)
-> Block<'blk, 'tcx> {
+ let t = g.ty();
+ let skip_dtor = match g { DropGlueKind::Ty(_) => false, DropGlueKind::TyContents(_) => true };
// NB: v0 is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("make_drop_glue");
match t.sty {
ty::ty_uniq(content_ty) => {
+ // Support for ty_uniq is built-in and its drop glue is
+ // special. It may move to library and have Drop impl. As
+ // a safe-guard, assert ty_uniq not used with TyContents.
+ assert!(!skip_dtor);
if !type_is_sized(bcx.tcx(), content_ty) {
let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
let llbox = Load(bcx, llval);
}
ty::ty_struct(did, substs) | ty::ty_enum(did, substs) => {
let tcx = bcx.tcx();
- match ty::ty_dtor(tcx, did) {
- ty::TraitDtor(dtor, true) => {
+ match (ty::ty_dtor(tcx, did), skip_dtor) {
+ (ty::TraitDtor(dtor, true), false) => {
// FIXME(16758) Since the struct is unsized, it is hard to
// find the drop flag (which is at the end of the struct).
// Lets just ignore the flag and pretend everything will be
trans_struct_drop(bcx, t, v0, dtor, did, substs)
}
}
- ty::TraitDtor(dtor, false) => {
+ (ty::TraitDtor(dtor, false), false) => {
trans_struct_drop(bcx, t, v0, dtor, did, substs)
}
- ty::NoDtor => {
+ (ty::NoDtor, _) | (_, true) => {
// No dtor? Just the default case
iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, DebugLoc::None))
}
}
}
ty::ty_trait(..) => {
+ // No support in vtable for distinguishing destroying with
+ // versus without calling Drop::drop. Assert caller is
+ // okay with always calling the Drop impl, if any.
+ assert!(!skip_dtor);
let data_ptr = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
let vtable_ptr = Load(bcx, GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]));
let dtor = Load(bcx, vtable_ptr);
ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1);
+ // Associated consts already have to be evaluated in `typeck`, so
+ // the logic to do that already exists in `middle`. In order to
+ // reuse that code, it needs to be able to look up the traits for
+ // inlined items.
+ let ty_trait_item = ty::impl_or_trait_item(ccx.tcx(), fn_id).clone();
+ ccx.tcx().impl_or_trait_items.borrow_mut()
+ .insert(local_def(trait_item.id), ty_trait_item);
+
// If this is a default method, we can't look up the
// impl type. But we aren't going to translate anyways, so
// don't.
ast::MethodImplItem(..) => {
visit::walk_impl_item(&mut v, impl_item);
}
- ast::TypeImplItem(_) |
- ast::MacImplItem(_) => {}
+ _ => {}
}
}
return;
}
visit::walk_impl_item(&mut v, impl_item);
}
- ast::TypeImplItem(_) |
- ast::MacImplItem(_) => {}
+ _ => {}
}
}
}
let impl_did = vtable_impl.impl_def_id;
let mname = match ty::trait_item(ccx.tcx(), trait_id, n_method) {
ty::MethodTraitItem(method) => method.name,
- ty::TypeTraitItem(_) => {
- bcx.tcx().sess.bug("can't monomorphize an associated \
- type")
+ _ => {
+ bcx.tcx().sess.bug("can't monomorphize a non-method trait \
+ item")
}
};
let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
// Lookup the type of this method as declared in the trait and apply substitutions.
let method_ty = match ty::trait_item(tcx, trait_id, method_offset_in_trait) {
ty::MethodTraitItem(method) => method,
- ty::TypeTraitItem(_) => {
- tcx.sess.bug("can't create a method shim for an associated type")
+ _ => {
+ tcx.sess.bug("can't create a method shim for a non-method item")
}
};
let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty);
trait_item_def_ids
.iter()
- // Filter out the associated types.
+ // Filter out non-method items.
.filter_map(|item_def_id| {
match *item_def_id {
ty::MethodTraitItemId(def_id) => Some(def_id),
- ty::TypeTraitItemId(_) => None,
+ _ => None,
}
})
let trait_method_type = match ty::impl_or_trait_item(tcx, trait_method_def_id) {
ty::MethodTraitItem(m) => m,
- ty::TypeTraitItem(_) => ccx.sess().bug("should be a method, not assoc type")
+ _ => ccx.sess().bug("should be a method, not other assoc item"),
};
let name = trait_method_type.name;
let impl_method_def_id = method_with_name(ccx, impl_id, name);
let impl_method_type = match ty::impl_or_trait_item(tcx, impl_method_def_id) {
ty::MethodTraitItem(m) => m,
- ty::TypeTraitItem(_) => ccx.sess().bug("should be a method, not assoc type")
+ _ => ccx.sess().bug("should be a method, not other assoc item"),
};
debug!("emit_vtable_methods: impl_method_type={}",
}
d
}
- ast::TypeImplItem(_) => {
- ccx.sess().bug("can't monomorphize an associated type")
- }
- ast::MacImplItem(_) => {
- ccx.sess().bug("can't monomorphize an unexpanded macro")
+ _ => {
+ ccx.sess().bug(&format!("can't monomorphize a {:?}",
+ map_node))
}
}
}
use middle::const_eval;
use middle::def;
use middle::infer;
-use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const};
+use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
+use middle::pat_util::pat_is_resolved_const;
+use middle::privacy::{AllPublic, LastMod};
use middle::subst::Substs;
use middle::ty::{self, Ty};
use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
-use check::{instantiate_path, structurally_resolved_type};
+use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type};
use require_same_types;
use util::nodemap::FnvHashMap;
use util::ppaux::Repr;
// subtyping doesn't matter here, as the value is some kind of scalar
demand::eqtype(fcx, pat.span, expected, lhs_ty);
}
- ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
+ ast::PatEnum(..) | ast::PatIdent(..) if pat_is_resolved_const(&tcx.def_map, pat) => {
let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id();
let const_scheme = ty::lookup_item_type(tcx, const_did);
assert!(const_scheme.generics.is_empty());
let subpats = subpats.as_ref().map(|v| &v[..]);
check_pat_enum(pcx, pat, path, subpats, expected);
}
+ ast::PatQPath(ref qself, ref path) => {
+ let self_ty = fcx.to_ty(&qself.ty);
+ let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) {
+ d
+ } else if qself.position == 0 {
+ def::PathResolution {
+ // This is just a sentinel for finish_resolving_def_to_ty.
+ base_def: def::DefMod(ast_util::local_def(ast::CRATE_NODE_ID)),
+ last_private: LastMod(AllPublic),
+ depth: path.segments.len()
+ }
+ } else {
+ tcx.sess.span_bug(pat.span,
+ &format!("unbound path {}", pat.repr(tcx)))
+ };
+ if let Some((opt_ty, segments, def)) =
+ resolve_ty_and_def_ufcs(fcx, path_res, Some(self_ty),
+ path, pat.span, pat.id) {
+ if check_assoc_item_is_const(pcx, def, pat.span) {
+ let scheme = ty::lookup_item_type(tcx, def.def_id());
+ let predicates = ty::lookup_predicates(tcx, def.def_id());
+ instantiate_path(fcx, segments,
+ scheme, &predicates,
+ opt_ty, def, pat.span, pat.id);
+ let const_ty = fcx.node_ty(pat.id);
+ demand::suptype(fcx, pat.span, expected, const_ty);
+ } else {
+ fcx.write_error(pat.id)
+ }
+ }
+ }
ast::PatStruct(ref path, ref fields, etc) => {
check_pat_struct(pcx, pat, path, fields, etc, expected);
}
// subtyping.
}
+fn check_assoc_item_is_const(pcx: &pat_ctxt, def: def::Def, span: Span) -> bool {
+ match def {
+ def::DefAssociatedConst(..) => true,
+ def::DefMethod(..) => {
+ span_err!(pcx.fcx.ccx.tcx.sess, span, E0327,
+ "associated items in match patterns must be constants");
+ false
+ }
+ _ => {
+ pcx.fcx.ccx.tcx.sess.span_bug(span, "non-associated item in
+ check_assoc_item_is_const");
+ }
+ }
+}
+
pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
span: Span, expected: Ty<'tcx>,
inner: &ast::Pat) -> bool {
let fcx = pcx.fcx;
let tcx = pcx.fcx.ccx.tcx;
- let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
+ let path_res = *tcx.def_map.borrow().get(&pat.id).unwrap();
+
+ let (opt_ty, segments, def) = match resolve_ty_and_def_ufcs(fcx, path_res,
+ None, path,
+ pat.span, pat.id) {
+ Some(resolution) => resolution,
+ // Error handling done inside resolve_ty_and_def_ufcs, so if
+ // resolution fails just return.
+ None => {return;}
+ };
+
+ // Items that were partially resolved before should have been resolved to
+ // associated constants (i.e. not methods).
+ if path_res.depth != 0 && !check_assoc_item_is_const(pcx, def, pat.span) {
+ fcx.write_error(pat.id);
+ return;
+ }
+
let enum_def = def.variant_def_ids()
.map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
} else {
ctor_scheme
};
- instantiate_path(pcx.fcx, &path.segments,
+ instantiate_path(pcx.fcx, segments,
path_scheme, &ctor_predicates,
- None, def, pat.span, pat.id);
+ opt_ty, def, pat.span, pat.id);
+
+ // If we didn't have a fully resolved path to start with, we had an
+ // associated const, and we should quit now, since the rest of this
+ // function uses checks specific to structs and enums.
+ if path_res.depth != 0 {
+ let pat_ty = fcx.node_ty(pat.id);
+ demand::suptype(fcx, pat.span, expected, pat_ty);
+ return;
+ }
let pat_ty = fcx.node_ty(pat.id);
demand::eqtype(fcx, pat.span, expected, pat_ty);
+
let real_path_ty = fcx.node_ty(pat.id);
let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
ty::ty_enum(enum_def_id, expected_substs)
return true;
}
}
+
+pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>,
+ impl_c: &ty::AssociatedConst<'tcx>,
+ impl_c_span: Span,
+ trait_c: &ty::AssociatedConst<'tcx>,
+ impl_trait_ref: &ty::TraitRef<'tcx>) {
+ debug!("compare_const_impl(impl_trait_ref={})",
+ impl_trait_ref.repr(tcx));
+
+ let infcx = infer::new_infer_ctxt(tcx);
+ let mut fulfillment_cx = traits::FulfillmentContext::new();
+
+ // The below is for the most part highly similar to the procedure
+ // for methods above. It is simpler in many respects, especially
+ // because we shouldn't really have to deal with lifetimes or
+ // predicates. In fact some of this should probably be put into
+ // shared functions because of DRY violations...
+ let trait_to_impl_substs = &impl_trait_ref.substs;
+
+ // Create a parameter environment that represents the implementation's
+ // method.
+ let impl_param_env =
+ ty::ParameterEnvironment::for_item(tcx, impl_c.def_id.node);
+
+ // Create mapping from impl to skolemized.
+ let impl_to_skol_substs = &impl_param_env.free_substs;
+
+ // Create mapping from trait to skolemized.
+ let trait_to_skol_substs =
+ trait_to_impl_substs
+ .subst(tcx, impl_to_skol_substs)
+ .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
+ impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
+ debug!("compare_const_impl: trait_to_skol_substs={}",
+ trait_to_skol_substs.repr(tcx));
+
+ // Compute skolemized form of impl and trait const tys.
+ let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
+ let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs);
+
+ let err = infcx.commit_if_ok(|_| {
+ let origin = infer::Misc(impl_c_span);
+
+ // There is no "body" here, so just pass dummy id.
+ let impl_ty =
+ assoc::normalize_associated_types_in(&infcx,
+ &impl_param_env,
+ &mut fulfillment_cx,
+ impl_c_span,
+ 0,
+ &impl_ty);
+ debug!("compare_const_impl: impl_ty={}",
+ impl_ty.repr(tcx));
+
+ let trait_ty =
+ assoc::normalize_associated_types_in(&infcx,
+ &impl_param_env,
+ &mut fulfillment_cx,
+ impl_c_span,
+ 0,
+ &trait_ty);
+ debug!("compare_const_impl: trait_ty={}",
+ trait_ty.repr(tcx));
+
+ infer::mk_subty(&infcx, false, origin, impl_ty, trait_ty)
+ });
+
+ match err {
+ Ok(()) => { }
+ Err(terr) => {
+ debug!("checking associated const for compatibility: impl ty {}, trait ty {}",
+ impl_ty.repr(tcx),
+ trait_ty.repr(tcx));
+ span_err!(tcx.sess, impl_c_span, E0326,
+ "implemented const `{}` has an incompatible type for \
+ trait: {}",
+ token::get_name(trait_c.name),
+ ty::type_err_to_str(tcx, &terr));
+ return;
+ }
+ }
+}
ty::Predicate::Trait(ty::Binder(ref t_pred)) => {
let def_id = t_pred.trait_ref.def_id;
match rcx.tcx().lang_items.to_builtin_kind(def_id) {
+ // Issue 24895: deliberately do not include `BoundCopy` here.
Some(ty::BoundSend) |
Some(ty::BoundSized) |
- Some(ty::BoundCopy) |
Some(ty::BoundSync) => false,
_ => true,
}
self.add_obligations(&pick, &all_substs, &method_predicates);
// Create the final `MethodCallee`.
+ let method_ty = pick.item.as_opt_method().unwrap();
let fty = ty::mk_bare_fn(self.tcx(), None, self.tcx().mk_bare_fn(ty::BareFnTy {
sig: ty::Binder(method_sig),
- unsafety: pick.method_ty.fty.unsafety,
- abi: pick.method_ty.fty.abi.clone(),
+ unsafety: method_ty.fty.unsafety,
+ abi: method_ty.fty.abi.clone(),
}));
let callee = MethodCallee {
origin: method_origin,
"impl {:?} is not an inherent impl", impl_def_id);
let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id);
- (impl_polytype.substs, MethodStatic(pick.method_ty.def_id))
+ (impl_polytype.substs, MethodStatic(pick.item.def_id()))
}
probe::ObjectPick(trait_def_id, method_num, vtable_index) => {
// If they were not explicitly supplied, just construct fresh
// variables.
let num_supplied_types = supplied_method_types.len();
- let num_method_types = pick.method_ty.generics.types.len(subst::FnSpace);
+ let num_method_types = pick.item.as_opt_method().unwrap()
+ .generics.types.len(subst::FnSpace);
let method_types = {
if num_supplied_types == 0 {
self.fcx.infcx().next_ty_vars(num_method_types)
let method_regions =
self.fcx.infcx().region_vars_for_defs(
self.span,
- pick.method_ty.generics.regions.get_slice(subst::FnSpace));
+ pick.item.as_opt_method().unwrap()
+ .generics.regions.get_slice(subst::FnSpace));
(method_types, method_regions)
}
// Instantiate the bounds on the method with the
// type/early-bound-regions substitutions performed. There can
// be no late-bound regions appearing here.
- let method_predicates = pick.method_ty.predicates.instantiate(self.tcx(), &all_substs);
+ let method_predicates = pick.item.as_opt_method().unwrap()
+ .predicates.instantiate(self.tcx(), &all_substs);
let method_predicates = self.fcx.normalize_associated_types_in(self.span,
&method_predicates);
// NB: Instantiate late-bound regions first so that
// `instantiate_type_scheme` can normalize associated types that
// may reference those regions.
- let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.method_ty.fty.sig);
+ let method_sig = self.replace_late_bound_regions_with_fresh_var(
+ &pick.item.as_opt_method().unwrap().fty.sig);
debug!("late-bound lifetimes from method instantiated, method_sig={}",
method_sig.repr(self.tcx()));
fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
// Disallow calls to the method `drop` defined in the `Drop` trait.
- match pick.method_ty.container {
+ match pick.item.container() {
ty::TraitContainer(trait_def_id) => {
callee::check_legal_trait_for_method_call(self.fcx.ccx, self.span, trait_def_id)
}
// potential calls to it will wind up in the other
// arm. But just to be sure, check that the method id
// does not appear in the list of destructors.
- assert!(!self.tcx().destructors.borrow().contains(&pick.method_ty.def_id));
+ assert!(!self.tcx().destructors.borrow().contains(&pick.item.def_id()));
}
}
}
TraitSource(/* trait id */ ast::DefId),
}
-type MethodIndex = usize; // just for doc purposes
+type ItemIndex = usize; // just for doc purposes
/// Determines whether the type `self_ty` supports a method name `method_name` or not.
pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
{
let mode = probe::Mode::Path;
let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
- let def_id = pick.method_ty.def_id;
+ let def_id = pick.item.def_id();
let mut lp = LastMod(AllPublic);
let provenance = match pick.kind {
probe::InherentImplPick(impl_def_id) => {
- if pick.method_ty.vis != ast::Public {
+ if pick.item.vis() != ast::Public {
lp = LastMod(DependsOn(def_id));
}
def::FromImpl(impl_def_id)
}
- _ => def::FromTrait(pick.method_ty.container.id())
+ _ => def::FromTrait(pick.item.container().id())
};
- Ok((def::DefMethod(def_id, provenance), lp))
+ let def_result = match pick.item {
+ ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id, provenance),
+ ImplOrTraitItem::ConstTraitItem(..) => def::DefAssociatedConst(def_id, provenance),
+ ImplOrTraitItem::TypeTraitItem(..) => {
+ fcx.tcx().sess.span_bug(span, "resolve_ufcs: probe picked associated type");
+ }
+ };
+ Ok((def_result, lp))
}
// except according to those terms.
use super::MethodError;
-use super::MethodIndex;
+use super::ItemIndex;
use super::{CandidateSource,ImplSource,TraitSource};
use super::suggest;
fcx: &'a FnCtxt<'a, 'tcx>,
span: Span,
mode: Mode,
- method_name: ast::Name,
+ item_name: ast::Name,
steps: Rc<Vec<CandidateStep<'tcx>>>,
opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>,
inherent_candidates: Vec<Candidate<'tcx>>,
struct Candidate<'tcx> {
xform_self_ty: Ty<'tcx>,
- method_ty: Rc<ty::Method<'tcx>>,
+ item: ty::ImplOrTraitItem<'tcx>,
kind: CandidateKind<'tcx>,
}
InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>),
ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ usize, /* vtable index */ usize),
ExtensionImplCandidate(/* Impl */ ast::DefId, Rc<ty::TraitRef<'tcx>>,
- subst::Substs<'tcx>, MethodIndex),
- ClosureCandidate(/* Trait */ ast::DefId, MethodIndex),
- WhereClauseCandidate(ty::PolyTraitRef<'tcx>, MethodIndex),
- ProjectionCandidate(ast::DefId, MethodIndex),
+ subst::Substs<'tcx>, ItemIndex),
+ ClosureCandidate(/* Trait */ ast::DefId, ItemIndex),
+ WhereClauseCandidate(ty::PolyTraitRef<'tcx>, ItemIndex),
+ ProjectionCandidate(ast::DefId, ItemIndex),
}
pub struct Pick<'tcx> {
- pub method_ty: Rc<ty::Method<'tcx>>,
+ pub item: ty::ImplOrTraitItem<'tcx>,
pub kind: PickKind<'tcx>,
// Indicates that the source expression should be autoderef'd N times
pub enum PickKind<'tcx> {
InherentImplPick(/* Impl */ ast::DefId),
ObjectPick(/* Trait */ ast::DefId, /* method_num */ usize, /* real_index */ usize),
- ExtensionImplPick(/* Impl */ ast::DefId, MethodIndex),
- TraitPick(/* Trait */ ast::DefId, MethodIndex),
- WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, MethodIndex),
+ ExtensionImplPick(/* Impl */ ast::DefId, ItemIndex),
+ TraitPick(/* Trait */ ast::DefId, ItemIndex),
+ WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, ItemIndex),
}
pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError>;
-#[derive(PartialEq, Eq, Copy, Clone)]
+#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum Mode {
// An expression of the form `receiver.method_name(...)`.
// Autoderefs are performed on `receiver`, lookup is done based on the
// `self` argument of the method, and static methods aren't considered.
MethodCall,
- // An expression of the form `Type::method` or `<T>::method`.
+ // An expression of the form `Type::item` or `<T>::item`.
// No autoderefs are performed, lookup is done based on the type each
// implementation is for, and static methods are included.
Path
pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
mode: Mode,
- method_name: ast::Name,
+ item_name: ast::Name,
self_ty: Ty<'tcx>,
scope_expr_id: ast::NodeId)
-> PickResult<'tcx>
{
- debug!("probe(self_ty={}, method_name={}, scope_expr_id={})",
+ debug!("probe(self_ty={}, item_name={}, scope_expr_id={})",
self_ty.repr(fcx.tcx()),
- method_name,
+ item_name,
scope_expr_id);
// FIXME(#18741) -- right now, creating the steps involves evaluating the
let mut probe_cx = ProbeContext::new(fcx,
span,
mode,
- method_name,
+ item_name,
steps,
opt_simplified_steps);
probe_cx.assemble_inherent_candidates();
fn new(fcx: &'a FnCtxt<'a,'tcx>,
span: Span,
mode: Mode,
- method_name: ast::Name,
+ item_name: ast::Name,
steps: Vec<CandidateStep<'tcx>>,
opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>)
-> ProbeContext<'a,'tcx>
fcx: fcx,
span: span,
mode: mode,
- method_name: method_name,
+ item_name: item_name,
inherent_candidates: Vec::new(),
extension_candidates: Vec::new(),
impl_dups: HashSet::new(),
debug!("assemble_inherent_impl_probe {:?}", impl_def_id);
- let method = match impl_method(self.tcx(), impl_def_id, self.method_name) {
+ let item = match impl_item(self.tcx(), impl_def_id, self.item_name) {
Some(m) => m,
None => { return; } // No method with correct name on this impl
};
- if !self.has_applicable_self(&*method) {
+ if !self.has_applicable_self(&item) {
// No receiver declared. Not a candidate.
return self.record_static_candidate(ImplSource(impl_def_id));
}
// Determine the receiver type that the method itself expects.
let xform_self_ty =
- self.xform_self_ty(&method, impl_ty, &impl_substs);
+ self.xform_self_ty(&item, impl_ty, &impl_substs);
self.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
- method_ty: method,
+ item: item,
kind: InherentImplCandidate(impl_def_id, impl_substs)
});
}
// itself. Hence, a `&self` method will wind up with an
// argument type like `&Trait`.
let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), self_ty);
- self.elaborate_bounds(&[trait_ref.clone()], |this, new_trait_ref, m, method_num| {
+ self.elaborate_bounds(&[trait_ref.clone()], |this, new_trait_ref, item, item_num| {
let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
let vtable_index =
traits::get_vtable_index_of_object_method(tcx,
trait_ref.clone(),
new_trait_ref.def_id,
- method_num);
+ item_num);
- let xform_self_ty = this.xform_self_ty(&m,
+ let xform_self_ty = this.xform_self_ty(&item,
new_trait_ref.self_ty(),
new_trait_ref.substs);
this.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
- method_ty: m,
- kind: ObjectCandidate(new_trait_ref.def_id, method_num, vtable_index)
+ item: item,
+ kind: ObjectCandidate(new_trait_ref.def_id, item_num, vtable_index)
});
});
}
})
.collect();
- self.elaborate_bounds(&bounds, |this, poly_trait_ref, m, method_num| {
+ self.elaborate_bounds(&bounds, |this, poly_trait_ref, item, item_num| {
let trait_ref =
this.erase_late_bound_regions(&poly_trait_ref);
let xform_self_ty =
- this.xform_self_ty(&m,
+ this.xform_self_ty(&item,
trait_ref.self_ty(),
trait_ref.substs);
- debug!("found match: trait_ref={} substs={} m={}",
- trait_ref.repr(this.tcx()),
- trait_ref.substs.repr(this.tcx()),
- m.repr(this.tcx()));
- assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
- trait_ref.substs.types.get_slice(subst::TypeSpace).len());
- assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
- trait_ref.substs.regions().get_slice(subst::TypeSpace).len());
- assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
- trait_ref.substs.types.get_slice(subst::SelfSpace).len());
- assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
- trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
+ if let Some(ref m) = item.as_opt_method() {
+ debug!("found match: trait_ref={} substs={} m={}",
+ trait_ref.repr(this.tcx()),
+ trait_ref.substs.repr(this.tcx()),
+ m.repr(this.tcx()));
+ assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
+ trait_ref.substs.types.get_slice(subst::TypeSpace).len());
+ assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
+ trait_ref.substs.regions().get_slice(subst::TypeSpace).len());
+ assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
+ trait_ref.substs.types.get_slice(subst::SelfSpace).len());
+ assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
+ trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
+ }
// Because this trait derives from a where-clause, it
// should not contain any inference variables or other
this.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
- method_ty: m,
- kind: WhereClauseCandidate(poly_trait_ref, method_num)
+ item: item,
+ kind: WhereClauseCandidate(poly_trait_ref, item_num)
});
});
}
F: for<'b> FnMut(
&mut ProbeContext<'b, 'tcx>,
ty::PolyTraitRef<'tcx>,
- Rc<ty::Method<'tcx>>,
+ ty::ImplOrTraitItem<'tcx>,
usize,
),
{
let tcx = self.tcx();
for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
- let (pos, method) = match trait_method(tcx,
- bound_trait_ref.def_id(),
- self.method_name) {
+ let (pos, item) = match trait_item(tcx,
+ bound_trait_ref.def_id(),
+ self.item_name) {
Some(v) => v,
None => { continue; }
};
- if !self.has_applicable_self(&*method) {
+ if !self.has_applicable_self(&item) {
self.record_static_candidate(TraitSource(bound_trait_ref.def_id()));
} else {
- mk_cand(self, bound_trait_ref, method, pos);
+ mk_cand(self, bound_trait_ref, item, pos);
}
}
}
ty::trait_items(self.tcx(), trait_def_id);
let matching_index =
trait_items.iter()
- .position(|item| item.name() == self.method_name);
+ .position(|item| item.name() == self.item_name);
let matching_index = match matching_index {
Some(i) => i,
None => { return Ok(()); }
};
- let method = match (&*trait_items)[matching_index].as_opt_method() {
- Some(m) => m,
- None => { return Ok(()); }
- };
+ let ref item = (&*trait_items)[matching_index];
// Check whether `trait_def_id` defines a method with suitable name:
- if !self.has_applicable_self(&*method) {
+ if !self.has_applicable_self(item) {
debug!("method has inapplicable self");
self.record_static_candidate(TraitSource(trait_def_id));
return Ok(());
}
self.assemble_extension_candidates_for_trait_impls(trait_def_id,
- method.clone(),
+ item.clone(),
matching_index);
try!(self.assemble_closure_candidates(trait_def_id,
- method.clone(),
+ item.clone(),
matching_index));
self.assemble_projection_candidates(trait_def_id,
- method.clone(),
+ item.clone(),
matching_index);
self.assemble_where_clause_candidates(trait_def_id,
- method,
+ item.clone(),
matching_index);
Ok(())
fn assemble_extension_candidates_for_trait_impls(&mut self,
trait_def_id: ast::DefId,
- method: Rc<ty::Method<'tcx>>,
- method_index: usize)
+ item: ty::ImplOrTraitItem<'tcx>,
+ item_index: usize)
{
ty::populate_implementations_for_trait_if_necessary(self.tcx(),
trait_def_id);
// Determine the receiver type that the method itself expects.
let xform_self_ty =
- self.xform_self_ty(&method,
+ self.xform_self_ty(&item,
impl_trait_ref.self_ty(),
impl_trait_ref.substs);
self.extension_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
- method_ty: method.clone(),
- kind: ExtensionImplCandidate(impl_def_id, impl_trait_ref, impl_substs, method_index)
+ item: item.clone(),
+ kind: ExtensionImplCandidate(impl_def_id, impl_trait_ref, impl_substs, item_index)
});
}
}
fn assemble_closure_candidates(&mut self,
trait_def_id: ast::DefId,
- method_ty: Rc<ty::Method<'tcx>>,
- method_index: usize)
+ item: ty::ImplOrTraitItem<'tcx>,
+ item_index: usize)
-> Result<(),MethodError>
{
// Check if this is one of the Fn,FnMut,FnOnce traits.
&trait_def.generics,
step.self_ty);
- let xform_self_ty = self.xform_self_ty(&method_ty,
+ let xform_self_ty = self.xform_self_ty(&item,
step.self_ty,
&substs);
self.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
- method_ty: method_ty.clone(),
- kind: ClosureCandidate(trait_def_id, method_index)
+ item: item.clone(),
+ kind: ClosureCandidate(trait_def_id, item_index)
});
}
fn assemble_projection_candidates(&mut self,
trait_def_id: ast::DefId,
- method: Rc<ty::Method<'tcx>>,
- method_index: usize)
+ item: ty::ImplOrTraitItem<'tcx>,
+ item_index: usize)
{
debug!("assemble_projection_candidates(\
trait_def_id={}, \
- method={}, \
- method_index={})",
+ item={}, \
+ item_index={})",
trait_def_id.repr(self.tcx()),
- method.repr(self.tcx()),
- method_index);
+ item.repr(self.tcx()),
+ item_index);
for step in &*self.steps {
debug!("assemble_projection_candidates: step={}",
bound.repr(self.tcx()));
if self.infcx().can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
- let xform_self_ty = self.xform_self_ty(&method,
+ let xform_self_ty = self.xform_self_ty(&item,
bound.self_ty(),
bound.substs);
self.extension_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
- method_ty: method.clone(),
- kind: ProjectionCandidate(trait_def_id, method_index)
+ item: item.clone(),
+ kind: ProjectionCandidate(trait_def_id, item_index)
});
}
}
fn assemble_where_clause_candidates(&mut self,
trait_def_id: ast::DefId,
- method_ty: Rc<ty::Method<'tcx>>,
- method_index: usize)
+ item: ty::ImplOrTraitItem<'tcx>,
+ item_index: usize)
{
debug!("assemble_where_clause_candidates(trait_def_id={})",
trait_def_id.repr(self.tcx()));
.filter(|b| b.def_id() == trait_def_id)
{
let bound = self.erase_late_bound_regions(&poly_bound);
- let xform_self_ty = self.xform_self_ty(&method_ty,
+ let xform_self_ty = self.xform_self_ty(&item,
bound.self_ty(),
bound.substs);
self.extension_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
- method_ty: method_ty.clone(),
- kind: WhereClauseCandidate(poly_bound, method_index)
+ item: item.clone(),
+ kind: WhereClauseCandidate(poly_bound, item_index)
});
}
}
try!(self.assemble_extension_candidates_for_all_traits());
let out_of_scope_traits = match self.pick_core() {
- Some(Ok(p)) => vec![p.method_ty.container.id()],
+ Some(Ok(p)) => vec![p.item.container().id()],
Some(Err(MethodError::Ambiguity(v))) => v.into_iter().map(|source| {
match source {
TraitSource(id) => id,
}
// If so, just use this trait and call it a day.
- let (trait_def_id, method_num) = trait_data;
- let method_ty = probes[0].method_ty.clone();
+ let (trait_def_id, item_num) = trait_data;
+ let item = probes[0].item.clone();
Some(Pick {
- method_ty: method_ty,
- kind: TraitPick(trait_def_id, method_num),
+ item: item,
+ kind: TraitPick(trait_def_id, item_num),
autoderefs: 0,
autoref: None,
unsize: None
self.infcx().sub_types(false, infer::Misc(DUMMY_SP), sub, sup)
}
- fn has_applicable_self(&self, method: &ty::Method) -> bool {
+ fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool {
// "fast track" -- check for usage of sugar
- match method.explicit_self {
- ty::StaticExplicitSelfCategory => {
- if self.mode == Mode::Path {
- return true;
- }
- }
- ty::ByValueExplicitSelfCategory |
- ty::ByReferenceExplicitSelfCategory(..) |
- ty::ByBoxExplicitSelfCategory => {
- return true;
- }
+ match *item {
+ ty::ImplOrTraitItem::MethodTraitItem(ref method) =>
+ match method.explicit_self {
+ ty::StaticExplicitSelfCategory => self.mode == Mode::Path,
+ ty::ByValueExplicitSelfCategory |
+ ty::ByReferenceExplicitSelfCategory(..) |
+ ty::ByBoxExplicitSelfCategory => true,
+ },
+ ty::ImplOrTraitItem::ConstTraitItem(..) => self.mode == Mode::Path,
+ _ => false,
}
-
// FIXME -- check for types that deref to `Self`,
// like `Rc<Self>` and so on.
//
// Note also that the current code will break if this type
// includes any of the type parameters defined on the method
// -- but this could be overcome.
- return false;
}
fn record_static_candidate(&mut self, source: CandidateSource) {
}
fn xform_self_ty(&self,
- method: &Rc<ty::Method<'tcx>>,
+ item: &ty::ImplOrTraitItem<'tcx>,
impl_ty: Ty<'tcx>,
substs: &subst::Substs<'tcx>)
-> Ty<'tcx>
+ {
+ match item.as_opt_method() {
+ Some(ref method) => self.xform_method_self_ty(method, impl_ty,
+ substs),
+ None => impl_ty,
+ }
+ }
+
+ fn xform_method_self_ty(&self,
+ method: &Rc<ty::Method<'tcx>>,
+ impl_ty: Ty<'tcx>,
+ substs: &subst::Substs<'tcx>)
+ -> Ty<'tcx>
{
debug!("xform_self_ty(impl_ty={}, self_ty={}, substs={})",
impl_ty.repr(self.tcx()),
}
}
-fn impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
- impl_def_id: ast::DefId,
- method_name: ast::Name)
- -> Option<Rc<ty::Method<'tcx>>>
+fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>,
+ impl_def_id: ast::DefId,
+ item_name: ast::Name)
+ -> Option<ty::ImplOrTraitItem<'tcx>>
{
let impl_items = tcx.impl_items.borrow();
let impl_items = impl_items.get(&impl_def_id).unwrap();
impl_items
.iter()
.map(|&did| ty::impl_or_trait_item(tcx, did.def_id()))
- .find(|m| m.name() == method_name)
- .and_then(|item| item.as_opt_method())
+ .find(|item| item.name() == item_name)
}
-/// Find method with name `method_name` defined in `trait_def_id` and return it, along with its
-/// index (or `None`, if no such method).
-fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>,
- trait_def_id: ast::DefId,
- method_name: ast::Name)
- -> Option<(usize, Rc<ty::Method<'tcx>>)>
+/// Find item with name `item_name` defined in `trait_def_id` and return it,
+/// along with its index (or `None`, if no such item).
+fn trait_item<'tcx>(tcx: &ty::ctxt<'tcx>,
+ trait_def_id: ast::DefId,
+ item_name: ast::Name)
+ -> Option<(usize, ty::ImplOrTraitItem<'tcx>)>
{
let trait_items = ty::trait_items(tcx, trait_def_id);
debug!("trait_method; items: {:?}", trait_items);
trait_items
.iter()
.enumerate()
- .find(|&(_, ref item)| item.name() == method_name)
- .and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m)))
+ .find(|&(_, ref item)| item.name() == item_name)
+ .map(|(num, ref item)| (num, (*item).clone()))
}
impl<'tcx> Candidate<'tcx> {
fn to_unadjusted_pick(&self) -> Pick<'tcx> {
Pick {
- method_ty: self.method_ty.clone(),
+ item: self.item.clone(),
kind: match self.kind {
InherentImplCandidate(def_id, _) => {
InherentImplPick(def_id)
}
- ObjectCandidate(def_id, method_num, real_index) => {
- ObjectPick(def_id, method_num, real_index)
+ ObjectCandidate(def_id, item_num, real_index) => {
+ ObjectPick(def_id, item_num, real_index)
}
ExtensionImplCandidate(def_id, _, _, index) => {
ExtensionImplPick(def_id, index)
}
}
- fn to_trait_data(&self) -> Option<(ast::DefId,MethodIndex)> {
+ fn to_trait_data(&self) -> Option<(ast::DefId, ItemIndex)> {
match self.kind {
InherentImplCandidate(..) => {
None
}
- ObjectCandidate(trait_def_id, method_num, _) => {
- Some((trait_def_id, method_num))
+ ObjectCandidate(trait_def_id, item_num, _) => {
+ Some((trait_def_id, item_num))
}
- ClosureCandidate(trait_def_id, method_num) => {
- Some((trait_def_id, method_num))
+ ClosureCandidate(trait_def_id, item_num) => {
+ Some((trait_def_id, item_num))
}
- ExtensionImplCandidate(_, ref trait_ref, _, method_num) => {
- Some((trait_ref.def_id, method_num))
+ ExtensionImplCandidate(_, ref trait_ref, _, item_num) => {
+ Some((trait_ref.def_id, item_num))
}
- WhereClauseCandidate(ref trait_ref, method_num) => {
- Some((trait_ref.def_id(), method_num))
+ WhereClauseCandidate(ref trait_ref, item_num) => {
+ Some((trait_ref.def_id(), item_num))
}
- ProjectionCandidate(trait_def_id, method_num) => {
- Some((trait_def_id, method_num))
+ ProjectionCandidate(trait_def_id, item_num) => {
+ Some((trait_def_id, item_num))
}
}
}
impl<'tcx> Repr<'tcx> for Pick<'tcx> {
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("Pick(method_ty={}, autoderefs={},
+ format!("Pick(item={}, autoderefs={},
autoref={}, unsize={}, kind={:?})",
- self.method_ty.repr(tcx),
+ self.item.repr(tcx),
self.autoderefs,
self.autoref.repr(tcx),
self.unsize.repr(tcx),
pub use self::LvaluePreference::*;
pub use self::Expectation::*;
-pub use self::compare_method::compare_impl_method;
+pub use self::compare_method::{compare_impl_method, compare_const_impl};
use self::TupleArgumentsFlag::*;
use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode};
for impl_item in impl_items {
match impl_item.node {
+ ast::ConstImplItem(_, ref expr) => {
+ check_const(ccx, impl_item.span, &*expr, impl_item.id)
+ }
ast::MethodImplItem(ref sig, ref body) => {
check_method_body(ccx, &impl_pty.generics, sig, body,
impl_item.id, impl_item.span);
let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
for trait_item in trait_items {
match trait_item.node {
- ast::MethodTraitItem(_, None) => {
- // Nothing to do, since required methods don't have
- // bodies to check.
+ ast::ConstTraitItem(_, Some(ref expr)) => {
+ check_const(ccx, trait_item.span, &*expr, trait_item.id)
}
ast::MethodTraitItem(ref sig, Some(ref body)) => {
check_method_body(ccx, &trait_def.generics, sig, body,
trait_item.id, trait_item.span);
}
+ ast::ConstTraitItem(_, None) |
+ ast::MethodTraitItem(_, None) |
ast::TypeTraitItem(..) => {
// Nothing to do.
}
// and compatible with trait signature
for impl_item in impl_items {
match impl_item.node {
+ ast::ConstImplItem(..) => {
+ let impl_const_def_id = local_def(impl_item.id);
+ let impl_const_ty = ty::impl_or_trait_item(ccx.tcx,
+ impl_const_def_id);
+
+ // Find associated const definition.
+ let opt_associated_const =
+ trait_items.iter()
+ .find(|ac| ac.name() == impl_const_ty.name());
+ match opt_associated_const {
+ Some(associated_const) => {
+ match (associated_const, &impl_const_ty) {
+ (&ty::ConstTraitItem(ref const_trait),
+ &ty::ConstTraitItem(ref const_impl)) => {
+ compare_const_impl(ccx.tcx,
+ &const_impl,
+ impl_item.span,
+ &const_trait,
+ &*impl_trait_ref);
+ }
+ _ => {
+ span_err!(tcx.sess, impl_item.span, E0323,
+ "item `{}` is an associated const, \
+ which doesn't match its trait `{}`",
+ token::get_name(impl_const_ty.name()),
+ impl_trait_ref.repr(tcx))
+ }
+ }
+ }
+ None => {
+ // This is `span_bug` as it should have already been
+ // caught in resolve.
+ tcx.sess.span_bug(
+ impl_item.span,
+ &format!(
+ "associated const `{}` is not a member of \
+ trait `{}`",
+ token::get_name(impl_const_ty.name()),
+ impl_trait_ref.repr(tcx)));
+ }
+ }
+ }
ast::MethodImplItem(_, ref body) => {
let impl_method_def_id = local_def(impl_item.id);
let impl_item_ty = ty::impl_or_trait_item(ccx.tcx,
&*impl_trait_ref);
}
_ => {
- // This is span_bug as it should have already been
- // caught in resolve.
- tcx.sess.span_bug(
- impl_item.span,
- &format!("item `{}` is of a different kind from its trait `{}`",
- token::get_name(impl_item_ty.name()),
- impl_trait_ref.repr(tcx)));
+ span_err!(tcx.sess, impl_item.span, E0324,
+ "item `{}` is an associated method, \
+ which doesn't match its trait `{}`",
+ token::get_name(impl_item_ty.name()),
+ impl_trait_ref.repr(tcx))
}
}
}
match (associated_type, &typedef_ty) {
(&ty::TypeTraitItem(_), &ty::TypeTraitItem(_)) => {}
_ => {
- // This is `span_bug` as it should have
- // already been caught in resolve.
- tcx.sess.span_bug(
- impl_item.span,
- &format!("item `{}` is of a different kind from its trait `{}`",
- token::get_name(typedef_ty.name()),
- impl_trait_ref.repr(tcx)));
+ span_err!(tcx.sess, impl_item.span, E0325,
+ "item `{}` is an associated type, \
+ which doesn't match its trait `{}`",
+ token::get_name(typedef_ty.name()),
+ impl_trait_ref.repr(tcx))
}
}
}
// Check for missing items from trait
let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id);
+ let associated_consts = ty::associated_consts(tcx, impl_trait_ref.def_id);
let mut missing_methods = Vec::new();
for trait_item in &*trait_items {
match *trait_item {
+ ty::ConstTraitItem(ref associated_const) => {
+ let is_implemented = impl_items.iter().any(|ii| {
+ match ii.node {
+ ast::ConstImplItem(..) => {
+ ii.ident.name == associated_const.name
+ }
+ _ => false,
+ }
+ });
+ let is_provided =
+ associated_consts.iter().any(|ac| ac.default.is_some() &&
+ ac.name == associated_const.name);
+ if !is_implemented && !is_provided {
+ missing_methods.push(format!("`{}`",
+ token::get_name(associated_const.name)));
+ }
+ }
ty::MethodTraitItem(ref trait_method) => {
let is_implemented =
impl_items.iter().any(|ii| {
ast::MethodImplItem(..) => {
ii.ident.name == trait_method.name
}
- ast::TypeImplItem(_) |
- ast::MacImplItem(_) => false,
+ _ => false,
}
});
let is_provided =
ast::TypeImplItem(_) => {
ii.ident.name == associated_type.name
}
- ast::MethodImplItem(..) |
- ast::MacImplItem(_) => false,
+ _ => false,
}
});
if !is_implemented {
&format!("unbound path {}", expr.repr(tcx)))
};
- let def = path_res.base_def;
- if path_res.depth == 0 {
+ if let Some((opt_ty, segments, def)) =
+ resolve_ty_and_def_ufcs(fcx, path_res, opt_self_ty, path,
+ expr.span, expr.id) {
let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx,
expr.span,
def);
instantiate_path(fcx,
- &path.segments,
+ segments,
scheme,
&predicates,
- opt_self_ty,
+ opt_ty,
def,
expr.span,
id);
- } else {
- let ty_segments = path.segments.init();
- let base_ty_end = path.segments.len() - path_res.depth;
- let ty = astconv::finish_resolving_def_to_ty(fcx,
- fcx,
- expr.span,
- PathParamMode::Optional,
- &def,
- opt_self_ty,
- &ty_segments[..base_ty_end],
- &ty_segments[base_ty_end..]);
- let method_segment = path.segments.last().unwrap();
- let method_name = method_segment.identifier.name;
- match method::resolve_ufcs(fcx, expr.span, method_name, ty, id) {
- Ok((def, lp)) => {
- // Write back the new resolution.
- tcx.def_map.borrow_mut().insert(id, def::PathResolution {
- base_def: def,
- last_private: path_res.last_private.or(lp),
- depth: 0
- });
-
- let (scheme, predicates) =
- type_scheme_and_predicates_for_def(fcx, expr.span, def);
- instantiate_path(fcx, slice::ref_slice(method_segment),
- scheme, &predicates,
- Some(ty), def, expr.span, id);
- }
- Err(error) => {
- method::report_error(fcx, expr.span, ty,
- method_name, None, error);
- fcx.write_error(id);
- }
- }
}
// We always require that the type provided as the value for
unifier();
}
+pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
+ path_res: def::PathResolution,
+ opt_self_ty: Option<Ty<'tcx>>,
+ path: &'a ast::Path,
+ span: Span,
+ node_id: ast::NodeId)
+ -> Option<(Option<Ty<'tcx>>,
+ &'a [ast::PathSegment],
+ def::Def)>
+{
+ // If fully resolved already, we don't have to do anything.
+ if path_res.depth == 0 {
+ Some((opt_self_ty, &path.segments, path_res.base_def))
+ } else {
+ let mut def = path_res.base_def;
+ let ty_segments = path.segments.init();
+ let base_ty_end = path.segments.len() - path_res.depth;
+ let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, span,
+ PathParamMode::Optional,
+ &mut def,
+ opt_self_ty,
+ &ty_segments[..base_ty_end],
+ &ty_segments[base_ty_end..]);
+ let item_segment = path.segments.last().unwrap();
+ let item_name = item_segment.identifier.name;
+ match method::resolve_ufcs(fcx, span, item_name, ty, node_id) {
+ Ok((def, lp)) => {
+ // Write back the new resolution.
+ fcx.ccx.tcx.def_map.borrow_mut()
+ .insert(node_id, def::PathResolution {
+ base_def: def,
+ last_private: path_res.last_private.or(lp),
+ depth: 0
+ });
+ Some((Some(ty), slice::ref_slice(item_segment), def))
+ }
+ Err(error) => {
+ method::report_error(fcx, span, ty,
+ item_name, None, error);
+ fcx.write_error(node_id);
+ None
+ }
+ }
+ }
+}
+
fn constrain_path_type_parameters(fcx: &FnCtxt,
expr: &ast::Expr)
{
}
def::DefFn(id, _) | def::DefMethod(id, _) |
def::DefStatic(id, _) | def::DefVariant(_, id, _) |
- def::DefStruct(id) | def::DefConst(id) => {
+ def::DefStruct(id) | def::DefConst(id) | def::DefAssociatedConst(id, _) => {
(ty::lookup_item_type(fcx.tcx(), id), ty::lookup_predicates(fcx.tcx(), id))
}
def::DefTrait(_) |
// Luckily, we can (at least for now) deduce the intermediate steps
// just from the end-point.
//
- // There are basically three cases to consider:
+ // There are basically four cases to consider:
//
// 1. Reference to a *type*, such as a struct or enum:
//
// `SomeStruct::<A>`, contains parameters in TypeSpace, and the
// final segment, `foo::<B>` contains parameters in fn space.
//
+ // 4. Reference to an *associated const*:
+ //
+ // impl<A> AnotherStruct<A> {
+ // const FOO: B = BAR;
+ // }
+ //
+ // The path in this case will look like
+ // `a::b::AnotherStruct::<A>::FOO`, so the penultimate segment
+ // only will have parameters in TypeSpace.
+ //
// The first step then is to categorize the segments appropriately.
assert!(!segments.is_empty());
}
}
+ def::DefAssociatedConst(_, provenance) => {
+ match provenance {
+ def::FromTrait(trait_did) => {
+ callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did)
+ }
+ def::FromImpl(_) => {}
+ }
+
+ if segments.len() >= 2 {
+ segment_spaces = repeat(None).take(segments.len() - 2).collect();
+ segment_spaces.push(Some(subst::TypeSpace));
+ segment_spaces.push(None);
+ } else {
+ segment_spaces = vec![None];
+ }
+ }
+
// Other cases. Various nonsense that really shouldn't show up
// here. If they do, an error will have been reported
// elsewhere. (I hope)
use metadata::csearch;
use middle::subst::{self, Subst};
use middle::ty::RegionEscape;
-use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId};
-use middle::ty::{ParameterEnvironment, TypeTraitItemId, lookup_item_type};
+use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId};
+use middle::ty::{MethodTraitItemId, TypeTraitItemId};
+use middle::ty::{ParameterEnvironment, lookup_item_type};
use middle::ty::{Ty, ty_bool, ty_char, ty_enum, ty_err};
use middle::ty::{ty_param, TypeScheme, ty_ptr};
use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
let mut items: Vec<ImplOrTraitItemId> =
impl_items.iter().map(|impl_item| {
match impl_item.node {
+ ast::ConstImplItem(..) => {
+ ConstTraitItemId(local_def(impl_item.id))
+ }
ast::MethodImplItem(..) => {
MethodTraitItemId(local_def(impl_item.id))
}
.insert(item_def_id.def_id(), source);
}
}
- ty::TypeTraitItem(_) => {}
+ _ => {}
}
}
let def_id = local_def(method_id);
match *self.tcx.impl_or_trait_items.borrow().get(&def_id).unwrap() {
ty::MethodTraitItem(ref mty) => mty.clone(),
- ty::TypeTraitItem(..) => {
+ _ => {
self.tcx.sess.bug(&format!("method with id {} has the wrong type", method_id));
}
}
}
}
+fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+ container: ImplOrTraitItemContainer,
+ ident: ast::Ident,
+ id: ast::NodeId,
+ vis: ast::Visibility,
+ ty: ty::Ty<'tcx>,
+ default: Option<&ast::Expr>)
+{
+ ccx.tcx.predicates.borrow_mut().insert(local_def(id),
+ ty::GenericPredicates::empty());
+
+ write_ty_to_tcx(ccx.tcx, id, ty);
+ let default_id = default.map(|expr| local_def(expr.id));
+
+ let associated_const = Rc::new(ty::AssociatedConst {
+ name: ident.name,
+ vis: vis,
+ def_id: local_def(id),
+ container: container,
+ ty: ty,
+ default: default_id,
+ });
+ ccx.tcx.impl_or_trait_items.borrow_mut()
+ .insert(local_def(id), ty::ConstTraitItem(associated_const));
+}
+
fn as_refsociated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- container: ImplOrTraitItemContainer,
- ident: ast::Ident,
- id: ast::NodeId,
- vis: ast::Visibility)
+ container: ImplOrTraitItemContainer,
+ ident: ast::Ident,
+ id: ast::NodeId,
+ vis: ast::Visibility)
{
let associated_type = Rc::new(ty::AssociatedType {
name: ident.name,
it.vis
};
- // Convert all the associated types.
+ // Convert all the associated consts.
for impl_item in impl_items {
- match impl_item.node {
- ast::TypeImplItem(ref ty) => {
- if opt_trait_ref.is_none() {
- span_err!(tcx.sess, impl_item.span, E0202,
- "associated items are not allowed in inherent impls");
- }
-
- as_refsociated_type(ccx, ImplContainer(local_def(it.id)),
- impl_item.ident, impl_item.id, impl_item.vis);
+ if let ast::ConstImplItem(ref ty, ref expr) = impl_item.node {
+ let ty = ccx.icx(&ty_predicates)
+ .to_ty(&ExplicitRscope, &*ty);
+ tcx.tcache.borrow_mut().insert(local_def(impl_item.id),
+ TypeScheme {
+ generics: ty_generics.clone(),
+ ty: ty,
+ });
+ convert_associated_const(ccx, ImplContainer(local_def(it.id)),
+ impl_item.ident, impl_item.id,
+ impl_item.vis.inherit_from(parent_visibility),
+ ty, Some(&*expr));
+ }
+ }
- let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
- tcx.tcache.borrow_mut().insert(local_def(impl_item.id),
- TypeScheme {
- generics: ty::Generics::empty(),
- ty: typ,
- });
- tcx.predicates.borrow_mut().insert(local_def(impl_item.id),
- ty::GenericPredicates::empty());
- write_ty_to_tcx(tcx, impl_item.id, typ);
+ // Convert all the associated types.
+ for impl_item in impl_items {
+ if let ast::TypeImplItem(ref ty) = impl_item.node {
+ if opt_trait_ref.is_none() {
+ span_err!(tcx.sess, impl_item.span, E0202,
+ "associated items are not allowed in inherent impls");
}
- ast::MethodImplItem(..) |
- ast::MacImplItem(_) => {}
+
+ as_refsociated_type(ccx, ImplContainer(local_def(it.id)),
+ impl_item.ident, impl_item.id, impl_item.vis);
+
+ let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
+ tcx.tcache.borrow_mut().insert(local_def(impl_item.id),
+ TypeScheme {
+ generics: ty::Generics::empty(),
+ ty: typ,
+ });
+ tcx.predicates.borrow_mut().insert(local_def(impl_item.id),
+ ty::GenericPredicates::empty());
+ write_ty_to_tcx(tcx, impl_item.id, typ);
}
}
let methods = impl_items.iter().filter_map(|ii| {
- match ii.node {
- ast::MethodImplItem(ref sig, _) => {
- // if the method specifies a visibility, use that, otherwise
- // inherit the visibility from the impl (so `foo` in `pub impl
- // { fn foo(); }` is public, but private in `priv impl { fn
- // foo(); }`).
- let method_vis = ii.vis.inherit_from(parent_visibility);
- Some((sig, ii.id, ii.ident, method_vis, ii.span))
- }
- ast::TypeImplItem(_) |
- ast::MacImplItem(_) => None
+ if let ast::MethodImplItem(ref sig, _) = ii.node {
+ // if the method specifies a visibility, use that, otherwise
+ // inherit the visibility from the impl (so `foo` in `pub impl
+ // { fn foo(); }` is public, but private in `priv impl { fn
+ // foo(); }`).
+ let method_vis = ii.vis.inherit_from(parent_visibility);
+ Some((sig, ii.id, ii.ident, method_vis, ii.span))
+ } else {
+ None
}
});
convert_methods(ccx,
&ty_predicates);
for impl_item in impl_items {
- match impl_item.node {
- ast::MethodImplItem(ref sig, ref body) => {
- let body_id = body.id;
- check_method_self_type(ccx,
- &BindingRscope::new(),
- ccx.method_ty(impl_item.id),
- selfty,
- &sig.explicit_self,
- body_id);
- }
- ast::TypeImplItem(_) |
- ast::MacImplItem(_) => {}
+ if let ast::MethodImplItem(ref sig, ref body) = impl_item.node {
+ let body_id = body.id;
+ check_method_self_type(ccx,
+ &BindingRscope::new(),
+ ccx.method_ty(impl_item.id),
+ selfty,
+ &sig.explicit_self,
+ body_id);
}
}
// Convert all the associated types.
for trait_item in trait_items {
match trait_item.node {
- ast::MethodTraitItem(..) => {}
+ ast::ConstTraitItem(ref ty, ref default) => {
+ let ty = ccx.icx(&trait_predicates)
+ .to_ty(&ExplicitRscope, ty);
+ tcx.tcache.borrow_mut().insert(local_def(trait_item.id),
+ TypeScheme {
+ generics: trait_def.generics.clone(),
+ ty: ty,
+ });
+ convert_associated_const(ccx, TraitContainer(local_def(it.id)),
+ trait_item.ident, trait_item.id,
+ ast::Public, ty, default.as_ref().map(|d| &**d));
+ }
+ _ => {}
+ }
+ };
+
+ // Convert all the associated types.
+ for trait_item in trait_items {
+ match trait_item.node {
ast::TypeTraitItem(..) => {
as_refsociated_type(ccx, TraitContainer(local_def(it.id)),
trait_item.ident, trait_item.id, ast::Public);
}
+ _ => {}
}
};
let methods = trait_items.iter().filter_map(|ti| {
let sig = match ti.node {
ast::MethodTraitItem(ref sig, _) => sig,
- ast::TypeTraitItem(..) => return None,
+ _ => return None,
};
Some((sig, ti.id, ti.ident, ast::Inherited, ti.span))
});
let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| {
let def_id = local_def(trait_item.id);
match trait_item.node {
+ ast::ConstTraitItem(..) => {
+ ty::ConstTraitItemId(def_id)
+ }
ast::MethodTraitItem(..) => {
ty::MethodTraitItemId(def_id)
}
for trait_item in trait_items {
let sig = match trait_item.node {
ast::MethodTraitItem(ref sig, _) => sig,
- ast::TypeTraitItem(..) => continue
+ _ => continue
};
check_method_self_type(ccx,
&BindingRscope::new(),
let associated_type_names: Vec<_> = items.iter().filter_map(|trait_item| {
match trait_item.node {
- ast::MethodTraitItem(..) => None,
ast::TypeTraitItem(..) => Some(trait_item.ident.name),
+ _ => None,
}
}).collect();
trait_items.iter().any(|trait_item| {
match trait_item.node {
ast::TypeTraitItem(..) => trait_item.ident.name == assoc_name,
- ast::MethodTraitItem(..) => false,
+ _ => false,
}
})
}
trait_items.iter().flat_map(|trait_item| {
let bounds = match trait_item.node {
ast::TypeTraitItem(ref bounds, _) => bounds,
- ast::MethodTraitItem(..) => {
+ _ => {
return vec!().into_iter();
}
};
impl_items.iter()
.filter_map(|item| match item.node {
ast::TypeImplItem(..) => Some(ty::node_id_to_type(tcx, item.id)),
- ast::MethodImplItem(..) | ast::MacImplItem(..) => None,
+ ast::ConstImplItem(..) | ast::MethodImplItem(..) |
+ ast::MacImplItem(..) => None,
})
.flat_map(|ty| ctp::parameters_for_type(ty).into_iter())
.filter_map(|p| match p {
E0320, // recursive overflow during dropck
E0321, // extended coherence rules for defaulted traits violated
E0322, // cannot implement Sized explicitly
+ E0323, // implemented an associated const when another trait item expected
+ E0324, // implemented a method when another trait item expected
+ E0325, // implemented an associated type when another trait item expected
+ E0326, // associated const implemented with different type from trait
+ E0327, // referred to method instead of constant in match pattern
E0366, // dropck forbid specialization to concrete type or region
E0367, // dropck forbid specialization to predicate not in struct/enum
E0368, // binary operation `<op>=` cannot be applied to types
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
-#![feature(unsafe_destructor)]
#![feature(staged_api)]
#[macro_use] extern crate log;
use rustc::middle::ty;
use rustc::middle::subst;
use rustc::middle::stability;
+use rustc::middle::const_eval;
use core::DocContext;
use doctree;
use clean;
-use super::Clean;
+use super::{Clean, ToSource};
/// Attempt to inline the definition of a local node id into this AST.
///
record_extern_fqn(cx, did, clean::TypeStatic);
clean::StaticItem(build_static(cx, tcx, did, mtbl))
}
- def::DefConst(did) => {
+ def::DefConst(did) | def::DefAssociatedConst(did, _) => {
record_extern_fqn(cx, did, clean::TypeConst);
clean::ConstantItem(build_const(cx, tcx, did))
}
let did = did.def_id();
let impl_item = ty::impl_or_trait_item(tcx, did);
match impl_item {
+ ty::ConstTraitItem(ref assoc_const) => {
+ let did = assoc_const.def_id;
+ let type_scheme = ty::lookup_item_type(tcx, did);
+ let default = match assoc_const.default {
+ Some(_) => Some(const_eval::lookup_const_by_id(tcx, did, None)
+ .unwrap().span.to_src(cx)),
+ None => None,
+ };
+ Some(clean::Item {
+ name: Some(assoc_const.name.clean(cx)),
+ inner: clean::AssociatedConstItem(
+ type_scheme.ty.clean(cx),
+ default,
+ ),
+ source: clean::Span::empty(),
+ attrs: vec![],
+ visibility: None,
+ stability: stability::lookup(tcx, did).clean(cx),
+ def_id: did
+ })
+ }
ty::MethodTraitItem(method) => {
if method.vis != ast::Public && associated_trait.is_none() {
return None
use rustc::middle::const_eval;
use syntax::print::pprust;
- let expr = const_eval::lookup_const_by_id(tcx, did).unwrap_or_else(|| {
+ let expr = const_eval::lookup_const_by_id(tcx, did, None).unwrap_or_else(|| {
panic!("expected lookup_const_by_id to succeed for {:?}", did);
});
debug!("converting constant expr {:?} to snippet", expr);
ForeignStaticItem(Static),
MacroItem(Macro),
PrimitiveItem(PrimitiveType),
+ AssociatedConstItem(Type, Option<String>),
AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
DefaultImplItem(DefaultImpl),
}
impl Clean<Item> for ast::TraitItem {
fn clean(&self, cx: &DocContext) -> Item {
let inner = match self.node {
+ ast::ConstTraitItem(ref ty, ref default) => {
+ AssociatedConstItem(ty.clean(cx),
+ default.as_ref().map(|expr|
+ expr.span.to_src(cx)))
+ }
ast::MethodTraitItem(ref sig, Some(_)) => {
MethodItem(sig.clean(cx))
}
impl Clean<Item> for ast::ImplItem {
fn clean(&self, cx: &DocContext) -> Item {
let inner = match self.node {
+ ast::ConstImplItem(ref ty, ref expr) => {
+ ConstantItem(Constant{
+ type_: ty.clean(cx),
+ expr: expr.span.to_src(cx),
+ })
+ }
ast::MethodImplItem(ref sig, _) => {
MethodItem(sig.clean(cx))
}
impl<'tcx> Clean<Item> for ty::ImplOrTraitItem<'tcx> {
fn clean(&self, cx: &DocContext) -> Item {
match *self {
+ ty::ConstTraitItem(ref cti) => cti.clean(cx),
ty::MethodTraitItem(ref mti) => mti.clean(cx),
ty::TypeTraitItem(ref tti) => tti.clean(cx),
}
PatWild(PatWildMulti) => "..".to_string(),
PatIdent(_, ref p, _) => token::get_ident(p.node).to_string(),
PatEnum(ref p, _) => path_to_string(p),
+ PatQPath(..) => panic!("tried to get argument name from PatQPath, \
+ which is not allowed in function arguments"),
PatStruct(ref name, ref fields, etc) => {
format!("{} {{ {}{} }}", path_to_string(name),
fields.iter().map(|&Spanned { node: ref fp, .. }|
}
}
+impl<'tcx> Clean<Item> for ty::AssociatedConst<'tcx> {
+ fn clean(&self, cx: &DocContext) -> Item {
+ Item {
+ source: DUMMY_SP.clean(cx),
+ name: Some(self.name.clean(cx)),
+ attrs: Vec::new(),
+ inner: AssociatedConstItem(self.ty.clean(cx), None),
+ visibility: None,
+ def_id: self.def_id,
+ stability: None,
+ }
+ }
+}
+
impl Clean<Item> for ty::AssociatedType {
fn clean(&self, cx: &DocContext) -> Item {
// When loading a cross-crate associated type, the bounds for this type
Primitive = 15,
AssociatedType = 16,
Constant = 17,
+ AssociatedConst = 18,
}
impl ItemType {
clean::ForeignStaticItem(..) => ItemType::Static, // no ForeignStatic
clean::MacroItem(..) => ItemType::Macro,
clean::PrimitiveItem(..) => ItemType::Primitive,
+ clean::AssociatedConstItem(..) => ItemType::AssociatedConst,
clean::AssociatedTypeItem(..) => ItemType::AssociatedType,
clean::DefaultImplItem(..) => ItemType::Impl,
}
ItemType::Primitive => "primitive",
ItemType::AssociatedType => "associatedtype",
ItemType::Constant => "constant",
+ ItemType::AssociatedConst => "associatedconstant",
}
}
}
try!(write!(fmt, "<span class='out-of-band'>"));
try!(write!(fmt,
r##"<span id='render-detail'>
- <a id="toggle-all-docs" href="#" title="collapse all docs">[-]</a>
+ <a id="toggle-all-docs" href="#" title="collapse all docs">[−]</a>
</span>"##));
// Write `src` tag
ItemType::Macro => ("macros", "Macros"),
ItemType::Primitive => ("primitives", "Primitive Types"),
ItemType::AssociatedType => ("associated-types", "Associated Types"),
+ ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
};
try!(write!(w,
"<h2 id='{id}' class='section-header'>\
try!(write!(w, "{{\n"));
for t in &types {
try!(write!(w, " "));
- try!(render_method(w, t, MethodLink::Anchor));
+ try!(render_assoc_item(w, t, AssocItemLink::Anchor));
try!(write!(w, ";\n"));
}
if !types.is_empty() && !required.is_empty() {
}
for m in &required {
try!(write!(w, " "));
- try!(render_method(w, m, MethodLink::Anchor));
+ try!(render_assoc_item(w, m, AssocItemLink::Anchor));
try!(write!(w, ";\n"));
}
if !required.is_empty() && !provided.is_empty() {
}
for m in &provided {
try!(write!(w, " "));
- try!(render_method(w, m, MethodLink::Anchor));
+ try!(render_assoc_item(w, m, AssocItemLink::Anchor));
try!(write!(w, " {{ ... }}\n"));
}
try!(write!(w, "}}"));
ty = shortty(m),
name = *m.name.as_ref().unwrap(),
stab = m.stability_class()));
- try!(render_method(w, m, MethodLink::Anchor));
+ try!(render_assoc_item(w, m, AssocItemLink::Anchor));
try!(write!(w, "</code></h3>"));
try!(document(w, m));
Ok(())
}
// If there are methods directly on this trait object, render them here.
- try!(render_methods(w, it.def_id, MethodRender::All));
+ try!(render_assoc_items(w, it.def_id, AssocItemRender::All));
let cache = cache();
try!(write!(w, "
Ok(())
}
+fn assoc_const(w: &mut fmt::Formatter, it: &clean::Item,
+ ty: &clean::Type, default: &Option<String>)
+ -> fmt::Result {
+ try!(write!(w, "const {}", it.name.as_ref().unwrap()));
+ try!(write!(w, ": {}", ty));
+ if let Some(ref default) = *default {
+ try!(write!(w, " = {}", default));
+ }
+ Ok(())
+}
+
fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
bounds: &Vec<clean::TyParamBound>,
default: &Option<clean::Type>)
Ok(())
}
-fn render_method(w: &mut fmt::Formatter, meth: &clean::Item,
- link: MethodLink) -> fmt::Result {
+fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item,
+ link: AssocItemLink) -> fmt::Result {
fn method(w: &mut fmt::Formatter, it: &clean::Item,
unsafety: ast::Unsafety, abi: abi::Abi,
g: &clean::Generics, selfty: &clean::SelfTy,
- d: &clean::FnDecl, link: MethodLink) -> fmt::Result {
+ d: &clean::FnDecl, link: AssocItemLink) -> fmt::Result {
use syntax::abi::Abi;
let name = it.name.as_ref().unwrap();
let anchor = format!("#{}.{}", shortty(it), name);
let href = match link {
- MethodLink::Anchor => anchor,
- MethodLink::GotoSource(did) => {
+ AssocItemLink::Anchor => anchor,
+ AssocItemLink::GotoSource(did) => {
href(did).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
}
};
method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl,
link)
}
+ clean::AssociatedConstItem(ref ty, ref default) => {
+ assoc_const(w, meth, ty, default)
+ }
clean::AssociatedTypeItem(ref bounds, ref default) => {
assoc_type(w, meth, bounds, default)
}
- _ => panic!("render_method called on non-method")
+ _ => panic!("render_assoc_item called on non-associated-item")
}
}
try!(write!(w, "</table>"));
}
}
- render_methods(w, it.def_id, MethodRender::All)
+ render_assoc_items(w, it.def_id, AssocItemRender::All)
}
fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
try!(write!(w, "</table>"));
}
- try!(render_methods(w, it.def_id, MethodRender::All));
+ try!(render_assoc_items(w, it.def_id, AssocItemRender::All));
Ok(())
}
}
#[derive(Copy, Clone)]
-enum MethodLink {
+enum AssocItemLink {
Anchor,
GotoSource(ast::DefId),
}
-enum MethodRender<'a> {
+enum AssocItemRender<'a> {
All,
DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type },
}
-fn render_methods(w: &mut fmt::Formatter,
- it: ast::DefId,
- what: MethodRender) -> fmt::Result {
+fn render_assoc_items(w: &mut fmt::Formatter,
+ it: ast::DefId,
+ what: AssocItemRender) -> fmt::Result {
let c = cache();
let v = match c.impls.get(&it) {
Some(v) => v,
});
if !non_trait.is_empty() {
let render_header = match what {
- MethodRender::All => {
+ AssocItemRender::All => {
try!(write!(w, "<h2 id='methods'>Methods</h2>"));
true
}
- MethodRender::DerefFor { trait_, type_ } => {
+ AssocItemRender::DerefFor { trait_, type_ } => {
try!(write!(w, "<h2 id='deref-methods'>Methods from \
{}<Target={}></h2>", trait_, type_));
false
}
};
for i in &non_trait {
- try!(render_impl(w, i, MethodLink::Anchor, render_header));
+ try!(render_impl(w, i, AssocItemLink::Anchor, render_header));
}
}
- if let MethodRender::DerefFor { .. } = what {
+ if let AssocItemRender::DerefFor { .. } = what {
return Ok(())
}
if !traits.is_empty() {
});
for i in &manual {
let did = i.trait_did().unwrap();
- try!(render_impl(w, i, MethodLink::GotoSource(did), true));
+ try!(render_impl(w, i, AssocItemLink::GotoSource(did), true));
}
if !derived.is_empty() {
try!(write!(w, "<h3 id='derived_implementations'>\
</h3>"));
for i in &derived {
let did = i.trait_did().unwrap();
- try!(render_impl(w, i, MethodLink::GotoSource(did), true));
+ try!(render_impl(w, i, AssocItemLink::GotoSource(did), true));
}
}
}
_ => None,
}
}).next().unwrap();
- let what = MethodRender::DerefFor { trait_: deref_type, type_: target };
+ let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target };
match *target {
- clean::ResolvedPath { did, .. } => render_methods(w, did, what),
+ clean::ResolvedPath { did, .. } => render_assoc_items(w, did, what),
_ => {
if let Some(prim) = target.primitive_type() {
if let Some(c) = cache().primitive_locations.get(&prim) {
let did = ast::DefId { krate: *c, node: prim.to_node_id() };
- try!(render_methods(w, did, what));
+ try!(render_assoc_items(w, did, what));
}
}
Ok(())
}
}
-fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink,
+fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: AssocItemLink,
render_header: bool) -> fmt::Result {
if render_header {
try!(write!(w, "<h3 class='impl'><code>impl{} ",
}
fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item,
- link: MethodLink) -> fmt::Result {
+ link: AssocItemLink) -> fmt::Result {
match item.inner {
clean::MethodItem(..) | clean::TyMethodItem(..) => {
try!(write!(w, "<h4 id='method.{}' class='{}'><code>",
*item.name.as_ref().unwrap(),
shortty(item)));
- try!(render_method(w, item, link));
+ try!(render_assoc_item(w, item, link));
try!(write!(w, "</code></h4>\n"));
}
clean::TypedefItem(ref tydef) => {
try!(write!(w, "type {} = {}", name, tydef.type_));
try!(write!(w, "</code></h4>\n"));
}
+ clean::AssociatedConstItem(ref ty, ref default) => {
+ let name = item.name.as_ref().unwrap();
+ try!(write!(w, "<h4 id='assoc_const.{}' class='{}'><code>",
+ *name,
+ shortty(item)));
+ try!(assoc_const(w, item, ty, default));
+ try!(write!(w, "</code></h4>\n"));
+ }
clean::AssociatedTypeItem(ref bounds, ref default) => {
let name = item.name.as_ref().unwrap();
try!(write!(w, "<h4 id='assoc_type.{}' class='{}'><code>",
}
_ => panic!("can't make docs for trait item with name {:?}", item.name)
}
- if let MethodLink::Anchor = link {
+ if let AssocItemLink::Anchor = link {
document(w, item)
} else {
Ok(())
try!(doctraititem(w, trait_item, link));
}
- fn render_default_methods(w: &mut fmt::Formatter,
- did: ast::DefId,
- t: &clean::Trait,
- i: &clean::Impl) -> fmt::Result {
+ fn render_default_items(w: &mut fmt::Formatter,
+ did: ast::DefId,
+ t: &clean::Trait,
+ i: &clean::Impl) -> fmt::Result {
for trait_item in &t.items {
let n = trait_item.name.clone();
match i.items.iter().find(|m| { m.name == n }) {
None => {}
}
- try!(doctraititem(w, trait_item, MethodLink::GotoSource(did)));
+ try!(doctraititem(w, trait_item, AssocItemLink::GotoSource(did)));
}
Ok(())
}
// for them work.
if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ {
if let Some(t) = cache().traits.get(&did) {
- try!(render_default_methods(w, did, t, &i.impl_));
+ try!(render_default_items(w, did, t, &i.impl_));
}
}
try!(write!(w, "</div>"));
it: &clean::Item,
_p: &clean::PrimitiveType) -> fmt::Result {
try!(document(w, it));
- render_methods(w, it.def_id, MethodRender::All)
+ render_assoc_items(w, it.def_id, AssocItemRender::All)
}
fn get_basic_keywords() -> &'static str {
text-decoration: underline;
}
-.content span.trait, .content a.trait, .block a.current.trait { color: #ed9603; }
+.content span.trait, .content a.trait, .block a.current.trait { color: #8866ff; }
.content span.mod, .content a.mod, block a.current.mod { color: #4d76ae; }
.content span.enum, .content a.enum, .block a.current.enum { color: #5e9766; }
.content span.struct, .content a.struct, .block a.current.struct { color: #e53700; }
$("#toggle-all-docs").on("click", function() {
var toggle = $("#toggle-all-docs");
- if (toggle.html() == "[-]") {
- toggle.html("[+]");
+ if (toggle.html() == "[−]") {
+ toggle.html("[+]");
toggle.attr("title", "expand all docs");
$(".docblock").hide();
$(".toggle-label").show();
$(".toggle-wrapper").addClass("collapsed");
- $(".collapse-toggle").children(".inner").html("+");
+ $(".collapse-toggle").children(".inner").html("+");
} else {
- toggle.html("[-]");
+ toggle.html("[−]");
toggle.attr("title", "collapse all docs");
$(".docblock").show();
$(".toggle-label").hide();
$(".toggle-wrapper").removeClass("collapsed");
- $(".collapse-toggle").children(".inner").html("-");
+ $(".collapse-toggle").children(".inner").html("−");
}
});
if (relatedDoc.is(":visible")) {
relatedDoc.slideUp({duration:'fast', easing:'linear'});
toggle.parent(".toggle-wrapper").addClass("collapsed");
- toggle.children(".inner").html("+");
+ toggle.children(".inner").html("+");
toggle.children(".toggle-label").fadeIn();
} else {
relatedDoc.slideDown({duration:'fast', easing:'linear'});
toggle.parent(".toggle-wrapper").removeClass("collapsed");
- toggle.children(".inner").html("-");
+ toggle.children(".inner").html("−");
toggle.children(".toggle-label").hide();
}
}
$(function() {
var toggle = $("<a/>", {'href': 'javascript:void(0)', 'class': 'collapse-toggle'})
- .html("[<span class='inner'>-</span>]");
+ .html("[<span class='inner'>−</span>]");
$(".method").each(function() {
if ($(this).next().is(".docblock") ||
// Primitives are never stripped
clean::PrimitiveItem(..) => {}
- // Associated types are never stripped
+ // Associated consts and types are never stripped
+ clean::AssociatedConstItem(..) |
clean::AssociatedTypeItem(..) => {}
}
fn len(&self) -> usize { self.table.size() }
}
-#[unsafe_destructor]
impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> {
fn drop(&mut self) {
for _ in self.by_ref() {}
}
}
-#[unsafe_destructor]
impl<K, V> Drop for RawTable<K, V> {
fn drop(&mut self) {
if self.capacity == 0 || self.capacity == mem::POST_DROP_USIZE {
use path::Path;
#[test]
- #[cfg_attr(any(windows, target_os = "android"), ignore)] // FIXME #8818, #10379
+ #[cfg_attr(any(windows,
+ target_os = "android", // FIXME #10379
+ target_env = "musl"), ignore)]
fn test_loading_cosine() {
// The math library does not need to be loaded since it is already
// statically linked in
}
}
-#[unsafe_destructor]
impl<W: Write> Drop for BufWriter<W> {
fn drop(&mut self) {
if self.inner.is_some() {
where F: FnOnce(&mut Vec<u8>) -> Result<usize>
{
struct Guard<'a> { s: &'a mut Vec<u8>, len: usize }
- #[unsafe_destructor]
- impl<'a> Drop for Guard<'a> {
+ impl<'a> Drop for Guard<'a> {
fn drop(&mut self) {
unsafe { self.s.set_len(self.len); }
}
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(unicode)]
-#![feature(unsafe_destructor)]
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(macro_reexport)]
#![feature(unique)]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable]
-#[cfg(stage0)]
-macro_rules! panic {
- () => ({
- panic!("explicit panic")
- });
- ($msg:expr) => ({
- $crate::rt::begin_unwind($msg, {
- // static requires less code at runtime, more constant data
- static _FILE_LINE: (&'static str, usize) = (file!(), line!() as usize);
- &_FILE_LINE
- })
- });
- ($fmt:expr, $($arg:tt)+) => ({
- $crate::rt::begin_unwind_fmt(format_args!($fmt, $($arg)+), {
- // The leading _'s are to avoid dead code warnings if this is
- // used inside a dead function. Just `#[allow(dead_code)]` is
- // insufficient, since the user may have
- // `#[forbid(dead_code)]` and which cannot be overridden.
- static _FILE_LINE: (&'static str, u32) = (file!(), line!());
- &_FILE_LINE
- })
- });
-}
-
/// The entry point for panic of Rust tasks.
///
/// This macro is used to inject panic into a Rust task, causing the task to
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable]
-#[cfg(not(stage0))]
macro_rules! panic {
() => ({
panic!("explicit panic")
use cell::RefCell;
use rt::{backtrace, unwind};
use sys::stdio::Stderr;
-use thread;
+use sys_common::thread_info;
thread_local! {
pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
}
};
let mut err = Stderr::new();
- let thread = thread::current();
- let name = thread.name().unwrap_or("<unnamed>");
+ let thread = thread_info::current_thread();
+ let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
match prev {
Some(mut stderr) => {
extern "C" fn(unwind_code: _Unwind_Reason_Code,
exception: *mut _Unwind_Exception);
-#[cfg(any(target_os = "linux", target_os = "freebsd"))]
+#[cfg(any(all(target_os = "linux", not(target_env = "musl")),
+ target_os = "freebsd"))]
#[link(name = "gcc_s")]
extern {}
+#[cfg(all(target_os = "linux", target_env = "musl", not(test)))]
+#[link(name = "unwind", kind = "static")]
+extern {}
+
#[cfg(any(target_os = "android", target_os = "openbsd"))]
#[link(name = "gcc")]
extern {}
/// This is the entry point of unwinding for panic!() and assert!().
#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
-#[cfg(stage0)]
-pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, usize)) -> ! {
- // Note that this should be the only allocation performed in this code path.
- // Currently this means that panic!() on OOM will invoke this code path,
- // but then again we're not really ready for panic on OOM anyway. If
- // we do start doing this, then we should propagate this allocation to
- // be performed in the parent of this thread instead of the thread that's
- // panicking.
-
- // see below for why we do the `Any` coercion here.
- let (file, line) = *file_line;
- begin_unwind_inner(Box::new(msg), &(file, line as u32))
-}
-
-/// This is the entry point of unwinding for panic!() and assert!().
-#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
-#[cfg(not(stage0))]
pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, u32)) -> ! {
// Note that this should be the only allocation performed in this code path.
// Currently this means that panic!() on OOM will invoke this code path,
//
// On Linux, librt and libdl are indirect dependencies via std,
// and binutils 2.22+ won't add them automatically
-#[cfg(target_os = "linux")]
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
#[link(name = "dl")]
#[link(name = "pthread")]
extern {}
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Sender<T> {
fn drop(&mut self) {
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for SyncSender<T> {
fn drop(&mut self) {
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Queue<T> {
fn drop(&mut self) {
}
}
-#[unsafe_destructor]
impl<T> Drop for Packet<T> {
fn drop(&mut self) {
assert_eq!(self.state.load(Ordering::SeqCst), DISCONNECTED);
}
}
-#[unsafe_destructor]
impl Drop for Select {
fn drop(&mut self) {
assert!(self.head.is_null());
}
}
-#[unsafe_destructor]
impl<'rx, T: Send> Drop for Handle<'rx, T> {
fn drop(&mut self) {
unsafe { self.remove() }
}
}
-#[unsafe_destructor]
impl<T> Drop for Packet<T> {
fn drop(&mut self) {
// Note that this load is not only an assert for correctness about
}
}
-#[unsafe_destructor]
impl<T> Drop for Queue<T> {
fn drop(&mut self) {
unsafe {
}
}
-#[unsafe_destructor]
impl<T> Drop for Packet<T> {
fn drop(&mut self) {
// Note that this load is not only an assert for correctness about
}
}
-#[unsafe_destructor]
impl<T> Drop for Packet<T> {
fn drop(&mut self) {
assert_eq!(self.channels.load(Ordering::SeqCst), 0);
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Mutex<T> {
fn drop(&mut self) {
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Drop for MutexGuard<'a, T> {
#[inline]
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for RwLock<T> {
fn drop(&mut self) {
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Drop for RwLockReadGuard<'a, T> {
fn drop(&mut self) {
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Drop for RwLockWriteGuard<'a, T> {
fn drop(&mut self) {
}
}
-#[unsafe_destructor]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Drop for SemaphoreGuard<'a> {
fn drop(&mut self) {
}
}
-#[unsafe_destructor]
impl<T> Drop for ReentrantMutex<T> {
fn drop(&mut self) {
// This is actually safe b/c we know that there is no further usage of
}
}
-#[unsafe_destructor]
impl<'a, T> Drop for ReentrantMutexGuard<'a, T> {
#[inline]
fn drop(&mut self) {
thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = RefCell::new(None) }
impl ThreadInfo {
- fn with<R, F>(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R {
+ fn with<R, F>(f: F) -> Option<R> where F: FnOnce(&mut ThreadInfo) -> R {
if THREAD_INFO.state() == LocalKeyState::Destroyed {
- panic!("Use of std::thread::current() is not possible after \
- the thread's local data has been destroyed");
+ return None
}
THREAD_INFO.with(move |c| {
thread: NewThread::new(None),
})
}
- f(c.borrow_mut().as_mut().unwrap())
+ Some(f(c.borrow_mut().as_mut().unwrap()))
})
}
}
-pub fn current_thread() -> Thread {
+pub fn current_thread() -> Option<Thread> {
ThreadInfo::with(|info| info.thread.clone())
}
-pub fn stack_guard() -> usize {
+pub fn stack_guard() -> Option<usize> {
ThreadInfo::with(|info| info.stack_guard)
}
// We're calling into functions with stack checks
stack::record_sp_limit(0);
- let guard = thread_info::stack_guard();
+ let guard = thread_info::stack_guard().unwrap_or(0);
let addr = (*info).si_addr as usize;
if guard == 0 || addr < guard - PAGE_SIZE || addr >= guard {
static mut __pthread_get_minstack: Option<F> = None;
INIT.call_once(|| {
- let lib = DynamicLibrary::open(None).unwrap();
+ let lib = match DynamicLibrary::open(None) {
+ Ok(l) => l,
+ Err(..) => return,
+ };
unsafe {
if let Ok(f) = lib.symbol("__pthread_get_minstack") {
__pthread_get_minstack = Some(mem::transmute::<*const (), F>(f));
// OpenBSD provide it via libc
#[cfg(not(any(target_os = "android",
target_os = "bitrig",
- target_os = "openbsd")))]
+ target_os = "openbsd",
+ target_env = "musl")))]
#[link(name = "rt")]
extern {}
// Sure wish we had macro hygiene, no?
#[doc(hidden)]
-#[unstable(feature = "thread_local_internals")]
pub mod __impl {
pub use super::imp::Key as KeyInner;
pub use super::imp::destroy_value;
// This is trivially devirtualizable by LLVM because we never store anything
// to this field and rustc can declare the `static` as constant as well.
#[doc(hidden)]
- #[unstable(feature = "thread_local_internals")]
pub inner: fn() -> &'static __impl::KeyInner<UnsafeCell<Option<T>>>,
// initialization routine to invoke to create a value
#[doc(hidden)]
- #[unstable(feature = "thread_local_internals")]
pub init: fn() -> T,
}
}
#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
+#[doc(hidden)]
mod imp {
use prelude::v1::*;
use intrinsics;
use ptr;
- #[doc(hidden)]
- #[unstable(feature = "thread_local_internals")]
pub struct Key<T> {
// Place the inner bits in an `UnsafeCell` to currently get around the
// "only Sync statics" restriction. This allows any type to be placed in
//
// Note that all access requires `T: 'static` so it can't be a type with
// any borrowed pointers still.
- #[unstable(feature = "thread_local_internals")]
pub inner: UnsafeCell<T>,
// Metadata to keep track of the state of the destructor. Remember that
// these variables are thread-local, not global.
- #[unstable(feature = "thread_local_internals")]
pub dtor_registered: UnsafeCell<bool>, // should be Cell
- #[unstable(feature = "thread_local_internals")]
pub dtor_running: UnsafeCell<bool>, // should be Cell
}
unsafe impl<T> ::marker::Sync for Key<T> { }
- #[doc(hidden)]
impl<T> Key<T> {
pub unsafe fn get(&'static self) -> Option<&'static T> {
if intrinsics::needs_drop::<T>() && *self.dtor_running.get() {
use sys_common::thread_local as os;
extern {
+ #[linkage = "extern_weak"]
static __dso_handle: *mut u8;
#[linkage = "extern_weak"]
static __cxa_thread_atexit_impl: *const ();
_tlv_atexit(dtor, t);
}
- #[doc(hidden)]
- #[unstable(feature = "thread_local_internals")]
pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
let ptr = ptr as *mut Key<T>;
// Right before we run the user destructor be sure to flag the
}
#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
+#[doc(hidden)]
mod imp {
use prelude::v1::*;
use ptr;
use sys_common::thread_local::StaticKey as OsStaticKey;
- #[doc(hidden)]
- #[unstable(feature = "thread_local_internals")]
pub struct Key<T> {
// Statically allocated initialization expression, using an `UnsafeCell`
// for the same reasons as above.
- #[unstable(feature = "thread_local_internals")]
pub inner: UnsafeCell<T>,
// OS-TLS key that we'll use to key off.
- #[unstable(feature = "thread_local_internals")]
pub os: OsStaticKey,
}
value: T,
}
- #[doc(hidden)]
impl<T> Key<T> {
pub unsafe fn get(&'static self) -> Option<&'static T> {
self.ptr().map(|p| &*p)
key: self,
value: mem::transmute_copy(&self.inner),
};
- let ptr: *mut Value<T> = boxed::into_raw(ptr);
+ let ptr = boxed::into_raw(ptr);
self.os.set(ptr as *mut u8);
Some(&mut (*ptr).value as *mut T)
}
}
- #[doc(hidden)]
- #[unstable(feature = "thread_local_internals")]
pub unsafe extern fn destroy_value<T: 'static>(ptr: *mut u8) {
// The OS TLS ensures that this key contains a NULL value when this
// destructor starts to run. We set it back to a sentinel value of 1 to
//
// Note that to prevent an infinite loop we reset it back to null right
// before we return from the destructor ourselves.
- let ptr: Box<Value<T>> = Box::from_raw(ptr as *mut Value<T>);
+ let ptr = Box::from_raw(ptr as *mut Value<T>);
let key = ptr.key;
key.os.set(1 as *mut u8);
drop(ptr);
//! ## Configuring threads
//!
//! A new thread can be configured before it is spawned via the `Builder` type,
-//! which currently allows you to set the name, stack size, and writers for
-//! `println!` and `panic!` for the child thread:
+//! which currently allows you to set the name and stack size for the child thread:
//!
//! ```rust
//! # #![allow(unused_must_use)]
/// Gets a handle to the thread that invokes it.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn current() -> Thread {
- thread_info::current_thread()
+ thread_info::current_thread().expect("use of std::thread::current() is not \
+ possible after the thread's local \
+ data has been destroyed")
}
/// Cooperatively gives up a timeslice to the OS scheduler.
}
}
-#[unsafe_destructor]
#[unstable(feature = "scoped",
reason = "memory unsafe if destructor is avoided, see #24292")]
impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> {
key: &'a __impl::KeyInner<T>,
val: *mut T,
}
- #[unsafe_destructor]
- impl<'a, T> Drop for Reset<'a, T> {
+ impl<'a, T> Drop for Reset<'a, T> {
fn drop(&mut self) {
unsafe { self.key.set(self.val) }
}
/// "None" means a * pattern where we don't bind the fields to names.
PatEnum(Path, Option<Vec<P<Pat>>>),
+ /// An associated const named using the qualified path `<T>::CONST` or
+ /// `<T as Trait>::CONST`. Associated consts from inherent impls can be
+ /// refered to as simply `T::CONST`, in which case they will end up as
+ /// PatEnum, and the resolver will have to sort that out.
+ PatQPath(QSelf, Path),
+
/// Destructuring of a struct, e.g. `Foo {x, y, ..}`
/// The `bool` is `true` in the presence of a `..`
PatStruct(Path, Vec<Spanned<FieldPat>>, bool),
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum TraitItem_ {
+ ConstTraitItem(P<Ty>, Option<P<Expr>>),
MethodTraitItem(MethodSig, Option<P<Block>>),
TypeTraitItem(TyParamBounds, Option<P<Ty>>),
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum ImplItem_ {
+ ConstImplItem(P<Ty>, P<Expr>),
MethodImplItem(MethodSig, P<Block>),
TypeImplItem(P<Ty>),
MacImplItem(Mac),
ast::MethodImplItem(ref sig, ref body) => {
method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span)
}
- ast::TypeImplItem(_) |
- ast::MacImplItem(_) => {
+ _ => {
panic!("impl method FnLikeNode that is not fn-like")
}
}
}
Some(NodeImplItem(ii)) => {
match ii.node {
+ ConstImplItem(..) => {
+ format!("assoc const {} in {}{}",
+ token::get_ident(ii.ident),
+ map.path_to_string(id),
+ id_str)
+ }
MethodImplItem(..) => {
format!("method {} in {}{}",
token::get_ident(ii.ident),
}
Some(NodeTraitItem(ti)) => {
let kind = match ti.node {
+ ConstTraitItem(..) => "assoc constant",
MethodTraitItem(..) => "trait method",
TypeTraitItem(..) => "assoc type",
-// ConstTraitItem(..) => "assoc constant"
};
format!("{} {} in {}{}",
}
PatMac(_) => panic!("attempted to analyze unexpanded pattern"),
PatWild(_) | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) |
- PatEnum(_, _) => {
+ PatEnum(_, _) | PatQPath(_, _) => {
true
}
}
("fundamental", "1.0.0", Active),
- // Deprecate after snapshot
- // SNAP 5520801
- ("unsafe_destructor", "1.0.0", Active),
-
// A temporary feature gate used to enable parser extensions needed
// to bootstrap fix for #5723.
("issue_5723_bootstrap", "1.0.0", Accepted),
// Allows use of unary negate on unsigned integers, e.g. -e for e: u8
("negate_unsigned", "1.0.0", Active),
+
+ // Allows the definition of associated constants in `trait` or `impl`
+ // blocks.
+ ("associated_consts", "1.0.0", Active),
];
// (changing above list without updating src/doc/reference.md makes @cmr sad)
("link_args", Normal),
("macro_escape", Normal),
- ("unsafe_destructor", Gated("unsafe_destructor",
- "`#[unsafe_destructor]` does nothing anymore")),
("staged_api", Gated("staged_api",
"staged_api is for use by rustc only")),
("plugin", Gated("plugin",
}
visit::walk_fn(self, fn_kind, fn_decl, block, span);
}
+
+ fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
+ match ti.node {
+ ast::ConstTraitItem(..) => {
+ self.gate_feature("associated_consts",
+ ti.span,
+ "associated constants are experimental")
+ }
+ _ => {}
+ }
+ visit::walk_trait_item(self, ti);
+ }
+
+ fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
+ match ii.node {
+ ast::ConstImplItem(..) => {
+ self.gate_feature("associated_consts",
+ ii.span,
+ "associated constants are experimental")
+ }
+ _ => {}
+ }
+ visit::walk_impl_item(self, ii);
+ }
}
fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
ident: folder.fold_ident(ident),
attrs: fold_attrs(attrs, folder),
node: match node {
+ ConstTraitItem(ty, default) => {
+ ConstTraitItem(folder.fold_ty(ty),
+ default.map(|x| folder.fold_expr(x)))
+ }
MethodTraitItem(sig, body) => {
MethodTraitItem(noop_fold_method_sig(sig, folder),
body.map(|x| folder.fold_block(x)))
attrs: fold_attrs(attrs, folder),
vis: vis,
node: match node {
+ ConstImplItem(ty, expr) => {
+ ConstImplItem(folder.fold_ty(ty), folder.fold_expr(expr))
+ }
MethodImplItem(sig, body) => {
MethodImplItem(noop_fold_method_sig(sig, folder),
folder.fold_block(body))
PatEnum(folder.fold_path(pth),
pats.map(|pats| pats.move_map(|x| folder.fold_pat(x))))
}
+ PatQPath(qself, pth) => {
+ let qself = QSelf {ty: folder.fold_ty(qself.ty), .. qself};
+ PatQPath(qself, folder.fold_path(pth))
+ }
PatStruct(pth, fields, etc) => {
let pth = folder.fold_path(pth);
let fs = fields.move_map(|f| {
use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, BiGt, Block};
use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause};
-use ast::{Crate, CrateConfig, Decl, DeclItem};
-use ast::{DeclLocal, DefaultBlock, DefaultReturn};
+use ast::{ConstImplItem, ConstTraitItem, Crate, CrateConfig};
+use ast::{Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn};
use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf};
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource};
use ast::{MutTy, BiMul, Mutability};
use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
-use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatMac, PatRange, PatRegion};
-use ast::{PatStruct, PatTup, PatVec, PatWild, PatWildMulti, PatWildSingle};
+use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange};
+use ast::{PatRegion, PatStruct, PatTup, PatVec, PatWild, PatWildMulti};
+use ast::PatWildSingle;
use ast::{PolyTraitRef, QSelf};
use ast::{Return, BiShl, BiShr, Stmt, StmtDecl};
use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
LifetimeAndTypesWithColons,
}
+/// How to parse a qualified path, whether to allow trailing parameters.
+#[derive(Copy, Clone, PartialEq)]
+pub enum QPathParsingMode {
+ /// No trailing parameters, e.g. `<T as Trait>::Item`
+ NoParameters,
+ /// Optional parameters, e.g. `<T as Trait>::item::<'a, U>`
+ MaybeParameters,
+}
+
/// How to parse a bound, whether to allow bound modifiers such as `?`.
#[derive(Copy, Clone, PartialEq)]
pub enum BoundParsingMode {
let TyParam {ident, bounds, default, ..} = try!(p.parse_ty_param());
try!(p.expect(&token::Semi));
(ident, TypeTraitItem(bounds, default))
+ } else if try!(p.eat_keyword(keywords::Const)) {
+ let ident = try!(p.parse_ident());
+ try!(p.expect(&token::Colon));
+ let ty = try!(p.parse_ty_sum());
+ let default = if p.check(&token::Eq) {
+ try!(p.bump());
+ let expr = try!(p.parse_expr_nopanic());
+ try!(p.commit_expr_expecting(&expr, token::Semi));
+ Some(expr)
+ } else {
+ try!(p.expect(&token::Semi));
+ None
+ };
+ (ident, ConstTraitItem(ty, default))
} else {
let style = try!(p.parse_unsafety());
let abi = if try!(p.eat_keyword(keywords::Extern)) {
try!(self.expect(&token::CloseDelim(token::Paren)));
TyTypeof(e)
} else if try!(self.eat_lt()) {
- // QUALIFIED PATH `<TYPE as TRAIT_REF>::item`
- let self_type = try!(self.parse_ty_sum());
- let mut path = if try!(self.eat_keyword(keywords::As) ){
- try!(self.parse_path(LifetimeAndTypesWithoutColons))
- } else {
- ast::Path {
- span: self.span,
- global: false,
- segments: vec![]
- }
- };
-
- let qself = QSelf {
- ty: self_type,
- position: path.segments.len()
- };
-
- try!(self.expect(&token::Gt));
- try!(self.expect(&token::ModSep));
-
- path.segments.push(ast::PathSegment {
- identifier: try!(self.parse_ident()),
- parameters: ast::PathParameters::none()
- });
-
- if path.segments.len() == 1 {
- path.span.lo = self.last_span.lo;
- }
- path.span.hi = self.last_span.hi;
+ let (qself, path) =
+ try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
TyPath(Some(qself), path)
} else if self.check(&token::ModSep) ||
}
}
+ // QUALIFIED PATH `<TYPE [as TRAIT_REF]>::IDENT[::<PARAMS>]`
+ // Assumes that the leading `<` has been parsed already.
+ pub fn parse_qualified_path(&mut self, mode: QPathParsingMode)
+ -> PResult<(QSelf, ast::Path)> {
+ let self_type = try!(self.parse_ty_sum());
+ let mut path = if try!(self.eat_keyword(keywords::As)) {
+ try!(self.parse_path(LifetimeAndTypesWithoutColons))
+ } else {
+ ast::Path {
+ span: self.span,
+ global: false,
+ segments: vec![]
+ }
+ };
+
+ let qself = QSelf {
+ ty: self_type,
+ position: path.segments.len()
+ };
+
+ try!(self.expect(&token::Gt));
+ try!(self.expect(&token::ModSep));
+
+ let item_name = try!(self.parse_ident());
+ let parameters = match mode {
+ QPathParsingMode::NoParameters => ast::PathParameters::none(),
+ QPathParsingMode::MaybeParameters => {
+ if try!(self.eat(&token::ModSep)) {
+ try!(self.expect_lt());
+ // Consumed `item::<`, go look for types
+ let (lifetimes, types, bindings) =
+ try!(self.parse_generic_values_after_lt());
+ ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
+ lifetimes: lifetimes,
+ types: OwnedSlice::from_vec(types),
+ bindings: OwnedSlice::from_vec(bindings),
+ })
+ } else {
+ ast::PathParameters::none()
+ }
+ }
+ };
+ path.segments.push(ast::PathSegment {
+ identifier: item_name,
+ parameters: parameters
+ });
+
+ if path.segments.len() == 1 {
+ path.span.lo = self.last_span.lo;
+ }
+ path.span.hi = self.last_span.hi;
+
+ Ok((qself, path))
+ }
+
/// Parses a path and optional type parameter bounds, depending on the
/// mode. The `mode` parameter determines whether lifetimes, types, and/or
/// bounds are permitted and whether `::` must precede type parameter
}
_ => {
if try!(self.eat_lt()){
- // QUALIFIED PATH `<TYPE as TRAIT_REF>::item::<'a, T>`
- let self_type = try!(self.parse_ty_sum());
- let mut path = if try!(self.eat_keyword(keywords::As) ){
- try!(self.parse_path(LifetimeAndTypesWithoutColons))
- } else {
- ast::Path {
- span: self.span,
- global: false,
- segments: vec![]
- }
- };
- let qself = QSelf {
- ty: self_type,
- position: path.segments.len()
- };
- try!(self.expect(&token::Gt));
- try!(self.expect(&token::ModSep));
-
- let item_name = try!(self.parse_ident());
- let parameters = if try!(self.eat(&token::ModSep) ){
- try!(self.expect_lt());
- // Consumed `item::<`, go look for types
- let (lifetimes, types, bindings) =
- try!(self.parse_generic_values_after_lt());
- ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
- lifetimes: lifetimes,
- types: OwnedSlice::from_vec(types),
- bindings: OwnedSlice::from_vec(bindings),
- })
- } else {
- ast::PathParameters::none()
- };
- path.segments.push(ast::PathSegment {
- identifier: item_name,
- parameters: parameters
- });
- if path.segments.len() == 1 {
- path.span.lo = self.last_span.lo;
- }
- path.span.hi = self.last_span.hi;
+ let (qself, path) =
+ try!(self.parse_qualified_path(QPathParsingMode::MaybeParameters));
- let hi = self.span.hi;
return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path)));
}
if try!(self.eat_keyword(keywords::Move) ){
fn parse_pat_range_end(&mut self) -> PResult<P<Expr>> {
if self.is_path_start() {
let lo = self.span.lo;
- let path = try!(self.parse_path(LifetimeAndTypesWithColons));
+ let (qself, path) = if try!(self.eat_lt()) {
+ // Parse a qualified path
+ let (qself, path) =
+ try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
+ (Some(qself), path)
+ } else {
+ // Parse an unqualified path
+ (None, try!(self.parse_path(LifetimeAndTypesWithColons)))
+ };
let hi = self.last_span.hi;
- Ok(self.mk_expr(lo, hi, ExprPath(None, path)))
+ Ok(self.mk_expr(lo, hi, ExprPath(qself, path)))
} else {
self.parse_literal_maybe_minus()
}
}
fn is_path_start(&self) -> bool {
- (self.token == token::ModSep || self.token.is_ident() || self.token.is_path())
+ (self.token == token::Lt || self.token == token::ModSep
+ || self.token.is_ident() || self.token.is_path())
&& !self.token.is_keyword(keywords::True) && !self.token.is_keyword(keywords::False)
}
pat = try!(self.parse_pat_ident(BindByValue(MutImmutable)));
}
} else {
- // Parse as a general path
- let path = try!(self.parse_path(LifetimeAndTypesWithColons));
+ let (qself, path) = if try!(self.eat_lt()) {
+ // Parse a qualified path
+ let (qself, path) =
+ try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
+ (Some(qself), path)
+ } else {
+ // Parse an unqualified path
+ (None, try!(self.parse_path(LifetimeAndTypesWithColons)))
+ };
match self.token {
token::DotDotDot => {
// Parse range
let hi = self.last_span.hi;
- let begin = self.mk_expr(lo, hi, ExprPath(None, path));
+ let begin = self.mk_expr(lo, hi, ExprPath(qself, path));
try!(self.bump());
let end = try!(self.parse_pat_range_end());
pat = PatRange(begin, end);
}
token::OpenDelim(token::Brace) => {
- // Parse struct pattern
+ if qself.is_some() {
+ let span = self.span;
+ self.span_err(span,
+ "unexpected `{` after qualified path");
+ self.abort_if_errors();
+ }
+ // Parse struct pattern
try!(self.bump());
let (fields, etc) = try!(self.parse_pat_fields());
try!(self.bump());
pat = PatStruct(path, fields, etc);
}
token::OpenDelim(token::Paren) => {
+ if qself.is_some() {
+ let span = self.span;
+ self.span_err(span,
+ "unexpected `(` after qualified path");
+ self.abort_if_errors();
+ }
// Parse tuple struct or enum pattern
if self.look_ahead(1, |t| *t == token::DotDot) {
// This is a "top constructor only" pat
pat = PatEnum(path, Some(args));
}
}
+ _ if qself.is_some() => {
+ // Parse qualified path
+ pat = PatQPath(qself.unwrap(), path);
+ }
_ => {
// Parse nullary enum
pat = PatEnum(path, Some(vec![]));
let typ = try!(self.parse_ty_sum());
try!(self.expect(&token::Semi));
(name, TypeImplItem(typ))
+ } else if try!(self.eat_keyword(keywords::Const)) {
+ let name = try!(self.parse_ident());
+ try!(self.expect(&token::Colon));
+ let typ = try!(self.parse_ty_sum());
+ try!(self.expect(&token::Eq));
+ let expr = try!(self.parse_expr_nopanic());
+ try!(self.commit_expr_expecting(&expr, token::Semi));
+ (name, ConstImplItem(typ, expr))
} else {
let (name, inner_attrs, node) = try!(self.parse_impl_method(vis));
attrs.extend(inner_attrs.into_iter());
}
}
+ fn print_associated_const(&mut self,
+ ident: ast::Ident,
+ ty: &ast::Ty,
+ default: Option<&ast::Expr>,
+ vis: ast::Visibility)
+ -> io::Result<()>
+ {
+ try!(word(&mut self.s, &visibility_qualified(vis, "")));
+ try!(self.word_space("const"));
+ try!(self.print_ident(ident));
+ try!(self.word_space(":"));
+ try!(self.print_type(ty));
+ if let Some(expr) = default {
+ try!(space(&mut self.s));
+ try!(self.word_space("="));
+ try!(self.print_expr(expr));
+ }
+ word(&mut self.s, ";")
+ }
+
fn print_associated_type(&mut self,
ident: ast::Ident,
bounds: Option<&ast::TyParamBounds>,
try!(self.maybe_print_comment(ti.span.lo));
try!(self.print_outer_attributes(&ti.attrs));
match ti.node {
+ ast::ConstTraitItem(ref ty, ref default) => {
+ try!(self.print_associated_const(ti.ident, &ty,
+ default.as_ref().map(|expr| &**expr),
+ ast::Inherited));
+ }
ast::MethodTraitItem(ref sig, ref body) => {
if body.is_some() {
try!(self.head(""));
try!(self.maybe_print_comment(ii.span.lo));
try!(self.print_outer_attributes(&ii.attrs));
match ii.node {
+ ast::ConstImplItem(ref ty, ref expr) => {
+ try!(self.print_associated_const(ii.ident, &ty, Some(&expr), ii.vis));
+ }
ast::MethodImplItem(ref sig, ref body) => {
try!(self.head(""));
try!(self.print_method_sig(ii.ident, sig, ii.vis));
}
}
}
+ ast::PatQPath(ref qself, ref path) => {
+ try!(self.print_qpath(path, qself, false));
+ }
ast::PatStruct(ref path, ref fields, etc) => {
try!(self.print_path(path, true, 0));
try!(self.nbsp());
}
}
}
+ PatQPath(ref qself, ref path) => {
+ visitor.visit_ty(&qself.ty);
+ visitor.visit_path(path, pattern.id)
+ }
PatStruct(ref path, ref fields, _) => {
visitor.visit_path(path, pattern.id);
for field in fields {
visitor.visit_attribute(attr);
}
match trait_item.node {
+ ConstTraitItem(ref ty, ref default) => {
+ visitor.visit_ty(ty);
+ if let Some(ref expr) = *default {
+ visitor.visit_expr(expr);
+ }
+ }
MethodTraitItem(ref sig, None) => {
visitor.visit_explicit_self(&sig.explicit_self);
visitor.visit_generics(&sig.generics);
visitor.visit_attribute(attr);
}
match impl_item.node {
+ ConstImplItem(ref ty, ref expr) => {
+ visitor.visit_ty(ty);
+ visitor.visit_expr(expr);
+ }
MethodImplItem(ref sig, ref body) => {
visitor.visit_fn(FkMethod(impl_item.ident, sig, Some(impl_item.vis)), &sig.decl,
body, impl_item.span, impl_item.id);
+S 2015-04-27 857ef6e
+ bitrig-x86_64 d28e2a5f8b478e69720703e751774f5e728a8edd
+ freebsd-x86_64 18925db56f6298cc190d1f41615ab5871de1dda0
+ linux-i386 0bc8cffdce611fb71fd7d3d8e7cdbfaf748a4f16
+ linux-x86_64 94089740e48167c5975c92c139ae9c286764012f
+ macos-i386 54cc35e76497e6e94fddf38d6e40e9d168491ddb
+ macos-x86_64 43a1c1fba0d1dfee4c2ca310d506f8f5f51b3f6f
+ winnt-i386 3db3adf2eaf37075043ec4ee41a5ea9b88810c44
+ winnt-x86_64 82b6eaea67741517ce6d7901ad2a9fd223c3aaf1
+
S 2015-03-27 5520801
bitrig-x86_64 55a69b0ae5481ccda54c2fcfc54025a0945c4f57
freebsd-x86_64 0910bbad35e213f679d0433884fd51398eb3bc8d
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+#![crate_type="lib"]
+
+// These items are for testing that associated consts work cross-crate.
+pub trait Foo {
+ const BAR: usize;
+}
+
+pub struct FooNoDefault;
+
+impl Foo for FooNoDefault {
+ const BAR: usize = 0;
+}
+
+// These test that defaults and default resolution work cross-crate.
+pub trait FooDefault {
+ const BAR: usize = 1;
+}
+
+pub struct FooOverwriteDefault;
+
+impl FooDefault for FooOverwriteDefault {
+ const BAR: usize = 2;
+}
+
+pub struct FooUseDefault;
+
+impl FooDefault for FooUseDefault {}
+
+// Test inherent impls.
+pub struct InherentBar;
+
+impl InherentBar {
+ pub const BAR: usize = 3;
+}
// except according to those terms.
#![crate_type = "rlib"]
+
+#![allow(unused_variables)]
#![omit_gdb_pretty_printer_section]
// no-prefer-dynamic
#![crate_name="issue_2526"]
#![crate_type = "lib"]
-#![feature(unsafe_destructor)]
-
use std::marker;
struct arc_destruct<T: Sync> {
_marker: marker::PhantomData<T>
}
-#[unsafe_destructor]
impl<T: Sync> Drop for arc_destruct<T> {
fn drop(&mut self) {}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+#![crate_type="lib"]
+
+// This is a file that pulls in a separate file as a submodule, where
+// that separate file has many multi-byte characters, to try to
+// encourage the compiler to trip on them.
+
+mod issue24687_mbcs_in_comments;
+
+pub use issue24687_mbcs_in_comments::D;
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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::fmt;
+
+// This ia file with many multi-byte characters, to try to encourage
+// the compiler to trip on them. The Drop implementation below will
+// need to have its source location embedded into the debug info for
+// the output file.
+
+// αααααααααααααααααααααααααααααααααααααααααααααααααααααααααααααααααααααα
+// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+// γγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγγ
+// δδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδδ
+// εεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεεε
+
+// ζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζζ
+// ηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηηη
+// θθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθθ
+// ιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιιι
+// κκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκ
+
+pub struct D<X:fmt::Debug>(pub X);
+
+impl<X:fmt::Debug> Drop for D<X> {
+ fn drop(&mut self) {
+ // λλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλλ
+ println!("Dropping D({:?})", self.0);
+ }
+}
#![feature(std_misc)]
+// We're testing linkage visibility; the compiler warns us, but we want to
+// do the runtime check that these functions aren't exported.
+#![allow(private_no_mangle_fns)]
+
use std::dynamic_lib::DynamicLibrary;
#[no_mangle]
#[no_mangle]
fn bar() { }
+#[allow(dead_code)]
#[no_mangle]
fn baz() { }
fn main() {
let symbols = [' ', 'â–‘', 'â–’', 'â–“', 'â–ˆ', 'â–ˆ'];
- let mut pixels = [0f32; 256*256];
- let n2d = Noise2DContext::new();
+ let mut pixels = Box::new([0f32; 256*256]);
+ let n2d = Box::new(Noise2DContext::new());
for _ in 0..100 {
for y in 0..256 {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-android: FIXME(#10393)
+// ignore-android: FIXME(#10393) hangs without output
// ignore-pretty very bad with line comments
// multi tasking k-nucleotide
-#![allow(bad_style)]
-
use std::ascii::AsciiExt;
use std::cmp::Ordering::{self, Less, Greater, Equal};
use std::collections::HashMap;
}
// sort by key, then by value
- fn sortKV(mut orig: Vec<(Vec<u8> ,f64)> ) -> Vec<(Vec<u8> ,f64)> {
+ fn sort_kv(mut orig: Vec<(Vec<u8> ,f64)> ) -> Vec<(Vec<u8> ,f64)> {
orig.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b));
orig.sort_by(|&(_, a), &(_, b)| f64_cmp(b, a));
orig
pairs.push(((*key).clone(), pct(val, total)));
}
- let pairs_sorted = sortKV(pairs);
+ let pairs_sorted = sort_kv(pairs);
let mut buffer = String::new();
for &(ref k, v) in &pairs_sorted {
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
-// ignore-android see #10393 #13206
+// ignore-android: FIXME(#10393) hangs without output
#![feature(box_syntax, std_misc, collections)]
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
-// ignore-android see #10393 #13206
+// ignore-android: FIXME(#10393) hangs without output
#![feature(libc, scoped)]
use std::thread;
struct Tables {
- table8: [u8; 1 << 8],
- table16: [u16; 1 << 16]
+ table8: Box<[u8; 1 << 8]>,
+ table16: Box<[u16; 1 << 16]>,
}
impl Tables {
fn new() -> Tables {
- let mut table8 = [0;1 << 8];
+ let mut table8 = Box::new([0;1 << 8]);
for (i, v) in table8.iter_mut().enumerate() {
*v = Tables::computed_cpl8(i as u8);
}
- let mut table16 = [0;1 << 16];
+ let mut table16 = Box::new([0;1 << 16]);
for (i, v) in table16.iter_mut().enumerate() {
*v = (table8[i & 255] as u16) << 8 |
table8[i >> 8] as u16;
fn main() {
let mut data = Vec::with_capacity(1024 * 1024);
- io::stdin().read_to_end(&mut data);
+ io::stdin().read_to_end(&mut data).unwrap();
let tables = &Tables::new();
parallel(mut_dna_seqs(&mut data), |seq| reverse_complement(seq, tables));
io::stdout().write_all(&data).unwrap();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(unsafe_destructor, box_syntax, std_misc, collections)]
+#![feature(box_syntax, std_misc, collections)]
use std::env;
use std::thread;
_l: Box<nillist>,
}
-#[unsafe_destructor]
impl Drop for r {
fn drop(&mut self) {}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+#![deny(dead_code)]
+
+struct MyFoo;
+
+impl MyFoo {
+ const BAR: u32 = 1;
+ //~^ ERROR associated const is never used: `BAR`
+}
+
+fn main() {
+ let _: MyFoo = MyFoo;
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+trait Foo {
+ const BAR: u32;
+}
+
+struct SignedBar;
+
+impl Foo for SignedBar {
+ const BAR: i32 = -1;
+ //~^ ERROR E0326
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+mod bar1 {
+ pub use self::bar2::Foo;
+ mod bar2 {
+ pub struct Foo;
+
+ impl Foo {
+ const ID: i32 = 1;
+ }
+ }
+}
+
+fn main() {
+ assert_eq!(1, bar1::Foo::ID);
+ //~^ERROR associated const `ID` is private
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+#![deny(non_upper_case_globals)]
+#![allow(dead_code)]
+
+struct Foo;
+
+impl Foo {
+ const not_upper: bool = true;
+}
+//~^^ ERROR associated constant `not_upper` should have an upper case name such as `NOT_UPPER`
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(unsafe_destructor)]
-
struct defer<'a> {
x: &'a [&'a str],
}
-#[unsafe_destructor]
impl<'a> Drop for defer<'a> {
fn drop(&mut self) {
unsafe {
//
// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
-#![feature(unsafe_destructor)]
-
use std::cell::Cell;
use id::Id;
#[allow(non_snake_case)]
fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
-#[unsafe_destructor]
impl<T:HasId> Drop for CheckId<T> {
fn drop(&mut self) {
assert!(self.v.count() > 0);
// `'a` in `&'a D<'a>` cannot be satisfied when `D<'a>` implements
// `Drop`.)
-#![feature(unsafe_destructor)]
-
use std::cell::Cell;
struct D<'a> {
fn new(name: String) -> D<'a> { D { name: name, p: Cell::new(None) } }
}
-#[unsafe_destructor]
impl<'a> Drop for D<'a> {
fn drop(&mut self) {
println!("dropping {} whose sibling is {:?}",
// for the error message we see here.)
#![allow(unstable)]
-#![feature(unsafe_destructor)]
extern crate arena;
#[allow(non_snake_case)]
fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
-#[unsafe_destructor]
impl<T:HasId> Drop for CheckId<T> {
fn drop(&mut self) {
assert!(self.v.count() > 0);
// this was reduced to better understand its error message.)
#![allow(unstable)]
-#![feature(unsafe_destructor)]
extern crate arena;
// interface to CheckId does not (and cannot) know that, and therefore
// when encountering the a value V of type CheckId<S>, we must
// conservatively force the type S to strictly outlive V.
-#[unsafe_destructor]
impl<T:HasId> Drop for CheckId<T> {
fn drop(&mut self) {
assert!(self.v.count() > 0);
//
// (Compare against compile-fail/dropck_arr_cycle_checked.rs)
-#![feature(unsafe_destructor)]
-
use std::cell::Cell;
use id::Id;
#[allow(non_snake_case)]
fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
-#[unsafe_destructor]
impl<T:HasId> Drop for CheckId<T> {
fn drop(&mut self) {
assert!(self.v.count() > 0);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(unsafe_destructor)]
-
// issue #20126
#[derive(Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented
#[derive(Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented
struct Bar<T>(::std::marker::PhantomData<T>);
-#[unsafe_destructor]
impl<T> Drop for Bar<T> {
fn drop(&mut self) {}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+trait MyTrait {
+ const C: bool;
+ //~^ associated constants are experimental
+ //~| add #![feature(associated_consts)] to the crate attributes to enable
+}
+
+struct Foo;
+
+impl Foo {
+ const C: bool = true;
+ //~^ associated constants are experimental
+ //~| add #![feature(associated_consts)] to the crate attributes to enable
+}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <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.
-
-// Test that `#[unsafe_destructor]` attribute is gated by `unsafe_destructor`
-// feature gate.
-//
-// (This test can be removed entirely when we remove the
-// `unsafe_destructor` feature itself.)
-
-struct D<'a>(&'a u32);
-
-#[unsafe_destructor]
-//~^ ERROR `#[unsafe_destructor]` does nothing anymore
-impl<'a> Drop for D<'a> {
- fn drop(&mut self) { }
-}
-
-pub fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+trait Foo {
+ fn bar(&self);
+ const MY_CONST: u32;
+}
+
+pub struct FooConstForMethod;
+
+impl Foo for FooConstForMethod {
+ //~^ ERROR E0046
+ const bar: u64 = 1;
+ //~^ ERROR E0323
+ const MY_CONST: u32 = 1;
+}
+
+pub struct FooMethodForConst;
+
+impl Foo for FooMethodForConst {
+ //~^ ERROR E0046
+ fn bar(&self) {}
+ fn MY_CONST() {}
+ //~^ ERROR E0324
+}
+
+pub struct FooTypeForMethod;
+
+impl Foo for FooTypeForMethod {
+ //~^ ERROR E0046
+ type bar = u64;
+ //~^ ERROR E0325
+ const MY_CONST: u32 = 1;
+}
+
+fn main () {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+// Check that one cannot subvert Drop Check rule via a user-defined
+// Clone implementation.
+
+#![allow(unused_variables, unused_assignments)]
+
+struct D<T:Copy>(T, &'static str);
+
+#[derive(Copy)]
+struct S<'a>(&'a D<i32>, &'static str);
+impl<'a> Clone for S<'a> {
+ fn clone(&self) -> S<'a> {
+ println!("cloning `S(_, {})` and thus accessing: {}", self.1, (self.0).0);
+ S(self.0, self.1)
+ }
+}
+
+impl<T:Copy> Drop for D<T> {
+ fn drop(&mut self) {
+ println!("calling Drop for {}", self.1);
+ let _call = self.0.clone();
+ }
+}
+
+fn main() {
+ let (d2, d1);
+ d1 = D(34, "d1");
+ d2 = D(S(&d1, "inner"), "d2"); //~ ERROR `d1` does not live long enough
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+struct Foo;
+
+impl Foo {
+ fn bar(&self) {}
+}
+
+trait MyTrait {
+ fn trait_bar() {}
+}
+
+impl MyTrait for Foo {}
+
+fn main() {
+ match 0u32 {
+ Foo::bar => {} //~ ERROR E0327
+ }
+ match 0u32 {
+ <Foo>::bar => {} //~ ERROR E0327
+ }
+ match 0u32 {
+ <Foo>::trait_bar => {} //~ ERROR E0327
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+struct Foo;
+
+trait MyTrait {
+ fn trait_bar() {}
+}
+
+impl MyTrait for Foo {}
+
+fn main() {
+ match 0u32 {
+ <Foo as MyTrait>::trait_bar => {}
+ //~^ ERROR `trait_bar` is not an associated const
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(unsafe_destructor)]
-
use std::thread;
use std::rc::Rc;
_x: Port<()>,
}
- #[unsafe_destructor]
- impl Drop for foo {
+ impl Drop for foo {
fn drop(&mut self) {}
}
// Issue 8142: Test that Drop impls cannot be specialized beyond the
// predicates attached to the struct/enum definition itself.
-#![feature(unsafe_destructor)]
-
trait Bound { fn foo(&self) { } }
struct K<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
struct L<'l1,'l2> { x: &'l1 i8, y: &'l2 u8 }
struct V<Tva, Tvb> { x: *const Tva, y: *const Tvb }
struct W<'l1, 'l2> { x: &'l1 i8, y: &'l2 u8 }
-#[unsafe_destructor]
impl<'al,'adds_bnd:'al> Drop for K<'al,'adds_bnd> { // REJECT
//~^ ERROR The requirement `'adds_bnd : 'al` is added only by the Drop impl.
fn drop(&mut self) { } }
-#[unsafe_destructor]
impl<'al,'adds_bnd> Drop for L<'al,'adds_bnd> where 'adds_bnd:'al { // REJECT
//~^ ERROR The requirement `'adds_bnd : 'al` is added only by the Drop impl.
fn drop(&mut self) { } }
-#[unsafe_destructor]
impl<'ml> Drop for M<'ml> { fn drop(&mut self) { } } // ACCEPT
-#[unsafe_destructor]
impl Drop for N<'static> { fn drop(&mut self) { } } // REJECT
//~^ ERROR Implementations of Drop cannot be specialized
-#[unsafe_destructor]
impl<Cok_nobound> Drop for O<Cok_nobound> { fn drop(&mut self) { } } // ACCEPT
-#[unsafe_destructor]
impl Drop for P<i8> { fn drop(&mut self) { } } // REJECT
//~^ ERROR Implementations of Drop cannot be specialized
-#[unsafe_destructor]
impl<Adds_bnd:Bound> Drop for Q<Adds_bnd> { fn drop(&mut self) { } } // REJECT
//~^ ERROR The requirement `Adds_bnd : Bound` is added only by the Drop impl.
-#[unsafe_destructor]
impl<'rbnd,Adds_rbnd:'rbnd> Drop for R<Adds_rbnd> { fn drop(&mut self) { } } // REJECT
//~^ ERROR The requirement `Adds_rbnd : 'rbnd` is added only by the Drop impl.
-#[unsafe_destructor]
impl<Bs:Bound> Drop for S<Bs> { fn drop(&mut self) { } } // ACCEPT
-#[unsafe_destructor]
impl<'t,Bt:'t> Drop for T<'t,Bt> { fn drop(&mut self) { } } // ACCEPT
impl Drop for U { fn drop(&mut self) { } } // ACCEPT
-#[unsafe_destructor]
impl<One> Drop for V<One,One> { fn drop(&mut self) { } } // REJECT
//~^ERROR Implementations of Drop cannot be specialized
-#[unsafe_destructor]
impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
//~^ERROR Implementations of Drop cannot be specialized
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(unsafe_destructor)]
-
use std::cell::Cell;
#[derive(Debug)]
i: &'a Cell<isize>,
}
-#[unsafe_destructor]
impl<'a> Drop for r<'a> {
fn drop(&mut self) {
unsafe {
// conditions above to be satisfied, meaning that if the dropck is
// sound, it should reject this code.
-#![feature(unsafe_destructor)]
-
use std::cell::Cell;
use id::Id;
#[allow(non_snake_case)]
fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
-#[unsafe_destructor]
impl<T:HasId> Drop for CheckId<T> {
fn drop(&mut self) {
assert!(self.v.count() > 0);
// compile-flags:-g
-#![allow(unused_variables)]
-#![allow(dead_code)]
+#![allow(dead_code, unused_variables)]
#![omit_gdb_pretty_printer_section]
#![feature(std_misc, core)]
// compile-flags:-g
-#![allow(unused_variables)]
-#![allow(dead_code)]
+#![allow(dead_code, unused_variables)]
#![omit_gdb_pretty_printer_section]
// This test makes sure that the compiler doesn't crash when trying to assign
// === GDB TESTS ===================================================================================
-// gdb-command:break cross_crate_spans.rs:21
+// gdb-command:break cross_crate_spans.rs:23
// gdb-command:run
// gdb-command:print result
// === LLDB TESTS ==================================================================================
-// lldb-command:b cross_crate_spans.rs:21
+// lldb-command:b cross_crate_spans.rs:23
// lldb-command:run
// lldb-command:print result
// lldb-check:[...]$31 = 45
// lldb-command:continue
-#![allow(unused_variables)]
+#![allow(dead_code, unused_assignments, unused_variables)]
#![omit_gdb_pretty_printer_section]
#[no_stack_check]
// gdb-command: print none
// gdb-check:$6 = None
+#![allow(unused_variables)]
+
fn main() {
// &[]
// gdb-command: print c_style_enum3
// gdb-check:$5 = CStyleEnumVar3
+#![allow(dead_code, unused_variables)]
+
struct RegularStruct {
the_first_field: isize,
the_second_field: f64,
// gdb-command: print none_check2
// gdb-check:$18 = None
+#![allow(dead_code, unused_variables)]
+
use self::CStyleEnum::{CStyleEnumVar1, CStyleEnumVar2, CStyleEnumVar3};
use self::MixedEnum::{MixedEnumCStyleVar, MixedEnumTupleVar, MixedEnumStructVar};
use self::NestedEnum::{NestedVariant1, NestedVariant2};
// gdb-check:type = struct Struct1
// gdb-command:whatis generic_struct1
-// gdb-check:type = struct GenericStruct<type_names::Mod1::Struct2, type_names::Mod1::Mod2::Struct3>
+// gdb-check:type = struct GenericStruct<type_names::mod1::Struct2, type_names::mod1::mod2::Struct3>
// gdb-command:whatis generic_struct2
// gdb-check:type = struct GenericStruct<type_names::Struct1, extern "fastcall" fn(isize) -> usize>
// gdb-check:type = union Enum2
// gdb-command:whatis generic_enum_1
-// gdb-check:type = union Enum3<type_names::Mod1::Struct2>
+// gdb-check:type = union Enum3<type_names::mod1::Struct2>
// gdb-command:whatis generic_enum_2
// gdb-check:type = union Enum3<type_names::Struct1>
// TUPLES
// gdb-command:whatis tuple1
-// gdb-check:type = struct (u32, type_names::Struct1, type_names::Mod1::Mod2::Enum3<type_names::Mod1::Struct2>)
+// gdb-check:type = struct (u32, type_names::Struct1, type_names::mod1::mod2::Enum3<type_names::mod1::Struct2>)
// gdb-command:whatis tuple2
-// gdb-check:type = struct ((type_names::Struct1, type_names::Mod1::Mod2::Struct3), type_names::Mod1::Enum2, char)
+// gdb-check:type = struct ((type_names::Struct1, type_names::mod1::mod2::Struct3), type_names::mod1::Enum2, char)
// BOX
// gdb-check:type = struct (Box<f32>, i32)
// gdb-command:whatis box2
-// gdb-check:type = struct (Box<type_names::Mod1::Mod2::Enum3<f32>>, i32)
+// gdb-check:type = struct (Box<type_names::mod1::mod2::Enum3<f32>>, i32)
// REFERENCES
// gdb-check:type = struct (&mut type_names::Struct1, i32)
// gdb-command:whatis mut_ref2
-// gdb-check:type = struct (&mut type_names::GenericStruct<type_names::Mod1::Enum2, f64>, i32)
+// gdb-check:type = struct (&mut type_names::GenericStruct<type_names::mod1::Enum2, f64>, i32)
// RAW POINTERS
// gdb-check:type = struct (*mut isize, isize)
// gdb-command:whatis mut_ptr3
-// gdb-check:type = struct (*mut type_names::Mod1::Mod2::Enum3<type_names::Struct1>, isize)
+// gdb-check:type = struct (*mut type_names::mod1::mod2::Enum3<type_names::Struct1>, isize)
// gdb-command:whatis const_ptr1
// gdb-check:type = struct (*const type_names::Struct1, isize)
// gdb-check:type = struct (*const isize, isize)
// gdb-command:whatis const_ptr3
-// gdb-check:type = struct (*const type_names::Mod1::Mod2::Enum3<type_names::Struct1>, isize)
+// gdb-check:type = struct (*const type_names::mod1::mod2::Enum3<type_names::Struct1>, isize)
// VECTORS
// gdb-check:type = struct &[usize]
// gdb-command:whatis slice2
-// gdb-check:type = struct &[type_names::Mod1::Enum2]
+// gdb-check:type = struct &[type_names::mod1::Enum2]
// TRAITS
// gdb-check:type = struct &mut Trait1
// gdb-command:whatis generic_box_trait
-// gdb-check:type = struct Box<Trait2<i32, type_names::Mod1::Struct2>>
+// gdb-check:type = struct Box<Trait2<i32, type_names::mod1::Struct2>>
// gdb-command:whatis generic_ref_trait
// gdb-check:type = struct &Trait2<type_names::Struct1, type_names::Struct1>
// gdb-command:whatis generic_mut_ref_trait
-// gdb-check:type = struct &mut Trait2<type_names::Mod1::Mod2::Struct3, type_names::GenericStruct<usize, isize>>
+// gdb-check:type = struct &mut Trait2<type_names::mod1::mod2::Struct3, type_names::GenericStruct<usize, isize>>
// BARE FUNCTIONS
// gdb-command:whatis rust_fn
-// gdb-check:type = struct (fn(core::option::Option<isize>, core::option::Option<&type_names::Mod1::Struct2>), usize)
+// gdb-check:type = struct (fn(core::option::Option<isize>, core::option::Option<&type_names::mod1::Struct2>), usize)
// gdb-command:whatis extern_c_fn
// gdb-check:type = struct (extern "C" fn(isize), usize)
// gdb-check:type = struct (extern "C" fn() -> type_names::Struct1, usize)
// gdb-command:whatis unsafe_fn_with_return_value
-// gdb-check:type = struct (unsafe fn(type_names::GenericStruct<u16, u8>) -> type_names::Mod1::Struct2, usize)
+// gdb-check:type = struct (unsafe fn(type_names::GenericStruct<u16, u8>) -> type_names::mod1::Struct2, usize)
// gdb-command:whatis extern_stdcall_fn_with_return_value
// gdb-check:type = struct (extern "stdcall" fn(Box<isize>) -> usize, usize)
// gdb-check:type = struct (fn(isize) -> isize, usize)
// gdb-command:whatis generic_function_struct3
-// gdb-check:type = struct (fn(type_names::Mod1::Mod2::Struct3) -> type_names::Mod1::Mod2::Struct3, usize)
+// gdb-check:type = struct (fn(type_names::mod1::mod2::Struct3) -> type_names::mod1::mod2::Struct3, usize)
// gdb-command:whatis variadic_function
// gdb-check:type = struct (unsafe extern "C" fn(*const u8, ...) -> isize, usize)
// gdb-check:type = struct (closure, usize)
#![feature(box_syntax)]
+#![allow(unused_variables)]
#![omit_gdb_pretty_printer_section]
-use self::Enum1::{Variant1_1, Variant1_2};
+use self::Enum1::{Variant1, Variant2};
use std::marker::PhantomData;
use std::ptr;
struct GenericStruct<T1, T2>(PhantomData<(T1,T2)>);
enum Enum1 {
- Variant1_1,
- Variant1_2(isize)
+ Variant1,
+ Variant2(isize),
}
-mod Mod1 {
- pub use self::Enum2::{Variant2_1, Variant2_2};
+mod mod1 {
+ pub use self::Enum2::{Variant1, Variant2};
pub struct Struct2;
pub enum Enum2 {
- Variant2_1,
- Variant2_2(super::Struct1)
+ Variant1,
+ Variant2(super::Struct1),
}
- pub mod Mod2 {
- pub use self::Enum3::{Variant3_1, Variant3_2};
+ pub mod mod2 {
+ pub use self::Enum3::{Variant1, Variant2};
pub struct Struct3;
pub enum Enum3<T> {
- Variant3_1,
- Variant3_2(T),
+ Variant1,
+ Variant2(T),
}
}
}
impl Trait1 for isize {}
impl<T1, T2> Trait2<T1, T2> for isize {}
-fn rust_fn(_: Option<isize>, _: Option<&Mod1::Struct2>) {}
+fn rust_fn(_: Option<isize>, _: Option<&mod1::Struct2>) {}
extern "C" fn extern_c_fn(_: isize) {}
unsafe fn unsafe_fn(_: Result<char, f64>) {}
extern "stdcall" fn extern_stdcall_fn() {}
fn rust_fn_with_return_value(_: f64) -> usize { 4 }
extern "C" fn extern_c_fn_with_return_value() -> Struct1 { Struct1 }
-unsafe fn unsafe_fn_with_return_value(_: GenericStruct<u16, u8>) -> Mod1::Struct2 { Mod1::Struct2 }
+unsafe fn unsafe_fn_with_return_value(_: GenericStruct<u16, u8>) -> mod1::Struct2 { mod1::Struct2 }
extern "stdcall" fn extern_stdcall_fn_with_return_value(_: Box<isize>) -> usize { 0 }
fn generic_function<T>(x: T) -> T { x }
+#[allow(improper_ctypes)]
extern {
fn printf(_:*const u8, ...) -> isize;
}
// Structs
let simple_struct = Struct1;
- let generic_struct1: GenericStruct<Mod1::Struct2, Mod1::Mod2::Struct3> =
+ let generic_struct1: GenericStruct<mod1::Struct2, mod1::mod2::Struct3> =
GenericStruct(PhantomData);
let generic_struct2: GenericStruct<Struct1, extern "fastcall" fn(isize) -> usize> =
GenericStruct(PhantomData);
- let mod_struct = Mod1::Struct2;
+ let mod_struct = mod1::Struct2;
// Enums
- let simple_enum_1 = Variant1_1;
- let simple_enum_2 = Variant1_2(0);
- let simple_enum_3 = Mod1::Variant2_2(Struct1);
+ let simple_enum_1 = Variant1;
+ let simple_enum_2 = Variant2(0);
+ let simple_enum_3 = mod1::Variant2(Struct1);
- let generic_enum_1: Mod1::Mod2::Enum3<Mod1::Struct2> = Mod1::Mod2::Variant3_1;
- let generic_enum_2 = Mod1::Mod2::Variant3_2(Struct1);
+ let generic_enum_1: mod1::mod2::Enum3<mod1::Struct2> = mod1::mod2::Variant1;
+ let generic_enum_2 = mod1::mod2::Variant2(Struct1);
// Tuples
- let tuple1 = (8u32, Struct1, Mod1::Mod2::Variant3_2(Mod1::Struct2));
- let tuple2 = ((Struct1, Mod1::Mod2::Struct3), Mod1::Variant2_1, 'x');
+ let tuple1 = (8u32, Struct1, mod1::mod2::Variant2(mod1::Struct2));
+ let tuple2 = ((Struct1, mod1::mod2::Struct3), mod1::Variant1, 'x');
// Box
let box1 = (box 1f32, 0i32);
- let box2 = (box Mod1::Mod2::Variant3_2(1f32), 0i32);
+ let box2 = (box mod1::mod2::Variant2(1f32), 0i32);
// References
let ref1 = (&Struct1, 0i32);
let ref2 = (&GenericStruct::<char, Struct1>(PhantomData), 0i32);
let mut mut_struct1 = Struct1;
- let mut mut_generic_struct = GenericStruct::<Mod1::Enum2, f64>(PhantomData);
+ let mut mut_generic_struct = GenericStruct::<mod1::Enum2, f64>(PhantomData);
let mut_ref1 = (&mut mut_struct1, 0i32);
let mut_ref2 = (&mut mut_generic_struct, 0i32);
// Raw Pointers
let mut_ptr1: (*mut Struct1, isize) = (ptr::null_mut(), 0);
let mut_ptr2: (*mut isize, isize) = (ptr::null_mut(), 0);
- let mut_ptr3: (*mut Mod1::Mod2::Enum3<Struct1>, isize) = (ptr::null_mut(), 0);
+ let mut_ptr3: (*mut mod1::mod2::Enum3<Struct1>, isize) = (ptr::null_mut(), 0);
let const_ptr1: (*const Struct1, isize) = (ptr::null(), 0);
let const_ptr2: (*const isize, isize) = (ptr::null(), 0);
- let const_ptr3: (*const Mod1::Mod2::Enum3<Struct1>, isize) = (ptr::null(), 0);
+ let const_ptr3: (*const mod1::mod2::Enum3<Struct1>, isize) = (ptr::null(), 0);
// Vectors
let fixed_size_vec1 = ([Struct1, Struct1, Struct1], 0i16);
let vec1 = vec![0_usize, 2, 3];
let slice1 = &*vec1;
- let vec2 = vec![Mod1::Variant2_2(Struct1)];
+ let vec2 = vec![mod1::Variant2(Struct1)];
let slice2 = &*vec2;
// Trait Objects
let mut mut_int1 = 0_isize;
let mut_ref_trait = (&mut mut_int1) as &mut Trait1;
- let generic_box_trait = (box 0_isize) as Box<Trait2<i32, Mod1::Struct2>>;
+ let generic_box_trait = (box 0_isize) as Box<Trait2<i32, mod1::Struct2>>;
let generic_ref_trait = (&0_isize) as &Trait2<Struct1, Struct1>;
let mut generic_mut_ref_trait_impl = 0_isize;
let generic_mut_ref_trait = (&mut generic_mut_ref_trait_impl) as
- &mut Trait2<Mod1::Mod2::Struct3, GenericStruct<usize, isize>>;
+ &mut Trait2<mod1::mod2::Struct3, GenericStruct<usize, isize>>;
// Bare Functions
let rust_fn = (rust_fn, 0_usize);
let extern_stdcall_fn_with_return_value = (extern_stdcall_fn_with_return_value, 0_usize);
let generic_function_int = (generic_function::<isize>, 0_usize);
- let generic_function_struct3 = (generic_function::<Mod1::Mod2::Struct3>, 0_usize);
+ let generic_function_struct3 = (generic_function::<mod1::mod2::Struct3>, 0_usize);
let variadic_function = (printf, 0_usize);
// lldb-command:print padded_struct
// lldb-check:[...]$5 = &[AStruct { x: 10, y: 11, z: 12 }, AStruct { x: 13, y: 14, z: 15 }]
-#![allow(unused_variables)]
+#![allow(dead_code, unused_variables)]
#![omit_gdb_pretty_printer_section]
struct AStruct {
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 foo() {
+ match x {
+ <T as Trait>::Type{key: value} => (),
+ //~^ ERROR unexpected `{` after qualified path
+ _ => (),
+ }
+}
fn foo() {}
#[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
+} //~ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
fn main() {}
impl Foo {
#[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
+} //~ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
fn main() {}
// compile-flags: -Z parse-only
trait MyTrait<T>: Iterator {
- Item = T; //~ ERROR expected one of `extern`, `fn`, `type`, or `unsafe`, found `Item`
+ Item = T; //~ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `Item`
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 foo() {
+ match x {
+ <T as Trait>::Type(2) => (),
+ //~^ ERROR unexpected `(` after qualified path
+ _ => (),
+ }
+}
impl S {
static fn f() {}
- //~^ ERROR expected one of `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `static`
}
+//~^^ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `static`
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+trait Foo {
+ pub const Foo: u32;
+ //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
+}
+
+fn main() {}
// except according to those terms.
trait Foo {
- pub type Foo; //~ ERROR expected one of `extern`, `fn`, `type`, or `unsafe`, found `pub`
+ pub type Foo;
+ //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
}
fn main() {}
// except according to those terms.
trait Foo {
- pub fn foo(); //~ ERROR expected one of `extern`, `fn`, `type`, or `unsafe`, found `pub`
+ pub fn foo();
+ //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
}
fn main() {}
--- /dev/null
+// Copyright 2012-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-cross-compile
+
+// error-pattern:expected identifier, found keyword `let`
+
+#![feature(quote, rustc_private)]
+
+extern crate syntax;
+
+use syntax::ast;
+use syntax::codemap::{self, DUMMY_SP};
+use syntax::parse;
+use syntax::print::pprust;
+
+fn main() {
+ let ps = syntax::parse::new_parse_sess();
+ let mut cx = syntax::ext::base::ExtCtxt::new(
+ &ps, vec![],
+ syntax::ext::expand::ExpansionConfig::default("qquote".to_string()));
+ cx.bt_push(syntax::codemap::ExpnInfo {
+ call_site: DUMMY_SP,
+ callee: syntax::codemap::NameAndSpan {
+ name: "".to_string(),
+ format: syntax::codemap::MacroBang,
+ allow_internal_unstable: false,
+ span: None,
+ }
+ });
+ let cx = &mut cx;
+
+ assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23");
+
+ let expr = quote_expr!(&cx, let x isize = 20;);
+ assert_eq!(pprust::expr_to_string(&*expr), "let x isize = 20;");
+}
+++ /dev/null
-// Copyright 2012-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-cross-compile
-
-// error-pattern:expected identifier, found keyword `let`
-
-#![feature(quote, rustc_private)]
-
-extern crate syntax;
-
-use syntax::ast;
-use syntax::codemap::{self, DUMMY_SP};
-use syntax::parse;
-use syntax::print::pprust;
-
-fn main() {
- let ps = syntax::parse::new_parse_sess();
- let mut cx = syntax::ext::base::ExtCtxt::new(
- &ps, vec![],
- syntax::ext::expand::ExpansionConfig::default("qquote".to_string()));
- cx.bt_push(syntax::codemap::ExpnInfo {
- call_site: DUMMY_SP,
- callee: syntax::codemap::NameAndSpan {
- name: "".to_string(),
- format: syntax::codemap::MacroBang,
- allow_internal_unstable: false,
- span: None,
- }
- });
- let cx = &mut cx;
-
- assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23");
-
- let expr = quote_expr!(&cx, let x isize = 20;);
- assert_eq!(pprust::expr_to_string(&*expr), "let x isize = 20;");
-}
// aux-build:issue-13560-2.rs
// aux-build:issue-13560-3.rs
// ignore-stage1
+// ignore-musl
// Regression test for issue #13560, the test itself is all in the dependent
// libraries. The fail which previously failed to compile is the one numbered 3.
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+// aux-build:associated-const-cc-lib.rs
+
+#![feature(associated_consts)]
+
+extern crate associated_const_cc_lib as foolib;
+
+pub struct LocalFooUseDefault;
+
+impl foolib::FooDefault for LocalFooUseDefault {}
+
+pub struct LocalFooOverwriteDefault;
+
+impl foolib::FooDefault for LocalFooOverwriteDefault {
+ const BAR: usize = 4;
+}
+
+fn main() {
+ assert_eq!(1, <foolib::FooUseDefault as foolib::FooDefault>::BAR);
+ assert_eq!(2, <foolib::FooOverwriteDefault as foolib::FooDefault>::BAR);
+ assert_eq!(1, <LocalFooUseDefault as foolib::FooDefault>::BAR);
+ assert_eq!(4, <LocalFooOverwriteDefault as foolib::FooDefault>::BAR);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+// aux-build:associated-const-cc-lib.rs
+
+#![feature(associated_consts)]
+
+extern crate associated_const_cc_lib as foolib;
+
+pub struct LocalFoo;
+
+impl foolib::Foo for LocalFoo {
+ const BAR: usize = 1;
+}
+
+fn main() {
+ assert_eq!(0, <foolib::FooNoDefault as foolib::Foo>::BAR);
+ assert_eq!(1, <LocalFoo as foolib::Foo>::BAR);
+ assert_eq!(3, foolib::InherentBar::BAR);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+struct Foo;
+
+impl Foo {
+ const BAR: f32 = 1.5;
+}
+
+const FOOBAR: f32 = <Foo>::BAR;
+
+fn main() {
+ assert_eq!(1.5f32, FOOBAR);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+struct Foo;
+
+impl Foo {
+ const ID: i32 = 1;
+}
+
+fn main() {
+ assert_eq!(1, Foo::ID);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+#![deny(dead_code)]
+
+const GLOBAL_BAR: u32 = 1;
+
+struct Foo;
+
+impl Foo {
+ const BAR: u32 = GLOBAL_BAR;
+}
+
+pub fn main() {
+ let _: u32 = Foo::BAR;
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+struct Foo;
+
+enum Bar {
+ Var1,
+ Var2,
+}
+
+// Use inherent and trait impls to test UFCS syntax.
+impl Foo {
+ const MYBAR: Bar = Bar::Var2;
+}
+
+trait HasBar {
+ const THEBAR: Bar;
+}
+
+impl HasBar for Foo {
+ const THEBAR: Bar = Bar::Var1;
+}
+
+fn main() {
+ // Inherent impl
+ assert!(match Bar::Var2 {
+ Foo::MYBAR => true,
+ _ => false,
+ });
+ assert!(match Bar::Var2 {
+ <Foo>::MYBAR => true,
+ _ => false,
+ });
+ // Trait impl
+ assert!(match Bar::Var1 {
+ <Foo>::THEBAR => true,
+ _ => false,
+ });
+ assert!(match Bar::Var1 {
+ <Foo as HasBar>::THEBAR => true,
+ _ => false,
+ });
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+trait Foo {
+ const ID: i32 = 2;
+}
+
+impl Foo for i32 {
+ const ID: i32 = 1;
+}
+
+fn main() {
+ assert_eq!(1, <i32 as Foo>::ID);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+mod bar1 {
+ pub use self::bar2::Foo;
+ mod bar2 {
+ pub struct Foo;
+
+ impl Foo {
+ pub const ID: i32 = 1;
+ }
+ }
+}
+
+fn main() {
+ assert_eq!(1, bar1::Foo::ID);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+struct MyType;
+
+impl MyType {
+ const IMPL_IS_INHERENT: bool = true;
+}
+
+trait MyTrait {
+ const IMPL_IS_INHERENT: bool;
+ const IMPL_IS_ON_TRAIT: bool;
+}
+
+impl MyTrait for MyType {
+ const IMPL_IS_INHERENT: bool = false;
+ const IMPL_IS_ON_TRAIT: bool = true;
+}
+
+fn main() {
+ // Check that the inherent impl is used before the trait, but that the trait
+ // can still be accessed.
+ assert!(<MyType>::IMPL_IS_INHERENT);
+ assert!(!<MyType as MyTrait>::IMPL_IS_INHERENT);
+ assert!(<MyType>::IMPL_IS_ON_TRAIT);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+trait MyInt {
+ const ONE: Self;
+}
+
+impl MyInt for i32 {
+ const ONE: i32 = 1;
+}
+
+fn main() {
+ assert_eq!(1, <i32>::ONE);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+trait Foo {
+ const ID: i32;
+}
+
+impl Foo for i32 {
+ const ID: i32 = 1;
+}
+
+fn main() {
+ assert_eq!(1, <i32>::ID);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+trait Foo {
+ const ID: i32 = 1;
+}
+
+impl Foo for i32 {}
+
+fn main() {
+ assert_eq!(1, <i32 as Foo>::ID);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+// The main purpose of this test is to ensure that different impls of the same
+// trait can refer to each other without setting off the static recursion check
+// (as long as there's no actual recursion).
+
+trait Foo {
+ const BAR: u32;
+}
+
+struct IsFoo1;
+
+impl Foo for IsFoo1 {
+ const BAR: u32 = 1;
+}
+
+struct IsFoo2;
+
+impl Foo for IsFoo2 {
+ const BAR: u32 = <IsFoo1 as Foo>::BAR;
+}
+
+fn main() {
+ assert_eq!(<IsFoo1>::BAR, <IsFoo2 as Foo>::BAR);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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(associated_consts)]
+
+trait Foo {
+ const ID: i32;
+}
+
+impl Foo for i32 {
+ const ID: i32 = 1;
+}
+
+fn main() {
+ assert_eq!(1, <i32 as Foo>::ID);
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(unsafe_destructor)]
#![feature(unsafe_no_drop_flag)]
use std::mem::size_of;
a: T
}
-#[unsafe_destructor]
impl<T> Drop for Test<T> {
fn drop(&mut self) { }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(unsafe_destructor)]
-
struct S<T> {
x: T
}
-#[unsafe_destructor]
impl<T> ::std::ops::Drop for S<T> {
fn drop(&mut self) {
println!("bye");
// shows a similar setup, but restricts `f` so that the struct `C<'a>`
// is force-fed a lifetime equal to that of the borrowed arena.
-
#![allow(unstable)]
-#![feature(unsafe_destructor, rustc_private)]
+#![feature(rustc_private)]
extern crate arena;
// interface to CheckId does not (and cannot) know that, and therefore
// when encountering the a value V of type CheckId<S>, we must
// conservatively force the type S to strictly outlive V.
-#[unsafe_destructor]
impl<T:HasId> Drop for CheckId<T> {
fn drop(&mut self) {
assert!(self.v.count() > 0);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![allow(unknown_features)]
#![feature(box_syntax)]
-#![feature(unsafe_destructor)]
use std::cell::Cell;
struct BoxR<'a> { x: r<'a> }
-#[unsafe_destructor]
impl<'a> Drop for r<'a> {
fn drop(&mut self) {
self.i.set(self.i.get() + 1)
// aux-build:issue-12133-rlib.rs
// aux-build:issue-12133-dylib.rs
// aux-build:issue-12133-dylib2.rs
+// ignore-musl
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(unsafe_destructor)]
-
static mut DROP_RAN: bool = false;
trait Bar {
struct Foo<B: Bar>(B);
-#[unsafe_destructor]
impl<B: Bar> Drop for Foo<B> {
fn drop(&mut self) {
unsafe {
// pretty-expanded FIXME #23616
-#![feature(unsafe_destructor, rustc_private)]
+#![feature(rustc_private)]
extern crate serialize;
v: T,
}
-#[unsafe_destructor]
impl<T: Encodable> Drop for Foo<T> {
fn drop(&mut self) {
json::encode(&self.v);
// ignore-pretty
-#![feature(unsafe_destructor)]
-
use std::rc::Rc;
use std::cell::Cell;
}
}
-#[unsafe_destructor] // because Field isn't Send
impl Drop for Field {
fn drop(&mut self) {
println!("Dropping field {}", self.number);
_three: Field
}
-#[unsafe_destructor] // because HasDropImpl isn't Send
impl Drop for HasDropImpl {
fn drop(&mut self) {
println!("HasDropImpl.drop()");
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(unsafe_destructor)]
-
struct Leak<'a> {
dropped: &'a mut bool
}
-#[unsafe_destructor]
impl<'a> Drop for Leak<'a> {
fn drop(&mut self) {
*self.dropped = true;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+// Issue 23611: this test is ensuring that, for an instance `X` of the
+// enum `E`, if you swap in a different variant during the execution
+// of the `<E as Drop>::drop`, then the appropriate substructure will
+// be torn down after the `<E as Drop>::drop` method returns.
+
+use std::cell::RefCell;
+use std::mem;
+
+use self::d::D;
+
+pub fn main() {
+ let log = RefCell::new(vec![]);
+ d::println(&format!("created empty log"));
+ test(&log);
+
+ // println!("log: {:?}", &log.borrow()[..]);
+ assert_eq!(
+ &log.borrow()[..],
+ [
+ // created empty log
+ // +-- Make D(test_1, 10000000)
+ // | +-- Make D(g_b_5, 50000001)
+ // | | in g_B(b2b0) from E::drop, b=b4b0
+ // | +-- Drop D(g_b_5, 50000001)
+ 50000001,
+ // |
+ // | +-- Make D(drop_6, 60000002)
+ // | | +-- Make D(g_b_5, 50000003)
+ // | | | in g_B(b2b0) from E::drop, b=b4b1
+ // | | +-- Drop D(g_b_5, 50000003)
+ 50000003,
+ // | |
+ // | | +-- Make D(GaspB::drop_3, 30000004)
+ // | | | +-- Make D(g_b_5, 50000005)
+ // | | | | in g_B(b4b2) from GaspB::drop
+ // | | | +-- Drop D(g_b_5, 50000005)
+ 50000005,
+ // | | |
+ // | | +-- Drop D(GaspB::drop_3, 30000004)
+ 30000004,
+ // | |
+ // +-- Drop D(test_1, 10000000)
+ 10000000,
+ // |
+ // +-- Make D(GaspA::drop_2, 20000006)
+ // | | +-- Make D(f_a_4, 40000007)
+ // | | | in f_A(a3a0) from GaspA::drop
+ // | | +-- Drop D(f_a_4, 40000007)
+ 40000007,
+ // | |
+ // +-- Drop D(GaspA::drop_2, 20000006)
+ 20000006,
+ // |
+ // +-- Drop D(drop_6, 60000002)
+ 60000002
+ //
+ ]);
+
+ // For reference purposes, the old (incorrect) behavior would produce the following
+ // output, which you can compare to the above:
+ //
+ // created empty log
+ // +-- Make D(test_1, 10000000)
+ // | +-- Make D(g_b_5, 50000001)
+ // | | in g_B(b2b0) from E::drop, b=b4b0
+ // | +-- Drop D(g_b_5, 50000001)
+ // |
+ // | +-- Make D(drop_6, 60000002)
+ // | | +-- Make D(g_b_5, 50000003)
+ // | | | in g_B(b2b0) from E::drop, b=b4b1
+ // | | +-- Drop D(g_b_5, 50000003)
+ // | |
+ // | | +-- Make D(GaspB::drop_3, 30000004)
+ // | | | +-- Make D(g_b_5, 50000005)
+ // | | | | in g_B(b4b2) from GaspB::drop
+ // | | | +-- Drop D(g_b_5, 50000005)
+ // | | |
+ // | | +-- Drop D(GaspB::drop_3, 30000004)
+ // | |
+ // +-- Drop D(test_1, 10000000)
+ // |
+ // +-- Make D(GaspB::drop_3, 30000006)
+ // | | +-- Make D(f_a_4, 40000007)
+ // | | | in f_A(a3a0) from GaspB::drop
+ // | | +-- Drop D(f_a_4, 40000007)
+ // | |
+ // +-- Drop D(GaspB::drop_3, 30000006)
+ // |
+ // +-- Drop D(drop_6, 60000002)
+
+ // Note that this calls f_A from GaspB::drop (and thus creates a D
+ // with a uid incorporating the origin of GaspB's drop that
+ // surrounds the f_A invocation), but the code as written only
+ // ever hands f_A off to instances of GaspA, and thus one should
+ // be able to prove the invariant that f_A is *only* invoked from
+ // from an instance of GaspA (either via the GaspA drop
+ // implementation or the E drop implementaton). Yet the old (bad)
+ // behavior allowed a call to f_A to leak in while we are tearing
+ // down a value of type GaspB.
+}
+
+fn test<'a>(log: d::Log<'a>) {
+ let _e = E::B(GaspB(g_b, 0xB4B0, log, D::new("test", 1, log)), true);
+}
+
+struct GaspA<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>);
+struct GaspB<'a>(for <'b> fn(u32, &'b str, d::Log<'a>), u32, d::Log<'a>, d::D<'a>);
+
+impl<'a> Drop for GaspA<'a> {
+ fn drop(&mut self) {
+ let _d = d::D::new("GaspA::drop", 2, self.2);
+ (self.0)(self.1, "GaspA::drop", self.2);
+ }
+}
+
+impl<'a> Drop for GaspB<'a> {
+ fn drop(&mut self) {
+ let _d = d::D::new("GaspB::drop", 3, self.2);
+ (self.0)(self.1, "GaspB::drop", self.2);
+ }
+}
+
+enum E<'a> {
+ A(GaspA<'a>, bool), B(GaspB<'a>, bool),
+}
+
+fn f_a(x: u32, ctxt: &str, log: d::Log) {
+ let _d = d::D::new("f_a", 4, log);
+ d::println(&format!("in f_A({:x}) from {}", x, ctxt));
+}
+fn g_b(y: u32, ctxt: &str, log: d::Log) {
+ let _d = d::D::new("g_b", 5, log);
+ d::println(&format!("in g_B({:x}) from {}", y, ctxt));
+}
+
+impl<'a> Drop for E<'a> {
+ fn drop(&mut self) {
+ let (do_drop, log) = match *self {
+ E::A(GaspA(ref f, ref mut val_a, log, ref _d_a), ref mut do_drop) => {
+ f(0xA1A0, &format!("E::drop, a={:x}", val_a), log);
+ *val_a += 1;
+ // swap in do_drop := false to avoid infinite dtor regress
+ (mem::replace(do_drop, false), log)
+ }
+ E::B(GaspB(ref g, ref mut val_b, log, ref _d_b), ref mut do_drop) => {
+ g(0xB2B0, &format!("E::drop, b={:x}", val_b), log);
+ *val_b += 1;
+ // swap in do_drop := false to avoid infinite dtor regress
+ (mem::replace(do_drop, false), log)
+ }
+ };
+
+ if do_drop {
+ mem::replace(self, E::A(GaspA(f_a, 0xA3A0, log, D::new("drop", 6, log)), true));
+ }
+ }
+}
+
+// This module provides simultaneous printouts of the dynamic extents
+// of all of the D values, in addition to logging the order that each
+// is dropped.
+//
+// This code is similar to a support code module embedded within
+// test/run-pass/issue-123338-ensure-param-drop-order.rs; however,
+// that (slightly simpler) code only identifies objects in the log via
+// (creation) time-stamps; this incorporates both timestamping and the
+// point of origin within the source code into the unique ID (uid).
+
+const PREF_INDENT: u32 = 20;
+
+pub mod d {
+ #![allow(unused_parens)]
+ use std::fmt;
+ use std::mem;
+ use std::cell::RefCell;
+
+ static mut counter: u16 = 0;
+ static mut trails: u64 = 0;
+
+ pub type Log<'a> = &'a RefCell<Vec<u32>>;
+
+ pub fn current_width() -> u32 {
+ unsafe { max_width() - trails.leading_zeros() }
+ }
+
+ pub fn max_width() -> u32 {
+ unsafe {
+ (mem::size_of_val(&trails)*8) as u32
+ }
+ }
+
+ pub fn indent_println(my_trails: u32, s: &str) {
+ let mut indent: String = String::new();
+ for i in 0..my_trails {
+ unsafe {
+ if trails & (1 << i) != 0 {
+ indent = indent + "| ";
+ } else {
+ indent = indent + " ";
+ }
+ }
+ }
+ println!("{}{}", indent, s);
+ }
+
+ pub fn println(s: &str) {
+ indent_println(super::PREF_INDENT, s);
+ }
+
+ fn first_avail() -> u32 {
+ unsafe {
+ for i in 0..64 {
+ if trails & (1 << i) == 0 {
+ return i;
+ }
+ }
+ }
+ panic!("exhausted trails");
+ }
+
+ pub struct D<'a> {
+ name: &'static str, i: u8, uid: u32, trail: u32, log: Log<'a>
+ }
+
+ impl<'a> fmt::Display for D<'a> {
+ fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
+ write!(w, "D({}_{}, {})", self.name, self.i, self.uid)
+ }
+ }
+
+ impl<'a> D<'a> {
+ pub fn new(name: &'static str, i: u8, log: Log<'a>) -> D<'a> {
+ unsafe {
+ let trail = first_avail();
+ let ctr = ((i as u32) * 10_000_000) + (counter as u32);
+ counter += 1;
+ trails |= (1 << trail);
+ let ret = D {
+ name: name, i: i, log: log, uid: ctr, trail: trail
+ };
+ indent_println(trail, &format!("+-- Make {}", ret));
+ ret
+ }
+ }
+ }
+
+ impl<'a> Drop for D<'a> {
+ fn drop(&mut self) {
+ unsafe { trails &= !(1 << self.trail); };
+ self.log.borrow_mut().push(self.uid);
+ indent_println(self.trail, &format!("+-- Drop {}", self));
+ indent_println(::PREF_INDENT, "");
+ }
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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::thread;
+use std::env;
+use std::process::Command;
+
+struct Handle(i32);
+
+impl Drop for Handle {
+ fn drop(&mut self) { panic!(); }
+}
+
+thread_local!(static HANDLE: Handle = Handle(0));
+
+fn main() {
+ let args = env::args().collect::<Vec<_>>();
+ if args.len() == 1 {
+ let out = Command::new(&args[0]).arg("test").output().unwrap();
+ let stderr = std::str::from_utf8(&out.stderr).unwrap();
+ assert!(stderr.contains("panicked at 'explicit panic'"),
+ "bad failure message:\n{}\n", stderr);
+ } else {
+ // TLS dtors are not always run on process exit
+ thread::spawn(|| {
+ HANDLE.with(|h| {
+ println!("{}", h.0);
+ });
+ }).join().unwrap();
+ }
+}
+
// except according to those terms.
//
-#![feature(unsafe_destructor, std_misc)]
+#![feature(std_misc)]
pub type Task = isize;
p: Option<*const packet<T>>,
}
- #[unsafe_destructor]
- impl<T:Send> Drop for send_packet<T> {
+ impl<T:Send> Drop for send_packet<T> {
fn drop(&mut self) {
unsafe {
if self.p != None {
p: Option<*const packet<T>>,
}
- #[unsafe_destructor]
- impl<T:Send> Drop for recv_packet<T> {
+ impl<T:Send> Drop for recv_packet<T> {
fn drop(&mut self) {
unsafe {
if self.p != None {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(unsafe_destructor)]
-
use std::cell::Cell;
// This test should behave exactly like issue-2735-3
b: &'a Cell<bool>,
}
-#[unsafe_destructor]
impl<'a> Drop for defer<'a> {
fn drop(&mut self) {
self.b.set(true);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(unsafe_destructor)]
-
use std::cell::Cell;
// This test should behave exactly like issue-2735-2
b: &'a Cell<bool>,
}
-#[unsafe_destructor]
impl<'a> Drop for defer<'a> {
fn drop(&mut self) {
self.b.set(true);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(unsafe_destructor)]
-
trait X {
fn call<T: std::fmt::Debug>(&self, x: &T);
fn default_method<T: std::fmt::Debug>(&self, x: &T) {
}
}
-#[unsafe_destructor]
impl<T: X + std::fmt::Debug> Drop for Z<T> {
fn drop(&mut self) {
// These statements used to cause an ICE.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(unsafe_destructor)]
-
use std::cell::Cell;
struct r<'a> {
b: &'a Cell<isize>,
}
-#[unsafe_destructor]
impl<'a> Drop for r<'a> {
fn drop(&mut self) {
self.b.set(self.b.get() + 1);
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+// aux-build:issue24687_lib.rs
+
+extern crate issue24687_lib as d;
+
+fn main() {
+ // Create a d, which has a destructor whose body will be trans'ed
+ // into the generated code here, and thus the local debuginfo will
+ // need references into the original source locations from
+ // `importer` above.
+ let _d = d::D("Hi");
+}
// except according to those terms.
// aux-build:linkage-visibility.rs
-// ignore-android: FIXME(#10379)
+// ignore-android: FIXME(#10356)
// ignore-windows: std::dynamic_lib does not work on Windows well
+// ignore-musl
#![feature(std_misc)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(unsafe_destructor)]
-
// Make sure the destructor is run for newtype structs.
use std::cell::Cell;
struct Foo<'a>(&'a Cell<isize>);
-#[unsafe_destructor]
impl<'a> Drop for Foo<'a> {
fn drop(&mut self) {
let Foo(i) = *self;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(unsafe_destructor)]
-
use std::cell::Cell;
struct dtor<'a> {
x: &'a Cell<isize>,
}
-#[unsafe_destructor]
impl<'a> Drop for dtor<'a> {
fn drop(&mut self) {
self.x.set(self.x.get() - 1);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//ignore-android
-//ignore-freebsd
-//ignore-ios
-//ignore-dragonfly
-//ignore-bitrig
+// ignore-android
+// ignore-freebsd
+// ignore-ios
+// ignore-dragonfly
+// ignore-bitrig
+// ignore-musl
#![feature(asm)]
// pretty-expanded FIXME #23616
-#![feature(unsafe_destructor)]
-
use std::marker;
pub struct Foo<T>(marker::PhantomData<T>);
}
}
-#[unsafe_destructor]
impl<T> Drop for Foo<T> {
fn drop(&mut self) {
self.next();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(unsafe_destructor)]
-
use std::cell::Cell;
#[derive(Debug)]
i: &'a Cell<isize>,
}
-#[unsafe_destructor]
impl<'a> Drop for r<'a> {
fn drop(&mut self) {
self.i.set(self.i.get() + 1);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(unsafe_destructor)]
-
use std::cell::Cell;
struct shrinky_pointer<'a> {
i: &'a Cell<isize>,
}
-#[unsafe_destructor]
impl<'a> Drop for shrinky_pointer<'a> {
fn drop(&mut self) {
println!("Hello!"); self.i.set(self.i.get() - 1);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(unsafe_destructor)]
-
// Ensures that class dtors run if the object is inside an enum
// variant
}
-#[unsafe_destructor]
impl<'a> Drop for close_res<'a> {
fn drop(&mut self) {
self.i.set(false);
// Test accessing external items from multiple compilation units.
+extern crate sepcomp_extern_lib;
-#[link(name = "sepcomp_extern_lib")]
extern {
#[allow(ctypes)]
fn foo() -> usize;
#![allow(unused_mut)]
#![feature(collections)]
+#![feature(collections_drain)]
extern crate collections;
all_sync_send!(VecMap::<usize>::new(), iter, iter_mut, drain, into_iter, keys, values);
- all_sync_send!(Vec::<usize>::new(), into_iter, drain);
+ all_sync_send!(Vec::<usize>::new(), into_iter);
+ is_sync_send!(Vec::<usize>::new(), drain(..));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(unsafe_destructor)]
-
// Test that we are able to infer a suitable kind for this `move`
// closure that is just called (`FnOnce`).
struct DropMe<'a>(&'a mut i32);
-#[unsafe_destructor]
impl<'a> Drop for DropMe<'a> {
fn drop(&mut self) {
*self.0 += 1;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(unsafe_destructor)]
-
// Test that we are able to infer a suitable kind for this closure
// that is just called (`FnOnce`).
struct DropMe<'a>(&'a mut i32);
-#[unsafe_destructor]
impl<'a> Drop for DropMe<'a> {
fn drop(&mut self) {
*self.0 += 1;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(unsafe_destructor)]
-
use std::cell::Cell;
// Make sure that destructors get run on slice literals
x: &'a Cell<isize>,
}
-#[unsafe_destructor]
impl<'a> Drop for foo<'a> {
fn drop(&mut self) {
self.x.set(self.x.get() + 1);