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).
CFG_DISABLE_OPTIMIZE=1
CFG_DISABLE_OPTIMIZE_CXX=1
fi
- CFG_ENABLE_LLVM_ASSERTIONS=1
CFG_ENABLE_DEBUG_ASSERTIONS=1
CFG_ENABLE_DEBUG_JEMALLOC=1
+ CFG_ENABLE_DEBUGINFO=1
+ CFG_ENABLE_LLVM_ASSERTIONS=1
fi
# OK, now write the debugging options
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
## Special Unicode Productions
The following productions in the Rust grammar are defined in terms of Unicode
-properties: `ident`, `non_null`, `non_star`, `non_eol`, `non_slash_or_star`,
-`non_single_quote` and `non_double_quote`.
+properties: `ident`, `non_null`, `non_eol`, `non_single_quote` and
+`non_double_quote`.
### Identifiers
-The `ident` production is any nonempty Unicode string of the following form:
+The `ident` production is any nonempty Unicode[^non_ascii_idents] string of
+the following form:
+
+[^non_ascii_idents]: Non-ASCII characters in identifiers are currently feature
+ gated. This is expected to improve soon.
- The first character has property `XID_start`
- The remaining characters have property `XID_continue`
- `non_null` is any single Unicode character aside from `U+0000` (null)
- `non_eol` is `non_null` restricted to exclude `U+000A` (`'\n'`)
-- `non_star` is `non_null` restricted to exclude `U+002A` (`*`)
-- `non_slash_or_star` is `non_null` restricted to exclude `U+002F` (`/`) and `U+002A` (`*`)
- `non_single_quote` is `non_null` restricted to exclude `U+0027` (`'`)
- `non_double_quote` is `non_null` restricted to exclude `U+0022` (`"`)
<p id="keyword-table-marker"></p>
-| | | | | |
-|----------|----------|----------|----------|--------|
-| abstract | alignof | as | become | box |
-| break | const | continue | crate | do |
-| else | enum | extern | false | final |
-| fn | for | if | impl | in |
-| let | loop | match | mod | move |
-| mut | offsetof | once | override | priv |
-| proc | pub | pure | ref | return |
-| sizeof | static | self | struct | super |
-| true | trait | type | typeof | unsafe |
-| unsized | use | virtual | where | while |
-| yield | | | | |
+| | | | | |
+|----------|----------|----------|----------|---------|
+| abstract | alignof | as | become | box |
+| break | const | continue | crate | do |
+| else | enum | extern | false | final |
+| fn | for | if | impl | in |
+| let | loop | macro | match | mod |
+| move | mut | offsetof | override | priv |
+| proc | pub | pure | ref | return |
+| Self | self | sizeof | static | struct |
+| super | trait | true | type | typeof |
+| unsafe | unsized | use | virtual | where |
+| while | yield | | | |
Each of these keywords has special meaning in its grammar, and all of them are
idx_expr : expr '[' expr ']' ;
```
+### Range expressions
+
+```antlr
+range_expr : expr ".." expr |
+ expr ".." |
+ ".." expr |
+ ".." ;
+```
+
### Unary operator expressions
**FIXME:** grammar?
### While loops
```antlr
-while_expr : "while" no_struct_literal_expr '{' block '}' ;
+while_expr : [ lifetime ':' ] "while" no_struct_literal_expr '{' block '}' ;
```
### Infinite loops
### For expressions
```antlr
-for_expr : "for" pat "in" no_struct_literal_expr '{' block '}' ;
+for_expr : [ lifetime ':' ] "for" pat "in" no_struct_literal_expr '{' block '}' ;
```
### If expressions
# Notation
-Rust's grammar is defined over Unicode code points, each conventionally denoted
-`U+XXXX`, for 4 or more hexadecimal digits `X`. _Most_ of Rust's grammar is
-confined to the ASCII range of Unicode, and is described in this document by a
-dialect of Extended Backus-Naur Form (EBNF), specifically a dialect of EBNF
-supported by common automated LL(k) parsing tools such as `llgen`, rather than
-the dialect given in ISO 14977. The dialect can be defined self-referentially
-as follows:
-
-```{.ebnf .notation}
-grammar : rule + ;
-rule : nonterminal ':' productionrule ';' ;
-productionrule : production [ '|' production ] * ;
-production : term * ;
-term : element repeats ;
-element : LITERAL | IDENTIFIER | '[' productionrule ']' ;
-repeats : [ '*' | '+' ] NUMBER ? | NUMBER ? | '?' ;
-```
-
-Where:
-
-- Whitespace in the grammar is ignored.
-- Square brackets are used to group rules.
-- `LITERAL` is a single printable ASCII character, or an escaped hexadecimal
- ASCII code of the form `\xQQ`, in single quotes, denoting the corresponding
- Unicode code point `U+00QQ`.
-- `IDENTIFIER` is a nonempty string of ASCII letters and underscores.
-- The `repeat` forms apply to the adjacent `element`, and are as follows:
- - `?` means zero or one repetition
- - `*` means zero or more repetitions
- - `+` means one or more repetitions
- - NUMBER trailing a repeat symbol gives a maximum repetition count
- - NUMBER on its own gives an exact repetition count
-
-This EBNF dialect should hopefully be familiar to many readers.
-
## Unicode productions
A few productions in Rust's grammar permit Unicode code points outside the ASCII
provided to the grammar verifier, restricted to ASCII range, when verifying the
grammar in this document.
-## Special Unicode Productions
-
-The following productions in the Rust grammar are defined in terms of Unicode
-properties: `ident`, `non_null`, `non_star`, `non_eol`, `non_slash_or_star`,
-`non_single_quote` and `non_double_quote`.
+## Identifiers
-### Identifiers
+An identifier is any nonempty Unicode[^non_ascii_idents] string of the following form:
-The `ident` production is any nonempty Unicode string of the following form:
+[^non_ascii_idents]: Non-ASCII characters in identifiers are currently feature
+ gated. This is expected to improve soon.
- The first character has property `XID_start`
- The remaining characters have property `XID_continue`
> character ranges used to form the more familiar C and Java language-family
> identifiers.
-### Delimiter-restricted productions
-
-Some productions are defined by exclusion of particular Unicode characters:
-
-- `non_null` is any single Unicode character aside from `U+0000` (null)
-- `non_eol` is `non_null` restricted to exclude `U+000A` (`'\n'`)
-- `non_star` is `non_null` restricted to exclude `U+002A` (`*`)
-- `non_slash_or_star` is `non_null` restricted to exclude `U+002F` (`/`) and `U+002A` (`*`)
-- `non_single_quote` is `non_null` restricted to exclude `U+0027` (`'`)
-- `non_double_quote` is `non_null` restricted to exclude `U+0022` (`"`)
-
## Comments
-```{.ebnf .gram}
-comment : block_comment | line_comment ;
-block_comment : "/*" block_comment_body * "*/" ;
-block_comment_body : [block_comment | character] * ;
-line_comment : "//" non_eol * ;
-```
-
-Comments in Rust code follow the general C++ style of line and block-comment
-forms. Nested block comments are supported.
+Comments in Rust code follow the general C++ style of line (`//`) and
+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
sequence (`/**`), are interpreted as a special syntax for `doc`
[attributes](#attributes). That is, they are equivalent to writing
-`#[doc="..."]` around the body of the comment (this includes the comment
-characters themselves, i.e. `/// Foo` turns into `#[doc="/// Foo"]`).
+`#[doc="..."]` around the body of the comment, i.e., `/// Foo` turns into
+`#[doc="Foo"]`.
Line comments beginning with `//!` and block comments beginning with `/*!` are
doc comments that apply to the parent of the comment, rather than the item
that follows. That is, they are equivalent to writing `#![doc="..."]` around
-the body of the comment. `//!` comments are usually used to display
-information on the crate index page.
+the body of the comment. `//!` comments are usually used to document
+modules that occupy a source file.
Non-doc comments are interpreted as a form of whitespace.
## Whitespace
-```{.ebnf .gram}
-whitespace_char : '\x20' | '\x09' | '\x0a' | '\x0d' ;
-whitespace : [ whitespace_char | comment ] + ;
-```
+Whitespace is any non-empty string containing any the following characters:
-The `whitespace_char` production is any nonempty Unicode string consisting of
-any of the following Unicode characters: `U+0020` (space, `' '`), `U+0009`
-(tab, `'\t'`), `U+000A` (LF, `'\n'`), `U+000D` (CR, `'\r'`).
+- `U+0020` (space, `' '`)
+- `U+0009` (tab, `'\t'`)
+- `U+000A` (LF, `'\n'`)
+- `U+000D` (CR, `'\r'`)
Rust is a "free-form" language, meaning that all forms of whitespace serve only
to separate _tokens_ in the grammar, and have no semantic significance.
## Tokens
-```{.ebnf .gram}
-simple_token : keyword | unop | binop ;
-token : simple_token | ident | literal | symbol | whitespace token ;
-```
-
Tokens are primitive productions in the grammar defined by regular
(non-recursive) languages. "Simple" tokens are given in [string table
production](#string-table-productions) form, and occur in the rest of the
grammar as double-quoted strings. Other tokens have exact rules given.
-### Keywords
-
-<p id="keyword-table-marker"></p>
-
-| | | | | |
-|----------|----------|----------|----------|---------|
-| abstract | alignof | as | become | box |
-| break | const | continue | crate | do |
-| else | enum | extern | false | final |
-| fn | for | if | impl | in |
-| let | loop | macro | match | mod |
-| move | mut | offsetof | override | priv |
-| proc | pub | pure | ref | return |
-| Self | self | sizeof | static | struct |
-| super | trait | true | type | typeof |
-| unsafe | unsized | use | virtual | where |
-| while | yield | | | |
-
-
-Each of these keywords has special meaning in its grammar, and all of them are
-excluded from the `ident` rule.
-
-Note that some of these keywords are reserved, and do not currently do
-anything.
-
### Literals
A literal is an expression consisting of a single token, rather than a sequence
rather than referring to it by name or some other evaluation rule. A literal is
a form of constant expression, so is evaluated (primarily) at compile time.
-```{.ebnf .gram}
-lit_suffix : ident;
-literal : [ string_lit | char_lit | byte_string_lit | byte_lit | num_lit ] lit_suffix ?;
-```
-
The optional suffix is only used for certain numeric literals, but is
reserved for future extension, that is, the above gives the lexical
grammar, but a Rust parser will reject everything but the 12 special
#### Character and string literals
-```{.ebnf .gram}
-char_lit : '\x27' char_body '\x27' ;
-string_lit : '"' string_body * '"' | 'r' raw_string ;
-
-char_body : non_single_quote
- | '\x5c' [ '\x27' | common_escape | unicode_escape ] ;
-
-string_body : non_double_quote
- | '\x5c' [ '\x22' | common_escape | unicode_escape ] ;
-raw_string : '"' raw_string_body '"' | '#' raw_string '#' ;
-
-common_escape : '\x5c'
- | 'n' | 'r' | 't' | '0'
- | 'x' hex_digit 2
-
-unicode_escape : 'u' '{' hex_digit+ 6 '}';
-
-hex_digit : 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
- | 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
- | dec_digit ;
-oct_digit : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' ;
-dec_digit : '0' | nonzero_dec ;
-nonzero_dec: '1' | '2' | '3' | '4'
- | '5' | '6' | '7' | '8' | '9' ;
-```
-
##### Character literals
A _character literal_ is a single Unicode character enclosed within two
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";
Raw string literals do not process any escapes. They start with the character
`U+0072` (`r`), followed by zero or more of the character `U+0023` (`#`) and a
-`U+0022` (double-quote) character. The _raw string body_ is not defined in the
-EBNF grammar above: it can contain any sequence of Unicode characters and is
-terminated only by another `U+0022` (double-quote) character, followed by the
-same number of `U+0023` (`#`) characters that preceded the opening `U+0022`
-(double-quote) character.
+`U+0022` (double-quote) character. The _raw string body_ can contain any sequence
+of Unicode characters and is terminated only by another `U+0022` (double-quote)
+character, followed by the same number of `U+0023` (`#`) characters that preceded
+the opening `U+0022` (double-quote) character.
All Unicode characters contained in the raw string body represent themselves,
the characters `U+0022` (double-quote) (except when followed by at least as
#### Byte and byte string literals
-```{.ebnf .gram}
-byte_lit : "b\x27" byte_body '\x27' ;
-byte_string_lit : "b\x22" string_body * '\x22' | "br" raw_byte_string ;
-
-byte_body : ascii_non_single_quote
- | '\x5c' [ '\x27' | common_escape ] ;
-
-byte_string_body : ascii_non_double_quote
- | '\x5c' [ '\x22' | common_escape ] ;
-raw_byte_string : '"' raw_byte_string_body '"' | '#' raw_byte_string '#' ;
-
-```
-
##### Byte literals
A _byte literal_ is a single ASCII character (in the `U+0000` to `U+007F`
-range) enclosed within two `U+0027` (single-quote) characters, with the
-exception of `U+0027` itself, which must be _escaped_ by a preceding U+005C
-character (`\`), or a single _escape_. It is equivalent to a `u8` unsigned
-8-bit integer _number literal_.
+range) or a single _escape_ preceded by the characters `U+0062` (`b`) and
+`U+0027` (single-quote), and followed by the character `U+0027`. If the character
+`U+0027` is present within the literal, it must be _escaped_ by a preceding
+`U+005C` (`\`) character. It is equivalent to a `u8` unsigned 8-bit integer
+_number literal_.
##### Byte string literals
followed by the character `U+0022`. If the character `U+0022` is present within
the literal, it must be _escaped_ by a preceding `U+005C` (`\`) character.
Alternatively, a byte string literal can be a _raw byte string literal_, defined
-below. A byte string literal is equivalent to a `&'static [u8]` borrowed array
+below. A byte string literal of length `n` is equivalent to a `&'static [u8; n]` borrowed fixed-sized array
of unsigned 8-bit integers.
Some additional _escapes_ are available in either byte or non-raw byte string
Raw byte string literals do not process any escapes. They start with the
character `U+0062` (`b`), followed by `U+0072` (`r`), followed by zero or more
of the character `U+0023` (`#`), and a `U+0022` (double-quote) character. The
-_raw string body_ is not defined in the EBNF grammar above: it can contain any
-sequence of ASCII characters and is terminated only by another `U+0022`
-(double-quote) character, followed by the same number of `U+0023` (`#`)
-characters that preceded the opening `U+0022` (double-quote) character. A raw
-byte string literal can not contain any non-ASCII byte.
+_raw string body_ can contain any sequence of ASCII characters and is terminated
+only by another `U+0022` (double-quote) character, followed by the same number of
+`U+0023` (`#`) characters that preceded the opening `U+0022` (double-quote)
+character. A raw byte string literal can not contain any non-ASCII byte.
All characters contained in the raw string body represent their ASCII encoding,
the characters `U+0022` (double-quote) (except when followed by at least as
#### Number literals
-```{.ebnf .gram}
-num_lit : nonzero_dec [ dec_digit | '_' ] * float_suffix ?
- | '0' [ [ dec_digit | '_' ] * float_suffix ?
- | 'b' [ '1' | '0' | '_' ] +
- | 'o' [ oct_digit | '_' ] +
- | 'x' [ hex_digit | '_' ] + ] ;
-
-float_suffix : [ exponent | '.' dec_lit exponent ? ] ? ;
-
-exponent : ['E' | 'e'] ['-' | '+' ] ? dec_lit ;
-dec_lit : [ dec_digit | '_' ] + ;
-```
-
A _number literal_ is either an _integer literal_ or a _floating-point
literal_. The grammar for recognizing the two kinds of literals is mixed.
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:
```
### Symbols
-```{.ebnf .gram}
-symbol : "::" | "->"
- | '#' | '[' | ']' | '(' | ')' | '{' | '}'
- | ',' | ';' ;
-```
-
Symbols are a general class of printable [token](#tokens) that play structural
roles in a variety of grammar productions. They are catalogued here for
completeness as the set of remaining miscellaneous printable tokens that do not
## Paths
-```{.ebnf .gram}
-expr_path : [ "::" ] ident [ "::" expr_path_tail ] + ;
-expr_path_tail : '<' type_expr [ ',' type_expr ] + '>'
- | expr_path ;
-
-type_path : ident [ type_path_tail ] + ;
-type_path_tail : '<' type_expr [ ',' type_expr ] + '>'
- | "::" type_path ;
-```
-
A _path_ is a sequence of one or more path components _logically_ separated by
a namespace qualifier (`::`). If a path consists of only one component, it may
refer to either an [item](#items) or a [variable](#variables) in a local control
## Macros
-```{.ebnf .gram}
-expr_macro_rules : "macro_rules" '!' ident '(' macro_rule * ')' ;
-macro_rule : '(' matcher * ')' "=>" '(' transcriber * ')' ';' ;
-matcher : '(' matcher * ')' | '[' matcher * ']'
- | '{' matcher * '}' | '$' ident ':' ident
- | '$' '(' matcher * ')' sep_token? [ '*' | '+' ]
- | non_special_token ;
-transcriber : '(' transcriber * ')' | '[' transcriber * ']'
- | '{' transcriber * '}' | '$' ident
- | '$' '(' transcriber * ')' sep_token? [ '*' | '+' ]
- | non_special_token ;
-```
-
`macro_rules` allows users to define syntax extension in a declarative way. We
call such extensions "macros by example" or simply "macros" — to be distinguished
from the "procedural macros" defined in [compiler plugins][plugin].
## Items
-```{.ebnf .gram}
-item : extern_crate_decl | use_decl | mod_item | fn_item | type_item
- | struct_item | enum_item | static_item | trait_item | impl_item
- | extern_block ;
-```
-
An _item_ is a component of a crate. Items are organized within a crate by a
nested set of [modules](#modules). Every crate has a single "outermost"
anonymous module; all further items within the crate have [paths](#paths)
### Modules
-```{.ebnf .gram}
-mod_item : "mod" ident ( ';' | '{' mod '}' );
-mod : item * ;
-```
-
A module is a container for zero or more [items](#items).
A _module item_ is a module, surrounded in braces, named, and prefixed with the
##### Extern crate declarations
-```{.ebnf .gram}
-extern_crate_decl : "extern" "crate" crate_name
-crate_name: ident | ( string_lit "as" ident )
-```
-
An _`extern crate` declaration_ specifies a dependency on an external crate.
The external crate is then bound into the declaring scope as the `ident`
provided in the `extern_crate_decl`.
##### Use declarations
-```{.ebnf .gram}
-use_decl : "pub" ? "use" [ path "as" ident
- | path_glob ] ;
-
-path_glob : ident [ "::" [ path_glob
- | '*' ] ] ?
- | '{' path_item [ ',' path_item ] * '}' ;
-
-path_item : ident | "self" ;
-```
-
A _use declaration_ creates one or more local name bindings synonymous with
some other [path](#paths). Usually a `use` declaration is used to shorten the
path required to refer to a module item. These declarations may appear at the
### Constant items
-```{.ebnf .gram}
-const_item : "const" ident ':' type '=' expr ';' ;
-```
-
A *constant item* is a named _constant value_ which is not associated with a
specific memory location in the program. Constants are essentially inlined
wherever they are used, meaning that they are copied directly into the relevant
### Static items
-```{.ebnf .gram}
-static_item : "static" ident ':' type '=' expr ';' ;
-```
-
A *static item* is similar to a *constant*, except that it represents a precise
memory location in the program. A static is never "inlined" at the usage site,
and all references to it refer to the same memory location. Static items have
### External blocks
-```{.ebnf .gram}
-extern_block_item : "extern" '{' extern_block '}' ;
-extern_block : [ foreign_fn ] * ;
-```
-
External blocks form the basis for Rust's foreign function interface.
Declarations in an external block describe symbols in external, non-Rust
libraries.
## Attributes
-```{.ebnf .gram}
-attribute : '#' '!' ? '[' meta_item ']' ;
-meta_item : ident [ '=' literal
- | '(' meta_seq ')' ] ? ;
-meta_seq : meta_item [ ',' meta_seq ] ? ;
-```
-
Any item declaration may have an _attribute_ applied to it. Attributes in Rust
are modeled on Attributes in ECMA-335, with the syntax coming from ECMA-334
(C#). An attribute is a general, free-form metadatum that is interpreted
The lint checks supported by the compiler can be found via `rustc -W help`,
along with their default settings. [Compiler
-plugins](book/plugins.html#lint-plugins) can provide additional lint checks.
+plugins](book/compiler-plugins.html#lint-plugins) can provide additional lint checks.
```{.ignore}
mod m1 {
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.
terms of encapsulation).
If a feature is promoted to a language feature, then all existing programs will
-start to receive compilation warnings about #[feature] directives which enabled
+start to receive compilation warnings about `#![feature]` directives which enabled
the new feature (because the directive is no longer necessary). However, if a
feature is decided to be removed from the language, errors will be issued (if
there isn't a parser error first). The directive in this case is no longer
#### Variable declarations
-```{.ebnf .gram}
-let_decl : "let" pat [':' type ] ? [ init ] ? ';' ;
-init : [ '=' ] expr ;
-```
-
A _variable declaration_ introduces a new set of variable, given by a pattern. The
pattern may be followed by a type annotation, and/or an initializer expression.
When no type annotation is given, the compiler will infer the type, or signal
```{.tuple}
(0,);
(0.0, 4.5);
-("a", 4us, true);
+("a", 4usize, true);
```
### Unit expressions
### Structure expressions
-```{.ebnf .gram}
-struct_expr : expr_path '{' ident ':' expr
- [ ',' ident ':' expr ] *
- [ ".." expr ] '}' |
- expr_path '(' expr
- [ ',' expr ] * ')' |
- expr_path ;
-```
-
There are several forms of structure expressions. A _structure expression_
consists of the [path](#paths) of a [structure item](#structures), followed by
a brace-enclosed list of one or more comma-separated name-value pairs,
### Block expressions
-```{.ebnf .gram}
-block_expr : '{' [ stmt ';' | item ] *
- [ expr ] '}' ;
-```
-
A _block expression_ is similar to a module in terms of the declarations that
are possible. Each block conceptually introduces a new namespace scope. Use
items can bring new names into scopes and declared items are in scope for only
### Method-call expressions
-```{.ebnf .gram}
-method_call_expr : expr '.' ident paren_expr_list ;
-```
-
A _method call_ consists of an expression followed by a single dot, an
identifier, and a parenthesized expression-list. Method calls are resolved to
methods on specific traits, either statically dispatching to a method if the
### Field expressions
-```{.ebnf .gram}
-field_expr : expr '.' ident ;
-```
-
A _field expression_ consists of an expression followed by a single dot and an
identifier, when not immediately followed by a parenthesized expression-list
(the latter is a [method call expression](#method-call-expressions)). A field
### Array expressions
-```{.ebnf .gram}
-array_expr : '[' "mut" ? array_elems? ']' ;
-
-array_elems : [expr [',' expr]*] | [expr ';' expr] ;
-```
-
An [array](#array,-and-slice-types) _expression_ is written by enclosing zero
or more comma-separated expressions of uniform type in square brackets.
### Index expressions
-```{.ebnf .gram}
-idx_expr : expr '[' expr ']' ;
-```
-
[Array](#array,-and-slice-types)-typed expressions can be indexed by
writing a square-bracket-enclosed expression (the index) after them. When the
array is mutable, the resulting [lvalue](#lvalues,-rvalues-and-temporaries) can
### Range expressions
-```{.ebnf .gram}
-range_expr : expr ".." expr |
- expr ".." |
- ".." expr |
- ".." ;
-```
-
The `..` operator will construct an object of one of the `std::ops::Range` variants.
```
### Binary operator expressions
-```{.ebnf .gram}
-binop_expr : expr binop expr ;
-```
-
Binary operators expressions are given in terms of [operator
precedence](#operator-precedence).
expression. Parentheses can be used to explicitly specify evaluation order
within an expression.
-```{.ebnf .gram}
-paren_expr : '(' expr ')' ;
-```
-
An example of a parenthesized expression:
```
### Call expressions
-```{.ebnf .gram}
-expr_list : [ expr [ ',' expr ]* ] ? ;
-paren_expr_list : '(' expr_list ')' ;
-call_expr : expr paren_expr_list ;
-```
-
A _call expression_ invokes a function, providing zero or more input variables
and an optional location to move the function's output into. If the function
eventually returns, then the expression completes.
### Lambda expressions
-```{.ebnf .gram}
-ident_list : [ ident [ ',' ident ]* ] ? ;
-lambda_expr : '|' ident_list '|' expr ;
-```
-
A _lambda expression_ (sometimes called an "anonymous function expression")
defines a function and denotes it as a value, in a single expression. A lambda
expression is a pipe-symbol-delimited (`|`) list of identifiers followed by an
A `loop` expression denotes an infinite loop.
-```{.ebnf .gram}
-loop_expr : [ lifetime ':' ] "loop" '{' block '}';
-```
-
A `loop` expression may optionally have a _label_. The label is written as
a lifetime preceding the loop expression, as in `'foo: loop{ }`. If a
label is present, then labeled `break` and `continue` expressions nested
### Break expressions
-```{.ebnf .gram}
-break_expr : "break" [ lifetime ];
-```
-
A `break` expression has an optional _label_. If the label is absent, then
executing a `break` expression immediately terminates the innermost loop
enclosing it. It is only permitted in the body of a loop. If the label is
### Continue expressions
-```{.ebnf .gram}
-continue_expr : "continue" [ lifetime ];
-```
-
A `continue` expression has an optional _label_. If the label is absent, then
executing a `continue` expression immediately terminates the current iteration
of the innermost loop enclosing it, returning control to the loop *head*. In
### While loops
-```{.ebnf .gram}
-while_expr : [ lifetime ':' ] "while" no_struct_literal_expr '{' block '}' ;
-```
-
A `while` loop begins by evaluating the boolean loop conditional expression.
If the loop conditional expression evaluates to `true`, the loop body block
executes and control returns to the loop conditional expression. If the loop
### For expressions
-```{.ebnf .gram}
-for_expr : [ lifetime ':' ] "for" pat "in" no_struct_literal_expr '{' block '}' ;
-```
-
A `for` expression is a syntactic construct for looping over elements provided
-by an implementation of `std::iter::Iterator`.
+by an implementation of `std::iter::IntoIterator`.
An example of a for loop over the contents of an array:
```
# type Foo = i32;
-# fn bar(f: Foo) { }
+# fn bar(f: &Foo) { }
# let a = 0;
# let b = 0;
# let c = 0;
let v: &[Foo] = &[a, b, c];
-for e in v.iter() {
- bar(*e);
+for e in v {
+ bar(e);
}
```
### If expressions
-```{.ebnf .gram}
-if_expr : "if" no_struct_literal_expr '{' block '}'
- else_tail ? ;
-
-else_tail : "else" [ if_expr | if_let_expr
- | '{' block '}' ] ;
-```
-
An `if` expression is a conditional branch in program control. The form of an
`if` expression is a condition expression, followed by a consequent block, any
number of `else if` conditions and blocks, and an optional trailing `else`
### Match expressions
-```{.ebnf .gram}
-match_expr : "match" no_struct_literal_expr '{' match_arm * '}' ;
-
-match_arm : attribute * match_pat "=>" [ expr "," | '{' block '}' ] ;
-
-match_pat : pat [ '|' pat ] * [ "if" expr ] ? ;
-```
-
A `match` expression branches on a *pattern*. The exact form of matching that
occurs depends on the pattern. Patterns consist of some combination of
literals, destructured arrays or enum constructors, structures and tuples,
### If let expressions
-```{.ebnf .gram}
-if_let_expr : "if" "let" pat '=' expr '{' block '}'
- else_tail ? ;
-else_tail : "else" [ if_expr | if_let_expr | '{' block '}' ] ;
-```
-
An `if let` expression is semantically identical to an `if` expression but in place
of a condition expression it expects a refutable let statement. If the value of the
expression on the right hand side of the let statement matches the pattern, the corresponding
### While let loops
-```{.ebnf .gram}
-while_let_expr : "while" "let" pat '=' expr '{' block '}' ;
-```
-
A `while let` loop is semantically identical to a `while` loop but in place of a
condition expression it expects a refutable let statement. If the value of the
expression on the right hand side of the let statement matches the pattern, the
### Return expressions
-```{.ebnf .gram}
-return_expr : "return" expr ? ;
-```
-
Return expressions are denoted with the keyword `return`. Evaluating a `return`
expression moves its argument into the designated output location for the
current function call, destroys the current function activation frame, and
The primitive types are the following:
-* The "unit" type `()`, having the single "unit" value `()` (occasionally called
- "nil"). [^unittype]
* The boolean type `bool` with values `true` and `false`.
* The machine types.
* The machine-dependent integer and floating-point types.
-[^unittype]: The "unit" value `()` is *not* a sentinel "null pointer" value for
- reference variables; the "unit" type is the implicit return type from functions
- otherwise lacking a return type, and can be used in other contexts (such as
- message-sending or type-parametric code) as a zero-size type.]
-
#### Machine types
The machine types are the following:
A value of type `str` is a Unicode string, represented as an array of 8-bit
unsigned bytes holding a sequence of UTF-8 code points. Since `str` is of
unknown size, it is not a _first-class_ type, but can only be instantiated
-through a pointer type, such as `&str` or `String`.
+through a pointer type, such as `&str`.
### Tuple types
A `struct` *type* is a heterogeneous product of other types, called the
*fields* of the type.[^structtype]
-[^structtype]: `struct` types are analogous `struct` types in C,
+[^structtype]: `struct` types are analogous to `struct` types in C,
the *record* types of the ML family,
or the *structure* types of the Lisp family.
have the same memory layout.
The fields of a `struct` may be qualified by [visibility
-modifiers](#re-exporting-and-visibility), to allow access to data in a
+modifiers](#visibility-and-privacy), to allow access to data in a
structure outside a module.
A _tuple struct_ type is just like a structure type, except that the fields are
* References (`&`)
: These point to memory _owned by some other value_.
- A reference type is written `&type` for some lifetime-variable `f`,
- or just `&'a type` when you need an explicit lifetime.
+ A reference type is written `&type`,
+ or `&'a type` when you need to specify an explicit lifetime.
Copying a reference is a "shallow" operation:
it involves only copying the pointer itself.
- Releasing a reference typically has no effect on the value it points to,
- with the exception of temporary values, which are released when the last
- reference to them is released.
+ Releasing a reference has no effect on the value it points to,
+ but a reference of a temporary value will keep it alive during the scope
+ of the reference itself.
* Raw pointers (`*`)
: Raw pointers are pointers without safety or liveness guarantees.
Raw pointers are written as `*const T` or `*mut T`,
- for example `*const int` means a raw pointer to an integer.
+ for example `*const i32` means a raw pointer to a 32-bit integer.
Copying or dropping a raw pointer has no effect on the lifecycle of any
other value. Dereferencing a raw pointer or converting it to any other
pointer type is an [`unsafe` operation](#unsafe-functions).
### Closure types
-```{.ebnf .notation}
-closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|'
- [ ':' bound-list ] [ '->' type ]
-lifetime-list := lifetime | lifetime ',' lifetime-list
-arg-list := ident ':' type | ident ':' type ',' arg-list
-bound-list := bound | bound '+' bound-list
-bound := path | lifetime
-```
-
-The type of a closure mapping an input of type `A` to an output of type `B` is
-`|A| -> B`. A closure with no arguments or return values has type `||`.
+A [lambda expression](#lambda-expressions) produces a closure value with
+a unique, anonymous type that cannot be written out.
-An example of creating and calling a closure:
+Depending on the requirements of the closure, its type implements one or
+more of the closure traits:
-```rust
-let captured_var = 10;
+* `FnOnce`
+ : The closure can be called once. A closure called as `FnOnce`
+ can move out values from its environment.
-let closure_no_args = || println!("captured_var={}", captured_var);
+* `FnMut`
+ : The closure can be called multiple times as mutable. A closure called as
+ `FnMut` can mutate values from its environment. `FnMut` implies
+ `FnOnce`.
-let closure_args = |arg: i32| -> i32 {
- println!("captured_var={}, arg={}", captured_var, arg);
- arg // Note lack of semicolon after 'arg'
-};
+* `Fn`
+ : The closure can be called multiple times through a shared reference.
+ A closure called as `Fn` can neither move out from nor mutate values
+ from its environment. `Fn` implies `FnMut` and `FnOnce`.
-fn call_closure<F: Fn(), G: Fn(i32) -> i32>(c1: F, c2: G) {
- c1();
- c2(2);
-}
-
-call_closure(closure_no_args, closure_args);
-
-```
### Trait objects
its type parameters are types:
```ignore
-fn map<A: Clone, B: Clone>(f: |A| -> B, xs: &[A]) -> Vec<B> {
+fn to_vec<A: Clone>(xs: &[A]) -> Vec<A> {
if xs.is_empty() {
return vec![];
}
- let first: B = f(xs[0].clone());
- let mut rest: Vec<B> = map(f, xs.slice(1, xs.len()));
+ let first: A = xs[0].clone();
+ let mut rest: Vec<A> = to_vec(&xs[1..]);
rest.insert(0, first);
- return rest;
+ rest
}
```
-Here, `first` has type `B`, referring to `map`'s `B` type parameter; and `rest`
-has type `Vec<B>`, a vector type with element type `B`.
+Here, `first` has type `A`, referring to `to_vec`'s `A` type parameter; and `rest`
+has type `Vec<A>`, a vector with element type `A`.
### Self types
pattern syntax
[ffi]: book/ffi.html
-[plugin]: book/plugins.html
+[plugin]: book/compiler-plugins.html
% Unit testing
-Unit tests should live in a `test` submodule at the bottom of the module they
-test. Mark the `test` submodule with `#[cfg(test)]` so it is only compiled when
+Unit tests should live in a `tests` submodule at the bottom of the module they
+test. Mark the `tests` submodule with `#[cfg(test)]` so it is only compiled when
testing.
-The `test` module should contain:
+The `tests` module should contain:
* Imports needed only for testing.
* Functions marked with `#[test]` striving for full coverage of the parent module's
// Excerpt from std::str
#[cfg(test)]
-mod test {
+mod tests {
#[test]
fn test_eq() {
assert!((eq(&"".to_owned(), &"".to_owned())));
requirements, and writing low-level code, like device drivers and operating
systems. It improves on current languages targeting this space by having a
number of compile-time safety checks that produce no runtime overhead, while
-eliminating all data races. Rust also aims to achieve ‘zero-cost abstrations’
+eliminating all data races. Rust also aims to achieve ‘zero-cost abstractions’
even though some of these abstractions feel like those of a high-level
language. Even then, Rust still allows precise control like a low-level
language would.
* [Strings](strings.md)
* [Generics](generics.md)
* [Traits](traits.md)
- * [Operators and Overloading](operators-and-overloading.md)
* [Drop](drop.md)
* [if let](if-let.md)
* [Trait Objects](trait-objects.md)
* [Casting between types](casting-between-types.md)
* [Associated Types](associated-types.md)
* [Unsized Types](unsized-types.md)
+ * [Operators and Overloading](operators-and-overloading.md)
* [Deref coercions](deref-coercions.md)
* [Macros](macros.md)
* [Raw Pointers](raw-pointers.md)
There’s one other key point here: because we’re bounding a generic with a
trait, this will get monomorphized, and therefore, we’ll be doing static
-dispatch into the closure. That’s pretty neat. In many langauges, closures are
+dispatch into the closure. That’s pretty neat. In many languages, closures are
inherently heap allocated, and will always involve dynamic dispatch. In Rust,
we can stack allocate our closure environment, and statically dispatch the
call. This happens quite often with iterators and their adapters, which often
}
```
+[unsafe]: unsafe.html
+
Furthermore, any type stored in a `static` must be `Sync`.
# Initializing
% `Deref` coercions
-Coming soon!
+The standard library provides a special trait, [`Deref`][deref]. It’s normally
+used to overload `*`, the dereference operator:
+
+```rust
+use std::ops::Deref;
+
+struct DerefExample<T> {
+ value: T,
+}
+
+impl<T> Deref for DerefExample<T> {
+ type Target = T;
+
+ fn deref(&self) -> &T {
+ &self.value
+ }
+}
+
+fn main() {
+ let x = DerefExample { value: 'a' };
+ assert_eq!('a', *x);
+}
+```
+
+[deref]: ../std/ops/trait.Deref.html
+
+This is useful for writing custom pointer types. However, there’s a language
+feature related to `Deref`: ‘deref coercions’. Here’s the rule: If you have a
+type `U`, and it implements `Deref<Target=T>`, values of `&U` will
+automatically coerce to a `&T`. Here’s an example:
+
+```rust
+fn foo(s: &str) {
+ // borrow a string for a second
+}
+
+// String implements Deref<Target=str>
+let owned = "Hello".to_string();
+
+// therefore, this works:
+foo(&owned);
+```
+
+Using an ampersand in front of a value takes a reference to it. So `owned` is a
+`String`, `&owned` is an `&String`, and since `impl Deref<Target=str> for
+String`, `&String` will deref to `&str`, which `foo()` takes.
+
+That’s it. This rule is one of the only places in which Rust does an automatic
+conversion for you, but it adds a lot of flexibility. For example, the `Rc<T>`
+type implements `Deref<Target=T>`, so this works:
+
+```rust
+use std::rc::Rc;
+
+fn foo(s: &str) {
+ // borrow a string for a second
+}
+
+// String implements Deref<Target=str>
+let owned = "Hello".to_string();
+let counted = Rc::new(owned);
+
+// therefore, this works:
+foo(&counted);
+```
+
+All we’ve done is wrap our `String` in an `Rc<T>`. But we can now pass the
+`Rc<String>` around anywhere we’d have a `String`. The signature of `foo`
+didn’t change, but works just as well with either type. This example has two
+conversions: `Rc<String>` to `String` and then `String` to `&str`. Rust will do
+this as many times as possible until the types match.
+
+Another very common implementation provided by the standard library is:
+
+```rust
+fn foo(s: &[i32]) {
+ // borrow a slice for a second
+}
+
+// Vec<T> implements Deref<Target=[T]>
+let owned = vec![1, 2, 3];
+
+foo(&owned);
+```
+
+Vectors can `Deref` to a slice.
+
+## Deref and method calls
+
+`Deref` will also kick in when calling a method. In other words, these are
+the same two things in Rust:
+
+```rust
+struct Foo;
+
+impl Foo {
+ fn foo(&self) { println!("Foo"); }
+}
+
+let f = Foo;
+
+f.foo();
+```
+
+Even though `f` isn’t a reference, and `foo` takes `&self`, this works.
+That’s because these things are the same:
+
+```rust,ignore
+f.foo();
+(&f).foo();
+(&&f).foo();
+(&&&&&&&&f).foo();
+```
+
+A value of type `&&&&&&&&&&&&&&&&Foo` can still have methods defined on `Foo`
+called, because the compiler will insert as many * operations as necessary to
+get it right. And since it’s inserting `*`s, that uses `Deref`.
## Generation options
-`rustdoc` also contains a few other options on the command line, for further customiziation:
+`rustdoc` also contains a few other options on the command line, for further customization:
- `--html-in-header FILE`: includes the contents of FILE at the end of the
`<head>...</head>` section.
% Getting Started
This first section of the book will get you going with Rust and its tooling.
-First, we’ll install Rust. Then: the classic ‘Hello World’ program. Finally,
+First, we’ll install Rust. Then, the classic ‘Hello World’ program. Finally,
we’ll talk about Cargo, Rust’s build system and package manager.
When a compiler is compiling your program, it does a number of different
things. One of the things that it does is turn the text of your program into an
-'abstract syntax tree,' or 'AST.' This tree is a representation of the
+‘abstract syntax tree’, or‘AST’. This tree is a representation of the
structure of your program. For example, `2 + 3` can be turned into a tree:
```text
$ 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
Luckily, as you may have guessed with the leading question, you can! Rust provides
the ability to use this ‘method call syntax’ via the `impl` keyword.
-## Method calls
+# Method calls
Here’s how it works:
}
```
-## Chaining method calls
+# Chaining method calls
So, now we know how to call a method, such as `foo.bar()`. But what about our
original example, `foo.bar().baz()`? This is called ‘method chaining’, and we
We just say we’re returning a `Circle`. With this method, we can grow a new
circle to any arbitrary size.
-## Static methods
+# Static methods
You can also define methods that do not take a `self` parameter. Here’s a
pattern that’s very common in Rust code:
are called with the `Struct::method()` syntax, rather than the `ref.method()`
syntax.
-## Builder Pattern
+# Builder Pattern
Let’s say that we want our users to be able to create Circles, but we will
allow them to only set the properties they care about. Otherwise, the `x`
% Mutability
-Coming Soon
+Mutability, the ability to change something, works a bit differently in Rust
+than in other languages. The first aspect of mutability is its non-default
+status:
+
+```rust,ignore
+let x = 5;
+x = 6; // error!
+```
+
+We can introduce mutability with the `mut` keyword:
+
+```rust
+let mut x = 5;
+
+x = 6; // no problem!
+```
+
+This is a mutable [variable binding][vb]. When a binding is mutable, it means
+you’re allowed to change what the binding points to. So in the above example,
+it’s not so much that the value at `x` is changing, but that the binding
+changed from one `i32` to another.
+
+[vb]: variable-bindings.html
+
+If you want to change what the binding points to, you’ll need a [mutable reference][mr]:
+
+```rust
+let mut x = 5;
+let y = &mut x;
+```
+
+[mr]: references-and-borrowing.html
+
+`y` is an immutable binding to a mutable reference, which means that you can’t
+bind `y` to something else (`y = &mut z`), but you can mutate the thing that’s
+bound to `y`. (`*y = 5`) A subtle distinction.
+
+Of course, if you need both:
+
+```rust
+let mut x = 5;
+let mut y = &mut x;
+```
+
+Now `y` can be bound to another value, and the value it’s referencing can be
+changed.
+
+It’s important to note that `mut` is part of a [pattern][pattern], so you
+can do things like this:
+
+```rust
+let (mut x, y) = (5, 6);
+
+fn foo(mut x: i32) {
+# }
+```
+
+[pattern]: patterns.html
+
+# Interior vs. Exterior Mutability
+
+However, when we say something is ‘immutable’ in Rust, that doesn’t mean that
+it’s not able to be changed: We mean something has ‘exterior mutability’. Consider,
+for example, [`Arc<T>`][arc]:
+
+```rust
+use std::sync::Arc;
+
+let x = Arc::new(5);
+let y = x.clone();
+```
+
+[arc]: ../std/sync/struct.Arc.html
+
+When we call `clone()`, the `Arc<T>` needs to update the reference count. Yet
+we’ve not used any `mut`s here, `x` is an immutable binding, and we didn’t take
+`&mut 5` or anything. So what gives?
+
+To this, we have to go back to the core of Rust’s guiding philosophy, memory
+safety, and the mechanism by which Rust guarantees it, the
+[ownership][ownership] system, and more specifically, [borrowing][borrowing]:
+
+> You may have one or the other of these two kinds of borrows, but not both at
+> the same time:
+>
+> * 0 to N references (`&T`) to a resource.
+> * exactly one mutable reference (`&mut T`)
+
+[ownership]: ownership.html
+[borrowing]: borrowing.html#The-Rules
+
+So, that’s the real definition of ‘immutability’: is this safe to have two
+pointers to? In `Arc<T>`’s case, yes: the mutation is entirely contained inside
+the structure itself. It’s not user facing. For this reason, it hands out `&T`
+with `clone()`. If it handed out `&mut T`s, though, that would be a problem.
+
+Other types, like the ones in the [`std::cell`][stdcell] module, have the
+opposite: interior mutability. For example:
+
+```rust
+use std::cell::RefCell;
+
+let x = RefCell::new(42);
+
+let y = x.borrow_mut();
+```
+
+[stdcell]: ../std/cell/index.html
+
+RefCell hands out `&mut` references to what’s inside of it with the
+`borrow_mut()` method. Isn’t that dangerous? What if we do:
+
+```rust,ignore
+use std::cell::RefCell;
+
+let x = RefCell::new(42);
+
+let y = x.borrow_mut();
+let z = x.borrow_mut();
+# (y, z);
+```
+
+This will in fact panic, at runtime. This is what `RefCell` does: it enforces
+Rust’s borrowing rules at runtime, and `panic!`s if they’re violated. This
+allows us to get around another aspect of Rust’s mutability rules. Let’s talk
+about it first.
+
+## Field-level mutability
+
+Mutability is a property of either a borrow (`&mut`) or a binding (`let mut`).
+This means that, for example, you cannot have a [`struct`][struct] with
+some fields mutable and some immutable:
+
+```rust,ignore
+struct Point {
+ x: i32,
+ mut y: i32, // nope
+}
+```
+
+The mutability of a struct is in its binding:
+
+```rust,ignore
+struct Point {
+ x: i32,
+ y: i32,
+}
+
+let mut a = Point { x: 5, y: 6 };
+
+a.x = 10;
+
+let b = Point { x: 5, y: 6};
+
+b.x = 10; // error: cannot assign to immutable field `b.x`
+```
+
+[struct]: structs.html
+
+However, by using `Cell<T>`, you can emulate field-level mutability:
+
+```
+use std::cell::Cell;
+
+struct Point {
+ x: i32,
+ y: Cell<i32>,
+}
+
+let mut point = Point { x: 5, y: Cell::new(6) };
+
+point.y.set(7);
+
+println!("y: {:?}", point.y);
+```
+
+This will print `y: Cell { value: 7 }`. We’ve successfully updated `y`.
% Operators and Overloading
-Coming soon!
+Rust allows for a limited form of operator overloading. There are certain
+operators that are able to be overloaded. To support a particular operator
+between types, there’s a specific trait that you can implement, which then
+overloads the operator.
+
+For example, the `+` operator can be overloaded with the `Add` trait:
+
+```rust
+use std::ops::Add;
+
+#[derive(Debug)]
+struct Point {
+ x: i32,
+ y: i32,
+}
+
+impl Add for Point {
+ type Output = Point;
+
+ fn add(self, other: Point) -> Point {
+ Point { x: self.x + other.x, y: self.y + other.y }
+ }
+}
+
+fn main() {
+ let p1 = Point { x: 1, y: 0 };
+ let p2 = Point { x: 2, y: 3 };
+
+ let p3 = p1 + p2;
+
+ println!("{:?}", p3);
+}
+```
+
+In `main`, we can use `+` on our two `Point`s, since we’ve implemented
+`Add<Output=Point>` for `Point`.
+
+There are a number of operators that can be overloaded this way, and all of
+their associated traits live in the [`std::ops`][stdops] module. Check out its
+documentation for the full list.
+
+[stdops]: ../std/ops/index.html
+
+Implementing these traits follows a pattern. Let’s look at [`Add`][add] in more
+detail:
+
+```rust
+# mod foo {
+pub trait Add<RHS = Self> {
+ type Output;
+
+ fn add(self, rhs: RHS) -> Self::Output;
+}
+# }
+```
+
+[add]: ../std/ops/trait.Add.html
+
+There’s three types in total involved here: the type you `impl Add` for, `RHS`,
+which defaults to `Self`, and `Output`. For an expression `let z = x + y`, `x`
+is the `Self` type, `y` is the RHS, and `z` is the `Self::Output` type.
+
+```rust
+# struct Point;
+# use std::ops::Add;
+impl Add<i32> for Point {
+ type Output = f64;
+
+ fn add(self, rhs: i32) -> f64 {
+ // add an i32 to a Point and get an f64
+# 1.0
+ }
+}
+```
+
+will let you do this:
+
+```rust,ignore
+let p: Point = // ...
+let x: f64 = p + 2i32;
+```
Here’s a list of the different numeric types, with links to their documentation
in the standard library:
+* [i8](../std/primitive.i8.html)
* [i16](../std/primitive.i16.html)
* [i32](../std/primitive.i32.html)
* [i64](../std/primitive.i64.html)
-* [i8](../std/primitive.i8.html)
+* [u8](../std/primitive.u8.html)
* [u16](../std/primitive.u16.html)
* [u32](../std/primitive.u32.html)
* [u64](../std/primitive.u64.html)
-* [u8](../std/primitive.u8.html)
* [isize](../std/primitive.isize.html)
* [usize](../std/primitive.usize.html)
* [f32](../std/primitive.f32.html)
Integer types come in two varieties: signed and unsigned. To understand the
difference, let’s consider a number with four bits of size. A signed, four-bit
number would let you store numbers from `-8` to `+7`. Signed numbers use
-â\80\98twoâ\80\99s compliment representationâ\80\99. An unsigned four bit number, since it does
+â\80\9ctwoâ\80\99s compliment representationâ\80\9d. An unsigned four bit number, since it does
not need to store negatives, can store values from `0` to `+15`.
Unsigned types use a `u` for their category, and signed types use `i`. The `i`
is for ‘integer’. So `u8` is an eight-bit unsigned number, and `i8` is an
-eight-bit signed number.
+eight-bit signed number.
## Fixed size types
## Floating-point types
-Rust also two floating point types: `f32` and `f64`. These correspond to
+Rust also has two floating point types: `f32` and `f64`. These correspond to
IEEE-754 single and double precision numbers.
# Arrays
Remember [before][let] when I said the left-hand side of a `let` statement was more
powerful than just assigning a binding? Here we are. We can put a pattern on
the left-hand side of the `let`, and if it matches up to the right-hand side,
-we can assign multiple bindings at once. In this case, `let` "destructures,"
-or "breaks up," the tuple, and assigns the bits to three bindings.
+we can assign multiple bindings at once. In this case, `let` “destructures”
+or “breaks up” the tuple, and assigns the bits to three bindings.
[let]: variable-bindings.html
This is a very common use of `assert_eq!`: call some function with
some known arguments and compare it to the expected output.
-# The `test` module
+# The `tests` module
There is one way in which our existing example is not idiomatic: it's
-missing the test module. The idiomatic way of writing our example
+missing the `tests` module. The idiomatic way of writing our example
looks like this:
```{rust,ignore}
}
#[cfg(test)]
-mod test {
+mod tests {
use super::add_two;
#[test]
}
```
-There's a few changes here. The first is the introduction of a `mod test` with
+There's a few changes here. The first is the introduction of a `mod tests` with
a `cfg` attribute. The module allows us to group all of our tests together, and
to also define helper functions if needed, that don't become a part of the rest
of our crate. The `cfg` attribute only compiles our test code if we're
}
#[cfg(test)]
-mod test {
+mod tests {
use super::*;
#[test]
Running target/adder-91b3e234d4ed382a
running 1 test
-test test::it_works ... ok
+test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
It works!
-The current convention is to use the `test` module to hold your "unit-style"
+The current convention is to use the `tests` module to hold your "unit-style"
tests. Anything that just tests one small bit of functionality makes sense to
go here. But what about "integration-style" tests instead? For that, we have
the `tests` directory
Running target/adder-91b3e234d4ed382a
running 1 test
-test test::it_works ... ok
+test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
Now we have three sections: our previous test is also run, as well as our new
one.
-That's all there is to the `tests` directory. The `test` module isn't needed
+That's all there is to the `tests` directory. The `tests` module isn't needed
here, since the whole thing is focused on tests.
Let's finally check out that third section: documentation tests.
}
#[cfg(test)]
-mod test {
+mod tests {
use super::*;
#[test]
Running target/adder-91b3e234d4ed382a
running 1 test
-test test::it_works ... ok
+test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
that implements `Foo`: only one copy is generated, often (but not always)
resulting in less code bloat. However, this comes at the cost of requiring
slower virtual function calls, and effectively inhibiting any chance of
-inlining and related optimisations from occurring.
+inlining and related optimizations from occurring.
### Why pointers?
```rust,ignore
let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt");
let result = f.write("whatever".as_bytes());
-# result.unwrap(); // ignore the erorr
+# result.unwrap(); // ignore the error
```
Here’s the error:
let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt");
let result = f.write("whatever".as_bytes());
-# result.unwrap(); // ignore the erorr
+# result.unwrap(); // ignore the error
```
This will compile without error.
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
% Variable Bindings
-Vitually every non-’Hello World’ Rust program uses *variable bindings*. They
+Virtually every non-'Hello World’ Rust program uses *variable bindings*. They
look like this:
```rust
% 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
API documentation][vec].
[vec]: ../std/vec/index.html
+[generic]: generics.html
;
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
}
// -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 {}
}
#[cfg(test)]
-mod test {
+mod tests {
extern crate test;
use self::test::Bencher;
use boxed::Box;
#[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.
//!
//! ## Precision
//!
-//! For non-numeric types, this can be considered a "maximum width". If the
-//! resulting string is longer than this width, then it is truncated down to
-//! this many characters and only those are emitted.
+//! For non-numeric types, this can be considered a "maximum width". If the resulting string is
+//! longer than this width, then it is truncated down to this many characters and only those are
+//! emitted.
//!
//! For integral types, this has no meaning currently.
//!
-//! For floating-point types, this indicates how many digits after the decimal
-//! point should be printed.
+//! For floating-point types, this indicates how many digits after the decimal point should be
+//! printed.
+//!
+//! There are three possible ways to specify the desired `precision`:
+//!
+//! There are three possible ways to specify the desired `precision`:
+//! 1. An integer `.N`,
+//! 2. an integer followed by dollar sign `.N$`, or
+//! 3. an asterisk `.*`.
+//!
+//! The first specification, `.N`, means the integer `N` itself is the precision.
+//!
+//! The second, `.N$`, means use format *argument* `N` (which must be a `usize`) as the precision.
+//!
+//! Finally, `.*` means that this `{...}` is associated with *two* format inputs rather than one:
+//! the first input holds the `usize` precision, and the second holds the value to print. Note
+//! that in this case, if one uses the format string `{<arg>:<spec>.*}`, then the `<arg>` part
+//! refers to the *value* to print, and the `precision` must come in the input preceding `<arg>`.
+//!
+//! For example, these:
+//!
+//! ```
+//! // Hello {arg 0 (x)} is {arg 1 (0.01} with precision specified inline (5)}
+//! println!("Hello {0} is {1:.5}", "x", 0.01);
+//!
+//! // Hello {arg 1 (x)} is {arg 2 (0.01} with precision specified in arg 0 (5)}
+//! println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
+//!
+//! // Hello {arg 0 (x)} is {arg 2 (0.01} with precision specified in arg 1 (5)}
+//! println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
+//!
+//! // Hello {next arg (x)} is {second of next two args (0.01} with precision
+//! // specified in first of next two args (5)}
+//! println!("Hello {} is {:.*}", "x", 5, 0.01);
+//!
+//! // Hello {next arg (x)} is {arg 2 (0.01} with precision
+//! // specified in its predecessor (5)}
+//! println!("Hello {} is {2:.*}", "x", 5, 0.01);
+//! ```
+//!
+//! All print the same thing:
+//!
+//! ```text
+//! Hello x is 0.01000
+//! ```
+//!
+//! While these:
+//!
+//! ```
+//! println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56);
+//! println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56");
+//! ```
+//!
+//! print two significantly different things:
+//!
+//! ```text
+//! Hello, `1234.560` has 3 fractional digits
+//! Hello, `123` has 3 characters
+//! ```
//!
//! # Escaping
//!
#![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;
}
#[cfg(test)]
-mod test {
+mod tests {
use std::clone::Clone;
use std::iter::{Iterator, IntoIterator};
use std::option::Option::{Some, None, 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;
/// stack.push(2);
/// stack.push(3);
///
-/// loop {
-/// let top = match stack.pop() {
-/// None => break, // empty
-/// Some(x) => x,
-/// };
+/// while let Some(top) = stack.pop() {
/// // Prints 3, 2, 1
/// println!("{}", top);
/// }
///
/// # 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 _,
}
}
}
}
}
-/// 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>
////////////////////////////////////////////////////////////////////////////////
}
/// 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 {
}
#[cfg(test)]
-mod test {
+mod tests {
use core::iter::{Iterator, self};
use core::option::Option::Some;
}
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)]
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];
_marker: PhantomData<*mut T>,
}
+impl<T> Default for AtomicPtr<T> {
+ fn default() -> AtomicPtr<T> {
+ AtomicPtr::new(::ptr::null_mut())
+ }
+}
+
unsafe impl<T> Sync for AtomicPtr<T> {}
/// Atomic memory orderings
///
/// let result = thread::spawn(move || {
/// let c = RefCell::new(5);
- /// let m = c.borrow_mut();
+ /// let m = c.borrow();
///
/// let b = c.borrow_mut(); // this causes a panic
/// }).join();
//! Traits for conversions between types.
//!
//! The traits in this module provide a general way to talk about conversions from one type to
-//! another. They follow the standard Rust conventions of `as`/`to`/`into`/`from`.
+//! another. They follow the standard Rust conventions of `as`/`into`/`from`.
//!
//! Like many traits, these are often used as bounds for generic functions, to support arguments of
//! multiple types.
/// `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);
/// ```
/// Creates an iterator that iterates over both this and the specified
/// iterators simultaneously, yielding the two elements as pairs. When
- /// either iterator returns `None`, all further invocations of next() will
- /// return `None`.
+ /// either iterator returns `None`, all further invocations of `next()`
+ /// will return `None`.
///
/// # Examples
///
}
}
+#[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}
}
#[cfg(test)]
-mod test {
+mod tests {
use core::option::Option;
use core::option::Option::{Some, None};
use core::num::Float;
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.
#[cfg(test)]
-mod test {
+mod tests {
use std::prelude::v1::*;
use core::iter::order;
}
#[cfg(test)]
-mod test {
+mod tests {
use std::prelude::v1::*;
use distributions::{Sample, IndependentSample};
}
#[cfg(test)]
-mod test {
+mod tests {
use std::prelude::v1::*;
use distributions::{Sample, IndependentSample};
#[cfg(test)]
-mod test {
+mod tests {
use std::prelude::v1::*;
use core::iter::order;
}
#[cfg(test)]
-mod test {
+mod tests {
use std::prelude::v1::*;
use core::iter::{order, repeat};
pub mod entry;
pub mod expr_use_visitor;
pub mod fast_reject;
+ pub mod free_region;
pub mod intrinsicck;
pub mod infer;
+ pub mod implicator;
pub mod lang_items;
pub mod liveness;
pub mod mem_categorization;
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)
}
#[cfg(test)]
-trait fake_ext_ctxt {
+trait FakeExtCtxt {
+ fn call_site(&self) -> codemap::Span;
fn cfg(&self) -> ast::CrateConfig;
- fn parse_sess<'a>(&'a self) -> &'a parse::ParseSess;
- fn call_site(&self) -> Span;
fn ident_of(&self, st: &str) -> ast::Ident;
+ fn name_of(&self, st: &str) -> ast::Name;
+ fn parse_sess(&self) -> &parse::ParseSess;
}
#[cfg(test)]
-impl fake_ext_ctxt for parse::ParseSess {
- fn cfg(&self) -> ast::CrateConfig {
- Vec::new()
- }
- fn parse_sess<'a>(&'a self) -> &'a parse::ParseSess { self }
- fn call_site(&self) -> Span {
+impl FakeExtCtxt for parse::ParseSess {
+ fn call_site(&self) -> codemap::Span {
codemap::Span {
lo: codemap::BytePos(0),
hi: codemap::BytePos(0),
- expn_id: codemap::NO_EXPANSION
+ expn_id: codemap::NO_EXPANSION,
}
}
+ fn cfg(&self) -> ast::CrateConfig { Vec::new() }
fn ident_of(&self, st: &str) -> ast::Ident {
- token::str_to_ident(st)
+ parse::token::str_to_ident(st)
}
+ fn name_of(&self, st: &str) -> ast::Name {
+ parse::token::intern(st)
+ }
+ fn parse_sess(&self) -> &parse::ParseSess { self }
}
#[cfg(test)]
fn foo() {}
));
}
-/* NOTE: When there's a snapshot, update this (yay quasiquoter!)
+
#[test]
fn test_smalltalk() {
let cx = mk_ctxt();
fn foo() -> isize { 3 + 4 } // first smalltalk program ever executed.
));
}
-*/
#[test]
fn test_more() {
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
--- /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.
+
+//! This file defines
+
+use middle::implicator::Implication;
+use middle::ty::{self, FreeRegion};
+use util::common::can_reach;
+use util::nodemap::FnvHashMap;
+use util::ppaux::Repr;
+
+#[derive(Clone)]
+pub struct FreeRegionMap {
+ /// `free_region_map` maps from a free region `a` to a list of
+ /// free regions `bs` such that `a <= b for all b in bs`
+ map: FnvHashMap<FreeRegion, Vec<FreeRegion>>,
+}
+
+impl FreeRegionMap {
+ pub fn new() -> FreeRegionMap {
+ FreeRegionMap { map: FnvHashMap() }
+ }
+
+ pub fn relate_free_regions_from_implications<'tcx>(&mut self,
+ tcx: &ty::ctxt<'tcx>,
+ implications: &[Implication<'tcx>])
+ {
+ for implication in implications {
+ debug!("implication: {}", implication.repr(tcx));
+ match *implication {
+ Implication::RegionSubRegion(_, ty::ReFree(free_a), ty::ReFree(free_b)) => {
+ self.relate_free_regions(free_a, free_b);
+ }
+ Implication::RegionSubRegion(..) |
+ Implication::RegionSubClosure(..) |
+ Implication::RegionSubGeneric(..) |
+ Implication::Predicate(..) => {
+ }
+ }
+ }
+ }
+
+ pub fn relate_free_regions_from_predicates<'tcx>(&mut self,
+ tcx: &ty::ctxt<'tcx>,
+ predicates: &[ty::Predicate<'tcx>]) {
+ debug!("relate_free_regions_from_predicates(predicates={})", predicates.repr(tcx));
+ for predicate in predicates {
+ match *predicate {
+ ty::Predicate::Projection(..) |
+ ty::Predicate::Trait(..) |
+ ty::Predicate::Equate(..) |
+ ty::Predicate::TypeOutlives(..) => {
+ // No region bounds here
+ }
+ ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
+ match (r_a, r_b) {
+ (ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
+ // Record that `'a:'b`. Or, put another way, `'b <= 'a`.
+ self.relate_free_regions(fr_b, fr_a);
+ }
+ _ => {
+ // All named regions are instantiated with free regions.
+ tcx.sess.bug(
+ &format!("record_region_bounds: non free region: {} / {}",
+ r_a.repr(tcx),
+ r_b.repr(tcx)));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ pub fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) {
+ let mut sups = self.map.entry(sub).or_insert(Vec::new());
+ if !sups.contains(&sup) {
+ sups.push(sup);
+ }
+ }
+
+ /// Determines whether two free regions have a subregion relationship
+ /// by walking the graph encoded in `map`. Note that
+ /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
+ /// (that is, the user can give two different names to the same lifetime).
+ pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
+ can_reach(&self.map, sub, sup)
+ }
+
+ /// Determines whether one region is a subregion of another. This is intended to run *after
+ /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
+ pub fn is_subregion_of(&self,
+ tcx: &ty::ctxt,
+ sub_region: ty::Region,
+ super_region: ty::Region)
+ -> bool {
+ debug!("is_subregion_of(sub_region={:?}, super_region={:?})",
+ sub_region, super_region);
+
+ sub_region == super_region || {
+ match (sub_region, super_region) {
+ (ty::ReEmpty, _) |
+ (_, ty::ReStatic) =>
+ true,
+
+ (ty::ReScope(sub_scope), ty::ReScope(super_scope)) =>
+ tcx.region_maps.is_subscope_of(sub_scope, super_scope),
+
+ (ty::ReScope(sub_scope), ty::ReFree(ref fr)) =>
+ tcx.region_maps.is_subscope_of(sub_scope, fr.scope.to_code_extent()),
+
+ (ty::ReFree(sub_fr), ty::ReFree(super_fr)) =>
+ self.sub_free_region(sub_fr, super_fr),
+
+ _ =>
+ false,
+ }
+ }
+ }
+}
+
--- /dev/null
+// Copyright 2012 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.
+
+// #![warn(deprecated_mode)]
+
+use middle::infer::{InferCtxt, GenericKind};
+use middle::subst::Substs;
+use middle::traits;
+use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
+use middle::ty_fold::{TypeFoldable, TypeFolder};
+
+use std::rc::Rc;
+use syntax::ast;
+use syntax::codemap::Span;
+
+use util::common::ErrorReported;
+use util::nodemap::FnvHashSet;
+use util::ppaux::Repr;
+
+// Helper functions related to manipulating region types.
+
+pub enum Implication<'tcx> {
+ RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
+ RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
+ RegionSubClosure(Option<Ty<'tcx>>, ty::Region, ast::DefId, &'tcx Substs<'tcx>),
+ Predicate(ast::DefId, ty::Predicate<'tcx>),
+}
+
+struct Implicator<'a, 'tcx: 'a> {
+ infcx: &'a InferCtxt<'a,'tcx>,
+ closure_typer: &'a (ty::ClosureTyper<'tcx>+'a),
+ body_id: ast::NodeId,
+ stack: Vec<(ty::Region, Option<Ty<'tcx>>)>,
+ span: Span,
+ out: Vec<Implication<'tcx>>,
+ visited: FnvHashSet<Ty<'tcx>>,
+}
+
+/// This routine computes the well-formedness constraints that must hold for the type `ty` to
+/// appear in a context with lifetime `outer_region`
+pub fn implications<'a,'tcx>(
+ infcx: &'a InferCtxt<'a,'tcx>,
+ closure_typer: &ty::ClosureTyper<'tcx>,
+ body_id: ast::NodeId,
+ ty: Ty<'tcx>,
+ outer_region: ty::Region,
+ span: Span)
+ -> Vec<Implication<'tcx>>
+{
+ debug!("implications(body_id={}, ty={}, outer_region={})",
+ body_id,
+ ty.repr(closure_typer.tcx()),
+ outer_region.repr(closure_typer.tcx()));
+
+ let mut stack = Vec::new();
+ stack.push((outer_region, None));
+ let mut wf = Implicator { closure_typer: closure_typer,
+ infcx: infcx,
+ body_id: body_id,
+ span: span,
+ stack: stack,
+ out: Vec::new(),
+ visited: FnvHashSet() };
+ wf.accumulate_from_ty(ty);
+ debug!("implications: out={}", wf.out.repr(closure_typer.tcx()));
+ wf.out
+}
+
+impl<'a, 'tcx> Implicator<'a, 'tcx> {
+ fn tcx(&self) -> &'a ty::ctxt<'tcx> {
+ self.infcx.tcx
+ }
+
+ fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
+ debug!("accumulate_from_ty(ty={})",
+ ty.repr(self.tcx()));
+
+ // When expanding out associated types, we can visit a cyclic
+ // set of types. Issue #23003.
+ if !self.visited.insert(ty) {
+ return;
+ }
+
+ match ty.sty {
+ ty::ty_bool |
+ ty::ty_char |
+ ty::ty_int(..) |
+ ty::ty_uint(..) |
+ ty::ty_float(..) |
+ ty::ty_bare_fn(..) |
+ ty::ty_err |
+ ty::ty_str => {
+ // No borrowed content reachable here.
+ }
+
+ ty::ty_closure(def_id, substs) => {
+ let &(r_a, opt_ty) = self.stack.last().unwrap();
+ self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs));
+ }
+
+ ty::ty_trait(ref t) => {
+ let required_region_bounds =
+ object_region_bounds(self.tcx(), &t.principal, t.bounds.builtin_bounds);
+ self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
+ }
+
+ ty::ty_enum(def_id, substs) |
+ ty::ty_struct(def_id, substs) => {
+ let item_scheme = ty::lookup_item_type(self.tcx(), def_id);
+ self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs)
+ }
+
+ ty::ty_vec(t, _) |
+ ty::ty_ptr(ty::mt { ty: t, .. }) |
+ ty::ty_uniq(t) => {
+ self.accumulate_from_ty(t)
+ }
+
+ ty::ty_rptr(r_b, mt) => {
+ self.accumulate_from_rptr(ty, *r_b, mt.ty);
+ }
+
+ ty::ty_param(p) => {
+ self.push_param_constraint_from_top(p);
+ }
+
+ ty::ty_projection(ref data) => {
+ // `<T as TraitRef<..>>::Name`
+
+ self.push_projection_constraint_from_top(data);
+ }
+
+ ty::ty_tup(ref tuptys) => {
+ for &tupty in tuptys {
+ self.accumulate_from_ty(tupty);
+ }
+ }
+
+ ty::ty_infer(_) => {
+ // This should not happen, BUT:
+ //
+ // Currently we uncover region relationships on
+ // entering the fn check. We should do this after
+ // the fn check, then we can call this case a bug().
+ }
+ }
+ }
+
+ fn accumulate_from_rptr(&mut self,
+ ty: Ty<'tcx>,
+ r_b: ty::Region,
+ ty_b: Ty<'tcx>) {
+ // We are walking down a type like this, and current
+ // position is indicated by caret:
+ //
+ // &'a &'b ty_b
+ // ^
+ //
+ // At this point, top of stack will be `'a`. We must
+ // require that `'a <= 'b`.
+
+ self.push_region_constraint_from_top(r_b);
+
+ // Now we push `'b` onto the stack, because it must
+ // constrain any borrowed content we find within `T`.
+
+ self.stack.push((r_b, Some(ty)));
+ self.accumulate_from_ty(ty_b);
+ self.stack.pop().unwrap();
+ }
+
+ /// Pushes a constraint that `r_b` must outlive the top region on the stack.
+ fn push_region_constraint_from_top(&mut self,
+ r_b: ty::Region) {
+
+ // Indicates that we have found borrowed content with a lifetime
+ // of at least `r_b`. This adds a constraint that `r_b` must
+ // outlive the region `r_a` on top of the stack.
+ //
+ // As an example, imagine walking a type like:
+ //
+ // &'a &'b T
+ // ^
+ //
+ // when we hit the inner pointer (indicated by caret), `'a` will
+ // be on top of stack and `'b` will be the lifetime of the content
+ // we just found. So we add constraint that `'a <= 'b`.
+
+ let &(r_a, opt_ty) = self.stack.last().unwrap();
+ self.push_sub_region_constraint(opt_ty, r_a, r_b);
+ }
+
+ /// Pushes a constraint that `r_a <= r_b`, due to `opt_ty`
+ fn push_sub_region_constraint(&mut self,
+ opt_ty: Option<Ty<'tcx>>,
+ r_a: ty::Region,
+ r_b: ty::Region) {
+ self.out.push(Implication::RegionSubRegion(opt_ty, r_a, r_b));
+ }
+
+ /// Pushes a constraint that `param_ty` must outlive the top region on the stack.
+ fn push_param_constraint_from_top(&mut self,
+ param_ty: ty::ParamTy) {
+ let &(region, opt_ty) = self.stack.last().unwrap();
+ self.push_param_constraint(region, opt_ty, param_ty);
+ }
+
+ /// Pushes a constraint that `projection_ty` must outlive the top region on the stack.
+ fn push_projection_constraint_from_top(&mut self,
+ projection_ty: &ty::ProjectionTy<'tcx>) {
+ let &(region, opt_ty) = self.stack.last().unwrap();
+ self.out.push(Implication::RegionSubGeneric(
+ opt_ty, region, GenericKind::Projection(projection_ty.clone())));
+ }
+
+ /// Pushes a constraint that `region <= param_ty`, due to `opt_ty`
+ fn push_param_constraint(&mut self,
+ region: ty::Region,
+ opt_ty: Option<Ty<'tcx>>,
+ param_ty: ty::ParamTy) {
+ self.out.push(Implication::RegionSubGeneric(
+ opt_ty, region, GenericKind::Param(param_ty)));
+ }
+
+ fn accumulate_from_adt(&mut self,
+ ty: Ty<'tcx>,
+ def_id: ast::DefId,
+ _generics: &ty::Generics<'tcx>,
+ substs: &Substs<'tcx>)
+ {
+ let predicates =
+ ty::lookup_predicates(self.tcx(), def_id).instantiate(self.tcx(), substs);
+ let predicates = match self.fully_normalize(&predicates) {
+ Ok(predicates) => predicates,
+ Err(ErrorReported) => { return; }
+ };
+
+ for predicate in predicates.predicates.as_slice() {
+ match *predicate {
+ ty::Predicate::Trait(ref data) => {
+ self.accumulate_from_assoc_types_transitive(data);
+ }
+ ty::Predicate::Equate(..) => { }
+ ty::Predicate::Projection(..) => { }
+ ty::Predicate::RegionOutlives(ref data) => {
+ match ty::no_late_bound_regions(self.tcx(), data) {
+ None => { }
+ Some(ty::OutlivesPredicate(r_a, r_b)) => {
+ self.push_sub_region_constraint(Some(ty), r_b, r_a);
+ }
+ }
+ }
+ ty::Predicate::TypeOutlives(ref data) => {
+ match ty::no_late_bound_regions(self.tcx(), data) {
+ None => { }
+ Some(ty::OutlivesPredicate(ty_a, r_b)) => {
+ self.stack.push((r_b, Some(ty)));
+ self.accumulate_from_ty(ty_a);
+ self.stack.pop().unwrap();
+ }
+ }
+ }
+ }
+ }
+
+ let obligations = predicates.predicates
+ .into_iter()
+ .map(|pred| Implication::Predicate(def_id, pred));
+ self.out.extend(obligations);
+
+ let variances = ty::item_variances(self.tcx(), def_id);
+
+ for (®ion, &variance) in substs.regions().iter().zip(variances.regions.iter()) {
+ match variance {
+ ty::Contravariant | ty::Invariant => {
+ // If any data with this lifetime is reachable
+ // within, it must be at least contravariant.
+ self.push_region_constraint_from_top(region)
+ }
+ ty::Covariant | ty::Bivariant => { }
+ }
+ }
+
+ for (&ty, &variance) in substs.types.iter().zip(variances.types.iter()) {
+ match variance {
+ ty::Covariant | ty::Invariant => {
+ // If any data of this type is reachable within,
+ // it must be at least covariant.
+ self.accumulate_from_ty(ty);
+ }
+ ty::Contravariant | ty::Bivariant => { }
+ }
+ }
+ }
+
+ /// Given that there is a requirement that `Foo<X> : 'a`, where
+ /// `Foo` is declared like `struct Foo<T> where T : SomeTrait`,
+ /// this code finds all the associated types defined in
+ /// `SomeTrait` (and supertraits) and adds a requirement that `<X
+ /// as SomeTrait>::N : 'a` (where `N` is some associated type
+ /// defined in `SomeTrait`). This rule only applies to
+ /// trait-bounds that are not higher-ranked, because we cannot
+ /// project out of a HRTB. This rule helps code using associated
+ /// types to compile, see Issue #22246 for an example.
+ fn accumulate_from_assoc_types_transitive(&mut self,
+ data: &ty::PolyTraitPredicate<'tcx>)
+ {
+ debug!("accumulate_from_assoc_types_transitive({})",
+ data.repr(self.tcx()));
+
+ for poly_trait_ref in traits::supertraits(self.tcx(), data.to_poly_trait_ref()) {
+ match ty::no_late_bound_regions(self.tcx(), &poly_trait_ref) {
+ Some(trait_ref) => { self.accumulate_from_assoc_types(trait_ref); }
+ None => { }
+ }
+ }
+ }
+
+ fn accumulate_from_assoc_types(&mut self,
+ trait_ref: Rc<ty::TraitRef<'tcx>>)
+ {
+ debug!("accumulate_from_assoc_types({})",
+ trait_ref.repr(self.tcx()));
+
+ let trait_def_id = trait_ref.def_id;
+ let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id);
+ let assoc_type_projections: Vec<_> =
+ trait_def.associated_type_names
+ .iter()
+ .map(|&name| ty::mk_projection(self.tcx(), trait_ref.clone(), name))
+ .collect();
+ debug!("accumulate_from_assoc_types: assoc_type_projections={}",
+ assoc_type_projections.repr(self.tcx()));
+ let tys = match self.fully_normalize(&assoc_type_projections) {
+ Ok(tys) => { tys }
+ Err(ErrorReported) => { return; }
+ };
+ for ty in tys {
+ self.accumulate_from_ty(ty);
+ }
+ }
+
+ fn accumulate_from_object_ty(&mut self,
+ ty: Ty<'tcx>,
+ region_bound: ty::Region,
+ required_region_bounds: Vec<ty::Region>)
+ {
+ // Imagine a type like this:
+ //
+ // trait Foo { }
+ // trait Bar<'c> : 'c { }
+ //
+ // &'b (Foo+'c+Bar<'d>)
+ // ^
+ //
+ // In this case, the following relationships must hold:
+ //
+ // 'b <= 'c
+ // 'd <= 'c
+ //
+ // The first conditions is due to the normal region pointer
+ // rules, which say that a reference cannot outlive its
+ // referent.
+ //
+ // The final condition may be a bit surprising. In particular,
+ // you may expect that it would have been `'c <= 'd`, since
+ // usually lifetimes of outer things are conservative
+ // approximations for inner things. However, it works somewhat
+ // differently with trait objects: here the idea is that if the
+ // user specifies a region bound (`'c`, in this case) it is the
+ // "master bound" that *implies* that bounds from other traits are
+ // all met. (Remember that *all bounds* in a type like
+ // `Foo+Bar+Zed` must be met, not just one, hence if we write
+ // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
+ // 'y.)
+ //
+ // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
+ // am looking forward to the future here.
+
+ // The content of this object type must outlive
+ // `bounds.region_bound`:
+ let r_c = region_bound;
+ self.push_region_constraint_from_top(r_c);
+
+ // And then, in turn, to be well-formed, the
+ // `region_bound` that user specified must imply the
+ // region bounds required from all of the trait types:
+ for &r_d in &required_region_bounds {
+ // Each of these is an instance of the `'c <= 'b`
+ // constraint above
+ self.out.push(Implication::RegionSubRegion(Some(ty), r_d, r_c));
+ }
+ }
+
+ fn fully_normalize<T>(&self, value: &T) -> Result<T,ErrorReported>
+ where T : TypeFoldable<'tcx> + ty::HasProjectionTypes + Clone + Repr<'tcx>
+ {
+ let value =
+ traits::fully_normalize(self.infcx,
+ self.closure_typer,
+ traits::ObligationCause::misc(self.span, self.body_id),
+ value);
+ match value {
+ Ok(value) => Ok(value),
+ Err(errors) => {
+ // I don't like reporting these errors here, but I
+ // don't know where else to report them just now. And
+ // I don't really expect errors to arise here
+ // frequently. I guess the best option would be to
+ // propagate them out.
+ traits::report_fulfillment_errors(self.infcx, &errors);
+ Err(ErrorReported)
+ }
+ }
+ }
+}
+
+/// Given an object type like `SomeTrait+Send`, computes the lifetime
+/// bounds that must hold on the elided self type. These are derived
+/// from the declarations of `SomeTrait`, `Send`, and friends -- if
+/// they declare `trait SomeTrait : 'static`, for example, then
+/// `'static` would appear in the list. The hard work is done by
+/// `ty::required_region_bounds`, see that for more information.
+pub fn object_region_bounds<'tcx>(
+ tcx: &ty::ctxt<'tcx>,
+ principal: &ty::PolyTraitRef<'tcx>,
+ others: ty::BuiltinBounds)
+ -> Vec<ty::Region>
+{
+ // Since we don't actually *know* the self type for an object,
+ // this "open(err)" serves as a kind of dummy standin -- basically
+ // a skolemized type.
+ let open_ty = ty::mk_infer(tcx, ty::FreshTy(0));
+
+ // Note that we preserve the overall binding levels here.
+ assert!(!open_ty.has_escaping_regions());
+ let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
+ let trait_refs = vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))));
+
+ let param_bounds = ty::ParamBounds {
+ region_bounds: Vec::new(),
+ builtin_bounds: others,
+ trait_bounds: trait_refs,
+ projection_bounds: Vec::new(), // not relevant to computing region bounds
+ };
+
+ let predicates = ty::predicates(tcx, open_ty, ¶m_bounds);
+ ty::required_region_bounds(tcx, open_ty, predicates)
+}
+
+impl<'tcx> Repr<'tcx> for Implication<'tcx> {
+ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+ match *self {
+ Implication::RegionSubRegion(_, ref r_a, ref r_b) => {
+ format!("RegionSubRegion({}, {})",
+ r_a.repr(tcx),
+ r_b.repr(tcx))
+ }
+
+ Implication::RegionSubGeneric(_, ref r, ref p) => {
+ format!("RegionSubGeneric({}, {})",
+ r.repr(tcx),
+ p.repr(tcx))
+ }
+
+ Implication::RegionSubClosure(_, ref a, ref b, ref c) => {
+ format!("RegionSubClosure({}, {}, {})",
+ a.repr(tcx),
+ b.repr(tcx),
+ c.repr(tcx))
+ }
+
+ Implication::Predicate(ref def_id, ref p) => {
+ format!("Predicate({}, {})",
+ def_id.repr(tcx),
+ p.repr(tcx))
+ }
+ }
+ }
+}
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
pub use self::freshen::TypeFreshener;
pub use self::region_inference::GenericKind;
+use middle::free_region::FreeRegionMap;
use middle::subst;
use middle::subst::Substs;
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
self.region_vars.new_bound(debruijn)
}
- pub fn resolve_regions_and_report_errors(&self, subject_node_id: ast::NodeId) {
- let errors = self.region_vars.resolve_regions(subject_node_id);
+ pub fn resolve_regions_and_report_errors(&self,
+ free_regions: &FreeRegionMap,
+ subject_node_id: ast::NodeId) {
+ let errors = self.region_vars.resolve_regions(free_regions, subject_node_id);
self.report_region_errors(&errors); // see error_reporting.rs
}
use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
use rustc_data_structures::graph::{self, Direction, NodeIndex};
+use middle::free_region::FreeRegionMap;
use middle::region;
use middle::ty::{self, Ty};
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
/// fixed-point iteration to find region values which satisfy all
/// constraints, assuming such values can be found; if they cannot,
/// errors are reported.
- pub fn resolve_regions(&self, subject_node: ast::NodeId) -> Vec<RegionResolutionError<'tcx>> {
+ pub fn resolve_regions(&self,
+ free_regions: &FreeRegionMap,
+ subject_node: ast::NodeId)
+ -> Vec<RegionResolutionError<'tcx>>
+ {
debug!("RegionVarBindings: resolve_regions()");
let mut errors = vec!();
- let v = self.infer_variable_values(&mut errors, subject_node);
+ let v = self.infer_variable_values(free_regions, &mut errors, subject_node);
*self.values.borrow_mut() = Some(v);
errors
}
- fn is_subregion_of(&self, sub: Region, sup: Region) -> bool {
- self.tcx.region_maps.is_subregion_of(sub, sup)
- }
-
- fn lub_concrete_regions(&self, a: Region, b: Region) -> Region {
+ fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, a: Region, b: Region) -> Region {
match (a, b) {
(ReLateBound(..), _) |
(_, ReLateBound(..)) |
}
(ReFree(ref a_fr), ReFree(ref b_fr)) => {
- self.lub_free_regions(a_fr, b_fr)
+ self.lub_free_regions(free_regions, a_fr, b_fr)
}
// For these types, we cannot define any additional
/// Computes a region that encloses both free region arguments. Guarantee that if the same two
/// regions are given as argument, in any order, a consistent result is returned.
fn lub_free_regions(&self,
+ free_regions: &FreeRegionMap,
a: &FreeRegion,
b: &FreeRegion)
-> ty::Region
{
return match a.cmp(b) {
- Less => helper(self, a, b),
- Greater => helper(self, b, a),
+ Less => helper(self, free_regions, a, b),
+ Greater => helper(self, free_regions, b, a),
Equal => ty::ReFree(*a)
};
- fn helper(this: &RegionVarBindings,
+ fn helper(_this: &RegionVarBindings,
+ free_regions: &FreeRegionMap,
a: &FreeRegion,
b: &FreeRegion) -> ty::Region
{
- if this.tcx.region_maps.sub_free_region(*a, *b) {
+ if free_regions.sub_free_region(*a, *b) {
ty::ReFree(*b)
- } else if this.tcx.region_maps.sub_free_region(*b, *a) {
+ } else if free_regions.sub_free_region(*b, *a) {
ty::ReFree(*a)
} else {
ty::ReStatic
}
fn glb_concrete_regions(&self,
+ free_regions: &FreeRegionMap,
a: Region,
b: Region)
-> RelateResult<'tcx, Region>
}
(ReFree(ref a_fr), ReFree(ref b_fr)) => {
- self.glb_free_regions(a_fr, b_fr)
+ self.glb_free_regions(free_regions, a_fr, b_fr)
}
// For these types, we cannot define any additional
/// if the same two regions are given as argument, in any order, a consistent result is
/// returned.
fn glb_free_regions(&self,
+ free_regions: &FreeRegionMap,
a: &FreeRegion,
b: &FreeRegion)
-> RelateResult<'tcx, ty::Region>
{
return match a.cmp(b) {
- Less => helper(self, a, b),
- Greater => helper(self, b, a),
+ Less => helper(self, free_regions, a, b),
+ Greater => helper(self, free_regions, b, a),
Equal => Ok(ty::ReFree(*a))
};
fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>,
+ free_regions: &FreeRegionMap,
a: &FreeRegion,
b: &FreeRegion) -> RelateResult<'tcx, ty::Region>
{
- if this.tcx.region_maps.sub_free_region(*a, *b) {
+ if free_regions.sub_free_region(*a, *b) {
Ok(ty::ReFree(*a))
- } else if this.tcx.region_maps.sub_free_region(*b, *a) {
+ } else if free_regions.sub_free_region(*b, *a) {
Ok(ty::ReFree(*b))
} else {
this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b),
impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
fn infer_variable_values(&self,
+ free_regions: &FreeRegionMap,
errors: &mut Vec<RegionResolutionError<'tcx>>,
subject: ast::NodeId) -> Vec<VarValue>
{
debug!("----() End constraint listing {:?}---", self.dump_constraints());
graphviz::maybe_print_constraints_for(self, subject);
- self.expansion(&mut var_data);
- self.contraction(&mut var_data);
+ self.expansion(free_regions, &mut var_data);
+ self.contraction(free_regions, &mut var_data);
let values =
- self.extract_values_and_collect_conflicts(&var_data[..],
+ self.extract_values_and_collect_conflicts(free_regions,
+ &var_data[..],
errors);
- self.collect_concrete_region_errors(&values, errors);
+ self.collect_concrete_region_errors(free_regions, &values, errors);
values
}
}
}
- fn expansion(&self, var_data: &mut [VarData]) {
+ fn expansion(&self, free_regions: &FreeRegionMap, var_data: &mut [VarData]) {
self.iterate_until_fixed_point("Expansion", |constraint| {
debug!("expansion: constraint={} origin={}",
constraint.repr(self.tcx),
match *constraint {
ConstrainRegSubVar(a_region, b_vid) => {
let b_data = &mut var_data[b_vid.index as usize];
- self.expand_node(a_region, b_vid, b_data)
+ self.expand_node(free_regions, a_region, b_vid, b_data)
}
ConstrainVarSubVar(a_vid, b_vid) => {
match var_data[a_vid.index as usize].value {
NoValue | ErrorValue => false,
Value(a_region) => {
let b_node = &mut var_data[b_vid.index as usize];
- self.expand_node(a_region, b_vid, b_node)
+ self.expand_node(free_regions, a_region, b_vid, b_node)
}
}
}
}
fn expand_node(&self,
+ free_regions: &FreeRegionMap,
a_region: Region,
b_vid: RegionVid,
b_data: &mut VarData)
}
Value(cur_region) => {
- let lub = self.lub_concrete_regions(a_region, cur_region);
+ let lub = self.lub_concrete_regions(free_regions, a_region, cur_region);
if lub == cur_region {
return false;
}
}
fn contraction(&self,
+ free_regions: &FreeRegionMap,
var_data: &mut [VarData]) {
self.iterate_until_fixed_point("Contraction", |constraint| {
debug!("contraction: constraint={} origin={}",
NoValue | ErrorValue => false,
Value(b_region) => {
let a_data = &mut var_data[a_vid.index as usize];
- self.contract_node(a_vid, a_data, b_region)
+ self.contract_node(free_regions, a_vid, a_data, b_region)
}
}
}
ConstrainVarSubReg(a_vid, b_region) => {
let a_data = &mut var_data[a_vid.index as usize];
- self.contract_node(a_vid, a_data, b_region)
+ self.contract_node(free_regions, a_vid, a_data, b_region)
}
}
})
}
fn contract_node(&self,
+ free_regions: &FreeRegionMap,
a_vid: RegionVid,
a_data: &mut VarData,
b_region: Region)
Value(a_region) => {
match a_data.classification {
- Expanding => check_node(self, a_vid, a_data, a_region, b_region),
- Contracting => adjust_node(self, a_vid, a_data, a_region, b_region),
+ Expanding =>
+ check_node(self, free_regions, a_vid, a_data, a_region, b_region),
+ Contracting =>
+ adjust_node(self, free_regions, a_vid, a_data, a_region, b_region),
}
}
};
fn check_node(this: &RegionVarBindings,
+ free_regions: &FreeRegionMap,
a_vid: RegionVid,
a_data: &mut VarData,
a_region: Region,
b_region: Region)
- -> bool {
- if !this.is_subregion_of(a_region, b_region) {
+ -> bool
+ {
+ if !free_regions.is_subregion_of(this.tcx, a_region, b_region) {
debug!("Setting {:?} to ErrorValue: {} not subregion of {}",
a_vid,
a_region.repr(this.tcx),
}
fn adjust_node(this: &RegionVarBindings,
+ free_regions: &FreeRegionMap,
a_vid: RegionVid,
a_data: &mut VarData,
a_region: Region,
b_region: Region)
-> bool {
- match this.glb_concrete_regions(a_region, b_region) {
+ match this.glb_concrete_regions(free_regions, a_region, b_region) {
Ok(glb) => {
if glb == a_region {
false
}
fn collect_concrete_region_errors(&self,
+ free_regions: &FreeRegionMap,
values: &Vec<VarValue>,
errors: &mut Vec<RegionResolutionError<'tcx>>)
{
for verify in &*self.verifys.borrow() {
match *verify {
VerifyRegSubReg(ref origin, sub, sup) => {
- if self.is_subregion_of(sub, sup) {
+ if free_regions.is_subregion_of(self.tcx, sub, sup) {
continue;
}
let sub = normalize(values, sub);
if sups.iter()
.map(|&sup| normalize(values, sup))
- .any(|sup| self.is_subregion_of(sub, sup))
+ .any(|sup| free_regions.is_subregion_of(self.tcx, sub, sup))
{
continue;
}
fn extract_values_and_collect_conflicts(
&self,
+ free_regions: &FreeRegionMap,
var_data: &[VarData],
errors: &mut Vec<RegionResolutionError<'tcx>>)
-> Vec<VarValue>
match var_data[idx].classification {
Expanding => {
self.collect_error_for_expanding_node(
- graph, var_data, &mut dup_vec,
+ free_regions, graph, var_data, &mut dup_vec,
node_vid, errors);
}
Contracting => {
self.collect_error_for_contracting_node(
- graph, var_data, &mut dup_vec,
+ free_regions, graph, var_data, &mut dup_vec,
node_vid, errors);
}
}
return graph;
}
- fn collect_error_for_expanding_node(
- &self,
- graph: &RegionGraph,
- var_data: &[VarData],
- dup_vec: &mut [u32],
- node_idx: RegionVid,
- errors: &mut Vec<RegionResolutionError<'tcx>>)
+ fn collect_error_for_expanding_node(&self,
+ free_regions: &FreeRegionMap,
+ graph: &RegionGraph,
+ var_data: &[VarData],
+ dup_vec: &mut [u32],
+ node_idx: RegionVid,
+ errors: &mut Vec<RegionResolutionError<'tcx>>)
{
// Errors in expanding nodes result from a lower-bound that is
// not contained by an upper-bound.
for lower_bound in &lower_bounds {
for upper_bound in &upper_bounds {
- if !self.is_subregion_of(lower_bound.region,
- upper_bound.region) {
+ if !free_regions.is_subregion_of(self.tcx,
+ lower_bound.region,
+ upper_bound.region) {
debug!("pushing SubSupConflict sub: {:?} sup: {:?}",
lower_bound.region, upper_bound.region);
errors.push(SubSupConflict(
fn collect_error_for_contracting_node(
&self,
+ free_regions: &FreeRegionMap,
graph: &RegionGraph,
var_data: &[VarData],
dup_vec: &mut [u32],
for upper_bound_1 in &upper_bounds {
for upper_bound_2 in &upper_bounds {
- match self.glb_concrete_regions(upper_bound_1.region,
+ match self.glb_concrete_regions(free_regions,
+ upper_bound_1.region,
upper_bound_2.region) {
Ok(_) => {}
Err(_) => {
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) {
//! `middle/typeck/infer/region_inference.rs`
use session::Session;
-use middle::ty::{self, Ty, FreeRegion};
+use middle::ty::{self, Ty};
use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
-use util::common::can_reach;
use std::cell::RefCell;
use syntax::codemap::{self, Span};
/// which that variable is declared.
var_map: RefCell<NodeMap<CodeExtent>>,
- /// `free_region_map` maps from a free region `a` to a list of
- /// free regions `bs` such that `a <= b for all b in bs`
- ///
- /// NB. the free region map is populated during type check as we
- /// check each function. See the function `relate_free_regions`
- /// for more information.
- free_region_map: RefCell<FnvHashMap<FreeRegion, Vec<FreeRegion>>>,
-
/// `rvalue_scopes` includes entries for those expressions whose cleanup scope is
/// larger than the default. The map goes from the expression id
/// to the cleanup scope id. For rvalues not present in this
e(child, parent)
}
}
- pub fn each_encl_free_region<E>(&self, mut e:E) where E: FnMut(&FreeRegion, &FreeRegion) {
- for (child, parents) in self.free_region_map.borrow().iter() {
- for parent in parents.iter() {
- e(child, parent)
- }
- }
- }
pub fn each_rvalue_scope<E>(&self, mut e:E) where E: FnMut(&ast::NodeId, &CodeExtent) {
for (child, parent) in self.rvalue_scopes.borrow().iter() {
e(child, parent)
}
}
- pub fn relate_free_regions(&self, sub: FreeRegion, sup: FreeRegion) {
- match self.free_region_map.borrow_mut().get_mut(&sub) {
- Some(sups) => {
- if !sups.iter().any(|x| x == &sup) {
- sups.push(sup);
- }
- return;
- }
- None => {}
- }
-
- debug!("relate_free_regions(sub={:?}, sup={:?})", sub, sup);
- self.free_region_map.borrow_mut().insert(sub, vec!(sup));
- }
-
/// Records that `sub_fn` is defined within `sup_fn`. These ids
/// should be the id of the block that is the fn body, which is
/// also the root of the region hierarchy for that fn.
return true;
}
- /// Determines whether two free regions have a subregion relationship
- /// by walking the graph encoded in `free_region_map`. Note that
- /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub`
- /// (that is, the user can give two different names to the same lifetime).
- pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool {
- can_reach(&*self.free_region_map.borrow(), sub, sup)
- }
-
- /// Determines whether one region is a subregion of another. This is intended to run *after
- /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
- pub fn is_subregion_of(&self,
- sub_region: ty::Region,
- super_region: ty::Region)
- -> bool {
- debug!("is_subregion_of(sub_region={:?}, super_region={:?})",
- sub_region, super_region);
-
- sub_region == super_region || {
- match (sub_region, super_region) {
- (ty::ReEmpty, _) |
- (_, ty::ReStatic) => {
- true
- }
-
- (ty::ReScope(sub_scope), ty::ReScope(super_scope)) => {
- self.is_subscope_of(sub_scope, super_scope)
- }
-
- (ty::ReScope(sub_scope), ty::ReFree(ref fr)) => {
- self.is_subscope_of(sub_scope, fr.scope.to_code_extent())
- }
-
- (ty::ReFree(sub_fr), ty::ReFree(super_fr)) => {
- self.sub_free_region(sub_fr, super_fr)
- }
-
- (ty::ReEarlyBound(data_a), ty::ReEarlyBound(data_b)) => {
- // This case is used only to make sure that explicitly-
- // specified `Self` types match the real self type in
- // implementations. Yuck.
- data_a == data_b
- }
-
- _ => {
- false
- }
- }
- }
- }
-
/// Finds the nearest common ancestor (if any) of two scopes. That is, finds the smallest
/// scope which is greater than or equal to both `scope_a` and `scope_b`.
pub fn nearest_common_ancestor(&self,
let maps = RegionMaps {
scope_map: RefCell::new(FnvHashMap()),
var_map: RefCell::new(NodeMap()),
- free_region_map: RefCell::new(FnvHashMap()),
rvalue_scopes: RefCell::new(NodeMap()),
terminating_scopes: RefCell::new(FnvHashSet()),
fn_tree: RefCell::new(NodeMap()),
pub use self::Vtable::*;
pub use self::ObligationCauseCode::*;
+use middle::free_region::FreeRegionMap;
use middle::subst;
use middle::ty::{self, HasProjectionTypes, Ty};
use middle::ty_fold::TypeFoldable;
}
};
- infcx.resolve_regions_and_report_errors(body_id);
+ let free_regions = FreeRegionMap::new();
+ infcx.resolve_regions_and_report_errors(&free_regions, body_id);
let predicates = match infcx.fully_resolve(&predicates) {
Ok(predicates) => predicates,
Err(fixup_err) => {
.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 middle::const_eval;
use middle::def::{self, DefMap, ExportMap};
use middle::dependency_format;
+use middle::free_region::FreeRegionMap;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::mem_categorization as mc;
use middle::region;
use middle::resolve_lifetime;
use middle::infer;
use middle::pat_util;
+use middle::region::RegionMaps;
use middle::stability;
use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
use middle::traits;
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,
pub named_region_map: resolve_lifetime::NamedRegionMap,
- pub region_maps: middle::region::RegionMaps,
+ pub region_maps: RegionMaps,
+
+ // For each fn declared in the local crate, type check stores the
+ // free-region relationships that were deduced from its where
+ // clauses and parameter types. These are then read-again by
+ // borrowck. (They are not used during trans, and hence are not
+ // serialized or needed for cross-crate fns.)
+ free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
/// Stores the types for various nodes in the AST. Note that this table
/// is not guaranteed to be populated until after typeck. See
pub fn node_type_insert(&self, id: NodeId, ty: Ty<'tcx>) {
self.node_types.borrow_mut().insert(id, ty);
}
+
+ pub fn store_free_region_map(&self, id: NodeId, map: FreeRegionMap) {
+ self.free_region_maps.borrow_mut()
+ .insert(id, map);
+ }
+
+ pub fn free_region_map(&self, id: NodeId) -> FreeRegionMap {
+ self.free_region_maps.borrow()[&id].clone()
+ }
}
// Flags that we track on types. These flags are propagated upwards
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?!")
}
}
}
named_region_map: resolve_lifetime::NamedRegionMap,
map: ast_map::Map<'tcx>,
freevars: RefCell<FreevarMap>,
- region_maps: middle::region::RegionMaps,
+ region_maps: RegionMaps,
lang_items: middle::lang_items::LanguageItems,
stability: stability::Index) -> ctxt<'tcx>
{
region_interner: RefCell::new(FnvHashMap()),
types: common_types,
named_region_map: named_region_map,
+ region_maps: region_maps,
+ free_region_maps: RefCell::new(FnvHashMap()),
item_variance_map: RefCell::new(DefIdMap()),
variance_computed: Cell::new(false),
sess: s,
def_map: def_map,
- region_maps: region_maps,
node_types: RefCell::new(FnvHashMap()),
item_substs: RefCell::new(NodeMap()),
impl_trait_refs: RefCell::new(NodeMap()),
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 bounds = liberate_late_bound_regions(tcx, free_id_outlive, &ty::Binder(bounds));
let predicates = bounds.predicates.into_vec();
- //
- // Compute region bounds. For now, these relations are stored in a
- // global table on the tcx, so just enter them there. I'm not
- // crazy about this scheme, but it's convenient, at least.
- //
-
- record_region_bounds(tcx, &*predicates);
-
debug!("construct_parameter_environment: free_id={:?} free_subst={:?} predicates={:?}",
free_id,
free_substs.repr(tcx),
};
let cause = traits::ObligationCause::misc(span, free_id);
- return traits::normalize_param_env_or_error(unnormalized_env, cause);
-
- fn record_region_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, predicates: &[ty::Predicate<'tcx>]) {
- debug!("record_region_bounds(predicates={:?})", predicates.repr(tcx));
-
- for predicate in predicates {
- match *predicate {
- Predicate::Projection(..) |
- Predicate::Trait(..) |
- Predicate::Equate(..) |
- Predicate::TypeOutlives(..) => {
- // No region bounds here
- }
- Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
- match (r_a, r_b) {
- (ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
- // Record that `'a:'b`. Or, put another way, `'b <= 'a`.
- tcx.region_maps.relate_free_regions(fr_b, fr_a);
- }
- _ => {
- // All named regions are instantiated with free regions.
- tcx.sess.bug(
- &format!("record_region_bounds: non free region: {} / {}",
- r_a.repr(tcx),
- r_b.repr(tcx)));
- }
- }
- }
- }
- }
- }
+ traits::normalize_param_env_or_error(unnormalized_env, cause)
}
impl BorrowKind {
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")));
}
#[cfg(test)]
-mod test {
+mod tests {
use session::config::{build_configuration, optgroups, build_session_options};
use session::build_session;
pub crate_metadata: RefCell<Vec<String>>,
pub features: RefCell<feature_gate::Features>,
+ pub delayed_span_bug: RefCell<Option<(codemap::Span, String)>>,
+
/// The maximum recursion limit for potentially infinitely recursive
/// operations such as auto-dereference and monomorphization.
pub recursion_limit: Cell<usize>,
self.diagnostic().handler().has_errors()
}
pub fn abort_if_errors(&self) {
- self.diagnostic().handler().abort_if_errors()
+ self.diagnostic().handler().abort_if_errors();
+
+ let delayed_bug = self.delayed_span_bug.borrow();
+ match *delayed_bug {
+ Some((span, ref errmsg)) => {
+ self.diagnostic().span_bug(span, errmsg);
+ },
+ _ => {}
+ }
}
pub fn span_warn(&self, sp: Span, msg: &str) {
if self.can_print_warnings {
None => self.bug(msg),
}
}
+ /// Delay a span_bug() call until abort_if_errors()
+ pub fn delay_span_bug(&self, sp: Span, msg: &str) {
+ let mut delayed = self.delayed_span_bug.borrow_mut();
+ *delayed = Some((sp, msg.to_string()));
+ }
pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
self.diagnostic().span_bug(sp, msg)
}
plugin_llvm_passes: RefCell::new(Vec::new()),
crate_types: RefCell::new(Vec::new()),
crate_metadata: RefCell::new(Vec::new()),
+ delayed_span_bug: RefCell::new(None),
features: RefCell::new(feature_gate::Features::new()),
recursion_limit: Cell::new(64),
can_print_warnings: can_print_warnings
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),
}
#[cfg(all(not(windows), test))]
-mod test {
+mod tests {
use tempdir::TempDir;
use std::fs::{self, File};
use super::realpath;
}
#[cfg(all(unix, test))]
-mod test {
+mod tests {
use super::{RPathConfig};
use super::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output};
use std::path::{Path, PathBuf};
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,
}
}
use rustc::middle::dataflow::KillFrom;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
+use rustc::middle::free_region::FreeRegionMap;
use rustc::middle::region;
use rustc::middle::ty::{self, Ty};
use rustc::util::ppaux::{note_and_explain_region, Repr, UserString};
+use std::mem;
use std::rc::Rc;
use std::string::String;
use syntax::ast;
impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> {
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl,
b: &'v Block, s: Span, id: ast::NodeId) {
- borrowck_fn(self, fk, fd, b, s, id);
+ match fk {
+ visit::FkItemFn(..) |
+ visit::FkMethod(..) => {
+ let new_free_region_map = self.tcx.free_region_map(id);
+ let old_free_region_map =
+ mem::replace(&mut self.free_region_map, new_free_region_map);
+ borrowck_fn(self, fk, fd, b, s, id);
+ self.free_region_map = old_free_region_map;
+ }
+
+ visit::FkFnBlock => {
+ borrowck_fn(self, fk, fd, b, s, id);
+ }
+ }
}
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) {
let mut bccx = BorrowckCtxt {
tcx: tcx,
+ free_region_map: FreeRegionMap::new(),
stats: BorrowStats {
loaned_paths_same: 0,
loaned_paths_imm: 0,
let cfg = cfg::CFG::new(this.tcx, body);
let AnalysisData { all_loans,
loans: loan_dfcx,
- move_data:flowed_moves } =
+ move_data: flowed_moves } =
build_borrowck_dataflow_data(this, fk, decl, &cfg, body, sp, id);
move_data::fragments::instrument_move_fragments(&flowed_moves.move_data,
- this.tcx, sp, id);
+ this.tcx,
+ sp,
+ id);
check_loans::check_loans(this,
&loan_dfcx,
cfg: &cfg::CFG,
body: &ast::Block,
sp: Span,
- id: ast::NodeId) -> AnalysisData<'a, 'tcx> {
+ id: ast::NodeId)
+ -> AnalysisData<'a, 'tcx>
+{
// Check the body of fn items.
let id_range = ast_util::compute_id_range_for_fn_body(fk, decl, body, sp, id);
let (all_loans, move_data) =
/// the `BorrowckCtxt` itself , e.g. the flowgraph visualizer.
pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
tcx: &'a ty::ctxt<'tcx>,
- input: FnPartsWithCFG<'a>) -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>) {
+ input: FnPartsWithCFG<'a>)
+ -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>)
+{
let mut bccx = BorrowckCtxt {
tcx: tcx,
+ free_region_map: FreeRegionMap::new(),
stats: BorrowStats {
loaned_paths_same: 0,
loaned_paths_imm: 0,
pub struct BorrowckCtxt<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
+ // Hacky. As we visit various fns, we have to load up the
+ // free-region map for each one. This map is computed by during
+ // typeck for each fn item and stored -- closures just use the map
+ // from the fn item that encloses them. Since we walk the fns in
+ // order, we basically just overwrite this field as we enter a fn
+ // item and restore it afterwards in a stack-like fashion. Then
+ // the borrow checking code can assume that `free_region_map` is
+ // always the correct map for the current fn. Feels like it'd be
+ // better to just recompute this, rather than store it, but it's a
+ // bit of a pain to factor that code out at the moment.
+ free_region_map: FreeRegionMap,
+
// Statistics:
stats: BorrowStats
}
impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region)
- -> bool {
- self.tcx.region_maps.is_subregion_of(r_sub, r_sup)
+ -> bool
+ {
+ self.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup)
}
pub fn report(&self, err: BckError<'tcx>) {
use snapshot_vec::{SnapshotVec, SnapshotVecDelegate};
#[cfg(test)]
-mod test;
+mod tests;
pub struct Graph<N,E> {
nodes: SnapshotVec<Node<N>> ,
+++ /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 graph::*;
-use std::fmt::Debug;
-
-type TestNode = Node<&'static str>;
-type TestEdge = Edge<&'static str>;
-type TestGraph = Graph<&'static str, &'static str>;
-
-fn create_graph() -> TestGraph {
- let mut graph = Graph::new();
-
- // Create a simple graph
- //
- // A -+> B --> C
- // | | ^
- // | v |
- // F D --> E
-
- let a = graph.add_node("A");
- let b = graph.add_node("B");
- let c = graph.add_node("C");
- let d = graph.add_node("D");
- let e = graph.add_node("E");
- let f = graph.add_node("F");
-
- graph.add_edge(a, b, "AB");
- graph.add_edge(b, c, "BC");
- graph.add_edge(b, d, "BD");
- graph.add_edge(d, e, "DE");
- graph.add_edge(e, c, "EC");
- graph.add_edge(f, b, "FB");
-
- return graph;
-}
-
-#[test]
-fn each_node() {
- let graph = create_graph();
- let expected = ["A", "B", "C", "D", "E", "F"];
- graph.each_node(|idx, node| {
- assert_eq!(&expected[idx.0], graph.node_data(idx));
- assert_eq!(expected[idx.0], node.data);
- true
- });
-}
-
-#[test]
-fn each_edge() {
- let graph = create_graph();
- let expected = ["AB", "BC", "BD", "DE", "EC", "FB"];
- graph.each_edge(|idx, edge| {
- assert_eq!(&expected[idx.0], graph.edge_data(idx));
- assert_eq!(expected[idx.0], edge.data);
- true
- });
-}
-
-fn test_adjacent_edges<N:PartialEq+Debug,E:PartialEq+Debug>(graph: &Graph<N,E>,
- start_index: NodeIndex,
- start_data: N,
- expected_incoming: &[(E,N)],
- expected_outgoing: &[(E,N)]) {
- assert!(graph.node_data(start_index) == &start_data);
-
- let mut counter = 0;
- for (edge_index, edge) in graph.incoming_edges(start_index) {
- assert!(graph.edge_data(edge_index) == &edge.data);
- assert!(counter < expected_incoming.len());
- debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
- counter, expected_incoming[counter], edge_index, edge);
- match expected_incoming[counter] {
- (ref e, ref n) => {
- assert!(e == &edge.data);
- assert!(n == graph.node_data(edge.source()));
- assert!(start_index == edge.target);
- }
- }
- counter += 1;
- }
- assert_eq!(counter, expected_incoming.len());
-
- let mut counter = 0;
- for (edge_index, edge) in graph.outgoing_edges(start_index) {
- assert!(graph.edge_data(edge_index) == &edge.data);
- assert!(counter < expected_outgoing.len());
- debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
- counter, expected_outgoing[counter], edge_index, edge);
- match expected_outgoing[counter] {
- (ref e, ref n) => {
- assert!(e == &edge.data);
- assert!(start_index == edge.source);
- assert!(n == graph.node_data(edge.target));
- }
- }
- counter += 1;
- }
- assert_eq!(counter, expected_outgoing.len());
-}
-
-#[test]
-fn each_adjacent_from_a() {
- let graph = create_graph();
- test_adjacent_edges(&graph, NodeIndex(0), "A",
- &[],
- &[("AB", "B")]);
-}
-
-#[test]
-fn each_adjacent_from_b() {
- let graph = create_graph();
- test_adjacent_edges(&graph, NodeIndex(1), "B",
- &[("FB", "F"), ("AB", "A"),],
- &[("BD", "D"), ("BC", "C"),]);
-}
-
-#[test]
-fn each_adjacent_from_c() {
- let graph = create_graph();
- test_adjacent_edges(&graph, NodeIndex(2), "C",
- &[("EC", "E"), ("BC", "B")],
- &[]);
-}
-
-#[test]
-fn each_adjacent_from_d() {
- let graph = create_graph();
- test_adjacent_edges(&graph, NodeIndex(3), "D",
- &[("BD", "B")],
- &[("DE", "E")]);
-}
--- /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 graph::*;
+use std::fmt::Debug;
+
+type TestNode = Node<&'static str>;
+type TestEdge = Edge<&'static str>;
+type TestGraph = Graph<&'static str, &'static str>;
+
+fn create_graph() -> TestGraph {
+ let mut graph = Graph::new();
+
+ // Create a simple graph
+ //
+ // A -+> B --> C
+ // | | ^
+ // | v |
+ // F D --> E
+
+ let a = graph.add_node("A");
+ let b = graph.add_node("B");
+ let c = graph.add_node("C");
+ let d = graph.add_node("D");
+ let e = graph.add_node("E");
+ let f = graph.add_node("F");
+
+ graph.add_edge(a, b, "AB");
+ graph.add_edge(b, c, "BC");
+ graph.add_edge(b, d, "BD");
+ graph.add_edge(d, e, "DE");
+ graph.add_edge(e, c, "EC");
+ graph.add_edge(f, b, "FB");
+
+ return graph;
+}
+
+#[test]
+fn each_node() {
+ let graph = create_graph();
+ let expected = ["A", "B", "C", "D", "E", "F"];
+ graph.each_node(|idx, node| {
+ assert_eq!(&expected[idx.0], graph.node_data(idx));
+ assert_eq!(expected[idx.0], node.data);
+ true
+ });
+}
+
+#[test]
+fn each_edge() {
+ let graph = create_graph();
+ let expected = ["AB", "BC", "BD", "DE", "EC", "FB"];
+ graph.each_edge(|idx, edge| {
+ assert_eq!(&expected[idx.0], graph.edge_data(idx));
+ assert_eq!(expected[idx.0], edge.data);
+ true
+ });
+}
+
+fn test_adjacent_edges<N:PartialEq+Debug,E:PartialEq+Debug>(graph: &Graph<N,E>,
+ start_index: NodeIndex,
+ start_data: N,
+ expected_incoming: &[(E,N)],
+ expected_outgoing: &[(E,N)]) {
+ assert!(graph.node_data(start_index) == &start_data);
+
+ let mut counter = 0;
+ for (edge_index, edge) in graph.incoming_edges(start_index) {
+ assert!(graph.edge_data(edge_index) == &edge.data);
+ assert!(counter < expected_incoming.len());
+ debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
+ counter, expected_incoming[counter], edge_index, edge);
+ match expected_incoming[counter] {
+ (ref e, ref n) => {
+ assert!(e == &edge.data);
+ assert!(n == graph.node_data(edge.source()));
+ assert!(start_index == edge.target);
+ }
+ }
+ counter += 1;
+ }
+ assert_eq!(counter, expected_incoming.len());
+
+ let mut counter = 0;
+ for (edge_index, edge) in graph.outgoing_edges(start_index) {
+ assert!(graph.edge_data(edge_index) == &edge.data);
+ assert!(counter < expected_outgoing.len());
+ debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}",
+ counter, expected_outgoing[counter], edge_index, edge);
+ match expected_outgoing[counter] {
+ (ref e, ref n) => {
+ assert!(e == &edge.data);
+ assert!(start_index == edge.source);
+ assert!(n == graph.node_data(edge.target));
+ }
+ }
+ counter += 1;
+ }
+ assert_eq!(counter, expected_outgoing.len());
+}
+
+#[test]
+fn each_adjacent_from_a() {
+ let graph = create_graph();
+ test_adjacent_edges(&graph, NodeIndex(0), "A",
+ &[],
+ &[("AB", "B")]);
+}
+
+#[test]
+fn each_adjacent_from_b() {
+ let graph = create_graph();
+ test_adjacent_edges(&graph, NodeIndex(1), "B",
+ &[("FB", "F"), ("AB", "A"),],
+ &[("BD", "D"), ("BC", "C"),]);
+}
+
+#[test]
+fn each_adjacent_from_c() {
+ let graph = create_graph();
+ test_adjacent_edges(&graph, NodeIndex(2), "C",
+ &[("EC", "E"), ("BC", "B")],
+ &[]);
+}
+
+#[test]
+fn each_adjacent_from_d() {
+ let graph = create_graph();
+ test_adjacent_edges(&graph, NodeIndex(3), "D",
+ &[("BD", "B")],
+ &[("DE", "E")]);
+}
use snapshot_vec as sv;
#[cfg(test)]
-mod test;
+mod tests;
/// This trait is implemented by any type that can serve as a type
/// variable. We call such variables *unification keys*. For example,
+++ /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.
-
-#![allow(non_snake_case)]
-
-extern crate test;
-use self::test::Bencher;
-use std::collections::HashSet;
-use unify::{UnifyKey, UnificationTable};
-
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-struct UnitKey(u32);
-
-impl UnifyKey for UnitKey {
- type Value = ();
- fn index(&self) -> u32 { self.0 }
- fn from_index(u: u32) -> UnitKey { UnitKey(u) }
- fn tag(_: Option<UnitKey>) -> &'static str { "UnitKey" }
-}
-
-#[test]
-fn basic() {
- let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
- let k1 = ut.new_key(());
- let k2 = ut.new_key(());
- assert_eq!(ut.unioned(k1, k2), false);
- ut.union(k1, k2);
- assert_eq!(ut.unioned(k1, k2), true);
-}
-
-#[test]
-fn big_array() {
- let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
- let mut keys = Vec::new();
- const MAX: usize = 1 << 15;
-
- for _ in 0..MAX {
- keys.push(ut.new_key(()));
- }
-
- for i in 1..MAX {
- let l = keys[i-1];
- let r = keys[i];
- ut.union(l, r);
- }
-
- for i in 0..MAX {
- assert!(ut.unioned(keys[0], keys[i]));
- }
-}
-
-#[bench]
-fn big_array_bench(b: &mut Bencher) {
- let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
- let mut keys = Vec::new();
- const MAX: usize = 1 << 15;
-
- for _ in 0..MAX {
- keys.push(ut.new_key(()));
- }
-
-
- b.iter(|| {
- for i in 1..MAX {
- let l = keys[i-1];
- let r = keys[i];
- ut.union(l, r);
- }
-
- for i in 0..MAX {
- assert!(ut.unioned(keys[0], keys[i]));
- }
- })
-}
-
-#[test]
-fn even_odd() {
- let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
- let mut keys = Vec::new();
- const MAX: usize = 1 << 10;
-
- for i in 0..MAX {
- let key = ut.new_key(());
- keys.push(key);
-
- if i >= 2 {
- ut.union(key, keys[i-2]);
- }
- }
-
- for i in 1..MAX {
- assert!(!ut.unioned(keys[i-1], keys[i]));
- }
-
- for i in 2..MAX {
- assert!(ut.unioned(keys[i-2], keys[i]));
- }
-}
-
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-struct IntKey(u32);
-
-impl UnifyKey for IntKey {
- type Value = Option<i32>;
- fn index(&self) -> u32 { self.0 }
- fn from_index(u: u32) -> IntKey { IntKey(u) }
- fn tag(_: Option<IntKey>) -> &'static str { "IntKey" }
-}
-
-/// Test unifying a key whose value is `Some(_)` with a key whose value is `None`.
-/// Afterwards both should be `Some(_)`.
-#[test]
-fn unify_key_Some_key_None() {
- let mut ut: UnificationTable<IntKey> = UnificationTable::new();
- let k1 = ut.new_key(Some(22));
- let k2 = ut.new_key(None);
- assert!(ut.unify_var_var(k1, k2).is_ok());
- assert_eq!(ut.probe(k2), Some(22));
- assert_eq!(ut.probe(k1), Some(22));
-}
-
-/// Test unifying a key whose value is `None` with a key whose value is `Some(_)`.
-/// Afterwards both should be `Some(_)`.
-#[test]
-fn unify_key_None_key_Some() {
- let mut ut: UnificationTable<IntKey> = UnificationTable::new();
- let k1 = ut.new_key(Some(22));
- let k2 = ut.new_key(None);
- assert!(ut.unify_var_var(k2, k1).is_ok());
- assert_eq!(ut.probe(k2), Some(22));
- assert_eq!(ut.probe(k1), Some(22));
-}
-
-/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(y)`.
-/// This should yield an error.
-#[test]
-fn unify_key_Some_x_key_Some_y() {
- let mut ut: UnificationTable<IntKey> = UnificationTable::new();
- let k1 = ut.new_key(Some(22));
- let k2 = ut.new_key(Some(23));
- assert_eq!(ut.unify_var_var(k1, k2), Err((22, 23)));
- assert_eq!(ut.unify_var_var(k2, k1), Err((23, 22)));
- assert_eq!(ut.probe(k1), Some(22));
- assert_eq!(ut.probe(k2), Some(23));
-}
-
-/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(x)`.
-/// This should be ok.
-#[test]
-fn unify_key_Some_x_key_Some_x() {
- let mut ut: UnificationTable<IntKey> = UnificationTable::new();
- let k1 = ut.new_key(Some(22));
- let k2 = ut.new_key(Some(22));
- assert!(ut.unify_var_var(k1, k2).is_ok());
- assert_eq!(ut.probe(k1), Some(22));
- assert_eq!(ut.probe(k2), Some(22));
-}
-
-/// Test unifying a key whose value is `None` with a value is `x`.
-/// Afterwards key should be `x`.
-#[test]
-fn unify_key_None_val() {
- let mut ut: UnificationTable<IntKey> = UnificationTable::new();
- let k1 = ut.new_key(None);
- assert!(ut.unify_var_value(k1, 22).is_ok());
- assert_eq!(ut.probe(k1), Some(22));
-}
-
-/// Test unifying a key whose value is `Some(x)` with the value `y`.
-/// This should yield an error.
-#[test]
-fn unify_key_Some_x_val_y() {
- let mut ut: UnificationTable<IntKey> = UnificationTable::new();
- let k1 = ut.new_key(Some(22));
- assert_eq!(ut.unify_var_value(k1, 23), Err((22, 23)));
- assert_eq!(ut.probe(k1), Some(22));
-}
-
-/// Test unifying a key whose value is `Some(x)` with the value `x`.
-/// This should be ok.
-#[test]
-fn unify_key_Some_x_val_x() {
- let mut ut: UnificationTable<IntKey> = UnificationTable::new();
- let k1 = ut.new_key(Some(22));
- assert!(ut.unify_var_value(k1, 22).is_ok());
- assert_eq!(ut.probe(k1), Some(22));
-}
-
--- /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.
+
+#![allow(non_snake_case)]
+
+extern crate test;
+use self::test::Bencher;
+use std::collections::HashSet;
+use unify::{UnifyKey, UnificationTable};
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+struct UnitKey(u32);
+
+impl UnifyKey for UnitKey {
+ type Value = ();
+ fn index(&self) -> u32 { self.0 }
+ fn from_index(u: u32) -> UnitKey { UnitKey(u) }
+ fn tag(_: Option<UnitKey>) -> &'static str { "UnitKey" }
+}
+
+#[test]
+fn basic() {
+ let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
+ let k1 = ut.new_key(());
+ let k2 = ut.new_key(());
+ assert_eq!(ut.unioned(k1, k2), false);
+ ut.union(k1, k2);
+ assert_eq!(ut.unioned(k1, k2), true);
+}
+
+#[test]
+fn big_array() {
+ let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
+ let mut keys = Vec::new();
+ const MAX: usize = 1 << 15;
+
+ for _ in 0..MAX {
+ keys.push(ut.new_key(()));
+ }
+
+ for i in 1..MAX {
+ let l = keys[i-1];
+ let r = keys[i];
+ ut.union(l, r);
+ }
+
+ for i in 0..MAX {
+ assert!(ut.unioned(keys[0], keys[i]));
+ }
+}
+
+#[bench]
+fn big_array_bench(b: &mut Bencher) {
+ let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
+ let mut keys = Vec::new();
+ const MAX: usize = 1 << 15;
+
+ for _ in 0..MAX {
+ keys.push(ut.new_key(()));
+ }
+
+
+ b.iter(|| {
+ for i in 1..MAX {
+ let l = keys[i-1];
+ let r = keys[i];
+ ut.union(l, r);
+ }
+
+ for i in 0..MAX {
+ assert!(ut.unioned(keys[0], keys[i]));
+ }
+ })
+}
+
+#[test]
+fn even_odd() {
+ let mut ut: UnificationTable<UnitKey> = UnificationTable::new();
+ let mut keys = Vec::new();
+ const MAX: usize = 1 << 10;
+
+ for i in 0..MAX {
+ let key = ut.new_key(());
+ keys.push(key);
+
+ if i >= 2 {
+ ut.union(key, keys[i-2]);
+ }
+ }
+
+ for i in 1..MAX {
+ assert!(!ut.unioned(keys[i-1], keys[i]));
+ }
+
+ for i in 2..MAX {
+ assert!(ut.unioned(keys[i-2], keys[i]));
+ }
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+struct IntKey(u32);
+
+impl UnifyKey for IntKey {
+ type Value = Option<i32>;
+ fn index(&self) -> u32 { self.0 }
+ fn from_index(u: u32) -> IntKey { IntKey(u) }
+ fn tag(_: Option<IntKey>) -> &'static str { "IntKey" }
+}
+
+/// Test unifying a key whose value is `Some(_)` with a key whose value is `None`.
+/// Afterwards both should be `Some(_)`.
+#[test]
+fn unify_key_Some_key_None() {
+ let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+ let k1 = ut.new_key(Some(22));
+ let k2 = ut.new_key(None);
+ assert!(ut.unify_var_var(k1, k2).is_ok());
+ assert_eq!(ut.probe(k2), Some(22));
+ assert_eq!(ut.probe(k1), Some(22));
+}
+
+/// Test unifying a key whose value is `None` with a key whose value is `Some(_)`.
+/// Afterwards both should be `Some(_)`.
+#[test]
+fn unify_key_None_key_Some() {
+ let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+ let k1 = ut.new_key(Some(22));
+ let k2 = ut.new_key(None);
+ assert!(ut.unify_var_var(k2, k1).is_ok());
+ assert_eq!(ut.probe(k2), Some(22));
+ assert_eq!(ut.probe(k1), Some(22));
+}
+
+/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(y)`.
+/// This should yield an error.
+#[test]
+fn unify_key_Some_x_key_Some_y() {
+ let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+ let k1 = ut.new_key(Some(22));
+ let k2 = ut.new_key(Some(23));
+ assert_eq!(ut.unify_var_var(k1, k2), Err((22, 23)));
+ assert_eq!(ut.unify_var_var(k2, k1), Err((23, 22)));
+ assert_eq!(ut.probe(k1), Some(22));
+ assert_eq!(ut.probe(k2), Some(23));
+}
+
+/// Test unifying a key whose value is `Some(x)` with a key whose value is `Some(x)`.
+/// This should be ok.
+#[test]
+fn unify_key_Some_x_key_Some_x() {
+ let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+ let k1 = ut.new_key(Some(22));
+ let k2 = ut.new_key(Some(22));
+ assert!(ut.unify_var_var(k1, k2).is_ok());
+ assert_eq!(ut.probe(k1), Some(22));
+ assert_eq!(ut.probe(k2), Some(22));
+}
+
+/// Test unifying a key whose value is `None` with a value is `x`.
+/// Afterwards key should be `x`.
+#[test]
+fn unify_key_None_val() {
+ let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+ let k1 = ut.new_key(None);
+ assert!(ut.unify_var_value(k1, 22).is_ok());
+ assert_eq!(ut.probe(k1), Some(22));
+}
+
+/// Test unifying a key whose value is `Some(x)` with the value `y`.
+/// This should yield an error.
+#[test]
+fn unify_key_Some_x_val_y() {
+ let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+ let k1 = ut.new_key(Some(22));
+ assert_eq!(ut.unify_var_value(k1, 23), Err((22, 23)));
+ assert_eq!(ut.probe(k1), Some(22));
+}
+
+/// Test unifying a key whose value is `Some(x)` with the value `x`.
+/// This should be ok.
+#[test]
+fn unify_key_Some_x_val_x() {
+ let mut ut: UnificationTable<IntKey> = UnificationTable::new();
+ let k1 = ut.new_key(Some(22));
+ assert!(ut.unify_var_value(k1, 22).is_ok());
+ assert_eq!(ut.probe(k1), Some(22));
+}
+
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,
use rustc_lint;
use rustc_resolve as resolve;
use rustc_typeck::middle::lang_items;
+use rustc_typeck::middle::free_region::FreeRegionMap;
use rustc_typeck::middle::region::{self, CodeExtent, DestructionScopeData};
use rustc_typeck::middle::resolve_lifetime;
use rustc_typeck::middle::stability;
stability::Index::new(krate));
let infcx = infer::new_infer_ctxt(&tcx);
body(Env { infcx: &infcx });
- infcx.resolve_regions_and_report_errors(ast::CRATE_NODE_ID);
+ let free_regions = FreeRegionMap::new();
+ infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID);
assert_eq!(tcx.sess.err_count(), expected_err_count);
}
}
}
+ 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,
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);
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;
}
assert_eq!(nonzero_fields.len(), 1);
let nonzero_field = ty::lookup_field_type(tcx, did, nonzero_fields[0].id, substs);
match nonzero_field.sty {
+ ty::ty_ptr(ty::mt { ty, .. }) if !type_is_sized(tcx, ty) => {
+ path.push_all(&[0, FAT_PTR_ADDR]);
+ Some(path)
+ },
ty::ty_ptr(..) | ty::ty_int(..) | ty::ty_uint(..) => {
path.push(0);
Some(path)
(_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();
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::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS};
use middle::const_eval;
use middle::def;
+use middle::implicator::object_region_bounds;
use middle::resolve_lifetime as rl;
use middle::privacy::{AllPublic, LastMod};
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
return r;
}
-/// Given an object type like `SomeTrait+Send`, computes the lifetime
-/// bounds that must hold on the elided self type. These are derived
-/// from the declarations of `SomeTrait`, `Send`, and friends -- if
-/// they declare `trait SomeTrait : 'static`, for example, then
-/// `'static` would appear in the list. The hard work is done by
-/// `ty::required_region_bounds`, see that for more information.
-pub fn object_region_bounds<'tcx>(
- tcx: &ty::ctxt<'tcx>,
- principal: &ty::PolyTraitRef<'tcx>,
- others: ty::BuiltinBounds)
- -> Vec<ty::Region>
-{
- // Since we don't actually *know* the self type for an object,
- // this "open(err)" serves as a kind of dummy standin -- basically
- // a skolemized type.
- let open_ty = ty::mk_infer(tcx, ty::FreshTy(0));
-
- // Note that we preserve the overall binding levels here.
- assert!(!open_ty.has_escaping_regions());
- let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
- let trait_refs = vec!(ty::Binder(Rc::new(ty::TraitRef::new(principal.0.def_id, substs))));
-
- let param_bounds = ty::ParamBounds {
- region_bounds: Vec::new(),
- builtin_bounds: others,
- trait_bounds: trait_refs,
- projection_bounds: Vec::new(), // not relevant to computing region bounds
- };
-
- let predicates = ty::predicates(tcx, open_ty, ¶m_bounds);
- ty::required_region_bounds(tcx, open_ty, predicates)
-}
-
pub struct PartitionedBounds<'a> {
pub builtin_bounds: ty::BuiltinBounds,
pub trait_bounds: Vec<&'a ast::PolyTraitRef>,
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)
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use middle::free_region::FreeRegionMap;
use middle::infer;
use middle::traits;
use middle::ty::{self};
Ok(_) => {}
}
- // Finally, resolve all regions. This catches wily misuses of lifetime
- // parameters.
- infcx.resolve_regions_and_report_errors(impl_m_body_id);
+ // Finally, resolve all regions. This catches wily misuses of
+ // lifetime parameters. We have to build up a plausible lifetime
+ // environment based on what we find in the trait. We could also
+ // include the obligations derived from the method argument types,
+ // but I don't think it's necessary -- after all, those are still
+ // in effect when type-checking the body, and all the
+ // where-clauses in the header etc should be implied by the trait
+ // anyway, so it shouldn't be needed there either. Anyway, we can
+ // always add more relations later (it's backwards compat).
+ let mut free_regions = FreeRegionMap::new();
+ free_regions.relate_free_regions_from_predicates(tcx, &trait_param_env.caller_bounds);
+
+ infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
fn check_region_bounds_on_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
span: Span,
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,
}
+++ /dev/null
-// Copyright 2012 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.
-
-// #![warn(deprecated_mode)]
-
-use astconv::object_region_bounds;
-use middle::infer::{InferCtxt, GenericKind};
-use middle::subst::Substs;
-use middle::traits;
-use middle::ty::{self, ToPolyTraitRef, Ty};
-use middle::ty_fold::{TypeFoldable, TypeFolder};
-
-use std::rc::Rc;
-use syntax::ast;
-use syntax::codemap::Span;
-
-use util::common::ErrorReported;
-use util::nodemap::FnvHashSet;
-use util::ppaux::Repr;
-
-// Helper functions related to manipulating region types.
-
-pub enum Implication<'tcx> {
- RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
- RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
- RegionSubClosure(Option<Ty<'tcx>>, ty::Region, ast::DefId, &'tcx Substs<'tcx>),
- Predicate(ast::DefId, ty::Predicate<'tcx>),
-}
-
-struct Implicator<'a, 'tcx: 'a> {
- infcx: &'a InferCtxt<'a,'tcx>,
- closure_typer: &'a (ty::ClosureTyper<'tcx>+'a),
- body_id: ast::NodeId,
- stack: Vec<(ty::Region, Option<Ty<'tcx>>)>,
- span: Span,
- out: Vec<Implication<'tcx>>,
- visited: FnvHashSet<Ty<'tcx>>,
-}
-
-/// This routine computes the well-formedness constraints that must hold for the type `ty` to
-/// appear in a context with lifetime `outer_region`
-pub fn implications<'a,'tcx>(
- infcx: &'a InferCtxt<'a,'tcx>,
- closure_typer: &ty::ClosureTyper<'tcx>,
- body_id: ast::NodeId,
- ty: Ty<'tcx>,
- outer_region: ty::Region,
- span: Span)
- -> Vec<Implication<'tcx>>
-{
- debug!("implications(body_id={}, ty={}, outer_region={})",
- body_id,
- ty.repr(closure_typer.tcx()),
- outer_region.repr(closure_typer.tcx()));
-
- let mut stack = Vec::new();
- stack.push((outer_region, None));
- let mut wf = Implicator { closure_typer: closure_typer,
- infcx: infcx,
- body_id: body_id,
- span: span,
- stack: stack,
- out: Vec::new(),
- visited: FnvHashSet() };
- wf.accumulate_from_ty(ty);
- debug!("implications: out={}", wf.out.repr(closure_typer.tcx()));
- wf.out
-}
-
-impl<'a, 'tcx> Implicator<'a, 'tcx> {
- fn tcx(&self) -> &'a ty::ctxt<'tcx> {
- self.infcx.tcx
- }
-
- fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
- debug!("accumulate_from_ty(ty={})",
- ty.repr(self.tcx()));
-
- // When expanding out associated types, we can visit a cyclic
- // set of types. Issue #23003.
- if !self.visited.insert(ty) {
- return;
- }
-
- match ty.sty {
- ty::ty_bool |
- ty::ty_char |
- ty::ty_int(..) |
- ty::ty_uint(..) |
- ty::ty_float(..) |
- ty::ty_bare_fn(..) |
- ty::ty_err |
- ty::ty_str => {
- // No borrowed content reachable here.
- }
-
- ty::ty_closure(def_id, substs) => {
- let &(r_a, opt_ty) = self.stack.last().unwrap();
- self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs));
- }
-
- ty::ty_trait(ref t) => {
- let required_region_bounds =
- object_region_bounds(self.tcx(), &t.principal, t.bounds.builtin_bounds);
- self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
- }
-
- ty::ty_enum(def_id, substs) |
- ty::ty_struct(def_id, substs) => {
- let item_scheme = ty::lookup_item_type(self.tcx(), def_id);
- self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs)
- }
-
- ty::ty_vec(t, _) |
- ty::ty_ptr(ty::mt { ty: t, .. }) |
- ty::ty_uniq(t) => {
- self.accumulate_from_ty(t)
- }
-
- ty::ty_rptr(r_b, mt) => {
- self.accumulate_from_rptr(ty, *r_b, mt.ty);
- }
-
- ty::ty_param(p) => {
- self.push_param_constraint_from_top(p);
- }
-
- ty::ty_projection(ref data) => {
- // `<T as TraitRef<..>>::Name`
-
- self.push_projection_constraint_from_top(data);
- }
-
- ty::ty_tup(ref tuptys) => {
- for &tupty in tuptys {
- self.accumulate_from_ty(tupty);
- }
- }
-
- ty::ty_infer(_) => {
- // This should not happen, BUT:
- //
- // Currently we uncover region relationships on
- // entering the fn check. We should do this after
- // the fn check, then we can call this case a bug().
- }
- }
- }
-
- fn accumulate_from_rptr(&mut self,
- ty: Ty<'tcx>,
- r_b: ty::Region,
- ty_b: Ty<'tcx>) {
- // We are walking down a type like this, and current
- // position is indicated by caret:
- //
- // &'a &'b ty_b
- // ^
- //
- // At this point, top of stack will be `'a`. We must
- // require that `'a <= 'b`.
-
- self.push_region_constraint_from_top(r_b);
-
- // Now we push `'b` onto the stack, because it must
- // constrain any borrowed content we find within `T`.
-
- self.stack.push((r_b, Some(ty)));
- self.accumulate_from_ty(ty_b);
- self.stack.pop().unwrap();
- }
-
- /// Pushes a constraint that `r_b` must outlive the top region on the stack.
- fn push_region_constraint_from_top(&mut self,
- r_b: ty::Region) {
-
- // Indicates that we have found borrowed content with a lifetime
- // of at least `r_b`. This adds a constraint that `r_b` must
- // outlive the region `r_a` on top of the stack.
- //
- // As an example, imagine walking a type like:
- //
- // &'a &'b T
- // ^
- //
- // when we hit the inner pointer (indicated by caret), `'a` will
- // be on top of stack and `'b` will be the lifetime of the content
- // we just found. So we add constraint that `'a <= 'b`.
-
- let &(r_a, opt_ty) = self.stack.last().unwrap();
- self.push_sub_region_constraint(opt_ty, r_a, r_b);
- }
-
- /// Pushes a constraint that `r_a <= r_b`, due to `opt_ty`
- fn push_sub_region_constraint(&mut self,
- opt_ty: Option<Ty<'tcx>>,
- r_a: ty::Region,
- r_b: ty::Region) {
- self.out.push(Implication::RegionSubRegion(opt_ty, r_a, r_b));
- }
-
- /// Pushes a constraint that `param_ty` must outlive the top region on the stack.
- fn push_param_constraint_from_top(&mut self,
- param_ty: ty::ParamTy) {
- let &(region, opt_ty) = self.stack.last().unwrap();
- self.push_param_constraint(region, opt_ty, param_ty);
- }
-
- /// Pushes a constraint that `projection_ty` must outlive the top region on the stack.
- fn push_projection_constraint_from_top(&mut self,
- projection_ty: &ty::ProjectionTy<'tcx>) {
- let &(region, opt_ty) = self.stack.last().unwrap();
- self.out.push(Implication::RegionSubGeneric(
- opt_ty, region, GenericKind::Projection(projection_ty.clone())));
- }
-
- /// Pushes a constraint that `region <= param_ty`, due to `opt_ty`
- fn push_param_constraint(&mut self,
- region: ty::Region,
- opt_ty: Option<Ty<'tcx>>,
- param_ty: ty::ParamTy) {
- self.out.push(Implication::RegionSubGeneric(
- opt_ty, region, GenericKind::Param(param_ty)));
- }
-
- fn accumulate_from_adt(&mut self,
- ty: Ty<'tcx>,
- def_id: ast::DefId,
- _generics: &ty::Generics<'tcx>,
- substs: &Substs<'tcx>)
- {
- let predicates =
- ty::lookup_predicates(self.tcx(), def_id).instantiate(self.tcx(), substs);
- let predicates = match self.fully_normalize(&predicates) {
- Ok(predicates) => predicates,
- Err(ErrorReported) => { return; }
- };
-
- for predicate in predicates.predicates.as_slice() {
- match *predicate {
- ty::Predicate::Trait(ref data) => {
- self.accumulate_from_assoc_types_transitive(data);
- }
- ty::Predicate::Equate(..) => { }
- ty::Predicate::Projection(..) => { }
- ty::Predicate::RegionOutlives(ref data) => {
- match ty::no_late_bound_regions(self.tcx(), data) {
- None => { }
- Some(ty::OutlivesPredicate(r_a, r_b)) => {
- self.push_sub_region_constraint(Some(ty), r_b, r_a);
- }
- }
- }
- ty::Predicate::TypeOutlives(ref data) => {
- match ty::no_late_bound_regions(self.tcx(), data) {
- None => { }
- Some(ty::OutlivesPredicate(ty_a, r_b)) => {
- self.stack.push((r_b, Some(ty)));
- self.accumulate_from_ty(ty_a);
- self.stack.pop().unwrap();
- }
- }
- }
- }
- }
-
- let obligations = predicates.predicates
- .into_iter()
- .map(|pred| Implication::Predicate(def_id, pred));
- self.out.extend(obligations);
-
- let variances = ty::item_variances(self.tcx(), def_id);
-
- for (®ion, &variance) in substs.regions().iter().zip(variances.regions.iter()) {
- match variance {
- ty::Contravariant | ty::Invariant => {
- // If any data with this lifetime is reachable
- // within, it must be at least contravariant.
- self.push_region_constraint_from_top(region)
- }
- ty::Covariant | ty::Bivariant => { }
- }
- }
-
- for (&ty, &variance) in substs.types.iter().zip(variances.types.iter()) {
- match variance {
- ty::Covariant | ty::Invariant => {
- // If any data of this type is reachable within,
- // it must be at least covariant.
- self.accumulate_from_ty(ty);
- }
- ty::Contravariant | ty::Bivariant => { }
- }
- }
- }
-
- /// Given that there is a requirement that `Foo<X> : 'a`, where
- /// `Foo` is declared like `struct Foo<T> where T : SomeTrait`,
- /// this code finds all the associated types defined in
- /// `SomeTrait` (and supertraits) and adds a requirement that `<X
- /// as SomeTrait>::N : 'a` (where `N` is some associated type
- /// defined in `SomeTrait`). This rule only applies to
- /// trait-bounds that are not higher-ranked, because we cannot
- /// project out of a HRTB. This rule helps code using associated
- /// types to compile, see Issue #22246 for an example.
- fn accumulate_from_assoc_types_transitive(&mut self,
- data: &ty::PolyTraitPredicate<'tcx>)
- {
- debug!("accumulate_from_assoc_types_transitive({})",
- data.repr(self.tcx()));
-
- for poly_trait_ref in traits::supertraits(self.tcx(), data.to_poly_trait_ref()) {
- match ty::no_late_bound_regions(self.tcx(), &poly_trait_ref) {
- Some(trait_ref) => { self.accumulate_from_assoc_types(trait_ref); }
- None => { }
- }
- }
- }
-
- fn accumulate_from_assoc_types(&mut self,
- trait_ref: Rc<ty::TraitRef<'tcx>>)
- {
- debug!("accumulate_from_assoc_types({})",
- trait_ref.repr(self.tcx()));
-
- let trait_def_id = trait_ref.def_id;
- let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id);
- let assoc_type_projections: Vec<_> =
- trait_def.associated_type_names
- .iter()
- .map(|&name| ty::mk_projection(self.tcx(), trait_ref.clone(), name))
- .collect();
- debug!("accumulate_from_assoc_types: assoc_type_projections={}",
- assoc_type_projections.repr(self.tcx()));
- let tys = match self.fully_normalize(&assoc_type_projections) {
- Ok(tys) => { tys }
- Err(ErrorReported) => { return; }
- };
- for ty in tys {
- self.accumulate_from_ty(ty);
- }
- }
-
- fn accumulate_from_object_ty(&mut self,
- ty: Ty<'tcx>,
- region_bound: ty::Region,
- required_region_bounds: Vec<ty::Region>)
- {
- // Imagine a type like this:
- //
- // trait Foo { }
- // trait Bar<'c> : 'c { }
- //
- // &'b (Foo+'c+Bar<'d>)
- // ^
- //
- // In this case, the following relationships must hold:
- //
- // 'b <= 'c
- // 'd <= 'c
- //
- // The first conditions is due to the normal region pointer
- // rules, which say that a reference cannot outlive its
- // referent.
- //
- // The final condition may be a bit surprising. In particular,
- // you may expect that it would have been `'c <= 'd`, since
- // usually lifetimes of outer things are conservative
- // approximations for inner things. However, it works somewhat
- // differently with trait objects: here the idea is that if the
- // user specifies a region bound (`'c`, in this case) it is the
- // "master bound" that *implies* that bounds from other traits are
- // all met. (Remember that *all bounds* in a type like
- // `Foo+Bar+Zed` must be met, not just one, hence if we write
- // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
- // 'y.)
- //
- // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
- // am looking forward to the future here.
-
- // The content of this object type must outlive
- // `bounds.region_bound`:
- let r_c = region_bound;
- self.push_region_constraint_from_top(r_c);
-
- // And then, in turn, to be well-formed, the
- // `region_bound` that user specified must imply the
- // region bounds required from all of the trait types:
- for &r_d in &required_region_bounds {
- // Each of these is an instance of the `'c <= 'b`
- // constraint above
- self.out.push(Implication::RegionSubRegion(Some(ty), r_d, r_c));
- }
- }
-
- fn fully_normalize<T>(&self, value: &T) -> Result<T,ErrorReported>
- where T : TypeFoldable<'tcx> + ty::HasProjectionTypes + Clone + Repr<'tcx>
- {
- let value =
- traits::fully_normalize(self.infcx,
- self.closure_typer,
- traits::ObligationCause::misc(self.span, self.body_id),
- value);
- match value {
- Ok(value) => Ok(value),
- Err(errors) => {
- // I don't like reporting these errors here, but I
- // don't know where else to report them just now. And
- // I don't really expect errors to arise here
- // frequently. I guess the best option would be to
- // propagate them out.
- traits::report_fulfillment_errors(self.infcx, &errors);
- Err(ErrorReported)
- }
- }
- }
-}
-
-impl<'tcx> Repr<'tcx> for Implication<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- match *self {
- Implication::RegionSubRegion(_, ref r_a, ref r_b) => {
- format!("RegionSubRegion({}, {})",
- r_a.repr(tcx),
- r_b.repr(tcx))
- }
-
- Implication::RegionSubGeneric(_, ref r, ref p) => {
- format!("RegionSubGeneric({}, {})",
- r.repr(tcx),
- p.repr(tcx))
- }
-
- Implication::RegionSubClosure(_, ref a, ref b, ref c) => {
- format!("RegionSubClosure({}, {}, {})",
- a.repr(tcx),
- b.repr(tcx),
- c.repr(tcx))
- }
-
- Implication::Predicate(ref def_id, ref p) => {
- format!("Predicate({}, {})",
- def_id.repr(tcx),
- p.repr(tcx))
- }
- }
- }
-}
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 struct AllTraits<'a> {
- borrow: cell::Ref<'a Option<AllTraitsVec>>,
+ borrow: cell::Ref<'a, Option<AllTraitsVec>>,
idx: usize
}
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};
pub mod _match;
pub mod vtable;
pub mod writeback;
-pub mod implicator;
pub mod regionck;
pub mod coercion;
pub mod demand;
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 astconv::AstConv;
use check::dropck;
use check::FnCtxt;
-use check::implicator;
use check::vtable;
+use middle::free_region::FreeRegionMap;
+use middle::implicator;
use middle::mem_categorization as mc;
use middle::region::CodeExtent;
use middle::subst::Substs;
pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) {
let mut rcx = Rcx::new(fcx, RepeatingScope(item.id), item.id, Subject(item.id));
+ let tcx = fcx.tcx();
+ rcx.free_region_map.relate_free_regions_from_predicates(tcx, &fcx.inh.param_env.caller_bounds);
rcx.visit_region_obligations(item.id);
rcx.resolve_regions_and_report_errors();
}
blk: &ast::Block) {
debug!("regionck_fn(id={})", fn_id);
let mut rcx = Rcx::new(fcx, RepeatingScope(blk.id), blk.id, Subject(fn_id));
+
if fcx.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
rcx.visit_fn_body(fn_id, decl, blk, fn_span);
}
+ let tcx = fcx.tcx();
+ rcx.free_region_map.relate_free_regions_from_predicates(tcx, &fcx.inh.param_env.caller_bounds);
+
rcx.resolve_regions_and_report_errors();
+
+ // For the top-level fn, store the free-region-map. We don't store
+ // any map for closures; they just share the same map as the
+ // function that created them.
+ fcx.tcx().store_free_region_map(fn_id, rcx.free_region_map);
}
/// Checks that the types in `component_tys` are well-formed. This will add constraints into the
region_bound_pairs: Vec<(ty::Region, GenericKind<'tcx>)>,
+ free_region_map: FreeRegionMap,
+
// id of innermost fn body id
body_id: ast::NodeId,
repeating_scope: initial_repeating_scope,
body_id: initial_body_id,
subject: subject,
- region_bound_pairs: Vec::new()
+ region_bound_pairs: Vec::new(),
+ free_region_map: FreeRegionMap::new(),
}
}
}
};
- let len = self.region_bound_pairs.len();
+ let old_region_bounds_pairs_len = self.region_bound_pairs.len();
+
let old_body_id = self.set_body_id(body.id);
self.relate_free_regions(&fn_sig[..], body.id, span);
link_fn_args(self, CodeExtent::from_node_id(body.id), &fn_decl.inputs[..]);
self.visit_block(body);
self.visit_region_obligations(body.id);
- self.region_bound_pairs.truncate(len);
+
+ self.region_bound_pairs.truncate(old_region_bounds_pairs_len);
+
self.set_body_id(old_body_id);
}
let body_scope = ty::ReScope(body_scope);
let implications = implicator::implications(self.fcx.infcx(), self.fcx, body_id,
ty, body_scope, span);
+
+ // Record any relations between free regions that we observe into the free-region-map.
+ self.free_region_map.relate_free_regions_from_implications(tcx, &implications);
+
+ // But also record other relationships, such as `T:'x`,
+ // that don't go into the free-region-map but which we use
+ // here.
for implication in implications {
debug!("implication: {}", implication.repr(tcx));
match implication {
- implicator::Implication::RegionSubRegion(_,
- ty::ReFree(free_a),
- ty::ReFree(free_b)) => {
- tcx.region_maps.relate_free_regions(free_a, free_b);
- }
implicator::Implication::RegionSubRegion(_,
ty::ReFree(free_a),
ty::ReInfer(ty::ReVar(vid_b))) => {
}
};
- self.fcx.infcx().resolve_regions_and_report_errors(subject_node_id);
+ self.fcx.infcx().resolve_regions_and_report_errors(&self.free_region_map,
+ subject_node_id);
}
}
}
Err(..) => {
let tcx = rcx.fcx.tcx();
- if tcx.sess.has_errors() {
- // cannot run dropck; okay b/c in error state anyway.
- } else {
- tcx.sess.span_bug(expr.span, "cat_expr_unadjusted Errd");
- }
+ tcx.sess.delay_span_bug(expr.span, "cat_expr_unadjusted Errd");
}
}
}
}
Err(..) => {
let tcx = rcx.fcx.tcx();
- if tcx.sess.has_errors() {
- // cannot run dropck; okay b/c in error state anyway.
- } else {
- tcx.sess.span_bug(expr.span, "cat_expr Errd");
- }
+ tcx.sess.delay_span_bug(expr.span, "cat_expr Errd");
}
}
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(_) => {}
+ _ => {}
}
}
use middle::def;
use constrained_type_params as ctp;
use middle::lang_items::SizedTraitLangItem;
+use middle::free_region::FreeRegionMap;
use middle::region;
use middle::resolve_lifetime;
use middle::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
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();
}
};
format!("mismatched self type: expected `{}`",
ppaux::ty_to_string(tcx, required_type))
}));
- infcx.resolve_regions_and_report_errors(body_id);
+
+ // We could conceviably add more free-reion relations here,
+ // but since this code is just concerned with checking that
+ // the `&Self` types etc match up, it's not really necessary.
+ // It would just allow people to be more approximate in some
+ // cases. In any case, we can do it later as we feel the need;
+ // I'd like this function to go away eventually.
+ let free_regions = FreeRegionMap::new();
+
+ infcx.resolve_regions_and_report_errors(&free_regions, body_id);
}
fn liberate_early_bound_regions<'tcx,T>(
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
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") ||
}
#[cfg(test)]
-mod test {
+mod tests {
use super::{TocBuilder, Toc, TocEntry};
#[test]
// Primitives are never stripped
clean::PrimitiveItem(..) => {}
- // Associated types are never stripped
+ // Associated consts and types are never stripped
+ clean::AssociatedConstItem(..) |
clean::AssociatedTypeItem(..) => {}
}
}
#[cfg(all(test, not(target_os = "ios")))]
-mod test {
+mod tests {
use super::*;
use prelude::v1::*;
use libc;
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
}
#[cfg(test)]
-mod test {
+mod tests {
use thread;
use super::*;
}
#[cfg(test)]
-mod test {
+mod tests {
use prelude::v1::*;
use io::prelude::*;
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) => {
///
/// Path::new("foo.txt");
/// ```
+ ///
+ /// You can create `Path`s from `String`s, or even other `Path`s:
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let s = String::from("bar.txt");
+ /// let p = Path::new(&s);
+ /// Path::new(&p);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
unsafe { mem::transmute(s.as_ref()) }
}
#[cfg(test)]
-mod test {
+mod tests {
use prelude::v1::*;
use sync::mpsc::channel;
}
#[cfg(test)]
-mod test {
+mod tests {
use prelude::v1::*;
use super::ReaderRng;
}
#[cfg(test)]
-mod test {
+mod tests {
use prelude::v1::*;
use sys_common;
macro_rules! t { ($a:expr, $b:expr) => ({
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 {}
//
// 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 {}
}
#[cfg(test)]
-mod test {
+mod tests {
use prelude::v1::*;
use sync::mpsc::channel;
use sync::Future;
}
#[cfg(test)]
-mod test {
+mod tests {
use prelude::v1::*;
use std::env;
#[cfg(test)]
#[allow(unused_imports)]
-mod test {
+mod tests {
use prelude::v1::*;
use thread;
}
#[cfg(test)]
-mod test {
+mod tests {
use prelude::v1::*;
use sync::Arc;
}
#[cfg(test)]
-mod test {
+mod tests {
use prelude::v1::*;
use sync::mpsc::channel;
}
#[cfg(test)]
-mod test {
+mod tests {
use prelude::v1::*;
use thread;
setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE,
seconds as c_int)
}
- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+ #[cfg(any(target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "linux"))]
fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> {
setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE,
seconds as c_int)
}
+
#[cfg(not(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd",
- target_os = "dragonfly")))]
+ target_os = "dragonfly",
+ target_os = "linux")))]
fn set_tcp_keepalive(&self, _seconds: u32) -> io::Result<()> {
Ok(())
}
#[cfg(test)]
-mod test {
+mod tests {
use prelude::v1::*;
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
use cell::RefCell;
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)
}
/// # Ok(())
/// # }
/// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
{
sys::fs2::symlink(src.as_ref(), dst.as_ref())
// 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 {}
/// # Ok(())
/// # }
/// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
-> io::Result<()>
{
/// # Ok(())
/// # }
/// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>> (src: P, dst: Q)
-> io::Result<()>
{
// Produces a wide string *without terminating null*
fn make_command_line(prog: &OsStr, args: &[OsString]) -> Vec<u16> {
+ // Encode the command and arguments in a command line string such
+ // that the spawned process may recover them using CommandLineToArgvW.
let mut cmd: Vec<u16> = Vec::new();
append_arg(&mut cmd, prog);
for arg in args {
}
let mut iter = arg.encode_wide();
+ let mut backslashes: usize = 0;
while let Some(x) = iter.next() {
- if x == '"' as u16 {
- // escape quotes
- cmd.push('\\' as u16);
- cmd.push('"' as u16);
- } else if x == '\\' as u16 {
- // is this a run of backslashes followed by a " ?
- if iter.clone().skip_while(|y| *y == '\\' as u16).next() == Some('"' as u16) {
- // Double it ... NOTE: this behavior is being
- // preserved as it's been part of Rust for a long
- // time, but no one seems to know exactly why this
- // is the right thing to do.
- cmd.push('\\' as u16);
- cmd.push('\\' as u16);
- } else {
- // Push it through unescaped
- cmd.push('\\' as u16);
- }
+ if x == '\\' as u16 {
+ backslashes += 1;
} else {
- cmd.push(x)
+ if x == '"' as u16 {
+ // Add n+1 backslashes to total 2n+1 before internal '"'.
+ for _ in 0..(backslashes+1) {
+ cmd.push('\\' as u16);
+ }
+ }
+ backslashes = 0;
}
+ cmd.push(x);
}
if quote {
+ // Add n backslashes to total 2n before ending '"'.
+ for _ in 0..backslashes {
+ cmd.push('\\' as u16);
+ }
cmd.push('"' as u16);
}
}
test_wrapper("echo", &["a b c"]),
"echo \"a b c\""
);
+ assert_eq!(
+ test_wrapper("echo", &["\" \\\" \\", "\\"]),
+ "echo \"\\\" \\\\\\\" \\\\\" \\"
+ );
assert_eq!(
test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}"
// 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.
////////////////////////////////////////////////////////////////////////////////
#[cfg(test)]
-mod test {
+mod tests {
use prelude::v1::*;
use any::Any;
pub fn as_str<'a>(&'a self) -> &'a str {
self.name.as_str()
}
-
- pub fn encode_with_hygiene(&self) -> String {
- format!("\x00name_{},ctxt_{}\x00",
- self.name.usize(),
- self.ctxt)
- }
}
impl fmt::Debug for Ident {
/// "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),
}
#[cfg(test)]
-mod test {
+mod tests {
use serialize;
use super::*;
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
}
}
}
#[cfg(test)]
-mod test {
+mod tests {
use ast::*;
use super::*;
//
#[cfg(test)]
-mod test {
+mod tests {
use super::*;
use std::rc::Rc;
#[cfg(test)]
-mod test {
+mod tests {
use super::{pattern_bindings, expand_crate};
use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
use ast;
use ext::base::ExtCtxt;
use parse::token;
use parse;
- use print::pprust;
use ptr::P;
+ use std::rc::Rc;
- use ast::{TokenTree, Generics, Expr};
+ use ast::{TokenTree, Expr};
pub use parse::new_parser_from_tts;
- pub use codemap::{BytePos, Span, dummy_spanned};
+ pub use codemap::{BytePos, Span, dummy_spanned, DUMMY_SP};
pub trait ToTokens {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> ;
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree>;
}
impl ToTokens for TokenTree {
}
}
- /* Should be (when bugs in default methods are fixed):
-
- trait ToSource : ToTokens {
- // Takes a thing and generates a string containing rust code for it.
- pub fn to_source() -> String;
-
- // If you can make source, you can definitely make tokens.
- pub fn to_tokens(cx: &ExtCtxt) -> ~[TokenTree] {
- cx.parse_tts(self.to_source())
+ impl ToTokens for ast::Ident {
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+ vec![ast::TtToken(DUMMY_SP, token::Ident(*self, token::Plain))]
}
}
- */
-
- // FIXME: Move this trait to pprust and get rid of *_to_str?
- pub trait ToSource {
- // Takes a thing and generates a string containing rust code for it.
- fn to_source(&self) -> String;
+ impl ToTokens for ast::Path {
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+ vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtPath(Box::new(self.clone()))))]
+ }
}
- // FIXME (Issue #16472): This should go away after ToToken impls
- // are revised to go directly to token-trees.
- trait ToSourceWithHygiene : ToSource {
- // Takes a thing and generates a string containing rust code
- // for it, encoding Idents as special byte sequences to
- // maintain hygiene across serialization and deserialization.
- fn to_source_with_hygiene(&self) -> String;
+ impl ToTokens for ast::Ty {
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+ vec![ast::TtToken(self.span, token::Interpolated(token::NtTy(P(self.clone()))))]
+ }
}
- macro_rules! impl_to_source {
- (P<$t:ty>, $pp:ident) => (
- impl ToSource for P<$t> {
- fn to_source(&self) -> String {
- pprust::$pp(&**self)
- }
- }
- impl ToSourceWithHygiene for P<$t> {
- fn to_source_with_hygiene(&self) -> String {
- pprust::with_hygiene::$pp(&**self)
- }
- }
- );
- ($t:ty, $pp:ident) => (
- impl ToSource for $t {
- fn to_source(&self) -> String {
- pprust::$pp(self)
- }
- }
- impl ToSourceWithHygiene for $t {
- fn to_source_with_hygiene(&self) -> String {
- pprust::with_hygiene::$pp(self)
- }
- }
- );
+ impl ToTokens for ast::Block {
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+ vec![ast::TtToken(self.span, token::Interpolated(token::NtBlock(P(self.clone()))))]
+ }
}
- fn slice_to_source<'a, T: ToSource>(sep: &'static str, xs: &'a [T]) -> String {
- xs.iter()
- .map(|i| i.to_source())
- .collect::<Vec<String>>()
- .connect(sep)
- .to_string()
+ impl ToTokens for P<ast::Item> {
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+ vec![ast::TtToken(self.span, token::Interpolated(token::NtItem(self.clone())))]
+ }
}
- fn slice_to_source_with_hygiene<'a, T: ToSourceWithHygiene>(
- sep: &'static str, xs: &'a [T]) -> String {
- xs.iter()
- .map(|i| i.to_source_with_hygiene())
- .collect::<Vec<String>>()
- .connect(sep)
- .to_string()
+ impl ToTokens for P<ast::ImplItem> {
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+ vec![ast::TtToken(self.span, token::Interpolated(token::NtImplItem(self.clone())))]
+ }
}
- macro_rules! impl_to_source_slice {
- ($t:ty, $sep:expr) => (
- impl ToSource for [$t] {
- fn to_source(&self) -> String {
- slice_to_source($sep, self)
- }
- }
-
- impl ToSourceWithHygiene for [$t] {
- fn to_source_with_hygiene(&self) -> String {
- slice_to_source_with_hygiene($sep, self)
- }
- }
- )
+ impl ToTokens for P<ast::TraitItem> {
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+ vec![ast::TtToken(self.span, token::Interpolated(token::NtTraitItem(self.clone())))]
+ }
}
- impl ToSource for ast::Ident {
- fn to_source(&self) -> String {
- token::get_ident(*self).to_string()
+ impl ToTokens for P<ast::Stmt> {
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+ vec![ast::TtToken(self.span, token::Interpolated(token::NtStmt(self.clone())))]
}
}
- impl ToSourceWithHygiene for ast::Ident {
- fn to_source_with_hygiene(&self) -> String {
- self.encode_with_hygiene()
+ impl ToTokens for P<ast::Expr> {
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+ vec![ast::TtToken(self.span, token::Interpolated(token::NtExpr(self.clone())))]
}
}
- impl_to_source! { ast::Path, path_to_string }
- impl_to_source! { ast::Ty, ty_to_string }
- impl_to_source! { ast::Block, block_to_string }
- impl_to_source! { ast::Arg, arg_to_string }
- impl_to_source! { Generics, generics_to_string }
- impl_to_source! { ast::WhereClause, where_clause_to_string }
- impl_to_source! { P<ast::Item>, item_to_string }
- impl_to_source! { P<ast::ImplItem>, impl_item_to_string }
- impl_to_source! { P<ast::TraitItem>, trait_item_to_string }
- impl_to_source! { P<ast::Stmt>, stmt_to_string }
- impl_to_source! { P<ast::Expr>, expr_to_string }
- impl_to_source! { P<ast::Pat>, pat_to_string }
- impl_to_source! { ast::Arm, arm_to_string }
- impl_to_source_slice! { ast::Ty, ", " }
- impl_to_source_slice! { P<ast::Item>, "\n\n" }
-
- impl ToSource for ast::Attribute_ {
- fn to_source(&self) -> String {
- pprust::attribute_to_string(&dummy_spanned(self.clone()))
+ impl ToTokens for P<ast::Pat> {
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+ vec![ast::TtToken(self.span, token::Interpolated(token::NtPat(self.clone())))]
}
}
- impl ToSourceWithHygiene for ast::Attribute_ {
- fn to_source_with_hygiene(&self) -> String {
- self.to_source()
+
+ impl ToTokens for ast::Arm {
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+ vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtArm(self.clone())))]
}
}
- impl ToSource for str {
- fn to_source(&self) -> String {
- let lit = dummy_spanned(ast::LitStr(
- token::intern_and_get_ident(self), ast::CookedStr));
- pprust::lit_to_string(&lit)
- }
+ macro_rules! impl_to_tokens_slice {
+ ($t: ty, $sep: expr) => {
+ impl ToTokens for [$t] {
+ fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+ let mut v = vec![];
+ for (i, x) in self.iter().enumerate() {
+ if i > 0 {
+ v.push_all(&$sep);
+ }
+ v.extend(x.to_tokens(cx));
+ }
+ v
+ }
+ }
+ };
}
- impl ToSourceWithHygiene for str {
- fn to_source_with_hygiene(&self) -> String {
- self.to_source()
+
+ impl_to_tokens_slice! { ast::Ty, [ast::TtToken(DUMMY_SP, token::Comma)] }
+ impl_to_tokens_slice! { P<ast::Item>, [] }
+
+ impl ToTokens for P<ast::MetaItem> {
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+ vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtMeta(self.clone())))]
}
}
- impl ToSource for () {
- fn to_source(&self) -> String {
- "()".to_string()
+ impl ToTokens for ast::Attribute {
+ fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+ let mut r = vec![];
+ // FIXME: The spans could be better
+ r.push(ast::TtToken(self.span, token::Pound));
+ if self.node.style == ast::AttrInner {
+ r.push(ast::TtToken(self.span, token::Not));
+ }
+ r.push(ast::TtDelimited(self.span, Rc::new(ast::Delimited {
+ delim: token::Bracket,
+ open_span: self.span,
+ tts: self.node.value.to_tokens(cx),
+ close_span: self.span,
+ })));
+ r
}
}
- impl ToSourceWithHygiene for () {
- fn to_source_with_hygiene(&self) -> String {
- self.to_source()
+
+ impl ToTokens for str {
+ fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+ let lit = ast::LitStr(
+ token::intern_and_get_ident(self), ast::CookedStr);
+ dummy_spanned(lit).to_tokens(cx)
}
}
- impl ToSource for bool {
- fn to_source(&self) -> String {
- let lit = dummy_spanned(ast::LitBool(*self));
- pprust::lit_to_string(&lit)
+ impl ToTokens for () {
+ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+ vec![ast::TtDelimited(DUMMY_SP, Rc::new(ast::Delimited {
+ delim: token::Paren,
+ open_span: DUMMY_SP,
+ tts: vec![],
+ close_span: DUMMY_SP,
+ }))]
}
}
- impl ToSourceWithHygiene for bool {
- fn to_source_with_hygiene(&self) -> String {
- self.to_source()
+
+ impl ToTokens for ast::Lit {
+ fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+ // FIXME: This is wrong
+ P(ast::Expr {
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ExprLit(P(self.clone())),
+ span: DUMMY_SP,
+ }).to_tokens(cx)
}
}
- impl ToSource for char {
- fn to_source(&self) -> String {
- let lit = dummy_spanned(ast::LitChar(*self));
- pprust::lit_to_string(&lit)
+ impl ToTokens for bool {
+ fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+ dummy_spanned(ast::LitBool(*self)).to_tokens(cx)
}
}
- impl ToSourceWithHygiene for char {
- fn to_source_with_hygiene(&self) -> String {
- self.to_source()
+
+ impl ToTokens for char {
+ fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+ dummy_spanned(ast::LitChar(*self)).to_tokens(cx)
}
}
- macro_rules! impl_to_source_int {
+ macro_rules! impl_to_tokens_int {
(signed, $t:ty, $tag:expr) => (
- impl ToSource for $t {
- fn to_source(&self) -> String {
+ impl ToTokens for $t {
+ fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
let lit = ast::LitInt(*self as u64, ast::SignedIntLit($tag,
ast::Sign::new(*self)));
- pprust::lit_to_string(&dummy_spanned(lit))
- }
- }
- impl ToSourceWithHygiene for $t {
- fn to_source_with_hygiene(&self) -> String {
- self.to_source()
+ dummy_spanned(lit).to_tokens(cx)
}
}
);
(unsigned, $t:ty, $tag:expr) => (
- impl ToSource for $t {
- fn to_source(&self) -> String {
+ impl ToTokens for $t {
+ fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
- pprust::lit_to_string(&dummy_spanned(lit))
- }
- }
- impl ToSourceWithHygiene for $t {
- fn to_source_with_hygiene(&self) -> String {
- self.to_source()
+ dummy_spanned(lit).to_tokens(cx)
}
}
);
}
- impl_to_source_int! { signed, isize, ast::TyIs }
- impl_to_source_int! { signed, i8, ast::TyI8 }
- impl_to_source_int! { signed, i16, ast::TyI16 }
- impl_to_source_int! { signed, i32, ast::TyI32 }
- impl_to_source_int! { signed, i64, ast::TyI64 }
-
- impl_to_source_int! { unsigned, usize, ast::TyUs }
- impl_to_source_int! { unsigned, u8, ast::TyU8 }
- impl_to_source_int! { unsigned, u16, ast::TyU16 }
- impl_to_source_int! { unsigned, u32, ast::TyU32 }
- impl_to_source_int! { unsigned, u64, ast::TyU64 }
-
- // Alas ... we write these out instead. All redundant.
-
- macro_rules! impl_to_tokens {
- ($t:ty) => (
- impl ToTokens for $t {
- fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
- }
- }
- )
- }
+ impl_to_tokens_int! { signed, isize, ast::TyIs }
+ impl_to_tokens_int! { signed, i8, ast::TyI8 }
+ impl_to_tokens_int! { signed, i16, ast::TyI16 }
+ impl_to_tokens_int! { signed, i32, ast::TyI32 }
+ impl_to_tokens_int! { signed, i64, ast::TyI64 }
- macro_rules! impl_to_tokens_lifetime {
- ($t:ty) => (
- impl<'a> ToTokens for $t {
- fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
- }
- }
- )
- }
-
- impl_to_tokens! { ast::Ident }
- impl_to_tokens! { ast::Path }
- impl_to_tokens! { P<ast::Item> }
- impl_to_tokens! { P<ast::ImplItem> }
- impl_to_tokens! { P<ast::TraitItem> }
- impl_to_tokens! { P<ast::Pat> }
- impl_to_tokens! { ast::Arm }
- impl_to_tokens_lifetime! { &'a [P<ast::Item>] }
- impl_to_tokens! { ast::Ty }
- impl_to_tokens_lifetime! { &'a [ast::Ty] }
- impl_to_tokens! { Generics }
- impl_to_tokens! { ast::WhereClause }
- impl_to_tokens! { P<ast::Stmt> }
- impl_to_tokens! { P<ast::Expr> }
- impl_to_tokens! { ast::Block }
- impl_to_tokens! { ast::Arg }
- impl_to_tokens! { ast::Attribute_ }
- impl_to_tokens_lifetime! { &'a str }
- impl_to_tokens! { () }
- impl_to_tokens! { char }
- impl_to_tokens! { bool }
- impl_to_tokens! { isize }
- impl_to_tokens! { i8 }
- impl_to_tokens! { i16 }
- impl_to_tokens! { i32 }
- impl_to_tokens! { i64 }
- impl_to_tokens! { usize }
- impl_to_tokens! { u8 }
- impl_to_tokens! { u16 }
- impl_to_tokens! { u32 }
- impl_to_tokens! { u64 }
+ impl_to_tokens_int! { unsigned, usize, ast::TyUs }
+ impl_to_tokens_int! { unsigned, u8, ast::TyU8 }
+ impl_to_tokens_int! { unsigned, u16, ast::TyU16 }
+ impl_to_tokens_int! { unsigned, u32, ast::TyU32 }
+ impl_to_tokens_int! { unsigned, u64, ast::TyU64 }
pub trait ExtParseUtils {
fn parse_item(&self, s: String) -> P<ast::Item>;
fn parse_tts(&self, s: String) -> Vec<ast::TokenTree>;
}
- trait ExtParseUtilsWithHygiene {
- // FIXME (Issue #16472): This should go away after ToToken impls
- // are revised to go directly to token-trees.
- fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree>;
- }
-
impl<'a> ExtParseUtils for ExtCtxt<'a> {
fn parse_item(&self, s: String) -> P<ast::Item> {
self.parse_sess())
}
}
-
- impl<'a> ExtParseUtilsWithHygiene for ExtCtxt<'a> {
-
- fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree> {
- use parse::with_hygiene::parse_tts_from_source_str;
- parse_tts_from_source_str("<quote expansion>".to_string(),
- s,
- self.cfg(),
- self.parse_sess())
- }
-
- }
-
}
pub fn expand_quote_tokens<'cx>(cx: &'cx mut ExtCtxt,
// 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)
are reserved for internal compiler diagnostics");
} else if name.starts_with("derive_") {
self.gate_feature("custom_derive", attr.span,
- "attributes of the form `#[derive_*]` are reserved
+ "attributes of the form `#[derive_*]` are reserved \
for the compiler");
} else {
self.gate_feature("custom_attribute", attr.span,
pattern.span,
"multiple-element slice matches anywhere \
but at the end of a slice (e.g. \
- `[0, ..xs, 0]` are experimental")
+ `[0, ..xs, 0]`) are experimental")
}
ast::PatVec(..) => {
self.gate_feature("slice_patterns",
}
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,
token::NtMeta(meta_item) => token::NtMeta(fld.fold_meta_item(meta_item)),
token::NtPath(path) => token::NtPath(Box::new(fld.fold_path(*path))),
token::NtTT(tt) => token::NtTT(P(fld.fold_tt(&*tt))),
+ token::NtArm(arm) => token::NtArm(fld.fold_arm(arm)),
+ token::NtImplItem(arm) =>
+ token::NtImplItem(fld.fold_impl_item(arm)
+ .expect_one("expected fold to produce exactly one item")),
+ token::NtTraitItem(arm) =>
+ token::NtTraitItem(fld.fold_trait_item(arm)
+ .expect_one("expected fold to produce exactly one item")),
}
}
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| {
}
#[cfg(test)]
-mod test {
+mod tests {
use std::io;
use ast;
use util::parser_testing::{string_to_crate, matches_codepattern};
}
#[cfg(test)]
-mod test {
+mod tests {
use super::*;
#[test] fn test_block_doc_comment_1() {
use std::borrow::Cow;
use std::char;
-use std::fmt;
use std::mem::replace;
use std::rc::Rc;
pub peek_tok: token::Token,
pub peek_span: Span,
- // FIXME (Issue #16472): This field should go away after ToToken impls
- // are revised to go directly to token-trees.
- /// Is \x00<name>,<ctxt>\x00 is interpreted as encoded ast::Ident?
- read_embedded_ident: bool,
-
// cache a direct reference to the source text, so that we don't have to
// retrieve it via `self.filemap.src.as_ref().unwrap()` all the time.
source_text: Rc<String>
}
}
-// FIXME (Issue #16472): This function should go away after
-// ToToken impls are revised to go directly to token-trees.
-pub fn make_reader_with_embedded_idents<'b>(span_diagnostic: &'b SpanHandler,
- filemap: Rc<codemap::FileMap>)
- -> StringReader<'b> {
- let mut sr = StringReader::new_raw(span_diagnostic, filemap);
- sr.read_embedded_ident = true;
- sr.advance_token();
- sr
-}
-
impl<'a> StringReader<'a> {
/// For comments.rs, which hackily pokes into pos and curr
pub fn new_raw<'b>(span_diagnostic: &'b SpanHandler,
/* dummy values; not read */
peek_tok: token::Eof,
peek_span: codemap::DUMMY_SP,
- read_embedded_ident: false,
source_text: source_text
};
sr.bump();
})
}
- // FIXME (Issue #16472): The scan_embedded_hygienic_ident function
- // should go away after we revise the syntax::ext::quote::ToToken
- // impls to go directly to token-trees instead of thing -> string
- // -> token-trees. (The function is currently used to resolve
- // Issues #15750 and #15962.)
- //
- // Since this function is only used for certain internal macros,
- // and the functionality it provides is not exposed to end user
- // programs, pnkfelix deliberately chose to write it in a way that
- // favors rustc debugging effectiveness over runtime efficiency.
-
- /// Scan through input of form \x00name_NNNNNN,ctxt_CCCCCCC\x00
- /// whence: `NNNNNN` is a string of characters forming an integer
- /// (the name) and `CCCCCCC` is a string of characters forming an
- /// integer (the ctxt), separate by a comma and delimited by a
- /// `\x00` marker.
- #[inline(never)]
- fn scan_embedded_hygienic_ident(&mut self) -> ast::Ident {
- fn bump_expecting_char<'a,D:fmt::Debug>(r: &mut StringReader<'a>,
- c: char,
- described_c: D,
- whence: &str) {
- match r.curr {
- Some(r_c) if r_c == c => r.bump(),
- Some(r_c) => panic!("expected {:?}, hit {:?}, {}", described_c, r_c, whence),
- None => panic!("expected {:?}, hit EOF, {}", described_c, whence),
- }
- }
-
- let whence = "while scanning embedded hygienic ident";
-
- // skip over the leading `\x00`
- bump_expecting_char(self, '\x00', "nul-byte", whence);
-
- // skip over the "name_"
- for c in "name_".chars() {
- bump_expecting_char(self, c, c, whence);
- }
-
- let start_bpos = self.last_pos;
- let base = 10;
-
- // find the integer representing the name
- self.scan_digits(base, base);
- let encoded_name : u32 = self.with_str_from(start_bpos, |s| {
- u32::from_str_radix(s, 10).unwrap_or_else(|_| {
- panic!("expected digits representing a name, got {:?}, {}, range [{:?},{:?}]",
- s, whence, start_bpos, self.last_pos);
- })
- });
-
- // skip over the `,`
- bump_expecting_char(self, ',', "comma", whence);
-
- // skip over the "ctxt_"
- for c in "ctxt_".chars() {
- bump_expecting_char(self, c, c, whence);
- }
-
- // find the integer representing the ctxt
- let start_bpos = self.last_pos;
- self.scan_digits(base, base);
- let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| {
- u32::from_str_radix(s, 10).unwrap_or_else(|_| {
- panic!("expected digits representing a ctxt, got {:?}, {}", s, whence);
- })
- });
-
- // skip over the `\x00`
- bump_expecting_char(self, '\x00', "nul-byte", whence);
-
- ast::Ident { name: ast::Name(encoded_name),
- ctxt: encoded_ctxt, }
- }
-
/// Scan through any digits (base `scan_radix`) or underscores,
/// and return how many digits there were.
///
return token::Literal(num, suffix)
}
- if self.read_embedded_ident {
- match (c.unwrap(), self.nextch(), self.nextnextch()) {
- ('\x00', Some('n'), Some('a')) => {
- let ast_ident = self.scan_embedded_hygienic_ident();
- return if self.curr_is(':') && self.nextch_is(':') {
- token::Ident(ast_ident, token::ModName)
- } else {
- token::Ident(ast_ident, token::Plain)
- };
- }
- _ => {}
- }
- }
-
match c.expect("next_token_inner called at EOF") {
// One-byte tokens.
';' => { self.bump(); return token::Semi; }
}
#[cfg(test)]
-mod test {
+mod tests {
use super::*;
use codemap::{BytePos, CodeMap, Span, NO_EXPANSION};
maybe_aborted(p.parse_stmt(), p)
}
-// Note: keep in sync with `with_hygiene::parse_tts_from_source_str`
-// until #16472 is resolved.
-//
// Warning: This parses with quote_depth > 0, which is not the default.
pub fn parse_tts_from_source_str(name: String,
source: String,
maybe_aborted(panictry!(p.parse_all_token_trees()),p)
}
-// Note: keep in sync with `with_hygiene::new_parser_from_source_str`
-// until #16472 is resolved.
// Create a new parser from a source string
pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess,
cfg: ast::CrateConfig,
p
}
-// Note: keep this in sync with `with_hygiene::filemap_to_parser` until
-// #16472 is resolved.
/// Given a filemap and config, return a parser
pub fn filemap_to_parser<'a>(sess: &'a ParseSess,
filemap: Rc<FileMap>,
sess.span_diagnostic.cm.new_filemap(path, source)
}
-// Note: keep this in sync with `with_hygiene::filemap_to_tts` (apart
-// from the StringReader constructor), until #16472 is resolved.
/// Given a filemap, produce a sequence of token-trees
pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
-> Vec<ast::TokenTree> {
p
}
-// FIXME (Issue #16472): The `with_hygiene` mod should go away after
-// ToToken impls are revised to go directly to token-trees.
-pub mod with_hygiene {
- use ast;
- use codemap::FileMap;
- use parse::parser::Parser;
- use std::rc::Rc;
- use super::ParseSess;
- use super::{maybe_aborted, string_to_filemap, tts_to_parser};
-
- // Note: keep this in sync with `super::parse_tts_from_source_str` until
- // #16472 is resolved.
- //
- // Warning: This parses with quote_depth > 0, which is not the default.
- pub fn parse_tts_from_source_str(name: String,
- source: String,
- cfg: ast::CrateConfig,
- sess: &ParseSess) -> Vec<ast::TokenTree> {
- let mut p = new_parser_from_source_str(
- sess,
- cfg,
- name,
- source
- );
- p.quote_depth += 1;
- // right now this is re-creating the token trees from ... token trees.
- maybe_aborted(panictry!(p.parse_all_token_trees()),p)
- }
-
- // Note: keep this in sync with `super::new_parser_from_source_str` until
- // #16472 is resolved.
- // Create a new parser from a source string
- fn new_parser_from_source_str<'a>(sess: &'a ParseSess,
- cfg: ast::CrateConfig,
- name: String,
- source: String) -> Parser<'a> {
- filemap_to_parser(sess, string_to_filemap(sess, source, name), cfg)
- }
-
- // Note: keep this in sync with `super::filemap_to_parserr` until
- // #16472 is resolved.
- /// Given a filemap and config, return a parser
- fn filemap_to_parser<'a>(sess: &'a ParseSess,
- filemap: Rc<FileMap>,
- cfg: ast::CrateConfig) -> Parser<'a> {
- tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg)
- }
-
- // Note: keep this in sync with `super::filemap_to_tts` until
- // #16472 is resolved.
- /// Given a filemap, produce a sequence of token-trees
- fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
- -> Vec<ast::TokenTree> {
- // it appears to me that the cfg doesn't matter here... indeed,
- // parsing tt's probably shouldn't require a parser at all.
- use super::lexer::make_reader_with_embedded_idents as make_reader;
- let cfg = Vec::new();
- let srdr = make_reader(&sess.span_diagnostic, filemap);
- let mut p1 = Parser::new(sess, cfg, Box::new(srdr));
- panictry!(p1.parse_all_token_trees())
- }
-}
-
/// Abort if necessary
pub fn maybe_aborted<T>(result: T, p: Parser) -> T {
p.abort_if_errors();
}
#[cfg(test)]
-mod test {
+mod tests {
use super::*;
use std::rc::Rc;
use codemap::{Span, BytePos, Pos, Spanned, NO_EXPANSION};
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 {
pub fn bump(&mut self) -> PResult<()> {
self.last_span = self.span;
// Stash token for error recovery (sometimes; clone is not necessarily cheap).
- self.last_token = if self.token.is_ident() || self.token.is_path() {
+ self.last_token = if self.token.is_ident() ||
+ self.token.is_path() ||
+ self.token == token::Comma {
Some(Box::new(self.token.clone()))
} else {
None
&token::OpenDelim(token::Brace),
&token::CloseDelim(token::Brace),
seq_sep_none(),
- |p| {
+ |p| -> PResult<P<TraitItem>> {
+ maybe_whole!(no_clone p, NtTraitItem);
let mut attrs = p.parse_outer_attributes();
let lo = p.span.lo;
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) ){
}
pub fn parse_arm_nopanic(&mut self) -> PResult<Arm> {
+ maybe_whole!(no_clone self, NtArm);
+
let attrs = self.parse_outer_attributes();
let pats = try!(self.parse_pats());
let mut guard = None;
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![]));
fn parse_generic_values_after_lt(&mut self) -> PResult<(Vec<ast::Lifetime>,
Vec<P<Ty>>,
Vec<P<TypeBinding>>)> {
+ let span_lo = self.span.lo;
let lifetimes = try!(self.parse_lifetimes(token::Comma));
+ let missing_comma = !lifetimes.is_empty() &&
+ !self.token.is_like_gt() &&
+ self.last_token
+ .as_ref().map_or(true,
+ |x| &**x != &token::Comma);
+
+ if missing_comma {
+
+ let msg = format!("expected `,` or `>` after lifetime \
+ name, found `{}`",
+ self.this_token_to_string());
+ self.span_err(self.span, &msg);
+
+ let span_hi = self.span.hi;
+ let span_hi = if self.parse_ty_nopanic().is_ok() {
+ self.span.hi
+ } else {
+ span_hi
+ };
+
+ let msg = format!("did you mean a single argument type &'a Type, \
+ or did you mean the comma-separated arguments \
+ 'a, Type?");
+ self.span_note(mk_sp(span_lo, span_hi), &msg);
+
+ self.abort_if_errors()
+ }
+
// First parse types.
let (types, returned) = try!(self.parse_seq_to_gt_or_return(
Some(token::Comma),
/// Parse an impl item.
pub fn parse_impl_item(&mut self) -> PResult<P<ImplItem>> {
+ maybe_whole!(no_clone self, NtImplItem);
+
let mut attrs = self.parse_outer_attributes();
let lo = self.span.lo;
let vis = try!(self.parse_visibility());
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());
}
impl Token {
+ /// Returns `true` if the token starts with '>'.
+ pub fn is_like_gt(&self) -> bool {
+ match *self {
+ BinOp(Shr) | BinOpEq(Shr) | Gt | Ge => true,
+ _ => false,
+ }
+ }
+
/// Returns `true` if the token can appear at the start of an expression.
pub fn can_begin_expr(&self) -> bool {
match *self {
NtMeta(P<ast::MetaItem>),
NtPath(Box<ast::Path>),
NtTT(P<ast::TokenTree>), // needs P'ed to break a circularity
+ // These is not exposed to macros, but is used by quasiquote.
+ NtArm(ast::Arm),
+ NtImplItem(P<ast::ImplItem>),
+ NtTraitItem(P<ast::TraitItem>),
}
impl fmt::Debug for Nonterminal {
NtMeta(..) => f.pad("NtMeta(..)"),
NtPath(..) => f.pad("NtPath(..)"),
NtTT(..) => f.pad("NtTT(..)"),
+ NtArm(..) => f.pad("NtArm(..)"),
+ NtImplItem(..) => f.pad("NtImplItem(..)"),
+ NtTraitItem(..) => f.pad("NtTraitItem(..)"),
}
}
}
}
#[cfg(test)]
-mod test {
+mod tests {
use super::*;
use ast;
use ext::mtwt;
cur_cmnt_and_lit: CurrentCommentAndLiteral,
boxes: Vec<pp::Breaks>,
ann: &'a (PpAnn+'a),
- encode_idents_with_hygiene: bool,
}
pub fn rust_printer<'a>(writer: Box<Write+'a>) -> State<'a> {
},
boxes: Vec::new(),
ann: ann,
- encode_idents_with_hygiene: false,
}
}
},
boxes: Vec::new(),
ann: ann,
- encode_idents_with_hygiene: false,
}
}
}
token::SpecialVarNt(var) => format!("${}", var.as_str()),
token::Interpolated(ref nt) => match *nt {
- token::NtExpr(ref e) => expr_to_string(&**e),
- token::NtMeta(ref e) => meta_item_to_string(&**e),
- token::NtTy(ref e) => ty_to_string(&**e),
- token::NtPath(ref e) => path_to_string(&**e),
- token::NtItem(..) => "an interpolated item".to_string(),
- token::NtBlock(..) => "an interpolated block".to_string(),
- token::NtStmt(..) => "an interpolated statement".to_string(),
- token::NtPat(..) => "an interpolated pattern".to_string(),
- token::NtIdent(..) => "an interpolated identifier".to_string(),
- token::NtTT(..) => "an interpolated tt".to_string(),
+ token::NtExpr(ref e) => expr_to_string(&**e),
+ token::NtMeta(ref e) => meta_item_to_string(&**e),
+ token::NtTy(ref e) => ty_to_string(&**e),
+ token::NtPath(ref e) => path_to_string(&**e),
+ token::NtItem(..) => "an interpolated item".to_string(),
+ token::NtBlock(..) => "an interpolated block".to_string(),
+ token::NtStmt(..) => "an interpolated statement".to_string(),
+ token::NtPat(..) => "an interpolated pattern".to_string(),
+ token::NtIdent(..) => "an interpolated identifier".to_string(),
+ token::NtTT(..) => "an interpolated tt".to_string(),
+ token::NtArm(..) => "an interpolated arm".to_string(),
+ token::NtImplItem(..) => "an interpolated impl item".to_string(),
+ token::NtTraitItem(..) => "an interpolated trait item".to_string(),
}
}
}
-// FIXME (Issue #16472): the thing_to_string_impls macro should go away
-// after we revise the syntax::ext::quote::ToToken impls to go directly
-// to token-trees instead of thing -> string -> token-trees.
-
-macro_rules! thing_to_string_impls {
- ($to_string:ident) => {
-
pub fn ty_to_string(ty: &ast::Ty) -> String {
- $to_string(|s| s.print_type(ty))
+ to_string(|s| s.print_type(ty))
}
pub fn bounds_to_string(bounds: &[ast::TyParamBound]) -> String {
- $to_string(|s| s.print_bounds("", bounds))
+ to_string(|s| s.print_bounds("", bounds))
}
pub fn pat_to_string(pat: &ast::Pat) -> String {
- $to_string(|s| s.print_pat(pat))
+ to_string(|s| s.print_pat(pat))
}
pub fn arm_to_string(arm: &ast::Arm) -> String {
- $to_string(|s| s.print_arm(arm))
+ to_string(|s| s.print_arm(arm))
}
pub fn expr_to_string(e: &ast::Expr) -> String {
- $to_string(|s| s.print_expr(e))
+ to_string(|s| s.print_expr(e))
}
pub fn lifetime_to_string(e: &ast::Lifetime) -> String {
- $to_string(|s| s.print_lifetime(e))
+ to_string(|s| s.print_lifetime(e))
}
pub fn tt_to_string(tt: &ast::TokenTree) -> String {
- $to_string(|s| s.print_tt(tt))
+ to_string(|s| s.print_tt(tt))
}
pub fn tts_to_string(tts: &[ast::TokenTree]) -> String {
- $to_string(|s| s.print_tts(tts))
+ to_string(|s| s.print_tts(tts))
}
pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
- $to_string(|s| s.print_stmt(stmt))
+ to_string(|s| s.print_stmt(stmt))
}
pub fn attr_to_string(attr: &ast::Attribute) -> String {
- $to_string(|s| s.print_attribute(attr))
+ to_string(|s| s.print_attribute(attr))
}
pub fn item_to_string(i: &ast::Item) -> String {
- $to_string(|s| s.print_item(i))
+ to_string(|s| s.print_item(i))
}
pub fn impl_item_to_string(i: &ast::ImplItem) -> String {
- $to_string(|s| s.print_impl_item(i))
+ to_string(|s| s.print_impl_item(i))
}
pub fn trait_item_to_string(i: &ast::TraitItem) -> String {
- $to_string(|s| s.print_trait_item(i))
+ to_string(|s| s.print_trait_item(i))
}
pub fn generics_to_string(generics: &ast::Generics) -> String {
- $to_string(|s| s.print_generics(generics))
+ to_string(|s| s.print_generics(generics))
}
pub fn where_clause_to_string(i: &ast::WhereClause) -> String {
- $to_string(|s| s.print_where_clause(i))
+ to_string(|s| s.print_where_clause(i))
}
pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
- $to_string(|s| s.print_fn_block_args(p))
+ to_string(|s| s.print_fn_block_args(p))
}
pub fn path_to_string(p: &ast::Path) -> String {
- $to_string(|s| s.print_path(p, false, 0))
+ to_string(|s| s.print_path(p, false, 0))
}
pub fn ident_to_string(id: &ast::Ident) -> String {
- $to_string(|s| s.print_ident(*id))
+ to_string(|s| s.print_ident(*id))
}
pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, name: ast::Ident,
opt_explicit_self: Option<&ast::ExplicitSelf_>,
generics: &ast::Generics) -> String {
- $to_string(|s| {
+ to_string(|s| {
try!(s.head(""));
try!(s.print_fn(decl, unsafety, abi::Rust, Some(name),
generics, opt_explicit_self, ast::Inherited));
}
pub fn block_to_string(blk: &ast::Block) -> String {
- $to_string(|s| {
+ to_string(|s| {
// containing cbox, will be closed by print-block at }
try!(s.cbox(indent_unit));
// head-ibox, will be closed by print-block after {
}
pub fn meta_item_to_string(mi: &ast::MetaItem) -> String {
- $to_string(|s| s.print_meta_item(mi))
+ to_string(|s| s.print_meta_item(mi))
}
pub fn attribute_to_string(attr: &ast::Attribute) -> String {
- $to_string(|s| s.print_attribute(attr))
+ to_string(|s| s.print_attribute(attr))
}
pub fn lit_to_string(l: &ast::Lit) -> String {
- $to_string(|s| s.print_literal(l))
+ to_string(|s| s.print_literal(l))
}
pub fn explicit_self_to_string(explicit_self: &ast::ExplicitSelf_) -> String {
- $to_string(|s| s.print_explicit_self(explicit_self, ast::MutImmutable).map(|_| {}))
+ to_string(|s| s.print_explicit_self(explicit_self, ast::MutImmutable).map(|_| {}))
}
pub fn variant_to_string(var: &ast::Variant) -> String {
- $to_string(|s| s.print_variant(var))
+ to_string(|s| s.print_variant(var))
}
pub fn arg_to_string(arg: &ast::Arg) -> String {
- $to_string(|s| s.print_arg(arg))
+ to_string(|s| s.print_arg(arg))
}
pub fn mac_to_string(arg: &ast::Mac) -> String {
- $to_string(|s| s.print_mac(arg, ::parse::token::Paren))
-}
-
-} }
-
-thing_to_string_impls! { to_string }
-
-// FIXME (Issue #16472): the whole `with_hygiene` mod should go away
-// after we revise the syntax::ext::quote::ToToken impls to go directly
-// to token-trees instea of thing -> string -> token-trees.
-
-pub mod with_hygiene {
- use abi;
- use ast;
- use std::io;
- use super::indent_unit;
-
- // This function is the trick that all the rest of the routines
- // hang on.
- pub fn to_string_hyg<F>(f: F) -> String where
- F: FnOnce(&mut super::State) -> io::Result<()>,
- {
- super::to_string(move |s| {
- s.encode_idents_with_hygiene = true;
- f(s)
- })
- }
-
- thing_to_string_impls! { to_string_hyg }
+ to_string(|s| s.print_mac(arg, ::parse::token::Paren))
}
pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> String {
}
}
+ 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));
}
pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> {
- if self.encode_idents_with_hygiene {
- let encoded = ident.encode_with_hygiene();
- try!(word(&mut self.s, &encoded[..]))
- } else {
- try!(word(&mut self.s, &token::get_ident(ident)))
- }
+ try!(word(&mut self.s, &token::get_ident(ident)));
self.ann.post(self, NodeIdent(&ident))
}
}
}
}
+ 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());
fn repeat(s: &str, n: usize) -> String { iter::repeat(s).take(n).collect() }
#[cfg(test)]
-mod test {
+mod tests {
use super::*;
use ast;
}
#[cfg(test)]
-mod test {
+mod tests {
use super::*;
#[test] fn eqmodws() {
}
#[cfg(test)]
-mod test {
+mod tests {
use super::*;
#[test]
}
}
}
+ 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);
}
#[cfg(test)]
-mod test {
+mod tests {
use super::{expand,Param,Words,Variables,Number};
use std::result::Result::Ok;
}
#[cfg(test)]
-mod test {
+mod tests {
use super::{boolnames, boolfnames, numnames, numfnames, stringnames, stringfnames};
}
for (var i = 0; i < toc.length; i++) {
- if (toc[i].attributes['href'].value === href) {
+ if (toc[i].attributes['href'].value.split('/').pop() === href) {
var nav = document.createElement('p');
if (i > 0) {
var prevNode = toc[i-1].cloneNode(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.
+
+#![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;
+}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_macro("make_a_1", expand_make_a_1);
- reg.register_macro("forged_ident", expand_forged_ident);
reg.register_macro("identity", expand_identity);
reg.register_syntax_extension(
token::intern("into_foo"),
}
}
-fn expand_forged_ident(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult+'static> {
- use syntax::ext::quote::rt::*;
-
- if !tts.is_empty() {
- cx.span_fatal(sp, "forged_ident takes no arguments");
- }
-
- // Most of this is modelled after the expansion of the `quote_expr!`
- // macro ...
- let parse_sess = cx.parse_sess();
- let cfg = cx.cfg();
-
- // ... except this is where we inject a forged identifier,
- // and deliberately do not call `cx.parse_tts_with_hygiene`
- // (because we are testing that this will be *rejected*
- // by the default parser).
-
- let expr = {
- let tt = cx.parse_tts("\x00name_2,ctxt_0\x00".to_string());
- let mut parser = new_parser_from_tts(parse_sess, cfg, tt);
- parser.parse_expr()
- };
- MacEager::expr(expr)
-}
-
pub fn foo() {}
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 {
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;
+++ /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.
-
-// aux-build:macro_crate_test.rs
-// ignore-stage1
-// error-pattern: unknown start of token: \u{0}
-
-// Issue #15750 and #15962 : this test is checking that the standard
-// parser rejects embedded idents. pnkfelix did not want to attempt
-// to make a test file that itself used the embedded ident input form,
-// since he worried that would be difficult to work with in many text
-// editors, so instead he made a macro that expands into the embedded
-// ident form.
-
-#![feature(plugin)]
-#![plugin(macro_crate_test)]
-
-fn main() {
- let x = 0;
- assert_eq!(3, forged_ident!());
-}
--- /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
+
+#![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, 2 - $abcd + 7); //~ ERROR unresolved name `abcd`
+ assert_eq!(pprust::expr_to_string(&*expr), "2 - $abcd + 7");
+}
--- /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() {}
--- /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 negating unsigned integers is gated by `negate_unsigned` feature
+// gate
+
+const MAX: usize = -1;
+//~^ ERROR unary negation of unsigned integers may be removed in the future
+
+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.
+
+// Test that `#[rustc_on_unimplemented]` is gated by `on_unimplemented` feature
+// gate.
+
+#[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
+//~^ ERROR the `#[rustc_on_unimplemented]` attribute is an experimental feature
+trait Foo<Bar>
+{}
+
+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.
+
+// Test that default and negative trait implementations are gated by
+// `optin_builtin_traits` feature gate
+
+struct DummyStruct;
+
+trait DummyTrait {
+ fn dummy(&self) {}
+}
+
+impl DummyTrait for .. {}
+//~^ ERROR default trait implementations are experimental and possibly buggy
+
+impl !DummyTrait for DummyStruct {}
+//~^ ERROR negative trait bounds are not yet fully implemented; use marker types for now
+
+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.
+
+// Test that `#![plugin(...)]` attribute is gated by `plugin` feature gate
+
+#![plugin(foo)]
+//~^ ERROR compiler plugins are experimental and possibly buggy
+
+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.
+
+// ignore-tidy-linelength
+
+// Test that `#[rustc_*]` attributes are gated by `rustc_attrs` feature gate.
+
+#[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is an experimental feature
+#[rustc_error] //~ ERROR the `#[rustc_error]` attribute is an experimental feature
+#[rustc_move_fragments] //~ ERROR the `#[rustc_move_fragments]` attribute is an experimental feature
+#[rustc_foo]
+//~^ ERROR unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics
+
+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.
+
+// Test that diagnostic macros are gated by `rustc_diagnostic_macros` feature
+// gate
+
+__register_diagnostic!(E0001);
+//~^ ERROR macro undefined: '__register_diagnostic!'
+
+fn main() {
+ __diagnostic_used!(E0001);
+ //~^ ERROR macro undefined: '__diagnostic_used!'
+}
+
+__build_diagnostic_array!(DIAGNOSTICS);
+//~^ ERROR macro undefined: '__build_diagnostic_array!'
--- /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 slice pattern syntax is gated by `slice_patterns` feature gate
+
+fn main() {
+ let x = [1, 2, 3, 4, 5];
+ match x {
+ [1, 2, xs..] => {} //~ ERROR slice pattern syntax is experimental
+ }
+}
--- /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 patterns including the box syntax are gated by `box_patterns` feature gate.
-
-fn main() {
- let x = Box::new(1);
-
- match x {
- box 1 => (),
- //~^ box pattern syntax is experimental
- _ => ()
- };
-}
+++ /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 the use of smid types in the ffi is gated by `smid_ffi` feature gate.
-
-#![feature(simd)]
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-#[simd]
-pub struct f32x4(f32, f32, f32, f32);
-
-#[allow(dead_code)]
-extern {
- fn foo(x: f32x4);
- //~^ ERROR use of SIMD type `f32x4` in FFI is highly experimental and may result in invalid code
- //~| HELP add #![feature(simd_ffi)] to the crate attributes to enable
-}
-
-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.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+type Type_1<'a T> = &'a T; //~ error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /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.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+type Type_2 = Type_1_<'static ()>; //~ error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /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.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+type Type_3<T> = Box<T,,>; //~ error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /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.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+type Type_4<T> = Type_1_<'static,, T>; //~ error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /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.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+type Type_5<'a> = Type_1_<'a, (),,>; //~ error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /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.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+type Type_6 = Type_5_<'a,,>; //~ error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /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.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+type Type_7 = Box<(),,>; //~ error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /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.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+type Type_8<'a,,> = &'a (); //~ error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /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.
+
+// We need all these 9 issue-20616-N.rs files
+// becase we can only catch one parsing error at a time
+
+
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+type Type_9<T,,> = Box<T>; //~ error: expected ident, found `,`
--- /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.
+
+trait Expr : PartialEq<Self::Item> {
+ //~^ ERROR: unsupported cyclic reference between types/traits detected
+ type Item = Expr;
+}
+
+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.
+
+fn main() { }
+
+// Before these errors would ICE as "cat_expr Errd" because the errors
+// were unknown when the bug was triggered.
+
+fn unconstrained_type() {
+ [];
+ //~^ ERROR cannot determine a type for this expression: unconstrained type
+}
--- /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::any::Any;
+fn main()
+{
+ fn bar(x:i32) ->i32 { 3*x };
+ let b:Box<Any> = Box::new(bar as fn(_)->_);
+ b.downcast_ref::<fn(_)->_>();
+ //~^ ERROR cannot determine a type for this expression: unconstrained type
+}
--- /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.
+
+enum Foo { Bar }
+
+fn main() {
+ Foo::Bar.a;
+ //~^ ERROR: attempted access of field `a` on type `Foo`, but no field with that name was found
+}
--- /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 main() {
+ "".chars().fold(|_, _| (), ());
+ //~^ ERROR cannot determine a type for this expression: unconstrained type
+}
--- /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 main() {
+ use std::mem::{transmute, swap};
+ let a = 1;
+ let b = 2;
+ unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
+ //~^ ERROR cannot determine a type for this expression: unconstrained type
+}
--- /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
+ }
+}
--- /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.
+
+// Regression test for issue #22779. An extra where clause was
+// permitted on the impl that is not present on the trait.
+
+trait Tr<'a, T> {
+ fn renew<'b: 'a>(self) -> &'b mut [T];
+}
+
+impl<'a, T> Tr<'a, T> for &'a mut [T] {
+ fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
+ //~^ ERROR lifetime bound not satisfied
+ &mut self[..]
+ }
+}
+
+fn main() { }
--- /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.
+
+// Test related to #22779. In this case, the impl is an inherent impl,
+// so it doesn't have to match any trait, so no error results.
+
+#![feature(rustc_attrs)]
+#![allow(dead_code)]
+
+struct MySlice<'a, T:'a>(&'a mut [T]);
+
+impl<'a, T> MySlice<'a, T> {
+ fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
+ &mut self.0[..]
+ }
+}
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
--- /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.
+
+// Test related to #22779, but where the `'a:'b` relation
+// appears in the trait too. No error here.
+
+#![feature(rustc_attrs)]
+
+trait Tr<'a, T> {
+ fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b;
+}
+
+impl<'a, T> Tr<'a, T> for &'a mut [T] {
+ fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b {
+ &mut self[..]
+ }
+}
+
+#[rustc_error]
+fn main() { } //~ ERROR compilation successful
fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
}
- fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {}
+ fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
+ //~^ ERROR lifetime bound not satisfied
+ }
}
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.
+
+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
+ _ => (),
+ }
+}
+++ /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.
-
-// compile-flags: -Z parse-only
-
-// ignore-test Can't use syntax crate here
-
-#![feature(quote)]
-
-extern crate syntax;
-
-use io::*;
-
-use syntax::diagnostic;
-use syntax::ast;
-use syntax::codemap;
-use syntax::parse;
-use syntax::print::*;
-
-
-trait fake_ext_ctxt {
- fn cfg() -> ast::CrateConfig;
- fn parse_sess() -> parse::parse_sess;
- fn call_site() -> span;
- fn ident_of(st: &str) -> ast::ident;
-}
-
-type fake_session = parse::parse_sess;
-
-impl fake_ext_ctxt for fake_session {
- fn cfg() -> ast::CrateConfig { Vec::new() }
- fn parse_sess() -> parse::parse_sess { self }
- fn call_site() -> span {
- codemap::span {
- lo: codemap::BytePos(0),
- hi: codemap::BytePos(0),
- expn_id: NO_EXPANSION
- }
- }
- fn ident_of(st: &str) -> ast::ident {
- self.interner.intern(st)
- }
-}
-
-fn mk_ctxt() -> fake_ext_ctxt {
- parse::new_parse_sess(None) as fake_ext_ctxt
-}
-
-
-
-fn main() {
- let cx = mk_ctxt();
-
- let abc = quote_expr!(cx, 23);
- check_pp(abc, pprust::print_expr, "23");
-
- let expr3 = quote_expr!(cx, 2 - $abcd + 7); //~ ERROR unresolved name: abcd
- check_pp(expr3, pprust::print_expr, "2 - 23 + 7");
-}
-
-fn check_pp<T>(expr: T, f: |pprust::ps, T|, expect: str) {
- panic!();
-}
+++ /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.
-
-// compile-flags: -Z parse-only
-
-// ignore-test Can't use syntax crate here
-
-#![feature(quote)]
-
-extern crate syntax;
-
-use syntax::diagnostic;
-use syntax::ast;
-use syntax::codemap;
-use syntax::parse::parser;
-use syntax::print::*;
-
-trait fake_ext_ctxt {
- fn cfg() -> ast::CrateConfig;
- fn parse_sess() -> parse::parse_sess;
- fn call_site() -> span;
- fn ident_of(st: &str) -> ast::ident;
-}
-
-type fake_session = parse::parse_sess;
-
-impl fake_ext_ctxt for fake_session {
- fn cfg() -> ast::CrateConfig { Vec::new() }
- fn parse_sess() -> parse::parse_sess { self }
- fn call_site() -> span {
- codemap::span {
- lo: codemap::BytePos(0),
- hi: codemap::BytePos(0),
- expn_id: codemap::NO_EXPANSION
- }
- }
- fn ident_of(st: &str) -> ast::ident {
- self.interner.intern(st)
- }
-}
-
-fn mk_ctxt() -> fake_ext_ctxt {
- parse::new_parse_sess(None) as fake_ext_ctxt
-}
-
-
-fn main() {
- let cx = mk_ctxt();
-
- let stmt = quote_stmt!(cx, let x isize = 20;); //~ ERROR expected end-of-string
- check_pp(*stmt, pprust::print_stmt, "");
-}
-
-fn check_pp<T>(expr: T, f: |pprust::ps, T|, expect: str) {
- panic!();
-}
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
--include ../tools.mk
-
-# Issue #15750, #15962 : This test ensures that our special embedded
-# ident syntax hack is not treated as legitimate input by the lexer in
-# normal mode.
-#
-# It is modelled after the `unicode-input/` test, since we need to
-# create files with syntax that can trip up normal text editting tools
-# (namely text with embedded nul-bytes).
-
-# This test attempts to run rustc itself from the compiled binary; but
-# that means that you need to set the LD_LIBRARY_PATH for rustc itself
-# while running create_and_compile, and that won't work for stage1.
-
-# FIXME ignore windows
-ifndef IS_WINDOWS
-ifeq ($(RUST_BUILD_STAGE),1)
-DOTEST=
-else
-DOTEST=dotest
-endif
-endif
-
-all: $(DOTEST)
-
-dotest:
- $(RUSTC) create_and_compile.rs
- $(call RUN,create_and_compile) "$(RUSTC)" "$(TMPDIR)"
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::env;
-use std::fs::File;
-use std::process::Command;
-use std::io::Write;
-use std::path::Path;
-
-// creates broken.rs, which has the Ident \x00name_0,ctxt_0\x00
-// embedded within it, and then attempts to compile broken.rs with the
-// provided `rustc`
-
-fn main() {
- let args: Vec<String> = env::args().collect();
- let rustc = &args[1];
- let tmpdir = Path::new(&args[2]);
-
- let main_file = tmpdir.join("broken.rs");
- let _ = File::create(&main_file).unwrap()
- .write_all(b"pub fn main() {
- let \x00name_0,ctxt_0\x00 = 3;
- println!(\"{}\", \x00name_0,ctxt_0\x00);
- }").unwrap();
-
- // rustc is passed to us with --out-dir and -L etc., so we
- // can't exec it directly
- let result = Command::new("sh")
- .arg("-c")
- .arg(&format!("{} {}", rustc, main_file.display()))
- .output().unwrap();
- let err = String::from_utf8_lossy(&result.stderr);
-
- // positive test so that this test will be updated when the
- // compiler changes.
- assert!(err.contains("unknown start of token"))
-}
// 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.
// except according to those terms.
// ignore-cross-compile
-// ignore-pretty
-// ignore-test
-#![feature(quote)]
+#![feature(quote, rustc_private)]
extern crate syntax;
-use std::io::*;
+use syntax::codemap::DUMMY_SP;
+use syntax::print::pprust::*;
-use syntax::diagnostic;
-use syntax::ast;
-use syntax::codemap;
-use syntax::codemap::span;
-use syntax::parse;
-use syntax::print::*;
-
-
-trait fake_ext_ctxt {
- fn cfg() -> ast::CrateConfig;
- fn parse_sess() -> parse::parse_sess;
- fn call_site() -> span;
- fn ident_of(st: &str) -> ast::ident;
-}
-
-type fake_session = parse::parse_sess;
-
-impl fake_ext_ctxt for fake_session {
- fn cfg() -> ast::CrateConfig { Vec::new() }
- fn parse_sess() -> parse::parse_sess { self }
- fn call_site() -> span {
- codemap::span {
- lo: codemap::BytePos(0),
- hi: codemap::BytePos(0),
- expn_id: codemap::NO_EXPANSION
+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,
}
- }
- fn ident_of(st: &str) -> ast::ident {
- self.interner.intern(st)
- }
-}
-
-fn mk_ctxt() -> fake_ext_ctxt {
- parse::new_parse_sess(None) as fake_ext_ctxt
-}
+ });
+ let cx = &mut cx;
-fn main() {
- let cx = mk_ctxt();
+ macro_rules! check {
+ ($f: ident, $($e: expr),+; $expect: expr) => ({
+ $(assert_eq!($f(&$e), $expect);)+
+ });
+ }
let abc = quote_expr!(cx, 23);
- check_pp(ext_cx, abc, pprust::print_expr, "23".to_string());
-
+ check!(expr_to_string, abc, *quote_expr!(cx, $abc); "23");
let ty = quote_ty!(cx, isize);
- check_pp(ext_cx, ty, pprust::print_type, "isize".to_string());
+ check!(ty_to_string, ty, *quote_ty!(cx, $ty); "isize");
- let item = quote_item!(cx, static x : isize = 10;).get();
- check_pp(ext_cx, item, pprust::print_item, "static x: isize = 10;".to_string());
+ let item = quote_item!(cx, static x: $ty = 10;).unwrap();
+ check!(item_to_string, item, quote_item!(cx, $item).unwrap(); "static x: isize = 10;");
- let stmt = quote_stmt!(cx, let x = 20;);
- check_pp(ext_cx, *stmt, pprust::print_stmt, "let x = 20;".to_string());
+ let twenty: u16 = 20;
+ let stmt = quote_stmt!(cx, let x = $twenty;).unwrap();
+ check!(stmt_to_string, stmt, *quote_stmt!(cx, $stmt).unwrap(); "let x = 20u16;");
let pat = quote_pat!(cx, Some(_));
- check_pp(ext_cx, pat, pprust::print_pat, "Some(_)".to_string());
+ check!(pat_to_string, pat, *quote_pat!(cx, $pat); "Some(_)");
- let arm = quote_arm!(cx, (ref x, ref y) => (x, y));
- check_pp(ext_cx, arm, pprust::print_stmt, "(ref x, ref y) = (x, y)".to_string());
+ let expr = quote_expr!(cx, (x, y));
+ let arm = quote_arm!(cx, (ref x, ref y) => $expr,);
+ check!(arm_to_string, arm, quote_arm!(cx, $arm); " (ref x, ref y) => (x, y),");
let attr = quote_attr!(cx, #![cfg(foo = "bar")]);
- check_pp(ext_cx, attr, pprust::print_attribute, "#![cfg(foo = "bar")]".to_string());
-}
-
-fn check_pp<T>(cx: fake_ext_ctxt,
- expr: T, f: |pprust::ps, T|, expect: String) {
- let s = io::with_str_writer(|wr| {
- let pp = pprust::rust_printer(wr, cx.parse_sess().interner);
- f(pp, expr);
- pp::eof(pp.s);
- });
- stdout().write_line(s);
- if expect != "".to_string() {
- println!("expect: '%s', got: '%s'", expect, s);
- assert_eq!(s, expect);
- }
+ check!(attribute_to_string, attr, quote_attr!(cx, $attr); r#"#![cfg(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.
+
+// 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);
+}
// aux-build:issue-12133-rlib.rs
// aux-build:issue-12133-dylib.rs
// aux-build:issue-12133-dylib2.rs
+// ignore-musl
// pretty-expanded FIXME #23616
// compile-flags:--test
// ignore-pretty turns out the pretty-printer doesn't handle gensym'd things...
-mod test {
+mod tests {
use super::*;
#[test]
--- /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.
+
+type MyType<'a, T> = &'a T;
+
+// combine lifetime bounds and type arguments in usual way
+type TypeA<'a> = MyType<'a, ()>;
+
+// ensure token `>>` works fine
+type TypeB = Box<TypeA<'static>>;
+type TypeB_ = Box<TypeA<'static,>>;
+
+// trailing comma when combine lifetime bounds and type arguments
+type TypeC<'a> = MyType<'a, (),>;
+
+// normal lifetime bounds
+type TypeD = TypeA<'static>;
+
+// trailing comma on lifetime bounds
+type TypeE = TypeA<'static,>;
+
+// normal type arugment
+type TypeF<T> = Box<T>;
+
+// type argument with trailing comma
+type TypeG<T> = Box<T,>;
+
+// trailing comma on liftime defs
+type TypeH<'a,> = &'a ();
+
+// trailing comma on type argument
+type TypeI<T,> = T;
+
+static STATIC: () = ();
+
+fn main() {
+
+ // ensure token `>=` works fine
+ let _: TypeA<'static>= &STATIC;
+ let _: TypeA<'static,>= &STATIC;
+
+ // ensure token `>>=` works fine
+ let _: Box<TypeA<'static>>= Box::new(&STATIC);
+ let _: Box<TypeA<'static,>>= Box::new(&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.
+
+// Don't fail if we encounter a NonZero<*T> where T is an unsized type
+
+#![feature(unique)]
+
+use std::ptr::Unique;
+
+fn main() {
+ let mut a = [0u8; 5];
+ let b: Option<Unique<[u8]>> = unsafe { Some(Unique::new(&mut a)) };
+ match b {
+ Some(_) => println!("Got `Some`"),
+ None => panic!("Unexpected `None`"),
+ }
+}
--- /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();
+ }
+}
+
// aux-build:linkage-visibility.rs
// ignore-android: FIXME(#10379)
// 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.
-//ignore-android
-//ignore-freebsd
-//ignore-ios
-//ignore-dragonfly
-//ignore-bitrig
+// ignore-android
+// ignore-freebsd
+// ignore-ios
+// ignore-dragonfly
+// ignore-bitrig
+// ignore-musl
#![feature(asm)]
// 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(..));
}