Longer version:
The Rust Project is copyright 2016, The Rust Project
-Developers (given in the file AUTHORS.txt).
+Developers.
Licensed under the Apache License, Version 2.0
<LICENSE-APACHE or
# The test suite
ifneq ($(strip $(findstring check,$(MAKECMDGOALS)) \
$(findstring test,$(MAKECMDGOALS)) \
- $(findstring perf,$(MAKECMDGOALS)) \
$(findstring tidy,$(MAKECMDGOALS))),)
CFG_INFO := $(info cfg: including test rules)
include $(CFG_SRC_DIR)mk/tests.mk
include $(CFG_SRC_DIR)mk/grammar.mk
endif
-# Performance and benchmarking
-ifneq ($(findstring perf,$(MAKECMDGOALS)),)
- CFG_INFO := $(info cfg: including perf rules)
- include $(CFG_SRC_DIR)mk/perf.mk
-endif
-
# Copy all the distributables to another directory for binary install
ifneq ($(strip $(findstring prepare,$(MAKECMDGOALS)) \
$(findstring dist,$(MAKECMDGOALS)) \
CFG_CONFIGURE_ARGS="$@"
-case "${CFG_SRC_DIR}" in
+case "${CFG_SRC_DIR}" in
*\ * )
err "The path to the rust source directory contains spaces, which is not supported"
;;
CFG_DISABLE_JEMALLOC=1
fi
+if [ $CFG_OSTYPE = pc-windows-gnu ]
+then
+ # FIXME(#31030) - there's not a great reason to disable jemalloc here
+ step_msg "on Windows, disabling jemalloc"
+ CFG_DISABLE_JEMALLOC=1
+fi
+
# OS X 10.9, gcc is actually clang. This can cause some confusion in the build
# system, so if we find that gcc is clang, we should just use clang directly.
if [ $CFG_OSTYPE = apple-darwin -a -z "$CFG_ENABLE_CLANG" ]
do
for t in $CFG_TARGET
do
+ # host bin dir stage0
+ make_dir $h/stage0/bin
+
# host lib dir stage0
make_dir $h/stage0/lib
+ # host test dir stage0
+ make_dir $h/stage0/test
+
# target bin dir stage0
make_dir $h/stage0/lib/rustlib/$t/bin
# target lib dir stage0
make_dir $h/stage0/lib/rustlib/$t/lib
- for i in 0 1 2 3
+ for i in 1 2 3
do
# host bin dir
make_dir $h/stage$i/bin
DEPS_rustc_lint := rustc log syntax
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
DEPS_rustc_metadata := rustc rustc_front syntax rbml
-DEPS_rustc_passes := syntax rustc core
+DEPS_rustc_passes := syntax rustc core rustc_front
DEPS_rustc_mir := rustc rustc_front syntax
DEPS_rustc_resolve := arena rustc rustc_front log syntax
DEPS_rustc_platform_intrinsics := rustc rustc_llvm
######################################################################
# The version number
-CFG_RELEASE_NUM=1.7.0
+CFG_RELEASE_NUM=1.8.0
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
# NB Make sure it starts with a dot to conform to semver pre-release
$$(CFG_RUSTC_FLAGS) $$(EXTRAFLAGS_STAGE$(1)) --target=$(2)) \
$$(RUSTC_FLAGS_$(2))
-PERF_STAGE$(1)_T_$(2)_H_$(3) := \
- $$(Q)$$(call CFG_RUN_TARG_$(3),$(1), \
- $$(CFG_PERF_TOOL) \
- $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
- --cfg $$(CFGFLAG$(1)_T_$(2)_H_$(3)) \
- $$(CFG_RUSTC_FLAGS) $$(EXTRAFLAGS_STAGE$(1)) --target=$(2)) \
- $$(RUSTC_FLAGS_$(2))
-
endef
$(foreach build,$(CFG_HOST), \
+++ /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.
-
-
-ifdef CFG_PERF_TOOL
-rustc-perf$(X): $(CFG_BUILD)/stage2/bin/rustc$(X_$(CFG_BUILD))
- @$(call E, perf compile: $@)
- $(PERF_STAGE2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) \
- -o $@ $(COMPILER_CRATE) >rustc-perf.err 2>&1
- $(Q)rm -f $(LIBRUSTC_GLOB)
-else
-rustc-perf$(X): $(CFG_BUILD)/stage2/bin/rustc$(X_$(CFG_BUILD))
- $(Q)touch $@
-endif
-
-perf: check-stage2-perf rustc-perf$(X_$(CFG_BUILD))
- $(Q)find $(CFG_BUILD)/test/perf -name \*.err | xargs cat
- $(Q)cat rustc-perf.err
endef
$(foreach t,$(CFG_TARGET),$(eval $(call DEF_GOOD_VALGRIND,$(t))))
-ifneq ($(findstring linux,$(CFG_OSTYPE)),)
- ifdef CFG_PERF
- ifneq ($(CFG_PERF_WITH_LOGFD),)
- CFG_PERF_TOOL := $(CFG_PERF) stat -r 3 --log-fd 2
- else
- CFG_PERF_TOOL := $(CFG_PERF) stat -r 3
- endif
- else
- ifdef CFG_VALGRIND
- CFG_PERF_TOOL := \
- $(CFG_VALGRIND) --tool=cachegrind --cache-sim=yes --branch-sim=yes
- else
- CFG_PERF_TOOL := /usr/bin/time --verbose
- endif
- endif
-endif
-
AR := ar
define SET_FROM_CFG
CTEST_RUNTOOL = --runtool "$(CFG_VALGRIND)"
endif
-# Arguments to the perf tests
-ifdef CFG_PERF_TOOL
- CTEST_PERF_RUNTOOL = --runtool "$(CFG_PERF_TOOL)"
-endif
-
CTEST_TESTARGS := $(TESTARGS)
# --bench is only relevant for crate tests, not for the compile tests
# This prevents tests from failing with some locales (fixes #17423).
export LC_ALL=C
-# If we're running perf then set this environment variable
-# to put the benchmarks into 'hard mode'
-ifeq ($(MAKECMDGOALS),perf)
- export RUST_BENCH=1
-endif
-
TEST_LOG_FILE=tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).log
TEST_OK_FILE=tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).ok
CODEGEN_CC := $(wildcard $(S)src/test/codegen/*.cc)
RUSTDOCCK_RS := $(wildcard $(S)src/test/rustdoc/*.rs)
-# perf tests are the same as bench tests only they run under
-# a performance monitor.
-PERF_RS := $(wildcard $(S)src/test/bench/*.rs)
-
RPASS_TESTS := $(RPASS_RS)
RPASS_VALGRIND_TESTS := $(RPASS_VALGRIND_RS)
RPASS_FULL_TESTS := $(RPASS_FULL_RS)
CFAIL_TESTS := $(CFAIL_RS)
PFAIL_TESTS := $(PFAIL_RS)
BENCH_TESTS := $(BENCH_RS)
-PERF_TESTS := $(PERF_RS)
PRETTY_TESTS := $(PRETTY_RS)
DEBUGINFO_GDB_TESTS := $(DEBUGINFO_GDB_RS)
DEBUGINFO_LLDB_TESTS := $(DEBUGINFO_LLDB_RS)
CTEST_MODE_bench = run-pass
CTEST_RUNTOOL_bench = $(CTEST_RUNTOOL)
-CTEST_SRC_BASE_perf = bench
-CTEST_BUILD_BASE_perf = perf
-CTEST_MODE_perf = run-pass
-CTEST_RUNTOOL_perf = $(CTEST_PERF_RUNTOOL)
-
CTEST_SRC_BASE_debuginfo-gdb = debuginfo
CTEST_BUILD_BASE_debuginfo-gdb = debuginfo-gdb
CTEST_MODE_debuginfo-gdb = debuginfo-gdb
$$(HBIN$(1)_H_$(3))/compiletest$$(X_$(3)) \
$$(SREQ$(1)_T_$(2)_H_$(3))
-# Rules for the cfail/rfail/rpass/bench/perf test runner
+# Rules for the cfail/rfail/rpass/bench test runner
# The tests select when to use debug configuration on their own;
# remove directive, if present, from CFG_RUSTC_FLAGS (issue #7898).
CTEST_DEPS_cfail_$(1)-T-$(2)-H-$(3) = $$(CFAIL_TESTS)
CTEST_DEPS_pfail_$(1)-T-$(2)-H-$(3) = $$(PFAIL_TESTS)
CTEST_DEPS_bench_$(1)-T-$(2)-H-$(3) = $$(BENCH_TESTS)
-CTEST_DEPS_perf_$(1)-T-$(2)-H-$(3) = $$(PERF_TESTS)
CTEST_DEPS_debuginfo-gdb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_GDB_TESTS)
CTEST_DEPS_debuginfo-lldb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_LLDB_TESTS) \
$(S)src/etc/lldb_batchmode.py \
endef
CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \
- bench perf debuginfo-gdb debuginfo-lldb codegen rustdocck
+ bench debuginfo-gdb debuginfo-lldb codegen rustdocck
$(foreach host,$(CFG_HOST), \
$(eval $(foreach target,$(CFG_TARGET), \
cfail \
pfail \
bench \
- perf \
rmake \
rustdocck \
debuginfo-gdb \
into memory. By nature, a slice is not created directly, but from an existing
variable binding. Slices have a defined length, can be mutable or immutable.
+Internally, slices are represented as a pointer to the beginning of the data
+and a length.
+
## Slicing syntax
You can use a combo of `&` and `[]` to create a slice from various things. The
<div id="versioninfo">
- <img src="https://www.rust-lang.org/logos/rust-logo-32x32-blk.png" width="32" height="32" alt><br>
+ <img src="https://www.rust-lang.org/logos/rust-logo-32x32-blk.png" width="32" height="32" alt="Rust logo"><br>
<span class="white-sticker"><a href="https://www.rust-lang.org">Rust</a> VERSION</span><br>
<a href="https://github.com/rust-lang/rust/commit/STAMP"
class="hash white-sticker">SHORT_HASH</a>
+++ /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.
-//
-//
-// This is a helper C program for generating required math constants
-//
-// Should only be required when porting to a different target architecture
-// (or c compiler/libmath)
-//
-// Call with <rust machine type of c_float> <rust machine type of c_double>
-// and ensure that libcore/cmath.rs complies to the output
-//
-// Requires a printf that supports "%a" specifiers
-//
-
-#include <float.h>
-#include <math.h>
-#include <stdio.h>
-
-// must match std::ctypes
-
-#define C_FLT(x) (float)x
-#define C_DBL(x) (double)x
-
-int main(int argc, char** argv) {
- if (argc != 3) {
- fprintf(stderr, "%s <ctypes::c_float> <ctypes::c_double>\n", argv[0]);
- return 1;
- }
- char* c_flt = argv[1];
- char* c_dbl = argv[2];
-
- printf("mod c_float_math_consts {\n");
- printf(" const pi: c_float = %a_%s;\n", C_FLT(M_PI), c_flt);
- printf(" const div_1_pi: c_float = %a_%s;\n", C_FLT(M_1_PI), c_flt);
- printf(" const div_2_pi: c_float = %a_%s;\n", C_FLT(M_2_PI), c_flt);
- printf(" const div_pi_2: c_float = %a_%s;\n", C_FLT(M_PI_2), c_flt);
- printf(" const div_pi_4: c_float = %a_%s;\n", C_FLT(M_PI_4), c_flt);
- printf(" const div_2_sqrtpi: c_float = %a_%s;\n",
- C_FLT(M_2_SQRTPI), c_flt);
- printf(" const e: c_float = %a_%s;\n", C_FLT(M_E), c_flt);
- printf(" const log2_e: c_float = %a_%s;\n", C_FLT(M_LOG2E), c_flt);
- printf(" const log10_e: c_float = %a_%s;\n", C_FLT(M_LOG10E), c_flt);
- printf(" const ln_2: c_float = %a_%s;\n", C_FLT(M_LN2), c_flt);
- printf(" const ln_10: c_float = %a_%s;\n", C_FLT(M_LN10), c_flt);
- printf(" const sqrt2: c_float = %a_%s;\n", C_FLT(M_SQRT2), c_flt);
- printf(" const div_1_sqrt2: c_float = %a_%s;\n",
- C_FLT(M_SQRT1_2), c_flt);
- printf("}\n\n");
-
- printf("mod c_double_math_consts {\n");
- printf(" const pi: c_double = %a_%s;\n", C_DBL(M_PI), c_dbl);
- printf(" const div_1_pi: c_double = %a_%s;\n", C_DBL(M_1_PI), c_dbl);
- printf(" const div_2_pi: c_double = %a_%s;\n", C_DBL(M_2_PI), c_dbl);
- printf(" const div_pi_2: c_double = %a_%s;\n", C_DBL(M_PI_2), c_dbl);
- printf(" const div_pi_4: c_double = %a_%s;\n", C_DBL(M_PI_4), c_dbl);
- printf(" const div_2_sqrtpi: c_double = %a_%s;\n",
- C_DBL(M_2_SQRTPI), c_dbl);
- printf(" const e: c_double = %a_%s;\n", C_DBL(M_E), c_dbl);
- printf(" const log2_e: c_double = %a_%s;\n", C_DBL(M_LOG2E), c_dbl);
- printf(" const log10_e: c_double = %a_%s;\n", C_DBL(M_LOG10E), c_dbl);
- printf(" const ln_2: c_double = %a_%s;\n", C_DBL(M_LN2), c_dbl);
- printf(" const ln_10: c_double = %a_%s;\n", C_DBL(M_LN10), c_dbl);
- printf(" const sqrt2: c_double = %a_%s;\n", C_DBL(M_SQRT2), c_dbl);
- printf(" const div_1_sqrt2: c_double = %a_%s;\n",
- C_DBL(M_SQRT1_2), c_dbl);
- printf("}\n\n");
-
- printf("mod c_float_targ_consts {\n");
- printf(" const radix: uint = %uu;\n", FLT_RADIX);
- printf(" const mantissa_digits: uint = %uu;\n", FLT_MANT_DIG);
- printf(" const digits: uint = %uu;\n", FLT_DIG);
- printf(" const min_exp: int = %i;\n", FLT_MIN_EXP);
- printf(" const max_exp: int = %i;\n", FLT_MAX_EXP);
- printf(" const min_10_exp: int = %i;\n", FLT_MIN_10_EXP);
- printf(" const max_10_exp: int = %i;\n", FLT_MAX_10_EXP);
- printf(" const min_value: c_float = %a_%s;\n", C_FLT(FLT_MIN), c_flt);
- printf(" const max_value: c_float = %a_%s;\n", C_FLT(FLT_MAX), c_flt);
- printf(" const epsilon: c_float = %a_%s;\n", C_FLT(FLT_EPSILON), c_flt);
- printf("}\n\n");
-
- printf("mod c_double_targ_consts {\n");
- printf(" const radix: uint = %uu;\n", FLT_RADIX);
- printf(" const mantissa_digits: uint = %uu;\n", DBL_MANT_DIG);
- printf(" const digits: uint = %uu;\n", DBL_DIG);
- printf(" const min_exp: int = %i;\n", DBL_MIN_EXP);
- printf(" const max_exp: int = %i;\n", DBL_MAX_EXP);
- printf(" const min_10_exp: int = %i;\n", DBL_MIN_10_EXP);
- printf(" const max_10_exp: int = %i;\n", DBL_MAX_10_EXP);
- printf(" const min_value: c_double = %a_%s;\n", C_DBL(DBL_MIN), c_dbl);
- printf(" const max_value: c_double = %a_%s;\n", C_DBL(DBL_MAX), c_dbl);
- printf(" const epsilon: c_double = %a_%s;\n", C_DBL(DBL_EPSILON), c_dbl);
- printf("}\n");
-
- return 0;
-}
+++ /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.
-
-/*
- * This calculates the platform-variable portion of the libc module.
- * Move code in here only as you discover it is platform-variable.
- *
- */
-
- /* c95 */
-#include <stddef.h>
-#include <time.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <wchar.h>
-
-/* c99 */
-#include <inttypes.h>
-
-/* posix */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#define S(T) ((((T)-1)<0) ? 'i' : 'u')
-#define B(T) (((int)sizeof(T)) * CHAR_BIT)
-#define put_type(N,T) \
- printf(" type %s = %c%d;\n", N, S(T), B(T))
-
-#define put_ftype(N,T) \
- printf(" type %s = f%d;\n", N, B(T))
-
-#define CT(T) ((((T)-1)<0) ? "int" : "uint")
-#define CS(T) ((((T)-1)<0) ? "" : "_u")
-#define put_const(N,T) \
- printf(" const %s : %s = %d%s;\n", \
- #N, CT(T), N, CS(T))
-
-void c95_types() {
- printf(" mod c95 {\n");
-
- put_type("c_char", char);
- put_type("c_schar", signed char);
- put_type("c_uchar", unsigned char);
-
- put_type("c_short", short);
- put_type("c_ushort", unsigned short);
-
- put_type("c_int", int);
- put_type("c_uint", unsigned int);
-
- put_type("c_long", long);
- put_type("c_ulong", unsigned long);
-
- put_ftype("c_float", float);
- put_ftype("c_double", double);
-
- put_type("size_t", size_t);
- put_type("ptrdiff_t", ptrdiff_t);
-
- put_type("clock_t", clock_t);
- put_type("time_t", time_t);
-
- put_type("wchar_t", wchar_t);
-
- printf(" }\n");
-}
-
-void c99_types() {
- printf(" mod c99 {\n");
-
- put_type("c_longlong", long long);
- put_type("c_ulonglong", unsigned long long);
-
- put_type("intptr_t", intptr_t);
- put_type("uintptr_t", uintptr_t);
-
- printf(" }\n");
-}
-
-void posix88_types() {
- printf(" mod posix88 {\n");
-
- put_type("off_t", off_t);
- put_type("dev_t", dev_t);
- put_type("ino_t", ino_t);
- put_type("pid_t", pid_t);
-#ifndef __WIN32__
- put_type("uid_t", uid_t);
- put_type("gid_t", gid_t);
-#endif
- put_type("useconds_t", useconds_t);
- put_type("mode_t", mode_t);
-
- put_type("ssize_t", ssize_t);
-
- printf(" }\n");
-}
-
-void extra_types() {
- printf(" mod extra {\n");
- printf(" }\n");
-}
-
-
-void c95_consts() {
- printf(" mod c95 {\n");
-
- put_const(EXIT_FAILURE, int);
- put_const(EXIT_SUCCESS, int);
- put_const(RAND_MAX, int);
-
- put_const(EOF, int);
- put_const(SEEK_SET, int);
- put_const(SEEK_CUR, int);
- put_const(SEEK_END, int);
-
- put_const(_IOFBF, int);
- put_const(_IONBF, int);
- put_const(_IOLBF, int);
-
- put_const(BUFSIZ, size_t);
- put_const(FOPEN_MAX, size_t);
- put_const(FILENAME_MAX, size_t);
- put_const(L_tmpnam, size_t);
- put_const(TMP_MAX, size_t);
-
- printf(" }\n");
-}
-
-
-void posix88_consts() {
- printf(" mod posix88 {\n");
- put_const(O_RDONLY, int);
- put_const(O_WRONLY, int);
- put_const(O_RDWR, int);
- put_const(O_APPEND, int);
- put_const(O_CREAT, int);
- put_const(O_EXCL, int);
- put_const(O_TRUNC, int);
-
- put_const(S_IFIFO, int);
- put_const(S_IFCHR, int);
- put_const(S_IFBLK, int);
- put_const(S_IFDIR, int);
- put_const(S_IFREG, int);
- put_const(S_IFLNK, int);
- put_const(S_IFMT, int);
-
- put_const(S_IEXEC, int);
- put_const(S_IWRITE, int);
- put_const(S_IREAD, int);
-
- put_const(S_IRWXU, int);
- put_const(S_IXUSR, int);
- put_const(S_IWUSR, int);
- put_const(S_IRUSR, int);
-
- put_const(S_IRWXG, int);
- put_const(S_IXGRP, int);
- put_const(S_IWGRP, int);
- put_const(S_IRGRP, int);
-
- put_const(S_IRWXO, int);
- put_const(S_IXOTH, int);
- put_const(S_IWOTH, int);
- put_const(S_IROTH, int);
-
-#ifdef F_OK
- put_const(F_OK, int);
-#endif
-#ifdef R_OK
- put_const(R_OK, int);
-#endif
-#ifdef W_OK
- put_const(W_OK, int);
-#endif
-#ifdef X_OK
- put_const(X_OK, int);
-#endif
-
-#ifdef STDIN_FILENO
- put_const(STDIN_FILENO, int);
-#endif
-#ifdef STDOUT_FILENO
- put_const(STDOUT_FILENO, int);
-#endif
-#ifdef STDERR_FILENO
- put_const(STDERR_FILENO, int);
-#endif
-
-#ifdef F_LOCK
- put_const(F_LOCK, int);
-#endif
-
-#ifdef F_TEST
- put_const(F_TEST, int);
-#endif
-
-#ifdef F_TLOCK
- put_const(F_TLOCK, int);
-#endif
-
-#ifdef F_ULOCK
- put_const(F_ULOCK, int);
-#endif
-
- printf(" }\n");
-}
-
-void extra_consts() {
- printf(" mod extra {\n");
-#ifdef O_RSYNC
- put_const(O_RSYNC, int);
-#endif
-
-#ifdef O_DSYNC
- put_const(O_DSYNC, int);
-#endif
-
-#ifdef O_SYNC
- put_const(O_SYNC, int);
-#endif
-
-#ifdef O_TEXT
- put_const(O_TEXT, int);
-#endif
-
-#ifdef O_BINARY
- put_const(O_BINARY, int);
-#endif
-
-#ifdef O_IRUSR
- put_const(O_IRUSR, int);
-#endif
-
-#ifdef O_IWUSR
- put_const(O_IWUSR, int);
-#endif
-
- printf(" }\n");
-}
-
-int main() {
- printf("mod types {");
- c95_types();
- c99_types();
- posix88_types();
- extra_types();
- printf("}\n");
-
- printf("mod consts {\n");
- c95_consts();
- posix88_consts();
- extra_consts();
- printf("}\n");
-}
+++ /dev/null
-The purpose of these headers is to fix issues with mingw v4.0, as described in #9246.
-
-This works by adding this directory to GCC include search path before mingw system headers directories,
-so we can intercept their inclusions and add missing definitions without having to modify files in mingw/include.
-
-Once mingw fixes all 3 issues mentioned in #9246, this directory and all references to it from rust/mk/* may be removed.
+++ /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.
-
-#ifndef _FIX_CXXCONFIG_H
-#define _FIX_CXXCONFIG_H 1
-
-#define _GLIBCXX_HAVE_FENV_H 1
-
-#include_next <bits/c++config.h>
-
-#endif
+++ /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.
-
-#ifndef _FIX_WINBASE_H
-#define _FIX_WINBASE_H 1
-
-#define NTDDK_VERSION NTDDI_VERSION
-
-#include_next <winbase.h>
-
-#endif
+++ /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.
-
-#ifndef _FIX_WINSOCK2_H
-#define _FIX_WINSOCK2_H 1
-
-#include_next <winsock2.h>
-
-// mingw 4.0.x has broken headers (#9246) but mingw-w64 does not.
-#if defined(__MINGW_MAJOR_VERSION) && __MINGW_MAJOR_VERSION == 4
-
-typedef struct pollfd {
- SOCKET fd;
- short events;
- short revents;
-} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
-
-#endif
-
-#endif // _FIX_WINSOCK2_H
+++ /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.
-
-import sys
-
-input_file = sys.argv[1]
-output_file = sys.argv[2]
-name = sys.argv[3]
-
-with open(input_file, 'r') as f:
- with open(output_file, 'w') as g:
- print >> g, 'LIBRARY ' + name
- print >> g, 'EXPORTS'
- for x in f:
- x = str(x)
- if not x.startswith(' pub fn LLVM'): continue
- name = x[11:x.find('(')]
- print >> g, ' ' + name
-Subproject commit f84e30927284b0c500ed3eaf09e8e159da20ddaf
+Subproject commit e24a1a025a1f214e40eedafe3b9c7b1d69937922
_ptr: Shared<ArcInner<T>>,
}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "arc_weak", since = "1.4.0")]
unsafe impl<T: ?Sized + Sync + Send> Send for Weak<T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "arc_weak", since = "1.4.0")]
unsafe impl<T: ?Sized + Sync + Send> Sync for Weak<T> {}
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "arc_weak", since = "1.4.0")]
impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(Weak)")
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "arc_weak", since = "1.4.0")]
impl<T: ?Sized> Drop for Weak<T> {
/// Drops the `Weak<T>`.
///
_ptr: Shared<RcBox<T>>,
}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "rc_weak", since = "1.4.0")]
impl<T: ?Sized> !marker::Send for Weak<T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "rc_weak", since = "1.4.0")]
impl<T: ?Sized> !marker::Sync for Weak<T> {}
#[unstable(feature = "coerce_unsized", issue = "27732")]
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "rc_weak", since = "1.4.0")]
impl<T: ?Sized> Drop for Weak<T> {
/// Drops the `Weak<T>`.
///
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "rc_weak", since = "1.4.0")]
impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(Weak)")
}
}
+#[stable(feature = "str_parse_error2", since = "1.8.0")]
+impl fmt::Display for ParseError {
+ fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
+ match *self {}
+ }
+}
+
#[stable(feature = "str_parse_error", since = "1.5.0")]
impl PartialEq for ParseError {
fn eq(&self, _: &ParseError) -> bool {
use self::Ordering::*;
-use mem;
use marker::Sized;
use option::Option::{self, Some};
}
impl Ordering {
- unsafe fn from_i8_unchecked(v: i8) -> Ordering {
- mem::transmute(v)
- }
-
/// Reverse the `Ordering`.
///
/// * `Less` becomes `Greater`.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn reverse(self) -> Ordering {
- unsafe {
- // this compiles really nicely (to a single instruction);
- // an explicit match has a pile of branches and
- // comparisons.
- //
- // NB. it is safe because of the explicit discriminants
- // given above.
- Ordering::from_i8_unchecked(-(self as i8))
+ match self {
+ Less => Greater,
+ Equal => Equal,
+ Greater => Less,
}
}
}
pub fn expect(self, msg: &str) -> T {
match self {
Some(val) => val,
- None => panic!("{}", msg),
+ None => expect_failed(msg),
}
}
}
}
+// This is a separate function to reduce the code size of .expect() itself.
+#[inline(never)]
+#[cold]
+fn expect_failed(msg: &str) -> ! {
+ panic!("{}", msg)
+}
+
+
/////////////////////////////////////////////////////////////////////////////
// Trait implementations
/////////////////////////////////////////////////////////////////////////////
pub fn unwrap(self) -> T {
match self {
Ok(t) => t,
- Err(e) =>
- panic!("called `Result::unwrap()` on an `Err` value: {:?}", e)
+ Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", e),
}
}
pub fn expect(self, msg: &str) -> T {
match self {
Ok(t) => t,
- Err(e) => panic!("{}: {:?}", msg, e),
+ Err(e) => unwrap_failed(msg, e),
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn unwrap_err(self) -> E {
match self {
- Ok(t) =>
- panic!("called `Result::unwrap_err()` on an `Ok` value: {:?}", t),
- Err(e) => e
+ Ok(t) => unwrap_failed("called `Result::unwrap_err()` on an `Ok` value", t),
+ Err(e) => e,
}
}
}
+// This is a separate function to reduce the code size of the methods
+#[inline(never)]
+#[cold]
+fn unwrap_failed<E: fmt::Debug>(msg: &str, error: E) -> ! {
+ panic!("{}: {:?}", msg, error)
+}
+
/////////////////////////////////////////////////////////////////////////////
// Trait implementations
/////////////////////////////////////////////////////////////////////////////
fn binary_search_by<F>(&self, mut f: F) -> Result<usize, usize> where
F: FnMut(&T) -> Ordering
{
- let mut base : usize = 0;
- let mut lim : usize = self.len();
+ let mut base = 0usize;
+ let mut s = self;
- while lim != 0 {
- let ix = base + (lim >> 1);
- match f(&self[ix]) {
- Equal => return Ok(ix),
+ loop {
+ let (head, tail) = s.split_at(s.len() >> 1);
+ if tail.is_empty() {
+ return Err(base)
+ }
+ match f(&tail[0]) {
Less => {
- base = ix + 1;
- lim -= 1;
+ base += head.len() + 1;
+ s = &tail[1..];
}
- Greater => ()
+ Greater => s = head,
+ Equal => return Ok(base + head.len()),
}
- lim >>= 1;
}
- Err(base)
}
#[inline]
Ok(unsafe { from_utf8_unchecked(v) })
}
+/// Forms a str from a pointer and a length.
+///
+/// The `len` argument is the number of bytes in the string.
+///
+/// # Safety
+///
+/// This function is unsafe as there is no guarantee that the given pointer is
+/// valid for `len` bytes, nor whether the lifetime inferred is a suitable
+/// lifetime for the returned str.
+///
+/// The data must be valid UTF-8
+///
+/// `p` must be non-null, even for zero-length str.
+///
+/// # Caveat
+///
+/// The lifetime for the returned str is inferred from its usage. To
+/// prevent accidental misuse, it's suggested to tie the lifetime to whichever
+/// source lifetime is safe in the context, such as by providing a helper
+/// function taking the lifetime of a host value for the str, or by explicit
+/// annotation.
+/// Performs the same functionality as `from_raw_parts`, except that a mutable
+/// str is returned.
+///
+unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str {
+ mem::transmute::<&mut [u8], &mut str>(slice::from_raw_parts_mut(p, len))
+}
+
/// Converts a slice of bytes to a string slice without checking
/// that the string contains valid UTF-8.
///
// is_char_boundary checks that the index is in [0, .len()]
if self.is_char_boundary(mid) {
let len = self.len();
+ let ptr = self.as_ptr() as *mut u8;
unsafe {
- let self2: &mut str = mem::transmute_copy(&self);
- (self.slice_mut_unchecked(0, mid),
- self2.slice_mut_unchecked(mid, len))
+ (from_raw_parts_mut(ptr, mid),
+ from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
}
} else {
slice_error_fail(self, 0, mid)
use core::result::Result::{Ok, Err};
#[test]
-fn binary_search_not_found() {
+fn test_binary_search() {
let b = [1, 2, 4, 6, 8, 9];
assert!(b.binary_search_by(|v| v.cmp(&6)) == Ok(3));
- let b = [1, 2, 4, 6, 8, 9];
assert!(b.binary_search_by(|v| v.cmp(&5)) == Err(3));
let b = [1, 2, 4, 6, 7, 8, 9];
assert!(b.binary_search_by(|v| v.cmp(&6)) == Ok(3));
- let b = [1, 2, 4, 6, 7, 8, 9];
assert!(b.binary_search_by(|v| v.cmp(&5)) == Err(3));
let b = [1, 2, 4, 6, 8, 9];
assert!(b.binary_search_by(|v| v.cmp(&8)) == Ok(4));
- let b = [1, 2, 4, 6, 8, 9];
assert!(b.binary_search_by(|v| v.cmp(&7)) == Err(4));
let b = [1, 2, 4, 6, 7, 8, 9];
assert!(b.binary_search_by(|v| v.cmp(&8)) == Ok(5));
let b = [1, 2, 4, 5, 6, 8, 9];
assert!(b.binary_search_by(|v| v.cmp(&7)) == Err(5));
- let b = [1, 2, 4, 5, 6, 8, 9];
assert!(b.binary_search_by(|v| v.cmp(&0)) == Err(0));
let b = [1, 2, 4, 5, 6, 8];
assert!(b.binary_search_by(|v| v.cmp(&9)) == Err(6));
-Subproject commit 9aa6600bd8f4e4f370a7d2fb76c4b3efc669cadf
+Subproject commit af77843345ec6fc7e51113bfd692138d89024bc0
use self::thread::{DepGraphThreadData, DepMessage};
use middle::def_id::DefId;
use middle::ty;
-use middle::ty::fast_reject::SimplifiedType;
use rustc_front::hir;
use rustc_front::intravisit::Visitor;
use std::rc::Rc;
// which would yield an overly conservative dep-graph.
TraitItems(DefId),
ReprHints(DefId),
- TraitSelect(DefId, Option<SimplifiedType>),
+ TraitSelect(DefId),
}
#[derive(Clone)]
```
"##,
-E0010: r##"
-The value of statics and constants must be known at compile time, and they live
-for the entire lifetime of a program. Creating a boxed value allocates memory on
-the heap at runtime, and therefore cannot be done at compile time. Erroneous
-code example:
-
-```
-#![feature(box_syntax)]
-
-const CON : Box<i32> = box 0;
-```
-"##,
-
-E0011: r##"
-Initializers for constants and statics are evaluated at compile time.
-User-defined operators rely on user-defined functions, which cannot be evaluated
-at compile time.
-
-Bad example:
-
-```
-use std::ops::Index;
-
-struct Foo { a: u8 }
-
-impl Index<u8> for Foo {
- type Output = u8;
-
- fn index<'a>(&'a self, idx: u8) -> &'a u8 { &self.a }
-}
-
-const a: Foo = Foo { a: 0u8 };
-const b: u8 = a[0]; // Index trait is defined by the user, bad!
-```
-
-Only operators on builtin types are allowed.
-
-Example:
-
-```
-const a: &'static [i32] = &[1, 2, 3];
-const b: i32 = a[0]; // Good!
-```
-"##,
-
-E0013: r##"
-Static and const variables can refer to other const variables. But a const
-variable cannot refer to a static variable. For example, `Y` cannot refer to `X`
-here:
-
-```
-static X: i32 = 42;
-const Y: i32 = X;
-```
-
-To fix this, the value can be extracted as a const and then used:
-
-```
-const A: i32 = 42;
-static X: i32 = A;
-const Y: i32 = A;
-```
-"##,
-
-E0014: r##"
-Constants can only be initialized by a constant value or, in a future
-version of Rust, a call to a const function. This error indicates the use
-of a path (like a::b, or x) denoting something other than one of these
-allowed items. Example:
-
-```
-const FOO: i32 = { let x = 0; x }; // 'x' isn't a constant nor a function!
-```
-
-To avoid it, you have to replace the non-constant value:
-
-```
-const FOO: i32 = { const X : i32 = 0; X };
-// or even:
-const FOO: i32 = { 0 }; // but brackets are useless here
-```
-"##,
-
-// FIXME(#24111) Change the language here when const fn stabilizes
-E0015: r##"
-The only functions that can be called in static or constant expressions are
-`const` functions, and struct/enum constructors. `const` functions are only
-available on a nightly compiler. Rust currently does not support more general
-compile-time function execution.
-
-```
-const FOO: Option<u8> = Some(1); // enum constructor
-struct Bar {x: u8}
-const BAR: Bar = Bar {x: 1}; // struct constructor
-```
-
-See [RFC 911] for more details on the design of `const fn`s.
-
-[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
-"##,
-
-E0017: r##"
-References in statics and constants may only refer to immutable values. Example:
-
-```
-static X: i32 = 1;
-const C: i32 = 2;
-
-// these three are not allowed:
-const CR: &'static mut i32 = &mut C;
-static STATIC_REF: &'static mut i32 = &mut X;
-static CONST_REF: &'static mut i32 = &mut C;
-```
-
-Statics are shared everywhere, and if they refer to mutable data one might
-violate memory safety since holding multiple mutable references to shared data
-is not allowed.
-
-If you really want global mutable state, try using `static mut` or a global
-`UnsafeCell`.
-"##,
-
-E0018: r##"
-The value of static and const variables must be known at compile time. You
-can't cast a pointer as an integer because we can't know what value the
-address will take.
-
-However, pointers to other constants' addresses are allowed in constants,
-example:
-
-```
-const X: u32 = 50;
-const Y: *const u32 = &X;
-```
-
-Therefore, casting one of these non-constant pointers to an integer results
-in a non-constant integer which lead to this error. Example:
-
-```
-const X: u32 = 1;
-const Y: usize = &X as *const u32 as usize;
-println!("{}", Y);
-```
-"##,
-
-E0019: r##"
-A function call isn't allowed in the const's initialization expression
-because the expression's value must be known at compile-time. Example of
-erroneous code:
-
-```
-enum Test {
- V1
-}
-
-impl Test {
- fn test(&self) -> i32 {
- 12
- }
-}
-
-fn main() {
- const FOO: Test = Test::V1;
-
- const A: i32 = FOO.test(); // You can't call Test::func() here !
-}
-```
-
-Remember: you can't use a function call inside a const's initialization
-expression! However, you can totally use it anywhere else:
-
-```
-fn main() {
- const FOO: Test = Test::V1;
-
- FOO.func(); // here is good
- let x = FOO.func(); // or even here!
-}
-```
-"##,
-
E0020: r##"
This error indicates that an attempt was made to divide by zero (or take the
remainder of a zero divisor) in a static or constant expression. Erroneous
```
"##,
-E0030: r##"
-When matching against a range, the compiler verifies that the range is
-non-empty. Range patterns include both end-points, so this is equivalent to
-requiring the start of the range to be less than or equal to the end of the
-range.
-
-For example:
-
-```
-match 5u32 {
- // This range is ok, albeit pointless.
- 1 ... 1 => ...
- // This range is empty, and the compiler can tell.
- 1000 ... 5 => ...
-}
-```
-"##,
-
E0038: r####"
Trait objects like `Box<Trait>` can only be constructed when certain
requirements are satisfied by the trait in question.
```
"##,
-E0161: r##"
-In Rust, you can only move a value when its size is known at compile time.
-
-To work around this restriction, consider "hiding" the value behind a reference:
-either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
-it around as usual.
-"##,
-
E0162: r##"
An if-let pattern attempts to match the pattern, and enters the body if the
match was successful. If the match is irrefutable (when it cannot fail to
```
"##,
-E0265: r##"
-This error indicates that a static or constant references itself.
-All statics and constants need to resolve to a value in an acyclic manner.
-
-For example, neither of the following can be sensibly compiled:
-
-```
-const X: u32 = X;
-```
-
-```
-const X: u32 = Y;
-const Y: u32 = X;
-```
-"##,
-
-E0267: r##"
-This error indicates the use of a loop keyword (`break` or `continue`) inside a
-closure but outside of any loop. Erroneous code example:
-
-```
-let w = || { break; }; // error: `break` inside of a closure
-```
-
-`break` and `continue` keywords can be used as normal inside closures as long as
-they are also contained within a loop. To halt the execution of a closure you
-should instead use a return statement. Example:
-
-```
-let w = || {
- for _ in 0..10 {
- break;
- }
-};
-
-w();
-```
-"##,
-
-E0268: r##"
-This error indicates the use of a loop keyword (`break` or `continue`) outside
-of a loop. Without a loop to break out of or continue in, no sensible action can
-be taken. Erroneous code example:
-
-```
-fn some_func() {
- break; // error: `break` outside of loop
-}
-```
-
-Please verify that you are using `break` and `continue` only in loops. Example:
-
-```
-fn some_func() {
- for _ in 0..10 {
- break; // ok!
- }
-}
-```
-"##,
-
E0269: r##"
Functions must eventually return a value of their return type. For example, in
the following function
```
"##,
-E0378: r##"
-Method calls that aren't calls to inherent `const` methods are disallowed
-in statics, constants, and constant functions.
-
-For example:
-
-```
-const BAZ: i32 = Foo(25).bar(); // error, `bar` isn't `const`
-
-struct Foo(i32);
-
-impl Foo {
- const fn foo(&self) -> i32 {
- self.bar() // error, `bar` isn't `const`
- }
-
- fn bar(&self) -> i32 { self.0 }
-}
-```
-
-For more information about `const fn`'s, see [RFC 911].
-
-[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
-"##,
-
-E0394: r##"
-From [RFC 246]:
-
- > It is invalid for a static to reference another static by value. It is
- > required that all references be borrowed.
-
-[RFC 246]: https://github.com/rust-lang/rfcs/pull/246
-"##,
-
-E0395: r##"
-The value assigned to a constant expression must be known at compile time,
-which is not the case when comparing raw pointers. Erroneous code example:
-
-```
-static foo: i32 = 42;
-static bar: i32 = 43;
-
-static baz: bool = { (&foo as *const i32) == (&bar as *const i32) };
-// error: raw pointers cannot be compared in statics!
-```
-
-Please check that the result of the comparison can be determined at compile time
-or isn't assigned to a constant expression. Example:
-
-```
-static foo: i32 = 42;
-static bar: i32 = 43;
-
-let baz: bool = { (&foo as *const i32) == (&bar as *const i32) };
-// baz isn't a constant expression so it's ok
-```
-"##,
-
-E0396: r##"
-The value assigned to a constant expression must be known at compile time,
-which is not the case when dereferencing raw pointers. Erroneous code
-example:
-
-```
-const foo: i32 = 42;
-const baz: *const i32 = (&foo as *const i32);
-
-const deref: i32 = *baz;
-// error: raw pointers cannot be dereferenced in constants
-```
-
-To fix this error, please do not assign this value to a constant expression.
-Example:
-
-```
-const foo: i32 = 42;
-const baz: *const i32 = (&foo as *const i32);
-
-unsafe { let deref: i32 = *baz; }
-// baz isn't a constant expression so it's ok
-```
-
-You'll also note that this assignment must be done in an unsafe block!
-"##,
-
-E0397: r##"
-It is not allowed for a mutable static to allocate or have destructors. For
-example:
-
-```
-// error: mutable statics are not allowed to have boxes
-static mut FOO: Option<Box<usize>> = None;
-
-// error: mutable statics are not allowed to have destructors
-static mut BAR: Option<Vec<i32>> = None;
-```
-"##,
-
E0398: r##"
In Rust 1.3, the default object lifetime bounds are expected to
change, as described in RFC #1156 [1]. You are getting a warning
[1]: https://github.com/rust-lang/rfcs/pull/1156
"##,
-E0400: r##"
-A user-defined dereference was attempted in an invalid context. Erroneous
-code example:
-
-```
-use std::ops::Deref;
-
-struct A;
-
-impl Deref for A {
- type Target = str;
-
- fn deref(&self)-> &str { "foo" }
-}
-
-const S: &'static str = &A;
-// error: user-defined dereference operators are not allowed in constants
-
-fn main() {
- let foo = S;
-}
-```
-
-You cannot directly use a dereference operation whilst initializing a constant
-or a static. To fix this error, restructure your code to avoid this dereference,
-perhaps moving it inline:
-
-```
-use std::ops::Deref;
-
-struct A;
-
-impl Deref for A {
- type Target = str;
-
- fn deref(&self)-> &str { "foo" }
-}
-
-fn main() {
- let foo : &str = &A;
-}
-```
-"##,
-
E0452: r##"
An invalid lint attribute has been given. Erroneous code example:
```
"##,
-E0492: r##"
-A borrow of a constant containing interior mutability was attempted. Erroneous
-code example:
-
-```
-use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
-
-const A: AtomicUsize = ATOMIC_USIZE_INIT;
-static B: &'static AtomicUsize = &A;
-// error: cannot borrow a constant which contains interior mutability, create a
-// static instead
-```
-
-A `const` represents a constant value that should never change. If one takes
-a `&` reference to the constant, then one is taking a pointer to some memory
-location containing the value. Normally this is perfectly fine: most values
-can't be changed via a shared `&` pointer, but interior mutability would allow
-it. That is, a constant value could be mutated. On the other hand, a `static` is
-explicitly a single memory location, which can be mutated at will.
-
-So, in order to solve this error, either use statics which are `Sync`:
-
-```
-use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
-
-static A: AtomicUsize = ATOMIC_USIZE_INIT;
-static B: &'static AtomicUsize = &A; // ok!
-```
-
-You can also have this error while using a cell type:
-
-```
-#![feature(const_fn)]
-
-use std::cell::Cell;
-
-const A: Cell<usize> = Cell::new(1);
-const B: &'static Cell<usize> = &A;
-// error: cannot borrow a constant which contains interior mutability, create
-// a static instead
-
-// or:
-struct C { a: Cell<usize> }
-
-const D: C = C { a: Cell::new(1) };
-const E: &'static Cell<usize> = &D.a; // error
-
-// or:
-const F: &'static C = &D; // error
-```
-
-This is because cell types do operations that are not thread-safe. Due to this,
-they don't implement Sync and thus can't be placed in statics. In this
-case, `StaticMutex` would work just fine, but it isn't stable yet:
-https://doc.rust-lang.org/nightly/std/sync/struct.StaticMutex.html
-
-However, if you still wish to use these types, you can achieve this by an unsafe
-wrapper:
-
-```
-#![feature(const_fn)]
-
-use std::cell::Cell;
-use std::marker::Sync;
-
-struct NotThreadSafe<T> {
- value: Cell<T>,
-}
-
-unsafe impl<T> Sync for NotThreadSafe<T> {}
-
-static A: NotThreadSafe<usize> = NotThreadSafe { value : Cell::new(1) };
-static B: &'static NotThreadSafe<usize> = &A; // ok!
-```
-
-Remember this solution is unsafe! You will have to ensure that accesses to the
-cell are synchronized.
-"##,
-
-E0493: r##"
-A type with a destructor was assigned to an invalid type of variable. Erroneous
-code example:
-
-```
-struct Foo {
- a: u32
-}
-
-impl Drop for Foo {
- fn drop(&mut self) {}
-}
-
-const F : Foo = Foo { a : 0 };
-// error: constants are not allowed to have destructors
-static S : Foo = Foo { a : 0 };
-// error: statics are not allowed to have destructors
-```
-
-To solve this issue, please use a type which does allow the usage of type with
-destructors.
-"##,
-
-E0494: r##"
-A reference of an interior static was assigned to another const/static.
-Erroneous code example:
-
-```
-struct Foo {
- a: u32
-}
-
-static S : Foo = Foo { a : 0 };
-static A : &'static u32 = &S.a;
-// error: cannot refer to the interior of another static, use a
-// constant instead
-```
-
-The "base" variable has to be a const if you want another static/const variable
-to refer to one of its fields. Example:
-
-```
-struct Foo {
- a: u32
-}
-
-const S : Foo = Foo { a : 0 };
-static A : &'static u32 = &S.a; // ok!
-```
-"##,
-
E0496: r##"
A lifetime name is shadowing another lifetime name. Erroneous code example:
pub mod astconv_util;
pub mod expr_use_visitor; // STAGE0: increase glitch immunity
pub mod cfg;
- pub mod check_const;
- pub mod check_static_recursion;
- pub mod check_loop;
pub mod check_match;
- pub mod check_rvalues;
pub mod const_eval;
+ pub mod const_qualif;
pub mod cstore;
pub mod dataflow;
pub mod dead;
* Almost certainly this could (and should) be refactored out of existence.
*/
-use middle::def;
+use middle::def::Def;
use middle::ty::{self, Ty};
use syntax::codemap::Span;
}
Some(d) => d.full_def()
};
- if let def::DefPrimTy(nty) = def {
+ if let Def::PrimTy(nty) = def {
Some(prim_ty_to_ty(tcx, &path.segments, nty))
} else {
None
use rustc_data_structures::graph;
use middle::cfg::*;
-use middle::def;
+use middle::def::Def;
use middle::pat_util;
use middle::ty;
use syntax::ast;
}
match self.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
- Some(def::DefLabel(loop_id)) => {
+ Some(Def::Label(loop_id)) => {
for l in &self.loop_scopes {
if l.loop_id == loop_id {
return *l;
+++ /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.
-
-// Verifies that the types and values of const and static items
-// are safe. The rules enforced by this module are:
-//
-// - For each *mutable* static item, it checks that its **type**:
-// - doesn't have a destructor
-// - doesn't own a box
-//
-// - For each *immutable* static item, it checks that its **value**:
-// - doesn't own a box
-// - doesn't contain a struct literal or a call to an enum variant / struct constructor where
-// - the type of the struct/enum has a dtor
-//
-// Rules Enforced Elsewhere:
-// - It's not possible to take the address of a static item with unsafe interior. This is enforced
-// by borrowck::gather_loans
-
-use dep_graph::DepNode;
-use middle::ty::cast::{CastKind};
-use middle::const_eval::{self, ConstEvalErr};
-use middle::const_eval::ErrKind::IndexOpFeatureGated;
-use middle::const_eval::EvalHint::ExprTypeChecked;
-use middle::def;
-use middle::def_id::DefId;
-use middle::expr_use_visitor as euv;
-use middle::infer;
-use middle::mem_categorization as mc;
-use middle::mem_categorization::Categorization;
-use middle::traits;
-use middle::ty::{self, Ty};
-use util::nodemap::NodeMap;
-
-use rustc_front::hir;
-use syntax::ast;
-use syntax::codemap::Span;
-use syntax::feature_gate::UnstableFeatures;
-use rustc_front::intravisit::{self, FnKind, Visitor};
-
-use std::collections::hash_map::Entry;
-use std::cmp::Ordering;
-
-// Const qualification, from partial to completely promotable.
-bitflags! {
- #[derive(RustcEncodable, RustcDecodable)]
- flags ConstQualif: u8 {
- // Inner mutability (can not be placed behind a reference) or behind
- // &mut in a non-global expression. Can be copied from static memory.
- const MUTABLE_MEM = 1 << 0,
- // Constant value with a type that implements Drop. Can be copied
- // from static memory, similar to MUTABLE_MEM.
- const NEEDS_DROP = 1 << 1,
- // Even if the value can be placed in static memory, copying it from
- // there is more expensive than in-place instantiation, and/or it may
- // be too large. This applies to [T; N] and everything containing it.
- // N.B.: references need to clear this flag to not end up on the stack.
- const PREFER_IN_PLACE = 1 << 2,
- // May use more than 0 bytes of memory, doesn't impact the constness
- // directly, but is not allowed to be borrowed mutably in a constant.
- const NON_ZERO_SIZED = 1 << 3,
- // Actually borrowed, has to always be in static memory. Does not
- // propagate, and requires the expression to behave like a 'static
- // lvalue. The set of expressions with this flag is the minimum
- // that have to be promoted.
- const HAS_STATIC_BORROWS = 1 << 4,
- // Invalid const for miscellaneous reasons (e.g. not implemented).
- const NOT_CONST = 1 << 5,
-
- // Borrowing the expression won't produce &'static T if any of these
- // bits are set, though the value could be copied from static memory
- // if `NOT_CONST` isn't set.
- const NON_STATIC_BORROWS = ConstQualif::MUTABLE_MEM.bits |
- ConstQualif::NEEDS_DROP.bits |
- ConstQualif::NOT_CONST.bits
- }
-}
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-enum Mode {
- Const,
- ConstFn,
- Static,
- StaticMut,
-
- // An expression that occurs outside of any constant context
- // (i.e. `const`, `static`, array lengths, etc.). The value
- // can be variable at runtime, but will be promotable to
- // static memory if we can prove it is actually constant.
- Var,
-}
-
-struct CheckCrateVisitor<'a, 'tcx: 'a> {
- tcx: &'a ty::ctxt<'tcx>,
- mode: Mode,
- qualif: ConstQualif,
- rvalue_borrows: NodeMap<hir::Mutability>
-}
-
-impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
- fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R where
- F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>) -> R,
- {
- let (old_mode, old_qualif) = (self.mode, self.qualif);
- self.mode = mode;
- self.qualif = ConstQualif::empty();
- let r = f(self);
- self.mode = old_mode;
- self.qualif = old_qualif;
- r
- }
-
- fn with_euv<'b, F, R>(&'b mut self, item_id: Option<ast::NodeId>, f: F) -> R where
- F: for<'t> FnOnce(&mut euv::ExprUseVisitor<'b, 't, 'b, 'tcx>) -> R,
- {
- let param_env = match item_id {
- Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
- None => self.tcx.empty_parameter_environment()
- };
-
- let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env));
-
- f(&mut euv::ExprUseVisitor::new(self, &infcx))
- }
-
- fn global_expr(&mut self, mode: Mode, expr: &hir::Expr) -> ConstQualif {
- assert!(mode != Mode::Var);
- match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) {
- Entry::Occupied(entry) => return *entry.get(),
- Entry::Vacant(entry) => {
- // Prevent infinite recursion on re-entry.
- entry.insert(ConstQualif::empty());
- }
- }
- self.with_mode(mode, |this| {
- this.with_euv(None, |euv| euv.consume_expr(expr));
- this.visit_expr(expr);
- this.qualif
- })
- }
-
- fn fn_like(&mut self,
- fk: FnKind,
- fd: &hir::FnDecl,
- b: &hir::Block,
- s: Span,
- fn_id: ast::NodeId)
- -> ConstQualif {
- match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) {
- Entry::Occupied(entry) => return *entry.get(),
- Entry::Vacant(entry) => {
- // Prevent infinite recursion on re-entry.
- entry.insert(ConstQualif::empty());
- }
- }
-
- let mode = match fk {
- FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _) => {
- Mode::ConstFn
- }
- FnKind::Method(_, m, _) => {
- if m.constness == hir::Constness::Const {
- Mode::ConstFn
- } else {
- Mode::Var
- }
- }
- _ => Mode::Var
- };
-
- let qualif = self.with_mode(mode, |this| {
- this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
- intravisit::walk_fn(this, fk, fd, b, s);
- this.qualif
- });
-
- // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
- // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
- let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
-
- self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
- qualif
- }
-
- fn add_qualif(&mut self, qualif: ConstQualif) {
- self.qualif = self.qualif | qualif;
- }
-
- /// Returns true if the call is to a const fn or method.
- fn handle_const_fn_call(&mut self,
- expr: &hir::Expr,
- def_id: DefId,
- ret_ty: Ty<'tcx>)
- -> bool {
- if let Some(fn_like) = const_eval::lookup_const_fn_by_id(self.tcx, def_id) {
- if
- // we are in a static/const initializer
- self.mode != Mode::Var &&
-
- // feature-gate is not enabled
- !self.tcx.sess.features.borrow().const_fn &&
-
- // this doesn't come from a macro that has #[allow_internal_unstable]
- !self.tcx.sess.codemap().span_allows_unstable(expr.span)
- {
- let mut err = self.tcx.sess.struct_span_err(
- expr.span,
- "const fns are an unstable feature");
- fileline_help!(
- &mut err,
- expr.span,
- "in Nightly builds, add `#![feature(const_fn)]` to the crate \
- attributes to enable");
- err.emit();
- }
-
- let qualif = self.fn_like(fn_like.kind(),
- fn_like.decl(),
- fn_like.body(),
- fn_like.span(),
- fn_like.id());
- self.add_qualif(qualif);
-
- if ret_ty.type_contents(self.tcx).interior_unsafe() {
- self.add_qualif(ConstQualif::MUTABLE_MEM);
- }
-
- true
- } else {
- false
- }
- }
-
- fn record_borrow(&mut self, id: ast::NodeId, mutbl: hir::Mutability) {
- match self.rvalue_borrows.entry(id) {
- Entry::Occupied(mut entry) => {
- // Merge the two borrows, taking the most demanding
- // one, mutability-wise.
- if mutbl == hir::MutMutable {
- entry.insert(mutbl);
- }
- }
- Entry::Vacant(entry) => {
- entry.insert(mutbl);
- }
- }
- }
-
- fn msg(&self) -> &'static str {
- match self.mode {
- Mode::Const => "constant",
- Mode::ConstFn => "constant function",
- Mode::StaticMut | Mode::Static => "static",
- Mode::Var => unreachable!(),
- }
- }
-
- fn check_static_mut_type(&self, e: &hir::Expr) {
- let node_ty = self.tcx.node_id_to_type(e.id);
- let tcontents = node_ty.type_contents(self.tcx);
-
- let suffix = if tcontents.has_dtor() {
- "destructors"
- } else if tcontents.owns_owned() {
- "boxes"
- } else {
- return
- };
-
- span_err!(self.tcx.sess, e.span, E0397,
- "mutable statics are not allowed to have {}", suffix);
- }
-
- fn check_static_type(&self, e: &hir::Expr) {
- let ty = self.tcx.node_id_to_type(e.id);
- let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
- let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
- let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();
- fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
- match fulfill_cx.select_all_or_error(&infcx) {
- Ok(()) => { },
- Err(ref errors) => {
- traits::report_fulfillment_errors(&infcx, errors);
- }
- }
- }
-}
-
-impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
- fn visit_item(&mut self, i: &hir::Item) {
- debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
- assert_eq!(self.mode, Mode::Var);
- match i.node {
- hir::ItemStatic(_, hir::MutImmutable, ref expr) => {
- self.check_static_type(&**expr);
- self.global_expr(Mode::Static, &**expr);
- }
- hir::ItemStatic(_, hir::MutMutable, ref expr) => {
- self.check_static_mut_type(&**expr);
- self.global_expr(Mode::StaticMut, &**expr);
- }
- hir::ItemConst(_, ref expr) => {
- self.global_expr(Mode::Const, &**expr);
- }
- hir::ItemEnum(ref enum_definition, _) => {
- for var in &enum_definition.variants {
- if let Some(ref ex) = var.node.disr_expr {
- self.global_expr(Mode::Const, &**ex);
- }
- }
- }
- _ => {
- intravisit::walk_item(self, i);
- }
- }
- }
-
- fn visit_trait_item(&mut self, t: &'v hir::TraitItem) {
- match t.node {
- hir::ConstTraitItem(_, ref default) => {
- if let Some(ref expr) = *default {
- self.global_expr(Mode::Const, &*expr);
- } else {
- intravisit::walk_trait_item(self, t);
- }
- }
- _ => self.with_mode(Mode::Var, |v| intravisit::walk_trait_item(v, t)),
- }
- }
-
- fn visit_impl_item(&mut self, i: &'v hir::ImplItem) {
- match i.node {
- hir::ImplItemKind::Const(_, ref expr) => {
- self.global_expr(Mode::Const, &*expr);
- }
- _ => self.with_mode(Mode::Var, |v| intravisit::walk_impl_item(v, i)),
- }
- }
-
- fn visit_fn(&mut self,
- fk: FnKind<'v>,
- fd: &'v hir::FnDecl,
- b: &'v hir::Block,
- s: Span,
- fn_id: ast::NodeId) {
- self.fn_like(fk, fd, b, s, fn_id);
- }
-
- fn visit_pat(&mut self, p: &hir::Pat) {
- match p.node {
- hir::PatLit(ref lit) => {
- self.global_expr(Mode::Const, &**lit);
- }
- hir::PatRange(ref start, ref end) => {
- self.global_expr(Mode::Const, &**start);
- self.global_expr(Mode::Const, &**end);
-
- match const_eval::compare_lit_exprs(self.tcx, start, end) {
- Some(Ordering::Less) |
- Some(Ordering::Equal) => {}
- Some(Ordering::Greater) => {
- span_err!(self.tcx.sess, start.span, E0030,
- "lower range bound must be less than or equal to upper");
- }
- None => {
- self.tcx.sess.delay_span_bug(start.span,
- "non-constant path in constant expr");
- }
- }
- }
- _ => intravisit::walk_pat(self, p)
- }
- }
-
- fn visit_block(&mut self, block: &hir::Block) {
- // Check all statements in the block
- for stmt in &block.stmts {
- match stmt.node {
- hir::StmtDecl(ref decl, _) => {
- match decl.node {
- hir::DeclLocal(_) => {},
- // Item statements are allowed
- hir::DeclItem(_) => continue
- }
- }
- hir::StmtExpr(_, _) => {},
- hir::StmtSemi(_, _) => {},
- }
- self.add_qualif(ConstQualif::NOT_CONST);
- // anything else should have been caught by check_const_fn
- assert_eq!(self.mode, Mode::Var);
- }
- intravisit::walk_block(self, block);
- }
-
- fn visit_expr(&mut self, ex: &hir::Expr) {
- let mut outer = self.qualif;
- self.qualif = ConstQualif::empty();
-
- let node_ty = self.tcx.node_id_to_type(ex.id);
- check_expr(self, ex, node_ty);
- check_adjustments(self, ex);
-
- // Special-case some expressions to avoid certain flags bubbling up.
- match ex.node {
- hir::ExprCall(ref callee, ref args) => {
- for arg in args {
- self.visit_expr(&**arg)
- }
-
- let inner = self.qualif;
- self.visit_expr(&**callee);
- // The callee's size doesn't count in the call.
- let added = self.qualif - inner;
- self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
- }
- hir::ExprRepeat(ref element, _) => {
- self.visit_expr(&**element);
- // The count is checked elsewhere (typeck).
- let count = match node_ty.sty {
- ty::TyArray(_, n) => n,
- _ => unreachable!()
- };
- // [element; 0] is always zero-sized.
- if count == 0 {
- self.qualif.remove(ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
- }
- }
- hir::ExprMatch(ref discr, ref arms, _) => {
- // Compute the most demanding borrow from all the arms'
- // patterns and set that on the discriminator.
- let mut borrow = None;
- for pat in arms.iter().flat_map(|arm| &arm.pats) {
- let pat_borrow = self.rvalue_borrows.remove(&pat.id);
- match (borrow, pat_borrow) {
- (None, _) | (_, Some(hir::MutMutable)) => {
- borrow = pat_borrow;
- }
- _ => {}
- }
- }
- if let Some(mutbl) = borrow {
- self.record_borrow(discr.id, mutbl);
- }
- intravisit::walk_expr(self, ex);
- }
- // Division by zero and overflow checking.
- hir::ExprBinary(op, _, _) => {
- intravisit::walk_expr(self, ex);
- let div_or_rem = op.node == hir::BiDiv || op.node == hir::BiRem;
- match node_ty.sty {
- ty::TyUint(_) | ty::TyInt(_) if div_or_rem => {
- if !self.qualif.intersects(ConstQualif::NOT_CONST) {
- match const_eval::eval_const_expr_partial(
- self.tcx, ex, ExprTypeChecked, None) {
- Ok(_) => {}
- Err(ConstEvalErr { kind: IndexOpFeatureGated, ..}) => {},
- Err(msg) => {
- self.tcx.sess.add_lint(::lint::builtin::CONST_ERR, ex.id,
- msg.span,
- msg.description().into_owned())
- }
- }
- }
- }
- _ => {}
- }
- }
- _ => intravisit::walk_expr(self, ex)
- }
-
- // Handle borrows on (or inside the autorefs of) this expression.
- match self.rvalue_borrows.remove(&ex.id) {
- Some(hir::MutImmutable) => {
- // Constants cannot be borrowed if they contain interior mutability as
- // it means that our "silent insertion of statics" could change
- // initializer values (very bad).
- // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
- // propagated from another error, so erroring again would be just noise.
- let tc = node_ty.type_contents(self.tcx);
- if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
- outer = outer | ConstQualif::NOT_CONST;
- if self.mode != Mode::Var {
- span_err!(self.tcx.sess, ex.span, E0492,
- "cannot borrow a constant which contains \
- interior mutability, create a static instead");
- }
- }
- // If the reference has to be 'static, avoid in-place initialization
- // as that will end up pointing to the stack instead.
- if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
- self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
- self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
- }
- }
- Some(hir::MutMutable) => {
- // `&mut expr` means expr could be mutated, unless it's zero-sized.
- if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) {
- if self.mode == Mode::Var {
- outer = outer | ConstQualif::NOT_CONST;
- self.add_qualif(ConstQualif::MUTABLE_MEM);
- } else {
- span_err!(self.tcx.sess, ex.span, E0017,
- "references in {}s may only refer \
- to immutable values", self.msg())
- }
- }
- if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
- self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
- }
- }
- None => {}
- }
- self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
- // Don't propagate certain flags.
- self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
- }
-}
-
-/// This function is used to enforce the constraints on
-/// const/static items. It walks through the *value*
-/// of the item walking down the expression and evaluating
-/// every nested expression. If the expression is not part
-/// of a const/static item, it is qualified for promotion
-/// instead of producing errors.
-fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
- e: &hir::Expr, node_ty: Ty<'tcx>) {
- match node_ty.sty {
- ty::TyStruct(def, _) |
- ty::TyEnum(def, _) if def.has_dtor() => {
- v.add_qualif(ConstQualif::NEEDS_DROP);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0493,
- "{}s are not allowed to have destructors",
- v.msg());
- }
- }
- _ => {}
- }
-
- let method_call = ty::MethodCall::expr(e.id);
- match e.node {
- hir::ExprUnary(..) |
- hir::ExprBinary(..) |
- hir::ExprIndex(..) if v.tcx.tables.borrow().method_map.contains_key(&method_call) => {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0011,
- "user-defined operators are not allowed in {}s", v.msg());
- }
- }
- hir::ExprBox(_) => {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0010,
- "allocations are not allowed in {}s", v.msg());
- }
- }
- hir::ExprUnary(op, ref inner) => {
- match v.tcx.node_id_to_type(inner.id).sty {
- ty::TyRawPtr(_) => {
- assert!(op == hir::UnDeref);
-
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0396,
- "raw pointers cannot be dereferenced in {}s", v.msg());
- }
- }
- _ => {}
- }
- }
- hir::ExprBinary(op, ref lhs, _) => {
- match v.tcx.node_id_to_type(lhs.id).sty {
- ty::TyRawPtr(_) => {
- assert!(op.node == hir::BiEq || op.node == hir::BiNe ||
- op.node == hir::BiLe || op.node == hir::BiLt ||
- op.node == hir::BiGe || op.node == hir::BiGt);
-
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0395,
- "raw pointers cannot be compared in {}s", v.msg());
- }
- }
- _ => {}
- }
- }
- hir::ExprCast(ref from, _) => {
- debug!("Checking const cast(id={})", from.id);
- match v.tcx.cast_kinds.borrow().get(&from.id) {
- None => v.tcx.sess.span_bug(e.span, "no kind for cast"),
- Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0018,
- "raw pointers cannot be cast to integers in {}s", v.msg());
- }
- }
- _ => {}
- }
- }
- hir::ExprPath(..) => {
- let def = v.tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
- match def {
- Some(def::DefVariant(_, _, _)) => {
- // Count the discriminator or function pointer.
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- }
- Some(def::DefStruct(_)) => {
- if let ty::TyBareFn(..) = node_ty.sty {
- // Count the function pointer.
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- }
- }
- Some(def::DefFn(..)) | Some(def::DefMethod(..)) => {
- // Count the function pointer.
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- }
- Some(def::DefStatic(..)) => {
- match v.mode {
- Mode::Static | Mode::StaticMut => {}
- Mode::Const | Mode::ConstFn => {
- span_err!(v.tcx.sess, e.span, E0013,
- "{}s cannot refer to other statics, insert \
- an intermediate constant instead", v.msg());
- }
- Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
- }
- }
- Some(def::DefConst(did)) |
- Some(def::DefAssociatedConst(did)) => {
- if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
- Some(e.id),
- None) {
- let inner = v.global_expr(Mode::Const, expr);
- v.add_qualif(inner);
- }
- }
- Some(def::DefLocal(..)) if v.mode == Mode::ConstFn => {
- // Sadly, we can't determine whether the types are zero-sized.
- v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
- }
- def => {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- debug!("(checking const) found bad def: {:?}", def);
- span_err!(v.tcx.sess, e.span, E0014,
- "paths in {}s may only refer to constants \
- or functions", v.msg());
- }
- }
- }
- }
- hir::ExprCall(ref callee, _) => {
- let mut callee = &**callee;
- loop {
- callee = match callee.node {
- hir::ExprBlock(ref block) => match block.expr {
- Some(ref tail) => &**tail,
- None => break
- },
- _ => break
- };
- }
- let def = v.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def());
- let is_const = match def {
- Some(def::DefStruct(..)) => true,
- Some(def::DefVariant(..)) => {
- // Count the discriminator.
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- true
- }
- Some(def::DefFn(did, _)) => {
- v.handle_const_fn_call(e, did, node_ty)
- }
- Some(def::DefMethod(did)) => {
- match v.tcx.impl_or_trait_item(did).container() {
- ty::ImplContainer(_) => {
- v.handle_const_fn_call(e, did, node_ty)
- }
- ty::TraitContainer(_) => false
- }
- }
- _ => false
- };
- if !is_const {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- // FIXME(#24111) Remove this check when const fn stabilizes
- let (msg, note) =
- if let UnstableFeatures::Disallow = v.tcx.sess.opts.unstable_features {
- (format!("function calls in {}s are limited to \
- struct and enum constructors",
- v.msg()),
- Some("a limited form of compile-time function \
- evaluation is available on a nightly \
- compiler via `const fn`"))
- } else {
- (format!("function calls in {}s are limited \
- to constant functions, \
- struct and enum constructors",
- v.msg()),
- None)
- };
- let mut err = struct_span_err!(v.tcx.sess, e.span, E0015, "{}", msg);
- if let Some(note) = note {
- err.span_note(e.span, note);
- }
- err.emit();
- }
- }
- }
- hir::ExprMethodCall(..) => {
- let method = v.tcx.tables.borrow().method_map[&method_call];
- let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() {
- ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
- ty::TraitContainer(_) => false
- };
- if !is_const {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0378,
- "method calls in {}s are limited to \
- constant inherent methods", v.msg());
- }
- }
- }
- hir::ExprStruct(..) => {
- let did = v.tcx.def_map.borrow().get(&e.id).map(|def| def.def_id());
- if did == v.tcx.lang_items.unsafe_cell_type() {
- v.add_qualif(ConstQualif::MUTABLE_MEM);
- }
- }
-
- hir::ExprLit(_) |
- hir::ExprAddrOf(..) => {
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- }
-
- hir::ExprRepeat(..) => {
- v.add_qualif(ConstQualif::PREFER_IN_PLACE);
- }
-
- hir::ExprClosure(..) => {
- // Paths in constant contexts cannot refer to local variables,
- // as there are none, and thus closures can't have upvars there.
- if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) {
- assert!(v.mode == Mode::Var,
- "global closures can't capture anything");
- v.add_qualif(ConstQualif::NOT_CONST);
- }
- }
-
- hir::ExprBlock(_) |
- hir::ExprIndex(..) |
- hir::ExprField(..) |
- hir::ExprTupField(..) |
- hir::ExprVec(_) |
- hir::ExprType(..) |
- hir::ExprTup(..) => {}
-
- // Conditional control flow (possible to implement).
- hir::ExprMatch(..) |
- hir::ExprIf(..) |
-
- // Loops (not very meaningful in constants).
- hir::ExprWhile(..) |
- hir::ExprLoop(..) |
-
- // More control flow (also not very meaningful).
- hir::ExprBreak(_) |
- hir::ExprAgain(_) |
- hir::ExprRet(_) |
-
- // Miscellaneous expressions that could be implemented.
- hir::ExprRange(..) |
-
- // Expressions with side-effects.
- hir::ExprAssign(..) |
- hir::ExprAssignOp(..) |
- hir::ExprInlineAsm(_) => {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0019,
- "{} contains unimplemented expression type", v.msg());
- }
- }
- }
-}
-
-/// Check the adjustments of an expression
-fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
- match v.tcx.tables.borrow().adjustments.get(&e.id) {
- None |
- Some(&ty::adjustment::AdjustReifyFnPointer) |
- Some(&ty::adjustment::AdjustUnsafeFnPointer) => {}
-
- Some(&ty::adjustment::AdjustDerefRef(
- ty::adjustment::AutoDerefRef { autoderefs, .. }
- )) => {
- if (0..autoderefs as u32).any(|autoderef| {
- v.tcx.is_overloaded_autoderef(e.id, autoderef)
- }) {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0400,
- "user-defined dereference operators are not allowed in {}s",
- v.msg());
- }
- }
- }
- }
-}
-
-pub fn check_crate(tcx: &ty::ctxt) {
- tcx.visit_all_items_in_krate(DepNode::CheckConst, &mut CheckCrateVisitor {
- tcx: tcx,
- mode: Mode::Var,
- qualif: ConstQualif::NOT_CONST,
- rvalue_borrows: NodeMap()
- });
- tcx.sess.abort_if_errors();
-}
-
-impl<'a, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'tcx> {
- fn consume(&mut self,
- _consume_id: ast::NodeId,
- consume_span: Span,
- cmt: mc::cmt,
- _mode: euv::ConsumeMode) {
- let mut cur = &cmt;
- loop {
- match cur.cat {
- Categorization::StaticItem => {
- if self.mode != Mode::Var {
- // statics cannot be consumed by value at any time, that would imply
- // that they're an initializer (what a const is for) or kept in sync
- // over time (not feasible), so deny it outright.
- span_err!(self.tcx.sess, consume_span, E0394,
- "cannot refer to other statics by value, use the \
- address-of operator or a constant instead");
- }
- break;
- }
- Categorization::Deref(ref cmt, _, _) |
- Categorization::Downcast(ref cmt, _) |
- Categorization::Interior(ref cmt, _) => cur = cmt,
-
- Categorization::Rvalue(..) |
- Categorization::Upvar(..) |
- Categorization::Local(..) => break
- }
- }
- }
- fn borrow(&mut self,
- borrow_id: ast::NodeId,
- borrow_span: Span,
- cmt: mc::cmt<'tcx>,
- _loan_region: ty::Region,
- bk: ty::BorrowKind,
- loan_cause: euv::LoanCause)
- {
- // Kind of hacky, but we allow Unsafe coercions in constants.
- // These occur when we convert a &T or *T to a *U, as well as
- // when making a thin pointer (e.g., `*T`) into a fat pointer
- // (e.g., `*Trait`).
- match loan_cause {
- euv::LoanCause::AutoUnsafe => {
- return;
- }
- _ => { }
- }
-
- let mut cur = &cmt;
- let mut is_interior = false;
- loop {
- match cur.cat {
- Categorization::Rvalue(..) => {
- if loan_cause == euv::MatchDiscriminant {
- // Ignore the dummy immutable borrow created by EUV.
- break;
- }
- let mutbl = bk.to_mutbl_lossy();
- if mutbl == hir::MutMutable && self.mode == Mode::StaticMut {
- // Mutable slices are the only `&mut` allowed in
- // globals, but only in `static mut`, nowhere else.
- // FIXME: This exception is really weird... there isn't
- // any fundamental reason to restrict this based on
- // type of the expression. `&mut [1]` has exactly the
- // same representation as &mut 1.
- match cmt.ty.sty {
- ty::TyArray(_, _) | ty::TySlice(_) => break,
- _ => {}
- }
- }
- self.record_borrow(borrow_id, mutbl);
- break;
- }
- Categorization::StaticItem => {
- if is_interior && self.mode != Mode::Var {
- // Borrowed statics can specifically *only* have their address taken,
- // not any number of other borrows such as borrowing fields, reading
- // elements of an array, etc.
- span_err!(self.tcx.sess, borrow_span, E0494,
- "cannot refer to the interior of another \
- static, use a constant instead");
- }
- break;
- }
- Categorization::Deref(ref cmt, _, _) |
- Categorization::Downcast(ref cmt, _) |
- Categorization::Interior(ref cmt, _) => {
- is_interior = true;
- cur = cmt;
- }
-
- Categorization::Upvar(..) |
- Categorization::Local(..) => break
- }
- }
- }
-
- fn decl_without_init(&mut self,
- _id: ast::NodeId,
- _span: Span) {}
- fn mutate(&mut self,
- _assignment_id: ast::NodeId,
- _assignment_span: Span,
- _assignee_cmt: mc::cmt,
- _mode: euv::MutateMode) {}
-
- fn matched_pat(&mut self,
- _: &hir::Pat,
- _: mc::cmt,
- _: euv::MatchMode) {}
-
- fn consume_pat(&mut self,
- _consume_pat: &hir::Pat,
- _cmt: mc::cmt,
- _mode: euv::ConsumeMode) {}
-}
+++ /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.
-use self::Context::*;
-
-use session::Session;
-
-use syntax::codemap::Span;
-use rustc_front::intravisit::{self, Visitor};
-use rustc_front::hir;
-
-#[derive(Clone, Copy, PartialEq)]
-enum Context {
- Normal, Loop, Closure
-}
-
-#[derive(Copy, Clone)]
-struct CheckLoopVisitor<'a> {
- sess: &'a Session,
- cx: Context
-}
-
-pub fn check_crate(sess: &Session, krate: &hir::Crate) {
- krate.visit_all_items(&mut CheckLoopVisitor { sess: sess, cx: Normal });
-}
-
-impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
- fn visit_item(&mut self, i: &hir::Item) {
- self.with_context(Normal, |v| intravisit::walk_item(v, i));
- }
-
- fn visit_expr(&mut self, e: &hir::Expr) {
- match e.node {
- hir::ExprWhile(ref e, ref b, _) => {
- self.visit_expr(&**e);
- self.with_context(Loop, |v| v.visit_block(&**b));
- }
- hir::ExprLoop(ref b, _) => {
- self.with_context(Loop, |v| v.visit_block(&**b));
- }
- hir::ExprClosure(_, _, ref b) => {
- self.with_context(Closure, |v| v.visit_block(&**b));
- }
- hir::ExprBreak(_) => self.require_loop("break", e.span),
- hir::ExprAgain(_) => self.require_loop("continue", e.span),
- _ => intravisit::walk_expr(self, e)
- }
- }
-}
-
-impl<'a> CheckLoopVisitor<'a> {
- fn with_context<F>(&mut self, cx: Context, f: F) where
- F: FnOnce(&mut CheckLoopVisitor<'a>),
- {
- let old_cx = self.cx;
- self.cx = cx;
- f(self);
- self.cx = old_cx;
- }
-
- fn require_loop(&self, name: &str, span: Span) {
- match self.cx {
- Loop => {}
- Closure => {
- span_err!(self.sess, span, E0267,
- "`{}` inside of a closure", name);
- }
- Normal => {
- span_err!(self.sess, span, E0268,
- "`{}` outside of loop", name);
- }
- }
- }
-}
let pat_ty = cx.tcx.pat_ty(p);
if let ty::TyEnum(edef, _) = pat_ty.sty {
let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
- if let Some(DefLocal(..)) = def {
+ if let Some(Def::Local(..)) = def {
if edef.variants.iter().any(|variant|
variant.name == ident.node.unhygienic_name
&& variant.kind() == VariantKind::Unit
hir::PatIdent(..) | hir::PatEnum(..) | hir::PatQPath(..) => {
let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
match def {
- Some(DefAssociatedConst(did)) |
- Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did,
+ Some(Def::AssociatedConst(did)) |
+ Some(Def::Const(did)) => match lookup_const_by_id(self.tcx, did,
Some(pat.id), None) {
Some(const_expr) => {
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
match pat.node {
hir::PatIdent(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
- Some(DefStruct(_)) => vec!(Single),
- Some(DefVariant(_, id, _)) => vec!(Variant(id)),
+ Some(Def::Struct(..)) => vec!(Single),
+ Some(Def::Variant(_, id)) => vec!(Variant(id)),
_ => vec!()
},
hir::PatEnum(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
- Some(DefVariant(_, id, _)) => vec!(Variant(id)),
+ Some(Def::Variant(_, id)) => vec!(Variant(id)),
_ => vec!(Single)
},
hir::PatQPath(..) =>
been rewritten"),
hir::PatStruct(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
- Some(DefVariant(_, id, _)) => vec!(Variant(id)),
+ Some(Def::Variant(_, id)) => vec!(Variant(id)),
_ => vec!(Single)
},
hir::PatLit(ref expr) =>
hir::PatIdent(_, _, _) => {
let opt_def = cx.tcx.def_map.borrow().get(&pat_id).map(|d| d.full_def());
match opt_def {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
- Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
+ Some(Def::Variant(_, id)) => if *constructor == Variant(id) {
Some(vec!())
} else {
None
hir::PatEnum(_, ref args) => {
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
match def {
- DefConst(..) | DefAssociatedConst(..) =>
+ Def::Const(..) | Def::AssociatedConst(..) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
- DefVariant(_, id, _) if *constructor != Variant(id) => None,
- DefVariant(..) | DefStruct(..) => {
+ Def::Variant(_, id) if *constructor != Variant(id) => None,
+ Def::Variant(..) | Def::Struct(..) => {
Some(match args {
&Some(ref args) => args.iter().map(|p| &**p).collect(),
&None => vec![DUMMY_WILD_PAT; arity],
+++ /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.
-
-// Checks that all rvalues in a crate have statically known size. check_crate
-// is the public starting point.
-
-use dep_graph::DepNode;
-use middle::expr_use_visitor as euv;
-use middle::infer;
-use middle::mem_categorization as mc;
-use middle::ty::ParameterEnvironment;
-use middle::ty;
-
-use rustc_front::hir;
-use rustc_front::intravisit;
-use syntax::ast;
-use syntax::codemap::Span;
-
-pub fn check_crate(tcx: &ty::ctxt) {
- let mut rvcx = RvalueContext { tcx: tcx };
- tcx.visit_all_items_in_krate(DepNode::RvalueCheck, &mut rvcx);
-}
-
-struct RvalueContext<'a, 'tcx: 'a> {
- tcx: &'a ty::ctxt<'tcx>,
-}
-
-impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
- fn visit_fn(&mut self,
- fk: intravisit::FnKind<'v>,
- fd: &'v hir::FnDecl,
- b: &'v hir::Block,
- s: Span,
- fn_id: ast::NodeId) {
- {
- // FIXME (@jroesch) change this to be an inference context
- let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
- let infcx = infer::new_infer_ctxt(self.tcx,
- &self.tcx.tables,
- Some(param_env.clone()));
- let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: ¶m_env };
- let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
- euv.walk_fn(fd, b);
- }
- intravisit::walk_fn(self, fk, fd, b, s)
- }
-}
-
-struct RvalueContextDelegate<'a, 'tcx: 'a> {
- tcx: &'a ty::ctxt<'tcx>,
- param_env: &'a ty::ParameterEnvironment<'a,'tcx>,
-}
-
-impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
- fn consume(&mut self,
- _: ast::NodeId,
- span: Span,
- cmt: mc::cmt<'tcx>,
- _: euv::ConsumeMode) {
- debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty);
- if !cmt.ty.is_sized(self.param_env, span) {
- span_err!(self.tcx.sess, span, E0161,
- "cannot move a value of type {0}: the size of {0} cannot be statically determined",
- cmt.ty);
- }
- }
-
- fn matched_pat(&mut self,
- _matched_pat: &hir::Pat,
- _cmt: mc::cmt,
- _mode: euv::MatchMode) {}
-
- fn consume_pat(&mut self,
- _consume_pat: &hir::Pat,
- _cmt: mc::cmt,
- _mode: euv::ConsumeMode) {
- }
-
- fn borrow(&mut self,
- _borrow_id: ast::NodeId,
- _borrow_span: Span,
- _cmt: mc::cmt,
- _loan_region: ty::Region,
- _bk: ty::BorrowKind,
- _loan_cause: euv::LoanCause) {
- }
-
- fn decl_without_init(&mut self,
- _id: ast::NodeId,
- _span: Span) {
- }
-
- fn mutate(&mut self,
- _assignment_id: ast::NodeId,
- _assignment_span: Span,
- _assignee_cmt: mc::cmt,
- _mode: euv::MutateMode) {
- }
-}
+++ /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.
-
-// This compiler pass detects constants that refer to themselves
-// recursively.
-
-use front::map as ast_map;
-use session::Session;
-use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefVariant, DefMap};
-use util::nodemap::NodeMap;
-
-use syntax::{ast};
-use syntax::codemap::Span;
-use syntax::feature_gate::{GateIssue, emit_feature_err};
-use rustc_front::intravisit::{self, Visitor};
-use rustc_front::hir;
-
-use std::cell::RefCell;
-
-struct CheckCrateVisitor<'a, 'ast: 'a> {
- sess: &'a Session,
- def_map: &'a DefMap,
- ast_map: &'a ast_map::Map<'ast>,
- // `discriminant_map` is a cache that associates the `NodeId`s of local
- // variant definitions with the discriminant expression that applies to
- // each one. If the variant uses the default values (starting from `0`),
- // then `None` is stored.
- discriminant_map: RefCell<NodeMap<Option<&'ast hir::Expr>>>,
-}
-
-impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
- fn visit_item(&mut self, it: &'ast hir::Item) {
- match it.node {
- hir::ItemStatic(..) |
- hir::ItemConst(..) => {
- let mut recursion_visitor =
- CheckItemRecursionVisitor::new(self, &it.span);
- recursion_visitor.visit_item(it);
- },
- hir::ItemEnum(ref enum_def, ref generics) => {
- // We could process the whole enum, but handling the variants
- // with discriminant expressions one by one gives more specific,
- // less redundant output.
- for variant in &enum_def.variants {
- if let Some(_) = variant.node.disr_expr {
- let mut recursion_visitor =
- CheckItemRecursionVisitor::new(self, &variant.span);
- recursion_visitor.populate_enum_discriminants(enum_def);
- recursion_visitor.visit_variant(variant, generics, it.id);
- }
- }
- }
- _ => {}
- }
- intravisit::walk_item(self, it)
- }
-
- fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
- match ti.node {
- hir::ConstTraitItem(_, ref default) => {
- if let Some(_) = *default {
- let mut recursion_visitor =
- CheckItemRecursionVisitor::new(self, &ti.span);
- recursion_visitor.visit_trait_item(ti);
- }
- }
- _ => {}
- }
- intravisit::walk_trait_item(self, ti)
- }
-
- fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
- match ii.node {
- hir::ImplItemKind::Const(..) => {
- let mut recursion_visitor =
- CheckItemRecursionVisitor::new(self, &ii.span);
- recursion_visitor.visit_impl_item(ii);
- }
- _ => {}
- }
- intravisit::walk_impl_item(self, ii)
- }
-}
-
-pub fn check_crate<'ast>(sess: &Session,
- krate: &'ast hir::Crate,
- def_map: &DefMap,
- ast_map: &ast_map::Map<'ast>) {
- let mut visitor = CheckCrateVisitor {
- sess: sess,
- def_map: def_map,
- ast_map: ast_map,
- discriminant_map: RefCell::new(NodeMap()),
- };
- sess.abort_if_new_errors(|| {
- krate.visit_all_items(&mut visitor);
- });
-}
-
-struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
- root_span: &'a Span,
- sess: &'a Session,
- ast_map: &'a ast_map::Map<'ast>,
- def_map: &'a DefMap,
- discriminant_map: &'a RefCell<NodeMap<Option<&'ast hir::Expr>>>,
- idstack: Vec<ast::NodeId>,
-}
-
-impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
- fn new(v: &'a 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,
- discriminant_map: &v.discriminant_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) {
- let any_static = self.idstack.iter().any(|&x| {
- if let ast_map::NodeItem(item) = self.ast_map.get(x) {
- if let hir::ItemStatic(..) = item.node {
- true
- } else {
- false
- }
- } else {
- false
- }
- });
- if any_static {
- if !self.sess.features.borrow().static_recursion {
- emit_feature_err(&self.sess.parse_sess.span_diagnostic,
- "static_recursion",
- *self.root_span, GateIssue::Language, "recursive static");
- }
- } else {
- span_err!(self.sess, *self.root_span, E0265, "recursive constant");
- }
- return;
- }
- self.idstack.push(id);
- f(self);
- self.idstack.pop();
- }
- // If a variant has an expression specifying its discriminant, then it needs
- // to be checked just like a static or constant. However, if there are more
- // variants with no explicitly specified discriminant, those variants will
- // increment the same expression to get their values.
- //
- // So for every variant, we need to track whether there is an expression
- // somewhere in the enum definition that controls its discriminant. We do
- // this by starting from the end and searching backward.
- fn populate_enum_discriminants(&self, enum_definition: &'ast hir::EnumDef) {
- // Get the map, and return if we already processed this enum or if it
- // has no variants.
- let mut discriminant_map = self.discriminant_map.borrow_mut();
- match enum_definition.variants.first() {
- None => { return; }
- Some(variant) if discriminant_map.contains_key(&variant.node.data.id()) => {
- return;
- }
- _ => {}
- }
-
- // Go through all the variants.
- let mut variant_stack: Vec<ast::NodeId> = Vec::new();
- for variant in enum_definition.variants.iter().rev() {
- variant_stack.push(variant.node.data.id());
- // When we find an expression, every variant currently on the stack
- // is affected by that expression.
- if let Some(ref expr) = variant.node.disr_expr {
- for id in &variant_stack {
- discriminant_map.insert(*id, Some(expr));
- }
- variant_stack.clear()
- }
- }
- // If we are at the top, that always starts at 0, so any variant on the
- // stack has a default value and does not need to be checked.
- for id in &variant_stack {
- discriminant_map.insert(*id, None);
- }
- }
-}
-
-impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
- fn visit_item(&mut self, it: &'ast hir::Item) {
- self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it));
- }
-
- fn visit_enum_def(&mut self, enum_definition: &'ast hir::EnumDef,
- generics: &'ast hir::Generics, item_id: ast::NodeId, _: Span) {
- self.populate_enum_discriminants(enum_definition);
- intravisit::walk_enum_def(self, enum_definition, generics, item_id);
- }
-
- fn visit_variant(&mut self, variant: &'ast hir::Variant,
- _: &'ast hir::Generics, _: ast::NodeId) {
- let variant_id = variant.node.data.id();
- let maybe_expr;
- if let Some(get_expr) = self.discriminant_map.borrow().get(&variant_id) {
- // This is necessary because we need to let the `discriminant_map`
- // borrow fall out of scope, so that we can reborrow farther down.
- maybe_expr = (*get_expr).clone();
- } else {
- self.sess.span_bug(variant.span,
- "`check_static_recursion` attempted to visit \
- variant with unknown discriminant")
- }
- // If `maybe_expr` is `None`, that's because no discriminant is
- // specified that affects this variant. Thus, no risk of recursion.
- if let Some(expr) = maybe_expr {
- self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr));
- }
- }
-
- fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
- self.with_item_id_pushed(ti.id, |v| intravisit::walk_trait_item(v, ti));
- }
-
- fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
- self.with_item_id_pushed(ii.id, |v| intravisit::walk_impl_item(v, ii));
- }
-
- fn visit_expr(&mut self, e: &'ast hir::Expr) {
- match e.node {
- hir::ExprPath(..) => {
- match self.def_map.get(&e.id).map(|d| d.base_def) {
- Some(DefStatic(def_id, _)) |
- Some(DefAssociatedConst(def_id)) |
- Some(DefConst(def_id)) => {
- if let Some(node_id) = self.ast_map.as_local_node_id(def_id) {
- match self.ast_map.get(node_id) {
- 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(_) => {},
- _ => {
- self.sess.span_bug(
- e.span,
- &format!("expected item, found {}",
- self.ast_map.node_to_string(node_id)));
- }
- }
- }
- }
- // For variants, we only want to check expressions that
- // affect the specific variant used, but we need to check
- // the whole enum definition to see what expression that
- // might be (if any).
- Some(DefVariant(enum_id, variant_id, false)) => {
- if let Some(enum_node_id) = self.ast_map.as_local_node_id(enum_id) {
- if let hir::ItemEnum(ref enum_def, ref generics) =
- self.ast_map.expect_item(enum_node_id).node
- {
- self.populate_enum_discriminants(enum_def);
- let enum_id = self.ast_map.as_local_node_id(enum_id).unwrap();
- let variant_id = self.ast_map.as_local_node_id(variant_id).unwrap();
- let variant = self.ast_map.expect_variant(variant_id);
- self.visit_variant(variant, generics, enum_id);
- } else {
- self.sess.span_bug(e.span,
- "`check_static_recursion` found \
- non-enum in DefVariant");
- }
- }
- }
- _ => ()
- }
- },
- _ => ()
- }
- intravisit::walk_expr(self, e);
- }
-}
use front::map as ast_map;
use front::map::blocks::FnLikeNode;
use middle::cstore::{self, CrateStore, InlinedItem};
-use middle::{def, infer, subst, traits};
+use middle::{infer, subst, traits};
+use middle::def::Def;
use middle::subst::Subst;
use middle::def_id::DefId;
use middle::pat_util::def_to_path;
entry.insert(def);
}
let path = match def.full_def() {
- def::DefStruct(def_id) => def_to_path(tcx, def_id),
- def::DefVariant(_, variant_did, _) => def_to_path(tcx, variant_did),
- def::DefFn(..) => return P(hir::Pat {
+ Def::Struct(def_id) => def_to_path(tcx, def_id),
+ Def::Variant(_, variant_did) => def_to_path(tcx, variant_did),
+ Def::Fn(..) => return P(hir::Pat {
id: expr.id,
node: hir::PatLit(P(expr.clone())),
span: span,
hir::ExprPath(_, ref path) => {
let opt_def = tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def());
match opt_def {
- Some(def::DefStruct(..)) =>
+ Some(Def::Struct(..)) =>
hir::PatStruct(path.clone(), hir::HirVec::new(), false),
- Some(def::DefVariant(..)) =>
+ Some(Def::Variant(..)) =>
hir::PatEnum(path.clone(), None),
- Some(def::DefConst(def_id)) |
- Some(def::DefAssociatedConst(def_id)) => {
+ Some(Def::Const(def_id)) |
+ Some(Def::AssociatedConst(def_id)) => {
let expr = lookup_const_by_id(tcx, def_id, Some(expr.id), None).unwrap();
return const_expr_to_pat(tcx, expr, span);
},
None
};
let (const_expr, const_ty) = match opt_def {
- Some(def::DefConst(def_id)) => {
+ Some(Def::Const(def_id)) => {
if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
match tcx.map.find(node_id) {
Some(ast_map::NodeItem(it)) => match it.node {
(lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
}
}
- Some(def::DefAssociatedConst(def_id)) => {
+ Some(Def::AssociatedConst(def_id)) => {
if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
match tcx.impl_or_trait_item(def_id).container() {
ty::TraitContainer(trait_id) => match tcx.map.find(node_id) {
(lookup_const_by_id(tcx, def_id, Some(e.id), None), None)
}
}
- Some(def::DefVariant(enum_def, variant_def, _)) => {
+ Some(Def::Variant(enum_def, variant_def)) => {
(lookup_variant_by_id(tcx, enum_def, variant_def), None)
}
- Some(def::DefStruct(_)) => {
+ Some(Def::Struct(..)) => {
return Ok(ConstVal::Struct(e.id))
}
- Some(def::DefLocal(_, id)) => {
- debug!("DefLocal({:?}): {:?}", id, fn_args);
+ Some(Def::Local(_, id)) => {
+ debug!("Def::Local({:?}): {:?}", id, fn_args);
if let Some(val) = fn_args.and_then(|args| args.get(&id)) {
return Ok(val.clone());
} else {
(None, None)
}
},
- Some(def::DefMethod(id)) | Some(def::DefFn(id, _)) => return Ok(Function(id)),
+ Some(Def::Method(id)) | Some(Def::Fn(id)) => return Ok(Function(id)),
_ => (None, None)
};
let const_expr = match const_expr {
rcvr_substs: subst::Substs<'tcx>)
-> Option<&'tcx Expr>
{
- 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);
- let trait_ref = ty::Binder(ty::TraitRef { def_id: trait_id,
- substs: trait_substs });
+ let trait_ref = ty::Binder(
+ rcvr_substs.erase_regions().to_trait_ref(tcx, trait_id)
+ );
+ debug!("resolve_trait_associated_const: trait_ref={:?}",
+ trait_ref);
tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None);
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Const qualification, from partial to completely promotable.
+bitflags! {
+ #[derive(RustcEncodable, RustcDecodable)]
+ flags ConstQualif: u8 {
+ // Inner mutability (can not be placed behind a reference) or behind
+ // &mut in a non-global expression. Can be copied from static memory.
+ const MUTABLE_MEM = 1 << 0,
+ // Constant value with a type that implements Drop. Can be copied
+ // from static memory, similar to MUTABLE_MEM.
+ const NEEDS_DROP = 1 << 1,
+ // Even if the value can be placed in static memory, copying it from
+ // there is more expensive than in-place instantiation, and/or it may
+ // be too large. This applies to [T; N] and everything containing it.
+ // N.B.: references need to clear this flag to not end up on the stack.
+ const PREFER_IN_PLACE = 1 << 2,
+ // May use more than 0 bytes of memory, doesn't impact the constness
+ // directly, but is not allowed to be borrowed mutably in a constant.
+ const NON_ZERO_SIZED = 1 << 3,
+ // Actually borrowed, has to always be in static memory. Does not
+ // propagate, and requires the expression to behave like a 'static
+ // lvalue. The set of expressions with this flag is the minimum
+ // that have to be promoted.
+ const HAS_STATIC_BORROWS = 1 << 4,
+ // Invalid const for miscellaneous reasons (e.g. not implemented).
+ const NOT_CONST = 1 << 5,
+
+ // Borrowing the expression won't produce &'static T if any of these
+ // bits are set, though the value could be copied from static memory
+ // if `NOT_CONST` isn't set.
+ const NON_STATIC_BORROWS = ConstQualif::MUTABLE_MEM.bits |
+ ConstQualif::NEEDS_DROP.bits |
+ ConstQualif::NOT_CONST.bits
+ }
+}
use back::svh::Svh;
use front::map as hir_map;
-use middle::def;
+use middle::def::{self, Def};
use middle::lang_items;
-use middle::ty::{self, Ty};
+use middle::ty::{self, Ty, VariantKind};
use middle::def_id::{DefId, DefIndex};
use mir::repr::Mir;
use session::Session;
// Something that a name can resolve to.
#[derive(Copy, Clone, Debug)]
pub enum DefLike {
- DlDef(def::Def),
+ DlDef(Def),
DlImpl(DefId),
DlField
}
// resolve
fn def_path(&self, def: DefId) -> hir_map::DefPath;
+ fn variant_kind(&self, def_id: DefId) -> Option<VariantKind>;
+ fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>;
fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>;
fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>;
fn item_children(&self, did: DefId) -> Vec<ChildItem>;
// resolve
fn def_path(&self, def: DefId) -> hir_map::DefPath { unimplemented!() }
+ fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> { unimplemented!() }
+ fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>
+ { unimplemented!() }
fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>
{ unimplemented!() }
fn struct_field_names(&self, def: DefId) -> Vec<ast::Name> { unimplemented!() }
use rustc_front::hir;
use rustc_front::intravisit::{self, Visitor};
-use middle::{def, pat_util, privacy, ty};
+use middle::{pat_util, privacy, ty};
+use middle::def::Def;
use middle::def_id::{DefId};
use lint;
self.tcx.def_map.borrow().get(id).map(|def| {
match def.full_def() {
- def::DefConst(_) | def::DefAssociatedConst(..) => {
+ Def::Const(_) | Def::AssociatedConst(..) => {
self.check_def_id(def.def_id());
}
_ if self.ignore_non_const_paths => (),
- def::DefPrimTy(_) => (),
- def::DefSelfTy(..) => (),
- def::DefVariant(enum_id, variant_id, _) => {
+ Def::PrimTy(_) => (),
+ Def::SelfTy(..) => (),
+ Def::Variant(enum_id, variant_id) => {
self.check_def_id(enum_id);
if !self.ignore_variant_stack.contains(&variant_id) {
self.check_def_id(variant_id);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub use self::Def::*;
-
use middle::def_id::DefId;
use middle::privacy::LastPrivate;
use middle::subst::ParamSpace;
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Def {
- DefFn(DefId, bool /* is_ctor */),
- DefSelfTy(Option<DefId>, // trait id
+ Fn(DefId),
+ SelfTy(Option<DefId>, // trait id
Option<(ast::NodeId, ast::NodeId)>), // (impl id, self type id)
- DefMod(DefId),
- DefForeignMod(DefId),
- DefStatic(DefId, bool /* is_mutbl */),
- DefConst(DefId),
- DefAssociatedConst(DefId),
- DefLocal(DefId, // def id of variable
+ Mod(DefId),
+ ForeignMod(DefId),
+ Static(DefId, bool /* is_mutbl */),
+ Const(DefId),
+ AssociatedConst(DefId),
+ Local(DefId, // def id of variable
ast::NodeId), // node id of variable
- DefVariant(DefId /* enum */, DefId /* variant */, bool /* is_structure */),
- DefTy(DefId, bool /* is_enum */),
- DefAssociatedTy(DefId /* trait */, DefId),
- DefTrait(DefId),
- DefPrimTy(hir::PrimTy),
- DefTyParam(ParamSpace, u32, DefId, ast::Name),
- DefUpvar(DefId, // def id of closed over local
+ Variant(DefId /* enum */, DefId /* variant */),
+ Enum(DefId),
+ TyAlias(DefId),
+ AssociatedTy(DefId /* trait */, DefId),
+ Trait(DefId),
+ PrimTy(hir::PrimTy),
+ TyParam(ParamSpace, u32, DefId, ast::Name),
+ Upvar(DefId, // def id of closed over local
ast::NodeId, // node id of closed over local
usize, // index in the freevars list of the closure
ast::NodeId), // expr node that creates the closure
- /// Note that if it's a tuple struct's definition, the node id of the DefId
- /// may either refer to the item definition's id or the VariantData.ctor_id.
- ///
- /// The cases that I have encountered so far are (this is not exhaustive):
- /// - If it's a ty_path referring to some tuple struct, then DefMap maps
- /// it to a def whose id is the item definition's id.
- /// - If it's an ExprPath referring to some tuple struct, then DefMap maps
- /// it to a def whose id is the VariantData.ctor_id.
- DefStruct(DefId),
- DefLabel(ast::NodeId),
- DefMethod(DefId),
- DefErr,
+ // If Def::Struct lives in type namespace it denotes a struct item and its DefId refers
+ // to NodeId of the struct itself.
+ // If Def::Struct lives in value namespace (e.g. tuple struct, unit struct expressions)
+ // it denotes a constructor and its DefId refers to NodeId of the struct's constructor.
+ Struct(DefId),
+ Label(ast::NodeId),
+ Method(DefId),
+ Err,
}
/// The result of resolving a path.
impl Def {
pub fn var_id(&self) -> ast::NodeId {
match *self {
- DefLocal(_, id) |
- DefUpvar(_, id, _, _) => {
+ Def::Local(_, id) |
+ Def::Upvar(_, id, _, _) => {
id
}
- DefFn(..) | DefMod(..) | DefForeignMod(..) | DefStatic(..) |
- DefVariant(..) | DefTy(..) | DefAssociatedTy(..) |
- DefTyParam(..) | DefStruct(..) | DefTrait(..) |
- DefMethod(..) | DefConst(..) | DefAssociatedConst(..) |
- DefPrimTy(..) | DefLabel(..) | DefSelfTy(..) | DefErr => {
+ Def::Fn(..) | Def::Mod(..) | Def::ForeignMod(..) | Def::Static(..) |
+ Def::Variant(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
+ Def::TyParam(..) | Def::Struct(..) | Def::Trait(..) |
+ Def::Method(..) | Def::Const(..) | Def::AssociatedConst(..) |
+ Def::PrimTy(..) | Def::Label(..) | Def::SelfTy(..) | Def::Err => {
panic!("attempted .def_id() on invalid {:?}", self)
}
}
pub fn def_id(&self) -> DefId {
match *self {
- DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) |
- DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
- DefTyParam(_, _, id, _) | DefStruct(id) | DefTrait(id) |
- DefMethod(id) | DefConst(id) | DefAssociatedConst(id) |
- DefLocal(id, _) | DefUpvar(id, _, _, _) => {
+ Def::Fn(id) | Def::Mod(id) | Def::ForeignMod(id) | Def::Static(id, _) |
+ Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) |
+ Def::TyParam(_, _, id, _) | Def::Struct(id) | Def::Trait(id) |
+ Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) |
+ Def::Local(id, _) | Def::Upvar(id, _, _, _) => {
id
}
- DefLabel(..) |
- DefPrimTy(..) |
- DefSelfTy(..) |
- DefErr => {
+ Def::Label(..) |
+ Def::PrimTy(..) |
+ Def::SelfTy(..) |
+ Def::Err => {
panic!("attempted .def_id() on invalid def: {:?}", self)
}
}
pub fn variant_def_ids(&self) -> Option<(DefId, DefId)> {
match *self {
- DefVariant(enum_id, var_id, _) => {
+ Def::Variant(enum_id, var_id) => {
Some((enum_id, var_id))
}
_ => None
//! `unsafe`.
use self::RootUnsafeContext::*;
-use middle::def;
+use middle::def::Def;
use middle::ty::{self, Ty};
use middle::ty::MethodCall;
self.require_unsafe(expr.span, "use of inline assembly");
}
hir::ExprPath(..) => {
- if let def::DefStatic(_, true) = self.tcx.resolve_expr(expr) {
+ if let Def::Static(_, true) = self.tcx.resolve_expr(expr) {
self.require_unsafe(expr.span, "use of mutable static");
}
}
use self::TrackMatchMode::*;
use self::OverloadedCallType::*;
-use middle::{def, pat_util};
+use middle::pat_util;
+use middle::def::Def;
use middle::def_id::{DefId};
use middle::infer;
use middle::mem_categorization as mc;
// struct or enum pattern.
}
- Some(def::DefVariant(enum_did, variant_did, _is_struct)) => {
+ Some(Def::Variant(enum_did, variant_did)) => {
let downcast_cmt =
if tcx.lookup_adt_def(enum_did).is_univariant() {
cmt_pat
delegate.matched_pat(pat, downcast_cmt, match_mode);
}
- Some(def::DefStruct(..)) | Some(def::DefTy(_, false)) => {
+ Some(Def::Struct(..)) | Some(Def::TyAlias(..)) => {
// A struct (in either the value or type
// namespace; we encounter the former on
// e.g. patterns for unit structs).
delegate.matched_pat(pat, cmt_pat, match_mode);
}
- Some(def::DefConst(..)) |
- Some(def::DefAssociatedConst(..)) |
- Some(def::DefLocal(..)) => {
+ Some(Def::Const(..)) |
+ Some(Def::AssociatedConst(..)) |
+ Some(Def::Local(..)) => {
// This is a leaf (i.e. identifier binding
// or constant value to match); thus no
// `matched_pat` call.
}
- Some(def @ def::DefTy(_, true)) => {
- // An enum's type -- should never be in a
- // pattern.
-
- if !tcx.sess.has_errors() {
- let msg = format!("Pattern has unexpected type: {:?} and type {:?}",
- def,
- cmt_pat.ty);
- tcx.sess.span_bug(pat.span, &msg)
- }
- }
-
Some(def) => {
- // Remaining cases are e.g. DefFn, to
+ // An enum type should never be in a pattern.
+ // Remaining cases are e.g. Def::Fn, to
// which identifiers within patterns
// should not resolve. However, we do
// encouter this when using the
fn cat_captured_var(&mut self,
closure_id: ast::NodeId,
closure_span: Span,
- upvar_def: def::Def)
+ upvar_def: Def)
-> mc::McResult<mc::cmt<'tcx>> {
// Create the cmt for the variable being borrowed, from the
// caller's perspective
use rustc_front::print::pprust;
use middle::cstore::CrateStore;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::infer::{self, TypeOrigin};
use middle::region;
Some(d) => d.full_def()
};
match a_def {
- def::DefTy(did, _) | def::DefStruct(did) => {
+ Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
let generics = self.tcx.lookup_item_type(did).generics;
let expected =
}
_ => ()
}
-
}
hir::TyPtr(ref mut_ty) => {
// except according to those terms.
use dep_graph::DepNode;
-use middle::def::DefFn;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::subst::{Subst, Substs, EnumeratedItems};
use middle::ty::{TransmuteRestriction, ctxt, TyBareFn};
fn visit_expr(&mut self, expr: &hir::Expr) {
if let hir::ExprPath(..) = expr.node {
match self.tcx.resolve_expr(expr) {
- DefFn(did, _) if self.def_id_is_transmute(did) => {
+ Def::Fn(did) if self.def_id_is_transmute(did) => {
let typ = self.tcx.node_id_to_type(expr.id);
match typ.sty {
TyBareFn(_, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
hir::ExprPath(..) => {
let def = ir.tcx.def_map.borrow().get(&expr.id).unwrap().full_def();
debug!("expr {}: path that leads to {:?}", expr.id, def);
- if let DefLocal(..) = def {
+ if let Def::Local(..) = def {
ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
}
intravisit::walk_expr(ir, expr);
let mut call_caps = Vec::new();
ir.tcx.with_freevars(expr.id, |freevars| {
for fv in freevars {
- if let DefLocal(_, rv) = fv.def {
+ if let Def::Local(_, rv) = fv.def {
let fv_ln = ir.add_live_node(FreeVarNode(fv.span));
call_caps.push(CaptureInfo {ln: fv_ln,
var_nid: rv});
// Refers to a labeled loop. Use the results of resolve
// to find with one
match self.ir.tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
- Some(DefLabel(loop_id)) => loop_id,
+ Some(Def::Label(loop_id)) => loop_id,
_ => self.ir.tcx.sess.span_bug(sp, "label on break/loop \
doesn't refer to a loop")
}
fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
-> LiveNode {
match self.ir.tcx.def_map.borrow().get(&expr.id).unwrap().full_def() {
- DefLocal(_, nid) => {
+ Def::Local(_, nid) => {
let ln = self.live_node(expr.id, expr.span);
if acc != 0 {
self.init_from_succ(ln, succ);
fn check_lvalue(&mut self, expr: &Expr) {
match expr.node {
hir::ExprPath(..) => {
- if let DefLocal(_, nid) = self.ir.tcx.def_map.borrow().get(&expr.id)
+ if let Def::Local(_, nid) = self.ir.tcx.def_map.borrow().get(&expr.id)
.unwrap()
.full_def() {
// Assignment to an immutable variable or argument: only legal
use middle::def_id::DefId;
use front::map as ast_map;
use middle::infer;
-use middle::check_const;
-use middle::def;
+use middle::const_qualif::ConstQualif;
+use middle::def::Def;
use middle::ty::adjustment;
use middle::ty::{self, Ty};
id: ast::NodeId,
span: Span,
expr_ty: Ty<'tcx>,
- def: def::Def)
+ def: Def)
-> McResult<cmt<'tcx>> {
debug!("cat_def: id={} expr={:?} def={:?}",
id, expr_ty, def);
match def {
- def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) |
- def::DefAssociatedConst(..) | def::DefFn(..) | def::DefMethod(..) => {
+ Def::Struct(..) | Def::Variant(..) | Def::Const(..) |
+ Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) => {
Ok(self.cat_rvalue_node(id, span, expr_ty))
}
- def::DefMod(_) | def::DefForeignMod(_) |
- def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
- def::DefTyParam(..) |
- def::DefLabel(_) | def::DefSelfTy(..) |
- def::DefAssociatedTy(..) => {
- Ok(Rc::new(cmt_ {
- id:id,
- span:span,
- cat:Categorization::StaticItem,
- mutbl: McImmutable,
- ty:expr_ty,
- note: NoteNone
- }))
+
+ Def::Mod(_) | Def::ForeignMod(_) |
+ Def::Trait(_) | Def::Enum(..) | Def::TyAlias(..) | Def::PrimTy(_) |
+ Def::TyParam(..) |
+ Def::Label(_) | Def::SelfTy(..) |
+ Def::AssociatedTy(..) => {
+ self.tcx().sess.span_bug(span, &format!("Unexpected definition in \
+ memory categorization: {:?}", def));
}
- def::DefStatic(_, mutbl) => {
+ Def::Static(_, mutbl) => {
Ok(Rc::new(cmt_ {
id:id,
span:span,
}))
}
- def::DefUpvar(_, var_id, _, fn_node_id) => {
+ Def::Upvar(_, var_id, _, fn_node_id) => {
let ty = try!(self.node_ty(fn_node_id));
match ty.sty {
ty::TyClosure(closure_id, _) => {
}
}
- def::DefLocal(_, vid) => {
+ Def::Local(_, vid) => {
Ok(Rc::new(cmt_ {
id: id,
span: span,
}))
}
- def::DefErr => panic!("DefErr in memory categorization")
+ Def::Err => panic!("Def::Err in memory categorization")
}
}
expr_ty: Ty<'tcx>)
-> cmt<'tcx> {
let qualif = self.tcx().const_qualif_map.borrow().get(&id).cloned()
- .unwrap_or(check_const::ConstQualif::NOT_CONST);
+ .unwrap_or(ConstQualif::NOT_CONST);
// Only promote `[T; 0]` before an RFC for rvalue promotions
// is accepted.
let qualif = match expr_ty.sty {
ty::TyArray(_, 0) => qualif,
- _ => check_const::ConstQualif::NOT_CONST
+ _ => ConstQualif::NOT_CONST
};
// Compute maximum lifetime of this rvalue. This is 'static if
// we can promote to a constant, otherwise equal to enclosing temp
// lifetime.
- let re = if qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS) {
+ let re = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.temporary_scope(id)
} else {
ty::ReStatic
(*op)(self, cmt.clone(), pat);
let opt_def = if let Some(path_res) = self.tcx().def_map.borrow().get(&pat.id) {
- if path_res.depth != 0 || path_res.base_def == def::DefErr {
+ if path_res.depth != 0 || path_res.base_def == Def::Err {
// Since patterns can be associated constants
// which are resolved during typeck, we might have
// some unresolved patterns reaching this stage
// alone) because struct patterns can refer to struct types or
// to struct variants within enums.
let cmt = match opt_def {
- Some(def::DefVariant(enum_did, variant_did, _))
+ Some(Def::Variant(enum_did, variant_did))
// univariant enums do not need downcasts
if !self.tcx().lookup_adt_def(enum_did).is_univariant() => {
self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did)
}
hir::PatEnum(_, Some(ref subpats)) => {
match opt_def {
- Some(def::DefVariant(..)) => {
+ Some(Def::Variant(..)) => {
// variant(x, y, z)
for (i, subpat) in subpats.iter().enumerate() {
let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
try!(self.cat_pattern_(subcmt, &**subpat, op));
}
}
- Some(def::DefStruct(..)) => {
+ Some(Def::Struct(..)) => {
for (i, subpat) in subpats.iter().enumerate() {
let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
let cmt_field =
try!(self.cat_pattern_(cmt_field, &**subpat, op));
}
}
- Some(def::DefConst(..)) | Some(def::DefAssociatedConst(..)) => {
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {
for subpat in subpats {
try!(self.cat_pattern_(cmt.clone(), &**subpat, op));
}
hir::PatIdent(_, _, None) |
hir::PatStruct(..) => {
match dm.get(&pat.id).map(|d| d.full_def()) {
- Some(DefVariant(..)) => true,
+ Some(Def::Variant(..)) => true,
_ => false
}
}
hir::PatIdent(_, _, None) |
hir::PatStruct(..) => {
match dm.get(&pat.id).map(|d| d.full_def()) {
- Some(DefVariant(..)) | Some(DefStruct(..)) => true,
+ Some(Def::Variant(..)) | Some(Def::Struct(..)) => true,
_ => false
}
}
match pat.node {
hir::PatIdent(_, _, None) | hir::PatEnum(..) | hir::PatQPath(..) => {
match dm.get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
_ => false
}
}
match dm.get(&pat.id)
.and_then(|d| if d.depth == 0 { Some(d.base_def) }
else { None } ) {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
_ => false
}
}
hir::PatIdent(_, _, None) |
hir::PatStruct(..) => {
match dm.get(&p.id) {
- Some(&PathResolution { base_def: DefVariant(_, id, _), .. }) => {
+ Some(&PathResolution { base_def: Def::Variant(_, id), .. }) => {
variants.push(id);
}
_ => ()
use dep_graph::DepNode;
use front::map as ast_map;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::ty;
use middle::privacy;
// 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::DefAssociatedConst(..) => {
+ Def::Const(..) | Def::AssociatedConst(..) => {
self.worklist.push(node_id);
}
use self::ScopeChain::*;
use session::Session;
-use middle::def::{self, DefMap};
+use middle::def::{Def, DefMap};
use middle::region;
use middle::subst;
use middle::ty;
// if this path references a trait, then this will resolve to
// a trait ref, which introduces a binding scope.
match self.def_map.get(&ty.id).map(|d| (d.base_def, d.depth)) {
- Some((def::DefTrait(..), 0)) => {
+ Some((Def::Trait(..), 0)) => {
self.with(LateScope(&[], self.scope), |_, this| {
this.visit_path(path, ty.id);
});
use session::Session;
use lint;
use middle::cstore::{CrateStore, LOCAL_CRATE};
-use middle::def;
+use middle::def::Def;
use middle::def_id::{CRATE_DEF_INDEX, DefId};
use middle::ty;
use middle::privacy::AccessLevels;
pub fn check_path(tcx: &ty::ctxt, path: &hir::Path, id: ast::NodeId,
cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option<Deprecation>)) {
match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
- Some(def::DefPrimTy(..)) => {}
- Some(def::DefSelfTy(..)) => {}
+ Some(Def::PrimTy(..)) => {}
+ Some(Def::SelfTy(..)) => {}
Some(def) => {
maybe_do_stability_check(tcx, def.def_id(), path.span, cb);
}
pub fn check_path_list_item(tcx: &ty::ctxt, item: &hir::PathListItem,
cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option<Deprecation>)) {
match tcx.def_map.borrow().get(&item.node.id()).map(|d| d.full_def()) {
- Some(def::DefPrimTy(..)) => {}
+ Some(Def::PrimTy(..)) => {}
Some(def) => {
maybe_do_stability_check(tcx, def.def_id(), item.span, cb);
}
pub use self::RegionSubsts::*;
use middle::cstore;
+use middle::def_id::DefId;
use middle::ty::{self, Ty};
use middle::ty::fold::{TypeFoldable, TypeFolder};
-> Substs<'tcx>
{
let Substs { types, regions } = self;
- let types = types.with_vec(FnSpace, m_types);
- let regions = regions.map(|r| r.with_vec(FnSpace, m_regions));
+ let types = types.with_slice(FnSpace, &m_types);
+ let regions = regions.map(|r| r.with_slice(FnSpace, &m_regions));
Substs { types: types, regions: regions }
}
- pub fn method_to_trait(self) -> Substs<'tcx> {
- let Substs { mut types, regions } = self;
+ pub fn with_method_from(self,
+ meth_substs: &Substs<'tcx>)
+ -> Substs<'tcx>
+ {
+ let Substs { types, regions } = self;
+ let types = types.with_slice(FnSpace, meth_substs.types.get_slice(FnSpace));
+ let regions = regions.map(|r| {
+ r.with_slice(FnSpace, meth_substs.regions().get_slice(FnSpace))
+ });
+ Substs { types: types, regions: regions }
+ }
+
+ /// Creates a trait-ref out of this substs, ignoring the FnSpace substs
+ pub fn to_trait_ref(&self, tcx: &ty::ctxt<'tcx>, trait_id: DefId)
+ -> ty::TraitRef<'tcx> {
+ let Substs { mut types, regions } = self.clone();
types.truncate(FnSpace, 0);
let regions = regions.map(|mut r| { r.truncate(FnSpace, 0); r });
- Substs { types: types, regions: regions }
+
+ ty::TraitRef {
+ def_id: trait_id,
+ substs: tcx.mk_substs(Substs { types: types, regions: regions })
+ }
}
}
}
}
- pub fn params_from_type(types: Vec<T>) -> VecPerParamSpace<T> {
- VecPerParamSpace::empty().with_vec(TypeSpace, types)
- }
-
/// `t` is the type space.
/// `s` is the self space.
/// `f` is the fn space.
}
}
- pub fn with_vec(mut self, space: ParamSpace, vec: Vec<T>)
+ pub fn with_slice(mut self, space: ParamSpace, slice: &[T])
-> VecPerParamSpace<T>
+ where T: Clone
{
assert!(self.is_empty_in(space));
- self.replace(space, vec);
+ for t in slice {
+ self.push(space, t.clone());
+ }
+
self
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use dep_graph::DepGraph;
use middle::infer::InferCtxt;
use middle::ty::{self, Ty, TypeFoldable};
use rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error};
use super::Unimplemented;
use super::util::predicate_for_builtin_bound;
-pub struct FulfilledPredicates<'tcx> {
+pub struct GlobalFulfilledPredicates<'tcx> {
+ set: FnvHashSet<ty::PolyTraitPredicate<'tcx>>,
+ dep_graph: DepGraph,
+}
+
+pub struct LocalFulfilledPredicates<'tcx> {
set: FnvHashSet<ty::Predicate<'tcx>>
}
// initially-distinct type variables are unified after being
// inserted. Deduplicating the predicate set on selection had a
// significant performance cost the last time I checked.
- duplicate_set: FulfilledPredicates<'tcx>,
+ duplicate_set: LocalFulfilledPredicates<'tcx>,
// A list of all obligations that have been registered with this
// fulfillment context.
/// Creates a new fulfillment context.
pub fn new() -> FulfillmentContext<'tcx> {
FulfillmentContext {
- duplicate_set: FulfilledPredicates::new(),
+ duplicate_set: LocalFulfilledPredicates::new(),
predicates: ObligationForest::new(),
region_obligations: NodeMap(),
}
// local cache). This is because the tcx cache maintains the
// invariant that it only contains things that have been
// proven, and we have not yet proven that `predicate` holds.
- if predicate.is_global() && tcx.fulfilled_predicates.borrow().is_duplicate(predicate) {
+ if tcx.fulfilled_predicates.borrow().check_duplicate(predicate) {
return true;
}
// these are obligations that were proven to be true.
for pending_obligation in outcome.completed {
let predicate = &pending_obligation.obligation.predicate;
- if predicate.is_global() {
- selcx.tcx().fulfilled_predicates.borrow_mut()
- .is_duplicate_or_add(predicate);
- }
+ selcx.tcx().fulfilled_predicates.borrow_mut().add_if_global(predicate);
}
errors.extend(
// However, this is a touch tricky, so I'm doing something
// a bit hackier for now so that the `huge-struct.rs` passes.
+ let tcx = selcx.tcx();
+
let retain_vec: Vec<_> = {
let mut dedup = FnvHashSet();
v.iter()
// Screen out obligations that we know globally
// are true. This should really be the DAG check
// mentioned above.
- if
- o.predicate.is_global() &&
- selcx.tcx().fulfilled_predicates.borrow().is_duplicate(&o.predicate)
- {
+ if tcx.fulfilled_predicates.borrow().check_duplicate(&o.predicate) {
return false;
}
}
-impl<'tcx> FulfilledPredicates<'tcx> {
- pub fn new() -> FulfilledPredicates<'tcx> {
- FulfilledPredicates {
+impl<'tcx> LocalFulfilledPredicates<'tcx> {
+ pub fn new() -> LocalFulfilledPredicates<'tcx> {
+ LocalFulfilledPredicates {
set: FnvHashSet()
}
}
- pub fn is_duplicate(&self, key: &ty::Predicate<'tcx>) -> bool {
- self.set.contains(key)
- }
-
fn is_duplicate_or_add(&mut self, key: &ty::Predicate<'tcx>) -> bool {
+ // For a `LocalFulfilledPredicates`, if we find a match, we
+ // don't need to add a read edge to the dep-graph. This is
+ // because it means that the predicate has already been
+ // considered by this `FulfillmentContext`, and hence the
+ // containing task will already have an edge. (Here we are
+ // assuming each `FulfillmentContext` only gets used from one
+ // task; but to do otherwise makes no sense)
!self.set.insert(key.clone())
}
}
+impl<'tcx> GlobalFulfilledPredicates<'tcx> {
+ pub fn new(dep_graph: DepGraph) -> GlobalFulfilledPredicates<'tcx> {
+ GlobalFulfilledPredicates {
+ set: FnvHashSet(),
+ dep_graph: dep_graph,
+ }
+ }
+
+ pub fn check_duplicate(&self, key: &ty::Predicate<'tcx>) -> bool {
+ if let ty::Predicate::Trait(ref data) = *key {
+ // For the global predicate registry, when we find a match, it
+ // may have been computed by some other task, so we want to
+ // add a read from the node corresponding to the predicate
+ // processing to make sure we get the transitive dependencies.
+ if self.set.contains(data) {
+ debug_assert!(data.is_global());
+ self.dep_graph.read(data.dep_node());
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ fn add_if_global(&mut self, key: &ty::Predicate<'tcx>) {
+ if let ty::Predicate::Trait(ref data) = *key {
+ // We only add things to the global predicate registry
+ // after the current task has proved them, and hence
+ // already has the required read edges, so we don't need
+ // to add any more edges here.
+ if data.is_global() {
+ self.set.insert(data.clone());
+ }
+ }
+ }
+}
+
fn to_fulfillment_error<'tcx>(
error: Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>)
-> FulfillmentError<'tcx>
pub use self::Vtable::*;
pub use self::ObligationCauseCode::*;
-use dep_graph::DepNode;
use middle::def_id::DefId;
use middle::free_region::FreeRegionMap;
use middle::subst;
use middle::ty::{self, Ty, TypeFoldable};
-use middle::ty::fast_reject;
use middle::infer::{self, fixup_err_to_string, InferCtxt};
use std::rc::Rc;
pub use self::coherence::orphan_check;
pub use self::coherence::overlapping_impls;
pub use self::coherence::OrphanCheckErr;
-pub use self::fulfill::{FulfillmentContext, FulfilledPredicates, RegionObligation};
+pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation};
pub use self::project::MismatchedProjectionTypes;
pub use self::project::normalize;
pub use self::project::Normalized;
}
impl<'tcx> TraitObligation<'tcx> {
- /// Creates the dep-node for selecting/evaluating this trait reference.
- fn dep_node(&self, tcx: &ty::ctxt<'tcx>) -> DepNode {
- let simplified_ty =
- fast_reject::simplify_type(tcx,
- self.predicate.skip_binder().self_ty(), // (*)
- true);
-
- // (*) skip_binder is ok because `simplify_type` doesn't care about regions
-
- DepNode::TraitSelect(self.predicate.def_id(), simplified_ty)
- }
-
fn self_ty(&self) -> ty::Binder<Ty<'tcx>> {
ty::Binder(self.predicate.skip_binder().self_ty())
}
debug!("select({:?})", obligation);
assert!(!obligation.predicate.has_escaping_regions());
- let dep_node = obligation.dep_node(self.tcx());
+ let dep_node = obligation.predicate.dep_node();
let _task = self.tcx().dep_graph.in_task(dep_node);
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
// have been proven elsewhere. This cache only contains
// predicates that are global in scope and hence unaffected by
// the current environment.
- if self.tcx().fulfilled_predicates.borrow().is_duplicate(&obligation.predicate) {
+ if self.tcx().fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) {
return EvaluatedToOk;
}
/// This is used to avoid duplicate work. Predicates are only
/// added to this set when they mention only "global" names
/// (i.e., no type or lifetime parameters).
- pub fulfilled_predicates: RefCell<traits::FulfilledPredicates<'tcx>>,
+ pub fulfilled_predicates: RefCell<traits::GlobalFulfilledPredicates<'tcx>>,
/// Caches the representation hints for struct definitions.
repr_hint_cache: RefCell<DepTrackingMap<maps::ReprHints<'tcx>>>,
/// Maps Expr NodeId's to their constant qualification.
- pub const_qualif_map: RefCell<NodeMap<middle::check_const::ConstQualif>>,
+ pub const_qualif_map: RefCell<NodeMap<middle::const_qualif::ConstQualif>>,
/// Caches CoerceUnsized kinds for impls on custom types.
pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>,
let interner = RefCell::new(FnvHashMap());
let common_types = CommonTypes::new(&arenas.type_, &interner);
let dep_graph = DepGraph::new(s.opts.incremental_compilation);
+ let fulfilled_predicates = traits::GlobalFulfilledPredicates::new(dep_graph.clone());
tls::enter(ctxt {
arenas: arenas,
interner: interner,
adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
super_predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
- fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()),
+ fulfilled_predicates: RefCell::new(fulfilled_predicates),
map: map,
freevars: RefCell::new(freevars),
tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
use front::map::LinkedPath;
use middle;
use middle::cstore::{self, CrateStore, LOCAL_CRATE};
-use middle::def::{self, ExportMap};
+use middle::def::{self, Def, ExportMap};
use middle::def_id::DefId;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::region::{CodeExtent};
#[derive(Copy, Clone)]
pub struct ClosureUpvar<'tcx> {
- pub def: def::Def,
+ pub def: Def,
pub span: Span,
pub ty: Ty<'tcx>,
}
self.trait_ref.def_id
}
+ /// Creates the dep-node for selecting/evaluating this trait reference.
+ fn dep_node(&self) -> DepNode {
+ DepNode::TraitSelect(self.def_id())
+ }
+
pub fn input_types(&self) -> &[Ty<'tcx>] {
self.trait_ref.substs.types.as_slice()
}
impl<'tcx> PolyTraitPredicate<'tcx> {
pub fn def_id(&self) -> DefId {
+ // ok to skip binder since trait def-id does not care about regions
self.0.def_id()
}
+
+ pub fn dep_node(&self) -> DepNode {
+ // ok to skip binder since depnode does not care about regions
+ self.0.dep_node()
+ }
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum AdtKind { Struct, Enum }
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum VariantKind { Struct, Tuple, Unit }
+impl VariantKind {
+ pub fn from_variant_data(vdata: &hir::VariantData) -> Self {
+ match *vdata {
+ hir::VariantData::Struct(..) => VariantKind::Struct,
+ hir::VariantData::Tuple(..) => VariantKind::Tuple,
+ hir::VariantData::Unit(..) => VariantKind::Unit,
+ }
+ }
+}
+
impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
fn new(tcx: &ctxt<'tcx>,
did: DefId,
.expect("variant_index_with_id: unknown variant")
}
- pub fn variant_of_def(&self, def: def::Def) -> &VariantDefData<'tcx, 'container> {
+ pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'tcx, 'container> {
match def {
- def::DefVariant(_, vid, _) => self.variant_with_id(vid),
- def::DefStruct(..) | def::DefTy(..) => self.struct_variant(),
+ Def::Variant(_, vid) => self.variant_with_id(vid),
+ Def::Struct(..) | Def::TyAlias(..) => self.struct_variant(),
_ => panic!("unexpected def {:?} in variant_of_def", def)
}
}
}
}
- pub fn resolve_expr(&self, expr: &hir::Expr) -> def::Def {
+ pub fn resolve_expr(&self, expr: &hir::Expr) -> Def {
match self.def_map.borrow().get(&expr.id) {
Some(def) => def.full_def(),
None => {
// rvalues.
match self.def_map.borrow().get(&expr.id) {
Some(&def::PathResolution {
- base_def: def::DefStatic(..), ..
+ base_def: Def::Static(..), ..
}) | Some(&def::PathResolution {
- base_def: def::DefUpvar(..), ..
+ base_def: Def::Upvar(..), ..
}) | Some(&def::PathResolution {
- base_def: def::DefLocal(..), ..
+ base_def: Def::Local(..), ..
}) => {
true
}
- Some(&def::PathResolution { base_def: def::DefErr, .. })=> true,
+ Some(&def::PathResolution { base_def: Def::Err, .. })=> true,
Some(..) => false,
None => self.sess.span_bug(expr.span, &format!(
"no def for path {}", expr.id))
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct Freevar {
/// The variable being accessed free.
- pub def: def::Def,
+ pub def: Def,
// First span where it is accessed (there can be multiple).
pub span: Span
}
impl<'tcx> ty::ctxt<'tcx> {
- #[inline(never)] // is this perfy enough?
pub fn get_impl_method(&self,
impl_def_id: DefId,
substs: Substs<'tcx>,
Use(Operand<'tcx>),
// [x; 32]
- Repeat(Operand<'tcx>, Constant<'tcx>),
+ Repeat(Operand<'tcx>, TypedConstVal<'tcx>),
// &x or &mut x
Ref(Region, BorrowKind, Lvalue<'tcx>),
pub literal: Literal<'tcx>,
}
+#[derive(Clone, RustcEncodable, RustcDecodable)]
+pub struct TypedConstVal<'tcx> {
+ pub ty: Ty<'tcx>,
+ pub span: Span,
+ pub value: ConstVal
+}
+
+impl<'tcx> Debug for TypedConstVal<'tcx> {
+ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
+ try!(write!(fmt, "const "));
+ fmt_const_val(fmt, &self.value)
+ }
+}
+
#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum ItemKind {
Constant,
}
Rvalue::Repeat(ref $($mutability)* value,
- ref $($mutability)* len) => {
+ _) => {
self.visit_operand(value);
- self.visit_constant(len);
}
Rvalue::Ref(r, bk, ref $($mutability)* path) => {
let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
let y = x.clone();
x.borrow_mut().s = 6;
- println!("{}", x.borrow.s);
+ println!("{}", x.borrow().s);
}
```
(self.data[word] & mask) != 0
}
+ /// Returns true if the bit has changed.
pub fn insert(&mut self, bit: usize) -> bool {
let (word, mask) = word_mask(bit);
let data = &mut self.data[word];
let value = *data;
- *data = value | mask;
- (value | mask) != value
+ let new_value = value | mask;
+ *data = new_value;
+ new_value != value
}
pub fn insert_all(&mut self, all: &BitVector) -> bool {
use rustc_plugin as plugin;
use rustc_front::hir;
use rustc_front::lowering::{lower_crate, LoweringContext};
+use rustc_passes::{no_asm, loops, consts, const_fn, rvalues, static_recursion};
use super::Compilation;
use serialize::json;
time(time_passes,
"checking for inline asm in case the target doesn't support it",
- || ::rustc_passes::no_asm::check_crate(sess, &krate));
+ || no_asm::check_crate(sess, &krate));
// One final feature gating of the true AST that gets compiled
// later, to make sure we've got everything (e.g. configuration
time(time_passes,
"const fn bodies and arguments",
- || ::rustc_passes::const_fn::check_crate(sess, &krate));
+ || const_fn::check_crate(sess, &krate));
if sess.opts.debugging_opts.input_stats {
println!("Post-expansion node count: {}", count_nodes(&krate));
time(time_passes,
"loop checking",
- || middle::check_loop::check_crate(sess, krate));
+ || loops::check_crate(sess, krate));
time(time_passes,
"static item recursion checking",
- || middle::check_static_recursion::check_crate(sess, krate, &def_map.borrow(), &hir_map));
+ || static_recursion::check_crate(sess, krate, &def_map.borrow(), &hir_map));
ty::ctxt::create_and_enter(sess,
arenas,
time(time_passes,
"const checking",
- || middle::check_const::check_crate(tcx));
+ || consts::check_crate(tcx));
let access_levels =
time(time_passes, "privacy checking", || {
time(time_passes,
"rvalue checking",
- || middle::check_rvalues::check_crate(tcx));
+ || rvalues::check_crate(tcx));
// Avoid overwhelming user with errors if type checking failed.
// I'm not sure how helpful this is, to be honest, but it avoids
cached_id: Cell<u32>,
// Keep track of gensym'ed idents.
gensym_cache: RefCell<HashMap<(NodeId, &'static str), hir::Ident>>,
- // A copy of cached_id, but is also set to an id while it is being cached.
+ // A copy of cached_id, but is also set to an id while a node is lowered for
+ // the first time.
gensym_key: Cell<u32>,
}
}
fn next_id(&self) -> NodeId {
- let cached = self.cached_id.get();
- if cached == 0 {
+ let cached_id = self.cached_id.get();
+ if cached_id == 0 {
return self.id_assigner.next_node_id();
}
- self.cached_id.set(cached + 1);
- cached
+ self.cached_id.set(cached_id + 1);
+ cached_id
}
fn str_to_ident(&self, s: &'static str) -> hir::Ident {
- let cached_id = self.gensym_key.get();
- if cached_id == 0 {
+ let gensym_key = self.gensym_key.get();
+ if gensym_key == 0 {
return hir::Ident::from_name(token::gensym(s));
}
- let cached = self.gensym_cache.borrow().contains_key(&(cached_id, s));
+ let cached = self.gensym_cache.borrow().contains_key(&(gensym_key, s));
if cached {
- self.gensym_cache.borrow()[&(cached_id, s)]
+ self.gensym_cache.borrow()[&(gensym_key, s)]
} else {
let result = hir::Ident::from_name(token::gensym(s));
- self.gensym_cache.borrow_mut().insert((cached_id, s), result);
+ self.gensym_cache.borrow_mut().insert((gensym_key, s), result);
result
}
}
}
+// Utility fn for setting and unsetting the cached id.
+fn cache_ids<'a, OP, R>(lctx: &LoweringContext, expr_id: NodeId, op: OP) -> R
+ where OP: FnOnce(&LoweringContext) -> R
+{
+ // Only reset the id if it was previously 0, i.e., was not cached.
+ // If it was cached, we are in a nested node, but our id count will
+ // still count towards the parent's count.
+ let reset_cached_id = lctx.cached_id.get() == 0;
+ // We always reset gensym_key so that if we use the same name in a nested
+ // node and after that node, they get different values.
+ let old_gensym_key = lctx.gensym_key.get();
+
+ {
+ let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut();
+
+ if id_cache.contains_key(&expr_id) {
+ let cached_id = lctx.cached_id.get();
+ if cached_id == 0 {
+ // We're entering a node where we need to track ids, but are not
+ // yet tracking.
+ lctx.cached_id.set(id_cache[&expr_id]);
+ } else {
+ // We're already tracking - check that the tracked id is the same
+ // as the expected id.
+ assert!(cached_id == id_cache[&expr_id], "id mismatch");
+ }
+ lctx.gensym_key.set(id_cache[&expr_id]);
+ } else {
+ // We've never lowered this node before, remember it for next time.
+ let next_id = lctx.id_assigner.peek_node_id();
+ id_cache.insert(expr_id, next_id);
+ lctx.gensym_key.set(next_id);
+ // self.cached_id is not set when we lower a node for the first time,
+ // only on re-lowering.
+ }
+ }
+
+ let result = op(lctx);
+
+ if reset_cached_id {
+ lctx.cached_id.set(0);
+ }
+ lctx.gensym_key.set(old_gensym_key);
+
+ result
+}
+
pub fn lower_ident(_lctx: &LoweringContext, ident: Ident) -> hir::Ident {
hir::Ident {
name: mtwt::resolve(ident),
})
}
-// Utility fn for setting and unsetting the cached id.
-fn cache_ids<'a, OP, R>(lctx: &LoweringContext, expr_id: NodeId, op: OP) -> R
- where OP: FnOnce(&LoweringContext) -> R
-{
- // Only reset the id if it was previously 0, i.e., was not cached.
- // If it was cached, we are in a nested node, but our id count will
- // still count towards the parent's count.
- let reset_cached_id = lctx.cached_id.get() == 0;
-
- {
- let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut();
-
- if id_cache.contains_key(&expr_id) {
- let cached_id = lctx.cached_id.get();
- if cached_id == 0 {
- // We're entering a node where we need to track ids, but are not
- // yet tracking.
- lctx.cached_id.set(id_cache[&expr_id]);
- lctx.gensym_key.set(id_cache[&expr_id]);
- } else {
- // We're already tracking - check that the tracked id is the same
- // as the expected id.
- assert!(cached_id == id_cache[&expr_id], "id mismatch");
- }
- } else {
- let next_id = lctx.id_assigner.peek_node_id();
- id_cache.insert(expr_id, next_id);
- lctx.gensym_key.set(next_id);
- }
- }
-
- let result = op(lctx);
-
- if reset_cached_id {
- lctx.cached_id.set(0);
- lctx.gensym_key.set(0);
- }
-
- result
-}
-
pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
P(hir::Expr {
id: e.id,
let ast_while_let = assigner.fold_expr(ast_while_let);
let ast_for = quote_expr!(&cx,
for i in 0..10 {
- foo(i);
+ for j in 0..10 {
+ foo(i, j);
+ }
});
let ast_for = assigner.fold_expr(ast_for);
let ast_in = quote_expr!(&cx, in HEAP { foo() });
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use middle::def;
+use middle::def::Def;
use middle::ty;
use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass};
fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
if let &hir::PatIdent(_, ref path1, _) = &p.node {
let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
- if let Some(def::DefLocal(..)) = def {
+ if let Some(Def::Local(..)) = def {
self.check_snake_case(cx, "variable", &path1.node.name.as_str(), Some(p.span));
}
}
fn check_pat(&mut self, cx: &LateContext, p: &hir::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())) {
- (&hir::PatIdent(_, ref path1, _), Some(def::DefConst(..))) => {
+ (&hir::PatIdent(_, ref path1, _), Some(Def::Const(..))) => {
NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
path1.node.name, p.span);
}
//! Use the former for unit-like structs and the latter for structs with
//! a `pub fn new()`.
-use middle::{cfg, def, infer, stability, traits};
+use middle::{cfg, infer, stability, traits};
+use middle::def::Def;
use middle::cstore::CrateStore;
use middle::def_id::DefId;
use middle::subst::Substs;
}
let def = def_map.get(&fieldpat.node.pat.id).map(|d| d.full_def());
if let Some(def_id) = cx.tcx.map.opt_local_def_id(fieldpat.node.pat.id) {
- def == Some(def::DefLocal(def_id, fieldpat.node.pat.id))
+ def == Some(Def::Local(def_id, fieldpat.node.pat.id))
} else {
false
}
match tcx.map.get(id) {
hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
match tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()) {
- Some(def::DefMethod(def_id)) => {
+ Some(Def::Method(def_id)) => {
let item_substs =
tcx.tables.borrow().item_substs
.get(&callee.id)
// A trait method, from any number of possible sources.
// Attempt to select a concrete impl before checking.
ty::TraitContainer(trait_def_id) => {
- let trait_substs = callee_substs.clone().method_to_trait();
- let trait_substs = tcx.mk_substs(trait_substs);
- let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
+ let trait_ref = callee_substs.to_trait_ref(tcx, trait_def_id);
let trait_ref = ty::Binder(trait_ref);
let span = tcx.map.span(expr_id);
let obligation =
hir::ExprPath(..) => (),
_ => return None
}
- if let def::DefFn(did, _) = cx.tcx.resolve_expr(expr) {
+ if let Def::Fn(did) = cx.tcx.resolve_expr(expr) {
if !def_id_is_transmute(cx, did) {
return None;
}
use middle::cstore::{InlinedItem, InlinedItemRef};
use middle::ty::adjustment;
use middle::ty::cast;
-use middle::check_const::ConstQualif;
-use middle::def;
+use middle::const_qualif::ConstQualif;
+use middle::def::{self, Def};
use middle::def_id::DefId;
use middle::privacy::{AllPublic, LastMod};
use middle::region;
// ______________________________________________________________________
// Encoding and decoding of ast::def
-fn decode_def(dcx: &DecodeContext, dsr: &mut reader::Decoder) -> def::Def {
- let def: def::Def = Decodable::decode(dsr).unwrap();
+fn decode_def(dcx: &DecodeContext, dsr: &mut reader::Decoder) -> Def {
+ let def: Def = Decodable::decode(dsr).unwrap();
def.tr(dcx)
}
-impl tr for def::Def {
- fn tr(&self, dcx: &DecodeContext) -> def::Def {
+impl tr for Def {
+ fn tr(&self, dcx: &DecodeContext) -> Def {
match *self {
- def::DefFn(did, is_ctor) => def::DefFn(did.tr(dcx), is_ctor),
- def::DefMethod(did) => def::DefMethod(did.tr(dcx)),
- def::DefSelfTy(opt_did, impl_ids) => { def::DefSelfTy(opt_did.map(|did| did.tr(dcx)),
+ Def::Fn(did) => Def::Fn(did.tr(dcx)),
+ Def::Method(did) => Def::Method(did.tr(dcx)),
+ Def::SelfTy(opt_did, impl_ids) => { Def::SelfTy(opt_did.map(|did| did.tr(dcx)),
impl_ids.map(|(nid1, nid2)| {
(dcx.tr_id(nid1),
dcx.tr_id(nid2))
})) }
- def::DefMod(did) => { def::DefMod(did.tr(dcx)) }
- 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) => def::DefAssociatedConst(did.tr(dcx)),
- def::DefLocal(_, nid) => {
+ Def::Mod(did) => { Def::Mod(did.tr(dcx)) }
+ Def::ForeignMod(did) => { Def::ForeignMod(did.tr(dcx)) }
+ Def::Static(did, m) => { Def::Static(did.tr(dcx), m) }
+ Def::Const(did) => { Def::Const(did.tr(dcx)) }
+ Def::AssociatedConst(did) => Def::AssociatedConst(did.tr(dcx)),
+ Def::Local(_, nid) => {
let nid = dcx.tr_id(nid);
let did = dcx.tcx.map.local_def_id(nid);
- def::DefLocal(did, nid)
+ Def::Local(did, nid)
}
- def::DefVariant(e_did, v_did, is_s) => {
- def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s)
- },
- def::DefTrait(did) => def::DefTrait(did.tr(dcx)),
- def::DefTy(did, is_enum) => def::DefTy(did.tr(dcx), is_enum),
- def::DefAssociatedTy(trait_did, did) =>
- def::DefAssociatedTy(trait_did.tr(dcx), did.tr(dcx)),
- def::DefPrimTy(p) => def::DefPrimTy(p),
- def::DefTyParam(s, index, def_id, n) => def::DefTyParam(s, index, def_id.tr(dcx), n),
- def::DefUpvar(_, nid1, index, nid2) => {
+ Def::Variant(e_did, v_did) => Def::Variant(e_did.tr(dcx), v_did.tr(dcx)),
+ Def::Trait(did) => Def::Trait(did.tr(dcx)),
+ Def::Enum(did) => Def::Enum(did.tr(dcx)),
+ Def::TyAlias(did) => Def::TyAlias(did.tr(dcx)),
+ Def::AssociatedTy(trait_did, did) =>
+ Def::AssociatedTy(trait_did.tr(dcx), did.tr(dcx)),
+ Def::PrimTy(p) => Def::PrimTy(p),
+ Def::TyParam(s, index, def_id, n) => Def::TyParam(s, index, def_id.tr(dcx), n),
+ Def::Upvar(_, nid1, index, nid2) => {
let nid1 = dcx.tr_id(nid1);
let nid2 = dcx.tr_id(nid2);
let did1 = dcx.tcx.map.local_def_id(nid1);
- def::DefUpvar(did1, nid1, index, nid2)
+ Def::Upvar(did1, nid1, index, nid2)
}
- def::DefStruct(did) => def::DefStruct(did.tr(dcx)),
- def::DefLabel(nid) => def::DefLabel(dcx.tr_id(nid)),
- def::DefErr => def::DefErr,
+ Def::Struct(did) => Def::Struct(did.tr(dcx)),
+ Def::Label(nid) => Def::Label(dcx.tr_id(nid)),
+ Def::Err => Def::Err,
}
}
}
use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
use middle::def;
use middle::lang_items;
-use middle::ty::{self, Ty};
+use middle::ty::{self, Ty, VariantKind};
use middle::def_id::{DefId, DefIndex};
use rustc::front::map as hir_map;
local_path.into_iter().chain(path).collect()
}
+ fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> {
+ let cdata = self.get_crate_data(def_id.krate);
+ decoder::get_variant_kind(&cdata, def_id.index)
+ }
+
+ fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>
+ {
+ let cdata = self.get_crate_data(struct_def_id.krate);
+ decoder::get_struct_ctor_def_id(&cdata, struct_def_id.index)
+ }
+
fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>
{
let cdata = self.get_crate_data(did.krate);
use middle::cstore::{LOCAL_CRATE, FoundAst, InlinedItem, LinkagePreference};
use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls};
-use middle::def;
+use middle::def::Def;
use middle::def_id::{DefId, DefIndex};
use middle::lang_items;
use middle::subst;
use middle::ty::{ImplContainer, TraitContainer};
-use middle::ty::{self, Ty, TypeFoldable};
+use middle::ty::{self, Ty, TypeFoldable, VariantKind};
use rustc::mir;
use rustc::mir::visit::MutVisitor;
index::DenseIndex::from_buf(index.data, index.start, index.end)
}
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq)]
enum Family {
ImmStatic, // c
MutStatic, // b
Fn, // f
- CtorFn, // o
StaticMethod, // F
Method, // h
Type, // y
Mod, // m
ForeignMod, // n
Enum, // t
- StructVariant, // V
- TupleVariant, // v
- UnitVariant, // w
+ Variant(VariantKind), // V, v, w
Impl, // i
DefaultImpl, // d
Trait, // I
- Struct, // S
- TupleStruct, // s
- UnitStruct, // u
+ Struct(VariantKind), // S, s, u
PublicField, // g
InheritedField, // N
Constant, // C
'c' => ImmStatic,
'b' => MutStatic,
'f' => Fn,
- 'o' => CtorFn,
'F' => StaticMethod,
'h' => Method,
'y' => Type,
'm' => Mod,
'n' => ForeignMod,
't' => Enum,
- 'V' => StructVariant,
- 'v' => TupleVariant,
- 'w' => UnitVariant,
+ 'V' => Variant(VariantKind::Struct),
+ 'v' => Variant(VariantKind::Tuple),
+ 'w' => Variant(VariantKind::Unit),
'i' => Impl,
'd' => DefaultImpl,
'I' => Trait,
- 'S' => Struct,
- 's' => TupleStruct,
- 'u' => UnitStruct,
+ 'S' => Struct(VariantKind::Struct),
+ 's' => Struct(VariantKind::Tuple),
+ 'u' => Struct(VariantKind::Unit),
'g' => PublicField,
'N' => InheritedField,
c => panic!("unexpected family char: {}", c)
}
}
+fn family_to_variant_kind<'tcx>(family: Family) -> Option<ty::VariantKind> {
+ match family {
+ Struct(VariantKind::Struct) | Variant(VariantKind::Struct) =>
+ Some(ty::VariantKind::Struct),
+ Struct(VariantKind::Tuple) | Variant(VariantKind::Tuple) =>
+ Some(ty::VariantKind::Tuple),
+ Struct(VariantKind::Unit) | Variant(VariantKind::Unit) =>
+ Some(ty::VariantKind::Unit),
+ _ => None,
+ }
+}
+
fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike {
let fam = item_family(item);
match fam {
// Check whether we have an associated const item.
match item_sort(item) {
Some('C') | Some('c') => {
- DlDef(def::DefAssociatedConst(did))
+ DlDef(Def::AssociatedConst(did))
}
_ => {
// Regular const item.
- DlDef(def::DefConst(did))
+ DlDef(Def::Const(did))
}
}
}
- ImmStatic => DlDef(def::DefStatic(did, false)),
- MutStatic => DlDef(def::DefStatic(did, true)),
- Struct | TupleStruct | UnitStruct => DlDef(def::DefStruct(did)),
- Fn => DlDef(def::DefFn(did, false)),
- CtorFn => DlDef(def::DefFn(did, true)),
+ ImmStatic => DlDef(Def::Static(did, false)),
+ MutStatic => DlDef(Def::Static(did, true)),
+ Struct(..) => DlDef(Def::Struct(did)),
+ Fn => DlDef(Def::Fn(did)),
Method | StaticMethod => {
- DlDef(def::DefMethod(did))
+ DlDef(Def::Method(did))
}
Type => {
if item_sort(item) == Some('t') {
let trait_did = item_require_parent_item(cdata, item);
- DlDef(def::DefAssociatedTy(trait_did, did))
+ DlDef(Def::AssociatedTy(trait_did, did))
} else {
- DlDef(def::DefTy(did, false))
+ DlDef(Def::TyAlias(did))
}
}
- Mod => DlDef(def::DefMod(did)),
- ForeignMod => DlDef(def::DefForeignMod(did)),
- StructVariant => {
+ Mod => DlDef(Def::Mod(did)),
+ ForeignMod => DlDef(Def::ForeignMod(did)),
+ Variant(..) => {
let enum_did = item_require_parent_item(cdata, item);
- DlDef(def::DefVariant(enum_did, did, true))
+ DlDef(Def::Variant(enum_did, did))
}
- TupleVariant | UnitVariant => {
- let enum_did = item_require_parent_item(cdata, item);
- DlDef(def::DefVariant(enum_did, did, false))
- }
- Trait => DlDef(def::DefTrait(did)),
- Enum => DlDef(def::DefTy(did, true)),
+ Trait => DlDef(Def::Trait(did)),
+ Enum => DlDef(Def::Enum(did)),
Impl | DefaultImpl => DlImpl(did),
PublicField | InheritedField => DlField,
}
item_id: DefIndex,
tcx: &ty::ctxt<'tcx>) -> ty::AdtDefMaster<'tcx>
{
- fn family_to_variant_kind<'tcx>(family: Family, tcx: &ty::ctxt<'tcx>) -> ty::VariantKind {
- match family {
- Struct | StructVariant => ty::VariantKind::Struct,
- TupleStruct | TupleVariant => ty::VariantKind::Tuple,
- UnitStruct | UnitVariant => ty::VariantKind::Unit,
+ fn expect_variant_kind<'tcx>(family: Family, tcx: &ty::ctxt<'tcx>) -> ty::VariantKind {
+ match family_to_variant_kind(family) {
+ Some(kind) => kind,
_ => tcx.sess.bug(&format!("unexpected family: {:?}", family)),
}
}
name: item_name(intr, item),
fields: get_variant_fields(intr, cdata, item, tcx),
disr_val: disr,
- kind: family_to_variant_kind(item_family(item), tcx),
+ kind: expect_variant_kind(item_family(item), tcx),
}
}).collect()
}
name: item_name(intr, doc),
fields: get_variant_fields(intr, cdata, doc, tcx),
disr_val: 0,
- kind: family_to_variant_kind(item_family(doc), tcx),
+ kind: expect_variant_kind(item_family(doc), tcx),
}
}
(ty::AdtKind::Enum,
get_enum_variants(intr, cdata, doc, tcx))
}
- Struct | TupleStruct | UnitStruct => {
+ Struct(..) => {
let ctor_did =
reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).
map_or(did, |ctor_doc| translated_def_id(cdata, ctor_doc));
}).collect()
}
+pub fn get_variant_kind(cdata: Cmd, node_id: DefIndex) -> Option<VariantKind>
+{
+ let item = cdata.lookup_item(node_id);
+ family_to_variant_kind(item_family(item))
+}
+
+pub fn get_struct_ctor_def_id(cdata: Cmd, node_id: DefIndex) -> Option<DefId>
+{
+ let item = cdata.lookup_item(node_id);
+ reader::maybe_get_doc(item, tag_items_data_item_struct_ctor).
+ map(|ctor_doc| translated_def_id(cdata, ctor_doc))
+}
+
/// If node_id is the constructor of a tuple struct, retrieve the NodeId of
/// the actual type definition, otherwise, return None
pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd,
fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
name: Name,
- ctor_id: NodeId,
+ struct_def: &hir::VariantData,
index: &mut CrateIndex<'tcx>,
struct_id: NodeId) {
+ let ctor_id = struct_def.id();
let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id);
index.record(ctor_def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, ctor_def_id);
- encode_family(rbml_w, 'o');
+ encode_family(rbml_w, match *struct_def {
+ hir::VariantData::Struct(..) => 'S',
+ hir::VariantData::Tuple(..) => 's',
+ hir::VariantData::Unit(..) => 'u',
+ });
encode_bounds_and_type_for_item(rbml_w, ecx, index, ctor_id);
encode_name(rbml_w, name);
ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path));
// If this is a tuple-like struct, encode the type of the constructor.
if !struct_def.is_struct() {
- encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def.id(), index, item.id);
+ encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def, index, item.id);
}
}
hir::ItemDefaultImpl(unsafety, _) => {
}
let dypair = self.dylibname();
+ let staticpair = self.staticlibname();
// want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
let dylib_prefix = format!("{}{}", dypair.0, self.crate_name);
let rlib_prefix = format!("lib{}", self.crate_name);
- let staticlib_prefix = format!("lib{}", self.crate_name);
+ let staticlib_prefix = format!("{}{}", staticpair.0, self.crate_name);
let mut candidates = HashMap::new();
let mut staticlibs = vec!();
false)
} else {
if file.starts_with(&staticlib_prefix[..]) &&
- file.ends_with(".a") {
+ file.ends_with(&staticpair.1) {
staticlibs.push(CrateMismatch {
path: path.to_path_buf(),
got: "static".to_string()
(t.options.dll_prefix.clone(), t.options.dll_suffix.clone())
}
+ // Returns the corresponding (prefix, suffix) that files need to have for
+ // static libraries
+ fn staticlibname(&self) -> (String, String) {
+ let t = &self.target;
+ (t.options.staticlib_prefix.clone(), t.options.staticlib_suffix.clone())
+ }
+
fn find_commandline_library(&mut self, locs: &[String]) -> Option<Library> {
// First, filter out all libraries that look suspicious. We only accept
// files which actually exist that have the correct naming scheme for
}
ExprKind::Repeat { value, count } => {
let value_operand = unpack!(block = this.as_operand(block, value));
- let count = this.as_constant(count);
block.and(Rvalue::Repeat(value_operand, count))
}
ExprKind::Borrow { region, borrow_kind, arg } => {
// start the loop
this.cfg.terminate(block, Terminator::Goto { target: loop_block });
- this.in_loop_scope(loop_block, exit_block, |this| {
+ let might_break = this.in_loop_scope(loop_block, exit_block, move |this| {
// conduct the test, if necessary
let body_block;
- let opt_cond_expr = opt_cond_expr; // FIXME rustc bug
if let Some(cond_expr) = opt_cond_expr {
+ // This loop has a condition, ergo its exit_block is reachable.
+ this.find_loop_scope(expr_span, None).might_break = true;
+
let loop_block_end;
let cond = unpack!(loop_block_end = this.as_operand(loop_block, cond_expr));
body_block = this.cfg.start_new_block();
body_block = loop_block;
}
- // execute the body, branching back to the test
- // We write body’s “return value” into the destination of loop. This is fine,
- // because:
- //
- // * In Rust both loop expression and its body are required to have `()`
- // as the “return value”;
- // * The destination will be considered uninitialised (given it was
- // uninitialised before the loop) during the first iteration, thus
- // disallowing its use inside the body. Alternatively, if it was already
- // initialised, the `destination` can only possibly have a value of `()`,
- // therefore, “mutating” the destination during iteration is fine.
- let body_block_end = unpack!(this.into(destination, body_block, body));
+ // The “return” value of the loop body must always be an unit, but we cannot
+ // reuse that as a “return” value of the whole loop expressions, because some
+ // loops are diverging (e.g. `loop {}`). Thus, we introduce a unit temporary as
+ // the destination for the loop body and assign the loop’s own “return” value
+ // immediately after the iteration is finished.
+ let tmp = this.get_unit_temp();
+ // Execute the body, branching back to the test.
+ let body_block_end = unpack!(this.into(&tmp, body_block, body));
this.cfg.terminate(body_block_end, Terminator::Goto { target: loop_block });
- exit_block.unit()
- })
+ });
+ // If the loop may reach its exit_block, we assign an empty tuple to the
+ // destination to keep the MIR well-formed.
+ if might_break {
+ this.cfg.push_assign_unit(exit_block, expr_span, destination);
+ }
+ exit_block.unit()
}
ExprKind::Assign { lhs, rhs } => {
// Note: we evaluate assignments right-to-left. This
|loop_scope| loop_scope.continue_block)
}
ExprKind::Break { label } => {
- this.break_or_continue(expr_span, label, block, |loop_scope| loop_scope.break_block)
+ this.break_or_continue(expr_span, label, block, |loop_scope| {
+ loop_scope.might_break = true;
+ loop_scope.break_block
+ })
}
ExprKind::Return { value } => {
block = match value {
block: BasicBlock,
exit_selector: F)
-> BlockAnd<()>
- where F: FnOnce(&LoopScope) -> BasicBlock
+ where F: FnOnce(&mut LoopScope) -> BasicBlock
{
- let loop_scope = self.find_loop_scope(span, label);
- let exit_block = exit_selector(&loop_scope);
- self.exit_scope(span, loop_scope.extent, block, exit_block);
+ let (exit_block, extent) = {
+ let loop_scope = self.find_loop_scope(span, label);
+ (exit_selector(loop_scope), loop_scope.extent)
+ };
+ self.exit_scope(span, extent, block, exit_block);
self.cfg.start_new_block().unit()
}
}
var_decls: Vec<VarDecl<'tcx>>,
var_indices: FnvHashMap<ast::NodeId, u32>,
temp_decls: Vec<TempDecl<'tcx>>,
+ unit_temp: Option<Lvalue<'tcx>>,
}
struct CFG<'tcx> {
temp_decls: vec![],
var_decls: vec![],
var_indices: FnvHashMap(),
+ unit_temp: None
};
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
block.and(arg_decls)
})
}
+
+ fn get_unit_temp(&mut self) -> Lvalue<'tcx> {
+ match self.unit_temp {
+ Some(ref tmp) => tmp.clone(),
+ None => {
+ let ty = self.hir.unit_ty();
+ let tmp = self.temp(ty);
+ self.unit_temp = Some(tmp.clone());
+ tmp
+ }
+ }
+ }
}
///////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug)]
pub struct LoopScope {
- pub extent: CodeExtent, // extent of the loop
- pub continue_block: BasicBlock, // where to go on a `loop`
+ /// Extent of the loop
+ pub extent: CodeExtent,
+ /// Where the body of the loop begins
+ pub continue_block: BasicBlock,
+ /// Block to branch into when the loop terminates (either by being `break`-en out from, or by
+ /// having its condition to become false)
pub break_block: BasicBlock, // where to go on a `break
+ /// Indicates the reachability of the break_block for this loop
+ pub might_break: bool
}
impl<'a,'tcx> Builder<'a,'tcx> {
/// Start a loop scope, which tracks where `continue` and `break`
/// should branch to. See module comment for more details.
- pub fn in_loop_scope<F, R>(&mut self,
+ ///
+ /// Returns the might_break attribute of the LoopScope used.
+ pub fn in_loop_scope<F>(&mut self,
loop_block: BasicBlock,
break_block: BasicBlock,
f: F)
- -> BlockAnd<R>
- where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>
+ -> bool
+ where F: FnOnce(&mut Builder<'a, 'tcx>)
{
let extent = self.extent_of_innermost_scope();
let loop_scope = LoopScope {
extent: extent.clone(),
continue_block: loop_block,
break_block: break_block,
+ might_break: false
};
self.loop_scopes.push(loop_scope);
- let r = f(self);
- assert!(self.loop_scopes.pop().unwrap().extent == extent);
- r
+ f(self);
+ let loop_scope = self.loop_scopes.pop().unwrap();
+ assert!(loop_scope.extent == extent);
+ loop_scope.might_break
}
/// Convenience wrapper that pushes a scope and then executes `f`
pub fn find_loop_scope(&mut self,
span: Span,
label: Option<CodeExtent>)
- -> LoopScope {
- let loop_scope =
- match label {
- None => {
- // no label? return the innermost loop scope
- self.loop_scopes.iter()
- .rev()
- .next()
- }
- Some(label) => {
- // otherwise, find the loop-scope with the correct id
- self.loop_scopes.iter()
- .rev()
- .filter(|loop_scope| loop_scope.extent == label)
- .next()
- }
- };
-
- match loop_scope {
- Some(loop_scope) => loop_scope.clone(),
- None => self.hir.span_bug(span, "no enclosing loop scope found?"),
- }
+ -> &mut LoopScope {
+ let Builder { ref mut loop_scopes, ref mut hir, .. } = *self;
+ match label {
+ None => {
+ // no label? return the innermost loop scope
+ loop_scopes.iter_mut().rev().next()
+ }
+ Some(label) => {
+ // otherwise, find the loop-scope with the correct id
+ loop_scopes.iter_mut()
+ .rev()
+ .filter(|loop_scope| loop_scope.extent == label)
+ .next()
+ }
+ }.unwrap_or_else(|| hir.span_bug(span, "no enclosing loop scope found?"))
}
/// Branch out of `block` to `target`, exiting all scopes up to
extent: CodeExtent,
block: BasicBlock,
target: BasicBlock) {
- let popped_scopes =
- match self.scopes.iter().rev().position(|scope| scope.extent == extent) {
- Some(p) => p + 1,
- None => self.hir.span_bug(span, &format!("extent {:?} does not enclose",
- extent)),
- };
-
- for scope in self.scopes.iter_mut().rev().take(popped_scopes) {
+ let Builder { ref mut scopes, ref mut cfg, ref mut hir, .. } = *self;
+
+ let scope_count = 1 + scopes.iter().rev().position(|scope| scope.extent == extent)
+ .unwrap_or_else(||{
+ hir.span_bug(span, &format!("extent {:?} does not enclose", extent))
+ });
+
+ for scope in scopes.iter_mut().rev().take(scope_count) {
for &(kind, drop_span, ref lvalue) in &scope.drops {
- self.cfg.push_drop(block, drop_span, kind, lvalue);
+ cfg.push_drop(block, drop_span, kind, lvalue);
}
}
-
- self.cfg.terminate(block, Terminator::Goto { target: target });
+ cfg.terminate(block, Terminator::Goto { target: target });
}
/// Creates a path that performs all required cleanup for unwinding.
use hair::cx::block;
use hair::cx::to_ref::ToRef;
use rustc::front::map;
-use rustc::middle::def;
+use rustc::middle::def::Def;
+use rustc::middle::const_eval;
use rustc::middle::region::CodeExtent;
use rustc::middle::pat_util;
use rustc::middle::ty::{self, VariantDef, Ty};
// Tuple-like ADTs are represented as ExprCall. We convert them here.
expr_ty.ty_adt_def().and_then(|adt_def|{
match cx.tcx.def_map.borrow()[&fun.id].full_def() {
- def::DefVariant(_, variant_id, false) => {
+ Def::Variant(_, variant_id) => {
Some((adt_def, adt_def.variant_index_with_id(variant_id)))
},
- def::DefStruct(_) => {
+ Def::Struct(..) => {
Some((adt_def, 0))
},
_ => None
}
ty::TyEnum(adt, substs) => {
match cx.tcx.def_map.borrow()[&self.id].full_def() {
- def::DefVariant(enum_id, variant_id, _) => {
+ Def::Variant(enum_id, variant_id) => {
debug_assert!(adt.did == enum_id);
let index = adt.variant_index_with_id(variant_id);
let field_refs = field_refs(&adt.variants[index], fields);
hir::ExprRepeat(ref v, ref c) => ExprKind::Repeat {
value: v.to_ref(),
- count: Expr {
+ count: TypedConstVal {
ty: cx.tcx.expr_ty(c),
- temp_lifetime: None,
span: c.span,
- kind: ExprKind::Literal {
- literal: cx.const_eval_literal(c)
- }
- }.to_ref()
+ value: const_eval::eval_const_expr(cx.tcx, c)
+ }
},
hir::ExprRet(ref v) =>
ExprKind::Return { value: v.to_ref() },
let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
let (def_id, kind) = match def {
// A regular function.
- def::DefFn(def_id, _) => (def_id, ItemKind::Function),
- def::DefMethod(def_id) => (def_id, ItemKind::Method),
- def::DefStruct(def_id) => match cx.tcx.node_id_to_type(expr.id).sty {
+ Def::Fn(def_id) => (def_id, ItemKind::Function),
+ Def::Method(def_id) => (def_id, ItemKind::Method),
+ Def::Struct(def_id) => match cx.tcx.node_id_to_type(expr.id).sty {
// A tuple-struct constructor. Should only be reached if not called in the same
// expression.
ty::TyBareFn(..) => (def_id, ItemKind::Function),
},
ref sty => panic!("unexpected sty: {:?}", sty)
},
- def::DefVariant(enum_id, variant_id, false) => match cx.tcx.node_id_to_type(expr.id).sty {
+ Def::Variant(enum_id, variant_id) => match cx.tcx.node_id_to_type(expr.id).sty {
// A variant constructor. Should only be reached if not called in the same
// expression.
ty::TyBareFn(..) => (variant_id, ItemKind::Function),
},
ref sty => panic!("unexpected sty: {:?}", sty)
},
- def::DefConst(def_id) |
- def::DefAssociatedConst(def_id) => {
+ Def::Const(def_id) |
+ Def::AssociatedConst(def_id) => {
if let Some(v) = cx.try_const_eval_literal(expr) {
return ExprKind::Literal { literal: v };
} else {
}
}
- def::DefStatic(node_id, _) => return ExprKind::StaticRef {
+ Def::Static(node_id, _) => return ExprKind::StaticRef {
id: node_id,
},
- def @ def::DefLocal(..) |
- def @ def::DefUpvar(..) => return convert_var(cx, expr, def),
+ def @ Def::Local(..) |
+ def @ Def::Upvar(..) => return convert_var(cx, expr, def),
def =>
cx.tcx.sess.span_bug(
fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
expr: &'tcx hir::Expr,
- def: def::Def)
+ def: Def)
-> ExprKind<'tcx> {
let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
match def {
- def::DefLocal(_, node_id) => {
+ Def::Local(_, node_id) => {
ExprKind::VarRef {
id: node_id,
}
}
- def::DefUpvar(_, id_var, index, closure_expr_id) => {
+ Def::Upvar(_, id_var, index, closure_expr_id) => {
debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id);
let var_ty = cx.tcx.node_id_to_type(id_var);
fn loop_label<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> CodeExtent {
match cx.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
- Some(def::DefLabel(loop_id)) => cx.tcx.region_maps.node_extent(loop_id),
+ Some(Def::Label(loop_id)) => cx.tcx.region_maps.node_extent(loop_id),
d => {
cx.tcx.sess.span_bug(expr.span, &format!("loop scope resolved to {:?}", d));
}
self.tcx.types.bool
}
+ pub fn unit_ty(&mut self) -> Ty<'tcx> {
+ self.tcx.mk_nil()
+ }
+
pub fn str_literal(&mut self, value: token::InternedString) -> Literal<'tcx> {
Literal::Value { value: ConstVal::Str(value) }
}
use hair::cx::Cx;
use rustc_data_structures::fnv::FnvHashMap;
use rustc::middle::const_eval;
-use rustc::middle::def;
+use rustc::middle::def::Def;
use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
use rustc::middle::ty::{self, Ty};
use rustc::mir::repr::*;
{
let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
match def {
- def::DefConst(def_id) | def::DefAssociatedConst(def_id) =>
+ Def::Const(def_id) | Def::AssociatedConst(def_id) =>
match const_eval::lookup_const_by_id(self.cx.tcx, def_id,
Some(pat.id), None) {
Some(const_expr) => {
-> PatternKind<'tcx> {
let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
match def {
- def::DefVariant(enum_id, variant_id, _) => {
+ Def::Variant(enum_id, variant_id) => {
let adt_def = self.cx.tcx.lookup_adt_def(enum_id);
if adt_def.variants.len() > 1 {
PatternKind::Variant {
}
}
- // NB: resolving to DefStruct means the struct *constructor*,
- // not the struct as a type.
- def::DefStruct(..) | def::DefTy(..) => {
+ Def::Struct(..) | Def::TyAlias(..) => {
PatternKind::Leaf { subpatterns: subpatterns }
}
//! unit-tested and separated from the Rust source and compiler data
//! structures.
-use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, ItemKind};
+use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, ItemKind,
+ TypedConstVal};
use rustc::middle::const_eval::ConstVal;
use rustc::middle::def_id::DefId;
use rustc::middle::region::CodeExtent;
},
Repeat {
value: ExprRef<'tcx>,
- // FIXME(#29789): Add a separate hair::Constant<'tcx> so this could be more explicit about
- // its contained data. Currently this should only contain expression of ExprKind::Literal
- // kind.
- count: ExprRef<'tcx>,
+ count: TypedConstVal<'tcx>,
},
Vec {
fields: Vec<ExprRef<'tcx>>,
Rvalue::Use(ref mut operand) => {
self.erase_regions_operand(operand)
}
- Rvalue::Repeat(ref mut operand, ref mut constant) => {
+ Rvalue::Repeat(ref mut operand, ref mut value) => {
self.erase_regions_operand(operand);
- self.erase_regions_constant(constant);
+ value.ty = self.tcx.erase_regions(&value.ty);
}
Rvalue::Ref(ref mut region, _, ref mut lvalue) => {
*region = ty::ReStatic;
--- /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.
+
+// Verifies that the types and values of const and static items
+// are safe. The rules enforced by this module are:
+//
+// - For each *mutable* static item, it checks that its **type**:
+// - doesn't have a destructor
+// - doesn't own a box
+//
+// - For each *immutable* static item, it checks that its **value**:
+// - doesn't own a box
+// - doesn't contain a struct literal or a call to an enum variant / struct constructor where
+// - the type of the struct/enum has a dtor
+//
+// Rules Enforced Elsewhere:
+// - It's not possible to take the address of a static item with unsafe interior. This is enforced
+// by borrowck::gather_loans
+
+use rustc::dep_graph::DepNode;
+use rustc::middle::ty::cast::{CastKind};
+use rustc::middle::const_eval::{self, ConstEvalErr};
+use rustc::middle::const_eval::ErrKind::IndexOpFeatureGated;
+use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
+use rustc::middle::def::Def;
+use rustc::middle::def_id::DefId;
+use rustc::middle::expr_use_visitor as euv;
+use rustc::middle::infer;
+use rustc::middle::mem_categorization as mc;
+use rustc::middle::mem_categorization::Categorization;
+use rustc::middle::traits;
+use rustc::middle::ty::{self, Ty};
+use rustc::util::nodemap::NodeMap;
+use rustc::middle::const_qualif::ConstQualif;
+use rustc::lint::builtin::CONST_ERR;
+
+use rustc_front::hir;
+use syntax::ast;
+use syntax::codemap::Span;
+use syntax::feature_gate::UnstableFeatures;
+use rustc_front::intravisit::{self, FnKind, Visitor};
+
+use std::collections::hash_map::Entry;
+use std::cmp::Ordering;
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+enum Mode {
+ Const,
+ ConstFn,
+ Static,
+ StaticMut,
+
+ // An expression that occurs outside of any constant context
+ // (i.e. `const`, `static`, array lengths, etc.). The value
+ // can be variable at runtime, but will be promotable to
+ // static memory if we can prove it is actually constant.
+ Var,
+}
+
+struct CheckCrateVisitor<'a, 'tcx: 'a> {
+ tcx: &'a ty::ctxt<'tcx>,
+ mode: Mode,
+ qualif: ConstQualif,
+ rvalue_borrows: NodeMap<hir::Mutability>
+}
+
+impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
+ fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R where
+ F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>) -> R,
+ {
+ let (old_mode, old_qualif) = (self.mode, self.qualif);
+ self.mode = mode;
+ self.qualif = ConstQualif::empty();
+ let r = f(self);
+ self.mode = old_mode;
+ self.qualif = old_qualif;
+ r
+ }
+
+ fn with_euv<'b, F, R>(&'b mut self, item_id: Option<ast::NodeId>, f: F) -> R where
+ F: for<'t> FnOnce(&mut euv::ExprUseVisitor<'b, 't, 'b, 'tcx>) -> R,
+ {
+ let param_env = match item_id {
+ Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
+ None => self.tcx.empty_parameter_environment()
+ };
+
+ let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env));
+
+ f(&mut euv::ExprUseVisitor::new(self, &infcx))
+ }
+
+ fn global_expr(&mut self, mode: Mode, expr: &hir::Expr) -> ConstQualif {
+ assert!(mode != Mode::Var);
+ match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) {
+ Entry::Occupied(entry) => return *entry.get(),
+ Entry::Vacant(entry) => {
+ // Prevent infinite recursion on re-entry.
+ entry.insert(ConstQualif::empty());
+ }
+ }
+ self.with_mode(mode, |this| {
+ this.with_euv(None, |euv| euv.consume_expr(expr));
+ this.visit_expr(expr);
+ this.qualif
+ })
+ }
+
+ fn fn_like(&mut self,
+ fk: FnKind,
+ fd: &hir::FnDecl,
+ b: &hir::Block,
+ s: Span,
+ fn_id: ast::NodeId)
+ -> ConstQualif {
+ match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) {
+ Entry::Occupied(entry) => return *entry.get(),
+ Entry::Vacant(entry) => {
+ // Prevent infinite recursion on re-entry.
+ entry.insert(ConstQualif::empty());
+ }
+ }
+
+ let mode = match fk {
+ FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _) => {
+ Mode::ConstFn
+ }
+ FnKind::Method(_, m, _) => {
+ if m.constness == hir::Constness::Const {
+ Mode::ConstFn
+ } else {
+ Mode::Var
+ }
+ }
+ _ => Mode::Var
+ };
+
+ let qualif = self.with_mode(mode, |this| {
+ this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
+ intravisit::walk_fn(this, fk, fd, b, s);
+ this.qualif
+ });
+
+ // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
+ // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
+ let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
+
+ self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
+ qualif
+ }
+
+ fn add_qualif(&mut self, qualif: ConstQualif) {
+ self.qualif = self.qualif | qualif;
+ }
+
+ /// Returns true if the call is to a const fn or method.
+ fn handle_const_fn_call(&mut self,
+ expr: &hir::Expr,
+ def_id: DefId,
+ ret_ty: Ty<'tcx>)
+ -> bool {
+ if let Some(fn_like) = const_eval::lookup_const_fn_by_id(self.tcx, def_id) {
+ if
+ // we are in a static/const initializer
+ self.mode != Mode::Var &&
+
+ // feature-gate is not enabled
+ !self.tcx.sess.features.borrow().const_fn &&
+
+ // this doesn't come from a macro that has #[allow_internal_unstable]
+ !self.tcx.sess.codemap().span_allows_unstable(expr.span)
+ {
+ let mut err = self.tcx.sess.struct_span_err(
+ expr.span,
+ "const fns are an unstable feature");
+ fileline_help!(
+ &mut err,
+ expr.span,
+ "in Nightly builds, add `#![feature(const_fn)]` to the crate \
+ attributes to enable");
+ err.emit();
+ }
+
+ let qualif = self.fn_like(fn_like.kind(),
+ fn_like.decl(),
+ fn_like.body(),
+ fn_like.span(),
+ fn_like.id());
+ self.add_qualif(qualif);
+
+ if ret_ty.type_contents(self.tcx).interior_unsafe() {
+ self.add_qualif(ConstQualif::MUTABLE_MEM);
+ }
+
+ true
+ } else {
+ false
+ }
+ }
+
+ fn record_borrow(&mut self, id: ast::NodeId, mutbl: hir::Mutability) {
+ match self.rvalue_borrows.entry(id) {
+ Entry::Occupied(mut entry) => {
+ // Merge the two borrows, taking the most demanding
+ // one, mutability-wise.
+ if mutbl == hir::MutMutable {
+ entry.insert(mutbl);
+ }
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(mutbl);
+ }
+ }
+ }
+
+ fn msg(&self) -> &'static str {
+ match self.mode {
+ Mode::Const => "constant",
+ Mode::ConstFn => "constant function",
+ Mode::StaticMut | Mode::Static => "static",
+ Mode::Var => unreachable!(),
+ }
+ }
+
+ fn check_static_mut_type(&self, e: &hir::Expr) {
+ let node_ty = self.tcx.node_id_to_type(e.id);
+ let tcontents = node_ty.type_contents(self.tcx);
+
+ let suffix = if tcontents.has_dtor() {
+ "destructors"
+ } else if tcontents.owns_owned() {
+ "boxes"
+ } else {
+ return
+ };
+
+ span_err!(self.tcx.sess, e.span, E0397,
+ "mutable statics are not allowed to have {}", suffix);
+ }
+
+ fn check_static_type(&self, e: &hir::Expr) {
+ let ty = self.tcx.node_id_to_type(e.id);
+ let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None);
+ let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
+ let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();
+ fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
+ match fulfill_cx.select_all_or_error(&infcx) {
+ Ok(()) => { },
+ Err(ref errors) => {
+ traits::report_fulfillment_errors(&infcx, errors);
+ }
+ }
+ }
+}
+
+impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
+ fn visit_item(&mut self, i: &hir::Item) {
+ debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
+ assert_eq!(self.mode, Mode::Var);
+ match i.node {
+ hir::ItemStatic(_, hir::MutImmutable, ref expr) => {
+ self.check_static_type(&**expr);
+ self.global_expr(Mode::Static, &**expr);
+ }
+ hir::ItemStatic(_, hir::MutMutable, ref expr) => {
+ self.check_static_mut_type(&**expr);
+ self.global_expr(Mode::StaticMut, &**expr);
+ }
+ hir::ItemConst(_, ref expr) => {
+ self.global_expr(Mode::Const, &**expr);
+ }
+ hir::ItemEnum(ref enum_definition, _) => {
+ for var in &enum_definition.variants {
+ if let Some(ref ex) = var.node.disr_expr {
+ self.global_expr(Mode::Const, &**ex);
+ }
+ }
+ }
+ _ => {
+ intravisit::walk_item(self, i);
+ }
+ }
+ }
+
+ fn visit_trait_item(&mut self, t: &'v hir::TraitItem) {
+ match t.node {
+ hir::ConstTraitItem(_, ref default) => {
+ if let Some(ref expr) = *default {
+ self.global_expr(Mode::Const, &*expr);
+ } else {
+ intravisit::walk_trait_item(self, t);
+ }
+ }
+ _ => self.with_mode(Mode::Var, |v| intravisit::walk_trait_item(v, t)),
+ }
+ }
+
+ fn visit_impl_item(&mut self, i: &'v hir::ImplItem) {
+ match i.node {
+ hir::ImplItemKind::Const(_, ref expr) => {
+ self.global_expr(Mode::Const, &*expr);
+ }
+ _ => self.with_mode(Mode::Var, |v| intravisit::walk_impl_item(v, i)),
+ }
+ }
+
+ fn visit_fn(&mut self,
+ fk: FnKind<'v>,
+ fd: &'v hir::FnDecl,
+ b: &'v hir::Block,
+ s: Span,
+ fn_id: ast::NodeId) {
+ self.fn_like(fk, fd, b, s, fn_id);
+ }
+
+ fn visit_pat(&mut self, p: &hir::Pat) {
+ match p.node {
+ hir::PatLit(ref lit) => {
+ self.global_expr(Mode::Const, &**lit);
+ }
+ hir::PatRange(ref start, ref end) => {
+ self.global_expr(Mode::Const, &**start);
+ self.global_expr(Mode::Const, &**end);
+
+ match const_eval::compare_lit_exprs(self.tcx, start, end) {
+ Some(Ordering::Less) |
+ Some(Ordering::Equal) => {}
+ Some(Ordering::Greater) => {
+ span_err!(self.tcx.sess, start.span, E0030,
+ "lower range bound must be less than or equal to upper");
+ }
+ None => {
+ self.tcx.sess.delay_span_bug(start.span,
+ "non-constant path in constant expr");
+ }
+ }
+ }
+ _ => intravisit::walk_pat(self, p)
+ }
+ }
+
+ fn visit_block(&mut self, block: &hir::Block) {
+ // Check all statements in the block
+ for stmt in &block.stmts {
+ match stmt.node {
+ hir::StmtDecl(ref decl, _) => {
+ match decl.node {
+ hir::DeclLocal(_) => {},
+ // Item statements are allowed
+ hir::DeclItem(_) => continue
+ }
+ }
+ hir::StmtExpr(_, _) => {},
+ hir::StmtSemi(_, _) => {},
+ }
+ self.add_qualif(ConstQualif::NOT_CONST);
+ // anything else should have been caught by check_const_fn
+ assert_eq!(self.mode, Mode::Var);
+ }
+ intravisit::walk_block(self, block);
+ }
+
+ fn visit_expr(&mut self, ex: &hir::Expr) {
+ let mut outer = self.qualif;
+ self.qualif = ConstQualif::empty();
+
+ let node_ty = self.tcx.node_id_to_type(ex.id);
+ check_expr(self, ex, node_ty);
+ check_adjustments(self, ex);
+
+ // Special-case some expressions to avoid certain flags bubbling up.
+ match ex.node {
+ hir::ExprCall(ref callee, ref args) => {
+ for arg in args {
+ self.visit_expr(&**arg)
+ }
+
+ let inner = self.qualif;
+ self.visit_expr(&**callee);
+ // The callee's size doesn't count in the call.
+ let added = self.qualif - inner;
+ self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
+ }
+ hir::ExprRepeat(ref element, _) => {
+ self.visit_expr(&**element);
+ // The count is checked elsewhere (typeck).
+ let count = match node_ty.sty {
+ ty::TyArray(_, n) => n,
+ _ => unreachable!()
+ };
+ // [element; 0] is always zero-sized.
+ if count == 0 {
+ self.qualif.remove(ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
+ }
+ }
+ hir::ExprMatch(ref discr, ref arms, _) => {
+ // Compute the most demanding borrow from all the arms'
+ // patterns and set that on the discriminator.
+ let mut borrow = None;
+ for pat in arms.iter().flat_map(|arm| &arm.pats) {
+ let pat_borrow = self.rvalue_borrows.remove(&pat.id);
+ match (borrow, pat_borrow) {
+ (None, _) | (_, Some(hir::MutMutable)) => {
+ borrow = pat_borrow;
+ }
+ _ => {}
+ }
+ }
+ if let Some(mutbl) = borrow {
+ self.record_borrow(discr.id, mutbl);
+ }
+ intravisit::walk_expr(self, ex);
+ }
+ // Division by zero and overflow checking.
+ hir::ExprBinary(op, _, _) => {
+ intravisit::walk_expr(self, ex);
+ let div_or_rem = op.node == hir::BiDiv || op.node == hir::BiRem;
+ match node_ty.sty {
+ ty::TyUint(_) | ty::TyInt(_) if div_or_rem => {
+ if !self.qualif.intersects(ConstQualif::NOT_CONST) {
+ match const_eval::eval_const_expr_partial(
+ self.tcx, ex, ExprTypeChecked, None) {
+ Ok(_) => {}
+ Err(ConstEvalErr { kind: IndexOpFeatureGated, ..}) => {},
+ Err(msg) => {
+ self.tcx.sess.add_lint(CONST_ERR, ex.id,
+ msg.span,
+ msg.description().into_owned())
+ }
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ _ => intravisit::walk_expr(self, ex)
+ }
+
+ // Handle borrows on (or inside the autorefs of) this expression.
+ match self.rvalue_borrows.remove(&ex.id) {
+ Some(hir::MutImmutable) => {
+ // Constants cannot be borrowed if they contain interior mutability as
+ // it means that our "silent insertion of statics" could change
+ // initializer values (very bad).
+ // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
+ // propagated from another error, so erroring again would be just noise.
+ let tc = node_ty.type_contents(self.tcx);
+ if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
+ outer = outer | ConstQualif::NOT_CONST;
+ if self.mode != Mode::Var {
+ span_err!(self.tcx.sess, ex.span, E0492,
+ "cannot borrow a constant which contains \
+ interior mutability, create a static instead");
+ }
+ }
+ // If the reference has to be 'static, avoid in-place initialization
+ // as that will end up pointing to the stack instead.
+ if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
+ self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
+ self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
+ }
+ }
+ Some(hir::MutMutable) => {
+ // `&mut expr` means expr could be mutated, unless it's zero-sized.
+ if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) {
+ if self.mode == Mode::Var {
+ outer = outer | ConstQualif::NOT_CONST;
+ self.add_qualif(ConstQualif::MUTABLE_MEM);
+ } else {
+ span_err!(self.tcx.sess, ex.span, E0017,
+ "references in {}s may only refer \
+ to immutable values", self.msg())
+ }
+ }
+ if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
+ self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
+ }
+ }
+ None => {}
+ }
+ self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
+ // Don't propagate certain flags.
+ self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
+ }
+}
+
+/// This function is used to enforce the constraints on
+/// const/static items. It walks through the *value*
+/// of the item walking down the expression and evaluating
+/// every nested expression. If the expression is not part
+/// of a const/static item, it is qualified for promotion
+/// instead of producing errors.
+fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
+ e: &hir::Expr, node_ty: Ty<'tcx>) {
+ match node_ty.sty {
+ ty::TyStruct(def, _) |
+ ty::TyEnum(def, _) if def.has_dtor() => {
+ v.add_qualif(ConstQualif::NEEDS_DROP);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0493,
+ "{}s are not allowed to have destructors",
+ v.msg());
+ }
+ }
+ _ => {}
+ }
+
+ let method_call = ty::MethodCall::expr(e.id);
+ match e.node {
+ hir::ExprUnary(..) |
+ hir::ExprBinary(..) |
+ hir::ExprIndex(..) if v.tcx.tables.borrow().method_map.contains_key(&method_call) => {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0011,
+ "user-defined operators are not allowed in {}s", v.msg());
+ }
+ }
+ hir::ExprBox(_) => {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0010,
+ "allocations are not allowed in {}s", v.msg());
+ }
+ }
+ hir::ExprUnary(op, ref inner) => {
+ match v.tcx.node_id_to_type(inner.id).sty {
+ ty::TyRawPtr(_) => {
+ assert!(op == hir::UnDeref);
+
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0396,
+ "raw pointers cannot be dereferenced in {}s", v.msg());
+ }
+ }
+ _ => {}
+ }
+ }
+ hir::ExprBinary(op, ref lhs, _) => {
+ match v.tcx.node_id_to_type(lhs.id).sty {
+ ty::TyRawPtr(_) => {
+ assert!(op.node == hir::BiEq || op.node == hir::BiNe ||
+ op.node == hir::BiLe || op.node == hir::BiLt ||
+ op.node == hir::BiGe || op.node == hir::BiGt);
+
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0395,
+ "raw pointers cannot be compared in {}s", v.msg());
+ }
+ }
+ _ => {}
+ }
+ }
+ hir::ExprCast(ref from, _) => {
+ debug!("Checking const cast(id={})", from.id);
+ match v.tcx.cast_kinds.borrow().get(&from.id) {
+ None => v.tcx.sess.span_bug(e.span, "no kind for cast"),
+ Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0018,
+ "raw pointers cannot be cast to integers in {}s", v.msg());
+ }
+ }
+ _ => {}
+ }
+ }
+ hir::ExprPath(..) => {
+ let def = v.tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
+ match def {
+ Some(Def::Variant(..)) => {
+ // Count the discriminator or function pointer.
+ v.add_qualif(ConstQualif::NON_ZERO_SIZED);
+ }
+ Some(Def::Struct(..)) => {
+ if let ty::TyBareFn(..) = node_ty.sty {
+ // Count the function pointer.
+ v.add_qualif(ConstQualif::NON_ZERO_SIZED);
+ }
+ }
+ Some(Def::Fn(..)) | Some(Def::Method(..)) => {
+ // Count the function pointer.
+ v.add_qualif(ConstQualif::NON_ZERO_SIZED);
+ }
+ Some(Def::Static(..)) => {
+ match v.mode {
+ Mode::Static | Mode::StaticMut => {}
+ Mode::Const | Mode::ConstFn => {
+ span_err!(v.tcx.sess, e.span, E0013,
+ "{}s cannot refer to other statics, insert \
+ an intermediate constant instead", v.msg());
+ }
+ Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
+ }
+ }
+ Some(Def::Const(did)) |
+ Some(Def::AssociatedConst(did)) => {
+ if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
+ Some(e.id),
+ None) {
+ let inner = v.global_expr(Mode::Const, expr);
+ v.add_qualif(inner);
+ }
+ }
+ Some(Def::Local(..)) if v.mode == Mode::ConstFn => {
+ // Sadly, we can't determine whether the types are zero-sized.
+ v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
+ }
+ def => {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ debug!("(checking const) found bad def: {:?}", def);
+ span_err!(v.tcx.sess, e.span, E0014,
+ "paths in {}s may only refer to constants \
+ or functions", v.msg());
+ }
+ }
+ }
+ }
+ hir::ExprCall(ref callee, _) => {
+ let mut callee = &**callee;
+ loop {
+ callee = match callee.node {
+ hir::ExprBlock(ref block) => match block.expr {
+ Some(ref tail) => &**tail,
+ None => break
+ },
+ _ => break
+ };
+ }
+ let def = v.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def());
+ let is_const = match def {
+ Some(Def::Struct(..)) => true,
+ Some(Def::Variant(..)) => {
+ // Count the discriminator.
+ v.add_qualif(ConstQualif::NON_ZERO_SIZED);
+ true
+ }
+ Some(Def::Fn(did)) => {
+ v.handle_const_fn_call(e, did, node_ty)
+ }
+ Some(Def::Method(did)) => {
+ match v.tcx.impl_or_trait_item(did).container() {
+ ty::ImplContainer(_) => {
+ v.handle_const_fn_call(e, did, node_ty)
+ }
+ ty::TraitContainer(_) => false
+ }
+ }
+ _ => false
+ };
+ if !is_const {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ // FIXME(#24111) Remove this check when const fn stabilizes
+ let (msg, note) =
+ if let UnstableFeatures::Disallow = v.tcx.sess.opts.unstable_features {
+ (format!("function calls in {}s are limited to \
+ struct and enum constructors",
+ v.msg()),
+ Some("a limited form of compile-time function \
+ evaluation is available on a nightly \
+ compiler via `const fn`"))
+ } else {
+ (format!("function calls in {}s are limited \
+ to constant functions, \
+ struct and enum constructors",
+ v.msg()),
+ None)
+ };
+ let mut err = struct_span_err!(v.tcx.sess, e.span, E0015, "{}", msg);
+ if let Some(note) = note {
+ err.span_note(e.span, note);
+ }
+ err.emit();
+ }
+ }
+ }
+ hir::ExprMethodCall(..) => {
+ let method = v.tcx.tables.borrow().method_map[&method_call];
+ let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() {
+ ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
+ ty::TraitContainer(_) => false
+ };
+ if !is_const {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0378,
+ "method calls in {}s are limited to \
+ constant inherent methods", v.msg());
+ }
+ }
+ }
+ hir::ExprStruct(..) => {
+ let did = v.tcx.def_map.borrow().get(&e.id).map(|def| def.def_id());
+ if did == v.tcx.lang_items.unsafe_cell_type() {
+ v.add_qualif(ConstQualif::MUTABLE_MEM);
+ }
+ }
+
+ hir::ExprLit(_) |
+ hir::ExprAddrOf(..) => {
+ v.add_qualif(ConstQualif::NON_ZERO_SIZED);
+ }
+
+ hir::ExprRepeat(..) => {
+ v.add_qualif(ConstQualif::PREFER_IN_PLACE);
+ }
+
+ hir::ExprClosure(..) => {
+ // Paths in constant contexts cannot refer to local variables,
+ // as there are none, and thus closures can't have upvars there.
+ if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) {
+ assert!(v.mode == Mode::Var,
+ "global closures can't capture anything");
+ v.add_qualif(ConstQualif::NOT_CONST);
+ }
+ }
+
+ hir::ExprBlock(_) |
+ hir::ExprIndex(..) |
+ hir::ExprField(..) |
+ hir::ExprTupField(..) |
+ hir::ExprVec(_) |
+ hir::ExprType(..) |
+ hir::ExprTup(..) => {}
+
+ // Conditional control flow (possible to implement).
+ hir::ExprMatch(..) |
+ hir::ExprIf(..) |
+
+ // Loops (not very meaningful in constants).
+ hir::ExprWhile(..) |
+ hir::ExprLoop(..) |
+
+ // More control flow (also not very meaningful).
+ hir::ExprBreak(_) |
+ hir::ExprAgain(_) |
+ hir::ExprRet(_) |
+
+ // Miscellaneous expressions that could be implemented.
+ hir::ExprRange(..) |
+
+ // Expressions with side-effects.
+ hir::ExprAssign(..) |
+ hir::ExprAssignOp(..) |
+ hir::ExprInlineAsm(_) => {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0019,
+ "{} contains unimplemented expression type", v.msg());
+ }
+ }
+ }
+}
+
+/// Check the adjustments of an expression
+fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
+ match v.tcx.tables.borrow().adjustments.get(&e.id) {
+ None |
+ Some(&ty::adjustment::AdjustReifyFnPointer) |
+ Some(&ty::adjustment::AdjustUnsafeFnPointer) => {}
+
+ Some(&ty::adjustment::AdjustDerefRef(
+ ty::adjustment::AutoDerefRef { autoderefs, .. }
+ )) => {
+ if (0..autoderefs as u32).any(|autoderef| {
+ v.tcx.is_overloaded_autoderef(e.id, autoderef)
+ }) {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0400,
+ "user-defined dereference operators are not allowed in {}s",
+ v.msg());
+ }
+ }
+ }
+ }
+}
+
+pub fn check_crate(tcx: &ty::ctxt) {
+ tcx.visit_all_items_in_krate(DepNode::CheckConst, &mut CheckCrateVisitor {
+ tcx: tcx,
+ mode: Mode::Var,
+ qualif: ConstQualif::NOT_CONST,
+ rvalue_borrows: NodeMap()
+ });
+ tcx.sess.abort_if_errors();
+}
+
+impl<'a, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'tcx> {
+ fn consume(&mut self,
+ _consume_id: ast::NodeId,
+ consume_span: Span,
+ cmt: mc::cmt,
+ _mode: euv::ConsumeMode) {
+ let mut cur = &cmt;
+ loop {
+ match cur.cat {
+ Categorization::StaticItem => {
+ if self.mode != Mode::Var {
+ // statics cannot be consumed by value at any time, that would imply
+ // that they're an initializer (what a const is for) or kept in sync
+ // over time (not feasible), so deny it outright.
+ span_err!(self.tcx.sess, consume_span, E0394,
+ "cannot refer to other statics by value, use the \
+ address-of operator or a constant instead");
+ }
+ break;
+ }
+ Categorization::Deref(ref cmt, _, _) |
+ Categorization::Downcast(ref cmt, _) |
+ Categorization::Interior(ref cmt, _) => cur = cmt,
+
+ Categorization::Rvalue(..) |
+ Categorization::Upvar(..) |
+ Categorization::Local(..) => break
+ }
+ }
+ }
+ fn borrow(&mut self,
+ borrow_id: ast::NodeId,
+ borrow_span: Span,
+ cmt: mc::cmt<'tcx>,
+ _loan_region: ty::Region,
+ bk: ty::BorrowKind,
+ loan_cause: euv::LoanCause)
+ {
+ // Kind of hacky, but we allow Unsafe coercions in constants.
+ // These occur when we convert a &T or *T to a *U, as well as
+ // when making a thin pointer (e.g., `*T`) into a fat pointer
+ // (e.g., `*Trait`).
+ match loan_cause {
+ euv::LoanCause::AutoUnsafe => {
+ return;
+ }
+ _ => { }
+ }
+
+ let mut cur = &cmt;
+ let mut is_interior = false;
+ loop {
+ match cur.cat {
+ Categorization::Rvalue(..) => {
+ if loan_cause == euv::MatchDiscriminant {
+ // Ignore the dummy immutable borrow created by EUV.
+ break;
+ }
+ let mutbl = bk.to_mutbl_lossy();
+ if mutbl == hir::MutMutable && self.mode == Mode::StaticMut {
+ // Mutable slices are the only `&mut` allowed in
+ // globals, but only in `static mut`, nowhere else.
+ // FIXME: This exception is really weird... there isn't
+ // any fundamental reason to restrict this based on
+ // type of the expression. `&mut [1]` has exactly the
+ // same representation as &mut 1.
+ match cmt.ty.sty {
+ ty::TyArray(_, _) | ty::TySlice(_) => break,
+ _ => {}
+ }
+ }
+ self.record_borrow(borrow_id, mutbl);
+ break;
+ }
+ Categorization::StaticItem => {
+ if is_interior && self.mode != Mode::Var {
+ // Borrowed statics can specifically *only* have their address taken,
+ // not any number of other borrows such as borrowing fields, reading
+ // elements of an array, etc.
+ span_err!(self.tcx.sess, borrow_span, E0494,
+ "cannot refer to the interior of another \
+ static, use a constant instead");
+ }
+ break;
+ }
+ Categorization::Deref(ref cmt, _, _) |
+ Categorization::Downcast(ref cmt, _) |
+ Categorization::Interior(ref cmt, _) => {
+ is_interior = true;
+ cur = cmt;
+ }
+
+ Categorization::Upvar(..) |
+ Categorization::Local(..) => break
+ }
+ }
+ }
+
+ fn decl_without_init(&mut self,
+ _id: ast::NodeId,
+ _span: Span) {}
+ fn mutate(&mut self,
+ _assignment_id: ast::NodeId,
+ _assignment_span: Span,
+ _assignee_cmt: mc::cmt,
+ _mode: euv::MutateMode) {}
+
+ fn matched_pat(&mut self,
+ _: &hir::Pat,
+ _: mc::cmt,
+ _: euv::MatchMode) {}
+
+ fn consume_pat(&mut self,
+ _consume_pat: &hir::Pat,
+ _cmt: mc::cmt,
+ _mode: euv::ConsumeMode) {}
+}
#![allow(non_snake_case)]
register_long_diagnostics! {
+
+E0010: r##"
+The value of statics and constants must be known at compile time, and they live
+for the entire lifetime of a program. Creating a boxed value allocates memory on
+the heap at runtime, and therefore cannot be done at compile time. Erroneous
+code example:
+
+```
+#![feature(box_syntax)]
+
+const CON : Box<i32> = box 0;
+```
+"##,
+
+E0011: r##"
+Initializers for constants and statics are evaluated at compile time.
+User-defined operators rely on user-defined functions, which cannot be evaluated
+at compile time.
+
+Bad example:
+
+```
+use std::ops::Index;
+
+struct Foo { a: u8 }
+
+impl Index<u8> for Foo {
+ type Output = u8;
+
+ fn index<'a>(&'a self, idx: u8) -> &'a u8 { &self.a }
+}
+
+const a: Foo = Foo { a: 0u8 };
+const b: u8 = a[0]; // Index trait is defined by the user, bad!
+```
+
+Only operators on builtin types are allowed.
+
+Example:
+
+```
+const a: &'static [i32] = &[1, 2, 3];
+const b: i32 = a[0]; // Good!
+```
+"##,
+
+E0013: r##"
+Static and const variables can refer to other const variables. But a const
+variable cannot refer to a static variable. For example, `Y` cannot refer to `X`
+here:
+
+```
+static X: i32 = 42;
+const Y: i32 = X;
+```
+
+To fix this, the value can be extracted as a const and then used:
+
+```
+const A: i32 = 42;
+static X: i32 = A;
+const Y: i32 = A;
+```
+"##,
+
+E0014: r##"
+Constants can only be initialized by a constant value or, in a future
+version of Rust, a call to a const function. This error indicates the use
+of a path (like a::b, or x) denoting something other than one of these
+allowed items. Example:
+
+```
+const FOO: i32 = { let x = 0; x }; // 'x' isn't a constant nor a function!
+```
+
+To avoid it, you have to replace the non-constant value:
+
+```
+const FOO: i32 = { const X : i32 = 0; X };
+// or even:
+const FOO: i32 = { 0 }; // but brackets are useless here
+```
+"##,
+
+// FIXME(#24111) Change the language here when const fn stabilizes
+E0015: r##"
+The only functions that can be called in static or constant expressions are
+`const` functions, and struct/enum constructors. `const` functions are only
+available on a nightly compiler. Rust currently does not support more general
+compile-time function execution.
+
+```
+const FOO: Option<u8> = Some(1); // enum constructor
+struct Bar {x: u8}
+const BAR: Bar = Bar {x: 1}; // struct constructor
+```
+
+See [RFC 911] for more details on the design of `const fn`s.
+
+[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
+"##,
+
E0016: r##"
Blocks in constants may only contain items (such as constant, function
definition, etc...) and a tail expression. Example:
```
"##,
+E0017: r##"
+References in statics and constants may only refer to immutable values. Example:
+
+```
+static X: i32 = 1;
+const C: i32 = 2;
+
+// these three are not allowed:
+const CR: &'static mut i32 = &mut C;
+static STATIC_REF: &'static mut i32 = &mut X;
+static CONST_REF: &'static mut i32 = &mut C;
+```
+
+Statics are shared everywhere, and if they refer to mutable data one might
+violate memory safety since holding multiple mutable references to shared data
+is not allowed.
+
+If you really want global mutable state, try using `static mut` or a global
+`UnsafeCell`.
+"##,
+
+E0018: r##"
+The value of static and const variables must be known at compile time. You
+can't cast a pointer as an integer because we can't know what value the
+address will take.
+
+However, pointers to other constants' addresses are allowed in constants,
+example:
+
+```
+const X: u32 = 50;
+const Y: *const u32 = &X;
+```
+
+Therefore, casting one of these non-constant pointers to an integer results
+in a non-constant integer which lead to this error. Example:
+
+```
+const X: u32 = 1;
+const Y: usize = &X as *const u32 as usize;
+println!("{}", Y);
+```
+"##,
+
+E0019: r##"
+A function call isn't allowed in the const's initialization expression
+because the expression's value must be known at compile-time. Example of
+erroneous code:
+
+```
+enum Test {
+ V1
+}
+
+impl Test {
+ fn test(&self) -> i32 {
+ 12
+ }
+}
+
+fn main() {
+ const FOO: Test = Test::V1;
+
+ const A: i32 = FOO.test(); // You can't call Test::func() here !
+}
+```
+
+Remember: you can't use a function call inside a const's initialization
+expression! However, you can totally use it anywhere else:
+
+```
+fn main() {
+ const FOO: Test = Test::V1;
+
+ FOO.func(); // here is good
+ let x = FOO.func(); // or even here!
+}
+```
+"##,
+
E0022: r##"
Constant functions are not allowed to mutate anything. Thus, binding to an
argument with a mutable pattern is not allowed. For example,
instead of using a `const fn`, or refactoring the code to a functional style to
avoid mutation if possible.
"##,
+
+E0030: r##"
+When matching against a range, the compiler verifies that the range is
+non-empty. Range patterns include both end-points, so this is equivalent to
+requiring the start of the range to be less than or equal to the end of the
+range.
+
+For example:
+
+```
+match 5u32 {
+ // This range is ok, albeit pointless.
+ 1 ... 1 => ...
+ // This range is empty, and the compiler can tell.
+ 1000 ... 5 => ...
+}
+```
+"##,
+
+E0161: r##"
+In Rust, you can only move a value when its size is known at compile time.
+
+To work around this restriction, consider "hiding" the value behind a reference:
+either `&x` or `&mut x`. Since a reference has a fixed size, this lets you move
+it around as usual.
+"##,
+
+E0265: r##"
+This error indicates that a static or constant references itself.
+All statics and constants need to resolve to a value in an acyclic manner.
+
+For example, neither of the following can be sensibly compiled:
+
+```
+const X: u32 = X;
+```
+
+```
+const X: u32 = Y;
+const Y: u32 = X;
+```
+"##,
+
+E0267: r##"
+This error indicates the use of a loop keyword (`break` or `continue`) inside a
+closure but outside of any loop. Erroneous code example:
+
+```
+let w = || { break; }; // error: `break` inside of a closure
+```
+
+`break` and `continue` keywords can be used as normal inside closures as long as
+they are also contained within a loop. To halt the execution of a closure you
+should instead use a return statement. Example:
+
+```
+let w = || {
+ for _ in 0..10 {
+ break;
+ }
+};
+
+w();
+```
+"##,
+
+E0268: r##"
+This error indicates the use of a loop keyword (`break` or `continue`) outside
+of a loop. Without a loop to break out of or continue in, no sensible action can
+be taken. Erroneous code example:
+
+```
+fn some_func() {
+ break; // error: `break` outside of loop
+}
+```
+
+Please verify that you are using `break` and `continue` only in loops. Example:
+
+```
+fn some_func() {
+ for _ in 0..10 {
+ break; // ok!
+ }
+}
+```
+"##,
+
+E0378: r##"
+Method calls that aren't calls to inherent `const` methods are disallowed
+in statics, constants, and constant functions.
+
+For example:
+
+```
+const BAZ: i32 = Foo(25).bar(); // error, `bar` isn't `const`
+
+struct Foo(i32);
+
+impl Foo {
+ const fn foo(&self) -> i32 {
+ self.bar() // error, `bar` isn't `const`
+ }
+
+ fn bar(&self) -> i32 { self.0 }
+}
+```
+
+For more information about `const fn`'s, see [RFC 911].
+
+[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
+"##,
+
+E0394: r##"
+From [RFC 246]:
+
+ > It is invalid for a static to reference another static by value. It is
+ > required that all references be borrowed.
+
+[RFC 246]: https://github.com/rust-lang/rfcs/pull/246
+"##,
+
+E0395: r##"
+The value assigned to a constant expression must be known at compile time,
+which is not the case when comparing raw pointers. Erroneous code example:
+
+```
+static foo: i32 = 42;
+static bar: i32 = 43;
+
+static baz: bool = { (&foo as *const i32) == (&bar as *const i32) };
+// error: raw pointers cannot be compared in statics!
+```
+
+Please check that the result of the comparison can be determined at compile time
+or isn't assigned to a constant expression. Example:
+
+```
+static foo: i32 = 42;
+static bar: i32 = 43;
+
+let baz: bool = { (&foo as *const i32) == (&bar as *const i32) };
+// baz isn't a constant expression so it's ok
+```
+"##,
+
+E0396: r##"
+The value assigned to a constant expression must be known at compile time,
+which is not the case when dereferencing raw pointers. Erroneous code
+example:
+
+```
+const foo: i32 = 42;
+const baz: *const i32 = (&foo as *const i32);
+
+const deref: i32 = *baz;
+// error: raw pointers cannot be dereferenced in constants
+```
+
+To fix this error, please do not assign this value to a constant expression.
+Example:
+
+```
+const foo: i32 = 42;
+const baz: *const i32 = (&foo as *const i32);
+
+unsafe { let deref: i32 = *baz; }
+// baz isn't a constant expression so it's ok
+```
+
+You'll also note that this assignment must be done in an unsafe block!
+"##,
+
+E0397: r##"
+It is not allowed for a mutable static to allocate or have destructors. For
+example:
+
+```
+// error: mutable statics are not allowed to have boxes
+static mut FOO: Option<Box<usize>> = None;
+
+// error: mutable statics are not allowed to have destructors
+static mut BAR: Option<Vec<i32>> = None;
+```
+"##,
+
+E0400: r##"
+A user-defined dereference was attempted in an invalid context. Erroneous
+code example:
+
+```
+use std::ops::Deref;
+
+struct A;
+
+impl Deref for A {
+ type Target = str;
+
+ fn deref(&self)-> &str { "foo" }
+}
+
+const S: &'static str = &A;
+// error: user-defined dereference operators are not allowed in constants
+
+fn main() {
+ let foo = S;
+}
+```
+
+You cannot directly use a dereference operation whilst initializing a constant
+or a static. To fix this error, restructure your code to avoid this dereference,
+perhaps moving it inline:
+
+```
+use std::ops::Deref;
+
+struct A;
+
+impl Deref for A {
+ type Target = str;
+
+ fn deref(&self)-> &str { "foo" }
+}
+
+fn main() {
+ let foo : &str = &A;
+}
+```
+"##,
+
+E0492: r##"
+A borrow of a constant containing interior mutability was attempted. Erroneous
+code example:
+
+```
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
+
+const A: AtomicUsize = ATOMIC_USIZE_INIT;
+static B: &'static AtomicUsize = &A;
+// error: cannot borrow a constant which contains interior mutability, create a
+// static instead
+```
+
+A `const` represents a constant value that should never change. If one takes
+a `&` reference to the constant, then one is taking a pointer to some memory
+location containing the value. Normally this is perfectly fine: most values
+can't be changed via a shared `&` pointer, but interior mutability would allow
+it. That is, a constant value could be mutated. On the other hand, a `static` is
+explicitly a single memory location, which can be mutated at will.
+
+So, in order to solve this error, either use statics which are `Sync`:
+
+```
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
+
+static A: AtomicUsize = ATOMIC_USIZE_INIT;
+static B: &'static AtomicUsize = &A; // ok!
+```
+
+You can also have this error while using a cell type:
+
+```
+#![feature(const_fn)]
+
+use std::cell::Cell;
+
+const A: Cell<usize> = Cell::new(1);
+const B: &'static Cell<usize> = &A;
+// error: cannot borrow a constant which contains interior mutability, create
+// a static instead
+
+// or:
+struct C { a: Cell<usize> }
+
+const D: C = C { a: Cell::new(1) };
+const E: &'static Cell<usize> = &D.a; // error
+
+// or:
+const F: &'static C = &D; // error
+```
+
+This is because cell types do operations that are not thread-safe. Due to this,
+they don't implement Sync and thus can't be placed in statics. In this
+case, `StaticMutex` would work just fine, but it isn't stable yet:
+https://doc.rust-lang.org/nightly/std/sync/struct.StaticMutex.html
+
+However, if you still wish to use these types, you can achieve this by an unsafe
+wrapper:
+
+```
+#![feature(const_fn)]
+
+use std::cell::Cell;
+use std::marker::Sync;
+
+struct NotThreadSafe<T> {
+ value: Cell<T>,
+}
+
+unsafe impl<T> Sync for NotThreadSafe<T> {}
+
+static A: NotThreadSafe<usize> = NotThreadSafe { value : Cell::new(1) };
+static B: &'static NotThreadSafe<usize> = &A; // ok!
+```
+
+Remember this solution is unsafe! You will have to ensure that accesses to the
+cell are synchronized.
+"##,
+
+E0493: r##"
+A type with a destructor was assigned to an invalid type of variable. Erroneous
+code example:
+
+```
+struct Foo {
+ a: u32
+}
+
+impl Drop for Foo {
+ fn drop(&mut self) {}
+}
+
+const F : Foo = Foo { a : 0 };
+// error: constants are not allowed to have destructors
+static S : Foo = Foo { a : 0 };
+// error: statics are not allowed to have destructors
+```
+
+To solve this issue, please use a type which does allow the usage of type with
+destructors.
+"##,
+
+E0494: r##"
+A reference of an interior static was assigned to another const/static.
+Erroneous code example:
+
+```
+struct Foo {
+ a: u32
+}
+
+static S : Foo = Foo { a : 0 };
+static A : &'static u32 = &S.a;
+// error: cannot refer to the interior of another static, use a
+// constant instead
+```
+
+The "base" variable has to be a const if you want another static/const variable
+to refer to one of its fields. Example:
+
+```
+struct Foo {
+ a: u32
+}
+
+const S : Foo = Foo { a : 0 };
+static A : &'static u32 = &S.a; // ok!
+```
+"##,
+
}
register_diagnostics! {
extern crate core;
extern crate rustc;
+extern crate rustc_front;
+#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
pub mod diagnostics;
+
pub mod const_fn;
+pub mod consts;
+pub mod loops;
pub mod no_asm;
+pub mod rvalues;
+pub mod static_recursion;
--- /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.
+use self::Context::*;
+
+use rustc::session::Session;
+
+use syntax::codemap::Span;
+use rustc_front::intravisit::{self, Visitor};
+use rustc_front::hir;
+
+#[derive(Clone, Copy, PartialEq)]
+enum Context {
+ Normal, Loop, Closure
+}
+
+#[derive(Copy, Clone)]
+struct CheckLoopVisitor<'a> {
+ sess: &'a Session,
+ cx: Context
+}
+
+pub fn check_crate(sess: &Session, krate: &hir::Crate) {
+ krate.visit_all_items(&mut CheckLoopVisitor { sess: sess, cx: Normal });
+}
+
+impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
+ fn visit_item(&mut self, i: &hir::Item) {
+ self.with_context(Normal, |v| intravisit::walk_item(v, i));
+ }
+
+ fn visit_expr(&mut self, e: &hir::Expr) {
+ match e.node {
+ hir::ExprWhile(ref e, ref b, _) => {
+ self.visit_expr(&**e);
+ self.with_context(Loop, |v| v.visit_block(&**b));
+ }
+ hir::ExprLoop(ref b, _) => {
+ self.with_context(Loop, |v| v.visit_block(&**b));
+ }
+ hir::ExprClosure(_, _, ref b) => {
+ self.with_context(Closure, |v| v.visit_block(&**b));
+ }
+ hir::ExprBreak(_) => self.require_loop("break", e.span),
+ hir::ExprAgain(_) => self.require_loop("continue", e.span),
+ _ => intravisit::walk_expr(self, e)
+ }
+ }
+}
+
+impl<'a> CheckLoopVisitor<'a> {
+ fn with_context<F>(&mut self, cx: Context, f: F) where
+ F: FnOnce(&mut CheckLoopVisitor<'a>),
+ {
+ let old_cx = self.cx;
+ self.cx = cx;
+ f(self);
+ self.cx = old_cx;
+ }
+
+ fn require_loop(&self, name: &str, span: Span) {
+ match self.cx {
+ Loop => {}
+ Closure => {
+ span_err!(self.sess, span, E0267,
+ "`{}` inside of a closure", name);
+ }
+ Normal => {
+ span_err!(self.sess, span, E0268,
+ "`{}` outside of loop", name);
+ }
+ }
+ }
+}
--- /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.
+
+// Checks that all rvalues in a crate have statically known size. check_crate
+// is the public starting point.
+
+use rustc::dep_graph::DepNode;
+use rustc::middle::expr_use_visitor as euv;
+use rustc::middle::infer;
+use rustc::middle::mem_categorization as mc;
+use rustc::middle::ty::{self, ParameterEnvironment};
+
+use rustc_front::hir;
+use rustc_front::intravisit;
+use syntax::ast;
+use syntax::codemap::Span;
+
+pub fn check_crate(tcx: &ty::ctxt) {
+ let mut rvcx = RvalueContext { tcx: tcx };
+ tcx.visit_all_items_in_krate(DepNode::RvalueCheck, &mut rvcx);
+}
+
+struct RvalueContext<'a, 'tcx: 'a> {
+ tcx: &'a ty::ctxt<'tcx>,
+}
+
+impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> {
+ fn visit_fn(&mut self,
+ fk: intravisit::FnKind<'v>,
+ fd: &'v hir::FnDecl,
+ b: &'v hir::Block,
+ s: Span,
+ fn_id: ast::NodeId) {
+ {
+ // FIXME (@jroesch) change this to be an inference context
+ let param_env = ParameterEnvironment::for_item(self.tcx, fn_id);
+ let infcx = infer::new_infer_ctxt(self.tcx,
+ &self.tcx.tables,
+ Some(param_env.clone()));
+ let mut delegate = RvalueContextDelegate { tcx: self.tcx, param_env: ¶m_env };
+ let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
+ euv.walk_fn(fd, b);
+ }
+ intravisit::walk_fn(self, fk, fd, b, s)
+ }
+}
+
+struct RvalueContextDelegate<'a, 'tcx: 'a> {
+ tcx: &'a ty::ctxt<'tcx>,
+ param_env: &'a ty::ParameterEnvironment<'a,'tcx>,
+}
+
+impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
+ fn consume(&mut self,
+ _: ast::NodeId,
+ span: Span,
+ cmt: mc::cmt<'tcx>,
+ _: euv::ConsumeMode) {
+ debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty);
+ if !cmt.ty.is_sized(self.param_env, span) {
+ span_err!(self.tcx.sess, span, E0161,
+ "cannot move a value of type {0}: the size of {0} cannot be statically determined",
+ cmt.ty);
+ }
+ }
+
+ fn matched_pat(&mut self,
+ _matched_pat: &hir::Pat,
+ _cmt: mc::cmt,
+ _mode: euv::MatchMode) {}
+
+ fn consume_pat(&mut self,
+ _consume_pat: &hir::Pat,
+ _cmt: mc::cmt,
+ _mode: euv::ConsumeMode) {
+ }
+
+ fn borrow(&mut self,
+ _borrow_id: ast::NodeId,
+ _borrow_span: Span,
+ _cmt: mc::cmt,
+ _loan_region: ty::Region,
+ _bk: ty::BorrowKind,
+ _loan_cause: euv::LoanCause) {
+ }
+
+ fn decl_without_init(&mut self,
+ _id: ast::NodeId,
+ _span: Span) {
+ }
+
+ fn mutate(&mut self,
+ _assignment_id: ast::NodeId,
+ _assignment_span: Span,
+ _assignee_cmt: mc::cmt,
+ _mode: euv::MutateMode) {
+ }
+}
--- /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.
+
+// This compiler pass detects constants that refer to themselves
+// recursively.
+
+use rustc::front::map as ast_map;
+use rustc::session::Session;
+use rustc::middle::def::{Def, DefMap};
+use rustc::util::nodemap::NodeMap;
+
+use syntax::{ast};
+use syntax::codemap::Span;
+use syntax::feature_gate::{GateIssue, emit_feature_err};
+use rustc_front::intravisit::{self, Visitor};
+use rustc_front::hir;
+
+use std::cell::RefCell;
+
+struct CheckCrateVisitor<'a, 'ast: 'a> {
+ sess: &'a Session,
+ def_map: &'a DefMap,
+ ast_map: &'a ast_map::Map<'ast>,
+ // `discriminant_map` is a cache that associates the `NodeId`s of local
+ // variant definitions with the discriminant expression that applies to
+ // each one. If the variant uses the default values (starting from `0`),
+ // then `None` is stored.
+ discriminant_map: RefCell<NodeMap<Option<&'ast hir::Expr>>>,
+}
+
+impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
+ fn visit_item(&mut self, it: &'ast hir::Item) {
+ match it.node {
+ hir::ItemStatic(..) |
+ hir::ItemConst(..) => {
+ let mut recursion_visitor =
+ CheckItemRecursionVisitor::new(self, &it.span);
+ recursion_visitor.visit_item(it);
+ },
+ hir::ItemEnum(ref enum_def, ref generics) => {
+ // We could process the whole enum, but handling the variants
+ // with discriminant expressions one by one gives more specific,
+ // less redundant output.
+ for variant in &enum_def.variants {
+ if let Some(_) = variant.node.disr_expr {
+ let mut recursion_visitor =
+ CheckItemRecursionVisitor::new(self, &variant.span);
+ recursion_visitor.populate_enum_discriminants(enum_def);
+ recursion_visitor.visit_variant(variant, generics, it.id);
+ }
+ }
+ }
+ _ => {}
+ }
+ intravisit::walk_item(self, it)
+ }
+
+ fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
+ match ti.node {
+ hir::ConstTraitItem(_, ref default) => {
+ if let Some(_) = *default {
+ let mut recursion_visitor =
+ CheckItemRecursionVisitor::new(self, &ti.span);
+ recursion_visitor.visit_trait_item(ti);
+ }
+ }
+ _ => {}
+ }
+ intravisit::walk_trait_item(self, ti)
+ }
+
+ fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
+ match ii.node {
+ hir::ImplItemKind::Const(..) => {
+ let mut recursion_visitor =
+ CheckItemRecursionVisitor::new(self, &ii.span);
+ recursion_visitor.visit_impl_item(ii);
+ }
+ _ => {}
+ }
+ intravisit::walk_impl_item(self, ii)
+ }
+}
+
+pub fn check_crate<'ast>(sess: &Session,
+ krate: &'ast hir::Crate,
+ def_map: &DefMap,
+ ast_map: &ast_map::Map<'ast>) {
+ let mut visitor = CheckCrateVisitor {
+ sess: sess,
+ def_map: def_map,
+ ast_map: ast_map,
+ discriminant_map: RefCell::new(NodeMap()),
+ };
+ sess.abort_if_new_errors(|| {
+ krate.visit_all_items(&mut visitor);
+ });
+}
+
+struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
+ root_span: &'a Span,
+ sess: &'a Session,
+ ast_map: &'a ast_map::Map<'ast>,
+ def_map: &'a DefMap,
+ discriminant_map: &'a RefCell<NodeMap<Option<&'ast hir::Expr>>>,
+ idstack: Vec<ast::NodeId>,
+}
+
+impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
+ fn new(v: &'a 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,
+ discriminant_map: &v.discriminant_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) {
+ let any_static = self.idstack.iter().any(|&x| {
+ if let ast_map::NodeItem(item) = self.ast_map.get(x) {
+ if let hir::ItemStatic(..) = item.node {
+ true
+ } else {
+ false
+ }
+ } else {
+ false
+ }
+ });
+ if any_static {
+ if !self.sess.features.borrow().static_recursion {
+ emit_feature_err(&self.sess.parse_sess.span_diagnostic,
+ "static_recursion",
+ *self.root_span, GateIssue::Language, "recursive static");
+ }
+ } else {
+ span_err!(self.sess, *self.root_span, E0265, "recursive constant");
+ }
+ return;
+ }
+ self.idstack.push(id);
+ f(self);
+ self.idstack.pop();
+ }
+ // If a variant has an expression specifying its discriminant, then it needs
+ // to be checked just like a static or constant. However, if there are more
+ // variants with no explicitly specified discriminant, those variants will
+ // increment the same expression to get their values.
+ //
+ // So for every variant, we need to track whether there is an expression
+ // somewhere in the enum definition that controls its discriminant. We do
+ // this by starting from the end and searching backward.
+ fn populate_enum_discriminants(&self, enum_definition: &'ast hir::EnumDef) {
+ // Get the map, and return if we already processed this enum or if it
+ // has no variants.
+ let mut discriminant_map = self.discriminant_map.borrow_mut();
+ match enum_definition.variants.first() {
+ None => { return; }
+ Some(variant) if discriminant_map.contains_key(&variant.node.data.id()) => {
+ return;
+ }
+ _ => {}
+ }
+
+ // Go through all the variants.
+ let mut variant_stack: Vec<ast::NodeId> = Vec::new();
+ for variant in enum_definition.variants.iter().rev() {
+ variant_stack.push(variant.node.data.id());
+ // When we find an expression, every variant currently on the stack
+ // is affected by that expression.
+ if let Some(ref expr) = variant.node.disr_expr {
+ for id in &variant_stack {
+ discriminant_map.insert(*id, Some(expr));
+ }
+ variant_stack.clear()
+ }
+ }
+ // If we are at the top, that always starts at 0, so any variant on the
+ // stack has a default value and does not need to be checked.
+ for id in &variant_stack {
+ discriminant_map.insert(*id, None);
+ }
+ }
+}
+
+impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
+ fn visit_item(&mut self, it: &'ast hir::Item) {
+ self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it));
+ }
+
+ fn visit_enum_def(&mut self, enum_definition: &'ast hir::EnumDef,
+ generics: &'ast hir::Generics, item_id: ast::NodeId, _: Span) {
+ self.populate_enum_discriminants(enum_definition);
+ intravisit::walk_enum_def(self, enum_definition, generics, item_id);
+ }
+
+ fn visit_variant(&mut self, variant: &'ast hir::Variant,
+ _: &'ast hir::Generics, _: ast::NodeId) {
+ let variant_id = variant.node.data.id();
+ let maybe_expr;
+ if let Some(get_expr) = self.discriminant_map.borrow().get(&variant_id) {
+ // This is necessary because we need to let the `discriminant_map`
+ // borrow fall out of scope, so that we can reborrow farther down.
+ maybe_expr = (*get_expr).clone();
+ } else {
+ self.sess.span_bug(variant.span,
+ "`check_static_recursion` attempted to visit \
+ variant with unknown discriminant")
+ }
+ // If `maybe_expr` is `None`, that's because no discriminant is
+ // specified that affects this variant. Thus, no risk of recursion.
+ if let Some(expr) = maybe_expr {
+ self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr));
+ }
+ }
+
+ fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
+ self.with_item_id_pushed(ti.id, |v| intravisit::walk_trait_item(v, ti));
+ }
+
+ fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
+ self.with_item_id_pushed(ii.id, |v| intravisit::walk_impl_item(v, ii));
+ }
+
+ fn visit_expr(&mut self, e: &'ast hir::Expr) {
+ match e.node {
+ hir::ExprPath(..) => {
+ match self.def_map.get(&e.id).map(|d| d.base_def) {
+ Some(Def::Static(def_id, _)) |
+ Some(Def::AssociatedConst(def_id)) |
+ Some(Def::Const(def_id)) => {
+ if let Some(node_id) = self.ast_map.as_local_node_id(def_id) {
+ match self.ast_map.get(node_id) {
+ 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(_) => {},
+ _ => {
+ self.sess.span_bug(
+ e.span,
+ &format!("expected item, found {}",
+ self.ast_map.node_to_string(node_id)));
+ }
+ }
+ }
+ }
+ // For variants, we only want to check expressions that
+ // affect the specific variant used, but we need to check
+ // the whole enum definition to see what expression that
+ // might be (if any).
+ Some(Def::Variant(enum_id, variant_id)) => {
+ if let Some(enum_node_id) = self.ast_map.as_local_node_id(enum_id) {
+ if let hir::ItemEnum(ref enum_def, ref generics) =
+ self.ast_map.expect_item(enum_node_id).node
+ {
+ self.populate_enum_discriminants(enum_def);
+ let enum_id = self.ast_map.as_local_node_id(enum_id).unwrap();
+ let variant_id = self.ast_map.as_local_node_id(variant_id).unwrap();
+ let variant = self.ast_map.expect_variant(variant_id);
+ self.visit_variant(variant, generics, enum_id);
+ } else {
+ self.sess.span_bug(e.span,
+ "`check_static_recursion` found \
+ non-enum in Def::Variant");
+ }
+ }
+ }
+ _ => ()
+ }
+ },
+ _ => ()
+ }
+ intravisit::walk_expr(self, e);
+ }
+}
use rustc::dep_graph::DepNode;
use rustc::lint;
-use rustc::middle::def;
+use rustc::middle::def::{self, Def};
use rustc::middle::def_id::DefId;
use rustc::middle::privacy::{AccessLevel, AccessLevels};
use rustc::middle::privacy::ImportUse::*;
fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
if let hir::TyPath(..) = ty.node {
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
- def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {
+ Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
Some(AccessLevel::Public)
}
def => {
hir::ItemTy(ref ty, _) if item_level.is_some() => {
if let hir::TyPath(..) = ty.node {
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
- def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {},
+ Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {},
def => {
if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
self.update(node_id, Some(AccessLevel::Reachable));
// be accurate and we can get slightly wonky error messages (but type
// checking is always correct).
match path_res.full_def() {
- 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"),
- def::DefTrait(..) => ck("trait"),
- def::DefStruct(..) => ck("struct"),
- def::DefMethod(..) => ck("method"),
- def::DefMod(..) => ck("module"),
+ Def::Fn(..) => ck("function"),
+ Def::Static(..) => ck("static"),
+ Def::Const(..) => ck("const"),
+ Def::AssociatedConst(..) => ck("associated const"),
+ Def::Variant(..) => ck("variant"),
+ Def::TyAlias(..) => ck("type"),
+ Def::Enum(..) => ck("enum"),
+ Def::Trait(..) => ck("trait"),
+ Def::Struct(..) => ck("struct"),
+ Def::Method(..) => ck("method"),
+ Def::Mod(..) => ck("module"),
_ => {}
}
}
}
hir::ExprPath(..) => {
- if let def::DefStruct(_) = self.tcx.resolve_expr(expr) {
+ if let Def::Struct(..) = self.tcx.resolve_expr(expr) {
let expr_ty = self.tcx.expr_ty(expr);
let def = match expr_ty.sty {
ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
fn path_is_private_type(&self, path_id: ast::NodeId) -> bool {
let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) {
// `int` etc. (None doesn't seem to occur.)
- None | Some(def::DefPrimTy(..)) | Some(def::DefSelfTy(..)) => return false,
+ None | Some(Def::PrimTy(..)) | Some(Def::SelfTy(..)) => return false,
Some(def) => def.def_id(),
};
if let hir::TyPath(_, ref path) = ty.node {
let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
match def {
- def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {
+ Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
// Public
}
- def::DefAssociatedTy(..) if self.is_quiet => {
+ Def::AssociatedTy(..) if self.is_quiet => {
// Conservatively approximate the whole type alias as public without
// recursing into its components when determining impl publicity.
// For example, `impl <Type as Trait>::Alias {...}` may be a public impl
// free type aliases, but this isn't done yet.
return
}
- def::DefStruct(def_id) | def::DefTy(def_id, _) |
- def::DefTrait(def_id) | def::DefAssociatedTy(def_id, _) => {
+ Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
+ Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
// Non-local means public (private items can't leave their crate, modulo bugs)
if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
let item = self.tcx.map.expect_item(node_id);
use rustc::middle::cstore::{CrateStore, ChildItem, DlDef, DlField, DlImpl};
use rustc::middle::def::*;
use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::middle::ty::VariantKind;
use syntax::ast::{Name, NodeId};
use syntax::attr::AttrMetaMethods;
};
self.external_exports.insert(def_id);
let parent_link = ModuleParentLink(parent, name);
- let def = DefMod(def_id);
+ let def = Def::Mod(def_id);
let external_module = self.new_module(parent_link, Some(def), false, true);
debug!("(build reduced graph for item) found extern `{}`",
let name_bindings = self.add_child(name, parent, ForbidDuplicateTypes, sp);
let parent_link = ModuleParentLink(parent, name);
- let def = DefMod(self.ast_map.local_def_id(item.id));
+ let def = Def::Mod(self.ast_map.local_def_id(item.id));
let module = self.new_module(parent_link, Some(def), false, is_public);
name_bindings.define_module(module.clone(), sp);
module
let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp);
let mutbl = m == hir::MutMutable;
- name_bindings.define_value(DefStatic(self.ast_map.local_def_id(item.id), mutbl),
+ name_bindings.define_value(Def::Static(self.ast_map.local_def_id(item.id), mutbl),
sp,
modifiers);
parent
}
ItemConst(_, _) => {
self.add_child(name, parent, ForbidDuplicateValues, sp)
- .define_value(DefConst(self.ast_map.local_def_id(item.id)), sp, modifiers);
+ .define_value(Def::Const(self.ast_map.local_def_id(item.id)), sp, modifiers);
parent
}
ItemFn(_, _, _, _, _, _) => {
let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp);
- let def = DefFn(self.ast_map.local_def_id(item.id), false);
+ let def = Def::Fn(self.ast_map.local_def_id(item.id));
name_bindings.define_value(def, sp, modifiers);
parent
}
sp);
let parent_link = ModuleParentLink(parent, name);
- let def = DefTy(self.ast_map.local_def_id(item.id), false);
+ let def = Def::TyAlias(self.ast_map.local_def_id(item.id));
let module = self.new_module(parent_link, Some(def), false, is_public);
name_bindings.define_module(module, sp);
parent
sp);
let parent_link = ModuleParentLink(parent, name);
- let def = DefTy(self.ast_map.local_def_id(item.id), true);
+ let def = Def::Enum(self.ast_map.local_def_id(item.id));
let module = self.new_module(parent_link, Some(def), false, is_public);
name_bindings.define_module(module.clone(), sp);
let name_bindings = self.add_child(name, parent, forbid, sp);
// Define a name in the type namespace.
- name_bindings.define_type(DefTy(self.ast_map.local_def_id(item.id), false),
+ name_bindings.define_type(Def::Struct(self.ast_map.local_def_id(item.id)),
sp,
modifiers);
// If this is a newtype or unit-like struct, define a name
// in the value namespace as well
if let Some(cid) = ctor_id {
- name_bindings.define_value(DefStruct(self.ast_map.local_def_id(cid)),
+ name_bindings.define_value(Def::Struct(self.ast_map.local_def_id(cid)),
sp,
modifiers);
}
// Add all the items within to a new module.
let parent_link = ModuleParentLink(parent, name);
- let def = DefTrait(def_id);
+ let def = Def::Trait(def_id);
let module_parent = self.new_module(parent_link, Some(def), false, is_public);
name_bindings.define_module(module_parent.clone(), sp);
match trait_item.node {
hir::ConstTraitItem(..) => {
- let def = DefAssociatedConst(self.ast_map.local_def_id(trait_item.id));
+ let def = Def::AssociatedConst(self.ast_map.
+ local_def_id(trait_item.id));
// NB: not DefModifiers::IMPORTABLE
name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC);
}
hir::MethodTraitItem(..) => {
- let def = DefMethod(self.ast_map.local_def_id(trait_item.id));
+ let def = Def::Method(self.ast_map.local_def_id(trait_item.id));
// NB: not DefModifiers::IMPORTABLE
name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC);
}
hir::TypeTraitItem(..) => {
- let def = DefAssociatedTy(self.ast_map.local_def_id(item.id),
+ let def = Def::AssociatedTy(self.ast_map.local_def_id(item.id),
self.ast_map.local_def_id(trait_item.id));
// NB: not DefModifiers::IMPORTABLE
name_bindings.define_type(def, trait_item.span, DefModifiers::PUBLIC);
parent: Module<'b>,
variant_modifiers: DefModifiers) {
let name = variant.node.name;
- let is_exported = if variant.node.data.is_struct() {
+ if variant.node.data.is_struct() {
// Not adding fields for variants as they are not accessed with a self receiver
let variant_def_id = self.ast_map.local_def_id(variant.node.data.id());
self.structs.insert(variant_def_id, Vec::new());
- true
- } else {
- false
- };
+ }
+ // Variants are always treated as importable to allow them to be glob used.
+ // All variants are defined in both type and value namespaces as future-proofing.
let child = self.add_child(name, parent, ForbidDuplicateTypesAndValues, variant.span);
- // variants are always treated as importable to allow them to be glob
- // used
- child.define_value(DefVariant(item_id,
- self.ast_map.local_def_id(variant.node.data.id()),
- is_exported),
+ child.define_value(Def::Variant(item_id, self.ast_map.local_def_id(variant.node.data.id())),
variant.span,
DefModifiers::PUBLIC | DefModifiers::IMPORTABLE | variant_modifiers);
- child.define_type(DefVariant(item_id,
- self.ast_map.local_def_id(variant.node.data.id()),
- is_exported),
+ child.define_type(Def::Variant(item_id, self.ast_map.local_def_id(variant.node.data.id())),
variant.span,
DefModifiers::PUBLIC | DefModifiers::IMPORTABLE | variant_modifiers);
}
let def = match foreign_item.node {
ForeignItemFn(..) => {
- DefFn(self.ast_map.local_def_id(foreign_item.id), false)
+ Def::Fn(self.ast_map.local_def_id(foreign_item.id))
}
ForeignItemStatic(_, m) => {
- DefStatic(self.ast_map.local_def_id(foreign_item.id), m)
+ Def::Static(self.ast_map.local_def_id(foreign_item.id), m)
}
};
name_bindings.define_value(def, foreign_item.span, modifiers);
if is_exported {
self.external_exports.insert(def.def_id());
}
+ let is_struct_ctor = if let Def::Struct(def_id) = def {
+ self.session.cstore.tuple_struct_definition_if_ctor(def_id).is_some()
+ } else {
+ false
+ };
match def {
- DefMod(_) |
- DefForeignMod(_) |
- DefStruct(_) |
- DefTy(..) => {
+ Def::Mod(_) |
+ Def::ForeignMod(_) |
+ Def::Struct(..) |
+ Def::Enum(..) |
+ Def::TyAlias(..) if !is_struct_ctor => {
if let Some(module_def) = child_name_bindings.type_ns.module() {
debug!("(building reduced graph for external crate) already created module");
module_def.def.set(Some(def));
}
match def {
- DefMod(_) | DefForeignMod(_) => {}
- DefVariant(_, variant_id, is_struct) => {
+ Def::Mod(_) | Def::ForeignMod(_) => {}
+ Def::Variant(_, variant_id) => {
debug!("(building reduced graph for external crate) building variant {}",
final_ident);
- // variants are always treated as importable to allow them to be
- // glob used
+ // Variants are always treated as importable to allow them to be glob used.
+ // All variants are defined in both type and value namespaces as future-proofing.
let modifiers = DefModifiers::PUBLIC | DefModifiers::IMPORTABLE;
- if is_struct {
- child_name_bindings.define_type(def, DUMMY_SP, modifiers);
+ child_name_bindings.define_type(def, DUMMY_SP, modifiers);
+ child_name_bindings.define_value(def, DUMMY_SP, modifiers);
+ if self.session.cstore.variant_kind(variant_id) == Some(VariantKind::Struct) {
// Not adding fields for variants as they are not accessed with a self receiver
self.structs.insert(variant_id, Vec::new());
- } else {
- child_name_bindings.define_value(def, DUMMY_SP, modifiers);
}
}
- DefFn(ctor_id, true) => {
- child_name_bindings.define_value(
- self.session.cstore.tuple_struct_definition_if_ctor(ctor_id)
- .map_or(def, |_| DefStruct(ctor_id)), DUMMY_SP, modifiers);
- }
- DefFn(..) |
- DefStatic(..) |
- DefConst(..) |
- DefAssociatedConst(..) |
- DefMethod(..) => {
+ Def::Fn(..) |
+ Def::Static(..) |
+ Def::Const(..) |
+ Def::AssociatedConst(..) |
+ Def::Method(..) => {
debug!("(building reduced graph for external crate) building value (fn/static) {}",
final_ident);
// impl methods have already been defined with the correct importability
}
child_name_bindings.define_value(def, DUMMY_SP, modifiers);
}
- DefTrait(def_id) => {
+ Def::Trait(def_id) => {
debug!("(building reduced graph for external crate) building type {}",
final_ident);
let module = self.new_module(parent_link, Some(def), true, is_public);
child_name_bindings.define_module(module, DUMMY_SP);
}
- DefTy(..) | DefAssociatedTy(..) => {
+ Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => {
debug!("(building reduced graph for external crate) building type {}",
final_ident);
_ => modifiers & !DefModifiers::IMPORTABLE,
};
- if let DefTy(..) = def {
+ if let Def::Enum(..) = def {
+ child_name_bindings.type_ns.set_modifiers(modifiers);
+ } else if let Def::TyAlias(..) = def {
child_name_bindings.type_ns.set_modifiers(modifiers);
} else {
child_name_bindings.define_type(def, DUMMY_SP, modifiers);
}
}
- DefStruct(def_id) => {
+ Def::Struct(..) if is_struct_ctor => {
+ // Do nothing
+ }
+ Def::Struct(def_id) => {
debug!("(building reduced graph for external crate) building type and value for \
{}",
final_ident);
- child_name_bindings.define_type(def, DUMMY_SP, modifiers);
- let fields = self.session.cstore.struct_field_names(def_id);
- if fields.is_empty() {
- child_name_bindings.define_value(def, DUMMY_SP, modifiers);
+ child_name_bindings.define_type(def, DUMMY_SP, modifiers);
+ if let Some(ctor_def_id) = self.session.cstore.struct_ctor_def_id(def_id) {
+ child_name_bindings.define_value(Def::Struct(ctor_def_id), DUMMY_SP, modifiers);
}
// Record the def ID and fields of this struct.
+ let fields = self.session.cstore.struct_field_names(def_id);
self.structs.insert(def_id, fields);
}
- DefLocal(..) |
- DefPrimTy(..) |
- DefTyParam(..) |
- DefUpvar(..) |
- DefLabel(..) |
- DefSelfTy(..) |
- DefErr => {
+ Def::Local(..) |
+ Def::PrimTy(..) |
+ Def::TyParam(..) |
+ Def::Upvar(..) |
+ Def::Label(..) |
+ Def::SelfTy(..) |
+ Def::Err => {
panic!("didn't expect `{:?}`", def);
}
}
DlDef(def) => {
// Add the new child item, if necessary.
match def {
- DefForeignMod(def_id) => {
+ Def::ForeignMod(def_id) => {
// Foreign modules have no names. Recur and populate
// eagerly.
for child in self.session.cstore.item_children(def_id) {
E0317: r##"
User-defined types or type parameters cannot shadow the primitive types.
This error indicates you tried to define a type, struct or enum with the same
-name as an existing primitive type.
+name as an existing primitive type:
+
+```
+struct u8 {
+ // ...
+}
+```
+
+To fix this, simply name it something else.
+
+Such an error may also occur if you define a type parameter which shadows a
+primitive type. An example would be something like:
+
+```
+impl<u8> MyTrait for Option<u8> {
+ // ...
+}
+```
+
+In such a case, if you meant for `u8` to be a generic type parameter (i.e. any
+type can be used in its place), use something like `T` instead:
+
+```
+impl<T> MyTrait for Option<T> {
+ // ...
+}
+```
+
+On the other hand, if you wished to refer to the specific type `u8`, remove it
+from the type parameter list:
+
+```
+impl MyTrait for Option<u8> {
+ // ...
+}
See the Types section of the reference for more information about the primitive
types:
}
// The rib kind controls the translation of local
-// definitions (`DefLocal`) to upvars (`DefUpvar`).
+// definitions (`Def::Local`) to upvars (`Def::Upvar`).
#[derive(Copy, Clone, Debug)]
enum RibKind {
// No translation needs to be applied.
fn is_normal(&self) -> bool {
match self.def.get() {
- Some(DefMod(_)) | Some(DefForeignMod(_)) => true,
+ Some(Def::Mod(_)) | Some(Def::ForeignMod(_)) => true,
_ => false,
}
}
fn is_trait(&self) -> bool {
match self.def.get() {
- Some(DefTrait(_)) => true,
+ Some(Def::Trait(_)) => true,
_ => false,
}
}
arenas: &'a ResolverArenas<'a>)
-> Resolver<'a, 'tcx> {
let root_def_id = ast_map.local_def_id(CRATE_NODE_ID);
- let graph_root = ModuleS::new(NoParentLink, Some(DefMod(root_def_id)), false, true);
+ let graph_root = ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false, true);
let graph_root = arenas.modules.alloc(graph_root);
Resolver {
ItemRibKind),
|this| {
let local_def_id = this.ast_map.local_def_id(item.id);
- this.with_self_rib(DefSelfTy(Some(local_def_id), None), |this| {
+ this.with_self_rib(Def::SelfTy(Some(local_def_id), None), |this| {
this.visit_generics(generics);
walk_list!(this, visit_ty_param_bound, bounds);
// check for imports shadowing primitive types
let check_rename = |this: &Self, id, name| {
match this.def_map.borrow().get(&id).map(|d| d.full_def()) {
- Some(DefTy(..)) | Some(DefStruct(..)) | Some(DefTrait(..)) | None => {
+ Some(Def::Enum(..)) | Some(Def::TyAlias(..)) | Some(Def::Struct(..)) |
+ Some(Def::Trait(..)) | None => {
this.check_if_primitive_type_name(name, item.span);
}
_ => {}
// plain insert (no renaming)
function_type_rib.bindings
.insert(name,
- DlDef(DefTyParam(space,
+ DlDef(Def::TyParam(space,
index as u32,
self.ast_map
.local_def_id(type_parameter.id),
path_depth: usize)
-> Result<PathResolution, ()> {
if let Some(path_res) = self.resolve_path(id, trait_path, path_depth, TypeNS, true) {
- if let DefTrait(_) = path_res.base_def {
+ if let Def::Trait(_) = path_res.base_def {
debug!("(resolving trait) found trait def: {:?}", path_res);
Ok(path_res)
} else {
path_depth)));
// If it's a typedef, give a note
- if let DefTy(..) = path_res.base_def {
+ if let Def::TyAlias(..) = path_res.base_def {
err.span_note(trait_path.span,
"`type` aliases cannot be used for traits");
}
&hir::WherePredicate::RegionPredicate(_) => {}
&hir::WherePredicate::EqPredicate(ref eq_pred) => {
let path_res = self.resolve_path(eq_pred.id, &eq_pred.path, 0, TypeNS, true);
- if let Some(PathResolution { base_def: DefTyParam(..), .. }) = path_res {
+ if let Some(PathResolution { base_def: Def::TyParam(..), .. }) = path_res {
self.record_def(eq_pred.id, path_res.unwrap());
} else {
resolve_error(self,
// Resolve the self type.
this.visit_ty(self_type);
- this.with_self_rib(DefSelfTy(trait_id, Some((item_id, self_type.id))), |this| {
+ this.with_self_rib(Def::SelfTy(trait_id, Some((item_id, self_type.id))), |this| {
this.with_current_self_type(self_type, |this| {
for impl_item in impl_items {
match impl_item.node {
debug!("(resolving pattern) binding `{}`", renamed);
let def_id = self.ast_map.local_def_id(pattern.id);
- let def = DefLocal(def_id, pattern.id);
+ let def = Def::Local(def_id, pattern.id);
// Record the definition so that later passes
// will be able to distinguish variants from
};
if let Some(path_res) = resolution {
match path_res.base_def {
- DefVariant(..) | DefStruct(..) | DefConst(..) => {
+ Def::Struct(..) if path_res.depth == 0 => {
self.record_def(pattern.id, path_res);
}
- DefStatic(..) => {
+ Def::Variant(..) | Def::Const(..) => {
+ self.record_def(pattern.id, path_res);
+ }
+ Def::Static(..) => {
resolve_error(&self,
path.span,
ResolutionError::StaticVariableReference);
match path_res.base_def {
// All `<T as Trait>::CONST` should end up here, and
// have the trait already selected.
- DefAssociatedConst(..) => {
+ Def::AssociatedConst(..) => {
self.record_def(pattern.id, path_res);
}
_ => {
// For the two success cases, this lookup can be
// considered as not having a private component because
// the lookup happened only within the current module.
- Some(def @ DefVariant(..)) | Some(def @ DefStruct(..)) => {
+ Some(def @ Def::Variant(..)) | Some(def @ Def::Struct(..)) => {
return FoundStructOrEnumVariant(def, LastMod(AllPublic));
}
- Some(def @ DefConst(..)) | Some(def @ DefAssociatedConst(..)) => {
+ Some(def @ Def::Const(..)) | Some(def @ Def::AssociatedConst(..)) => {
return FoundConst(def, LastMod(AllPublic), name);
}
- Some(DefStatic(..)) => {
+ Some(Def::Static(..)) => {
resolve_error(self, span, ResolutionError::StaticVariableReference);
return BareIdentifierPatternUnresolved;
}
resolution = this.resolve_path(id, path, depth, TypeNS, true);
});
}
- if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
+ if let Some(Def::Mod(_)) = resolution.map(|r| r.base_def) {
// A module is not a valid type or value.
resolution = None;
}
if let Some(&prim_ty) = self.primitive_type_table
.primitive_types
.get(&identifier.unhygienic_name) {
- return Some(LocalDef::from_def(DefPrimTy(prim_ty)));
+ return Some(LocalDef::from_def(Def::PrimTy(prim_ty)));
}
}
};
let mut def = local_def.def;
match def {
- DefUpvar(..) => {
+ Def::Upvar(..) => {
self.session.span_bug(span, &format!("unexpected {:?} in bindings", def))
}
- DefLocal(_, node_id) => {
+ Def::Local(_, node_id) => {
for rib in ribs {
match rib.kind {
NormalRibKind => {
.entry(function_id)
.or_insert_with(|| NodeMap());
if let Some(&index) = seen.get(&node_id) {
- def = DefUpvar(node_def_id, node_id, index, function_id);
+ def = Def::Upvar(node_def_id, node_id, index, function_id);
continue;
}
let vec = self.freevars
span: span,
});
- def = DefUpvar(node_def_id, node_id, depth, function_id);
+ def = Def::Upvar(node_def_id, node_id, depth, function_id);
seen.insert(node_id, depth);
}
ItemRibKind | MethodRibKind => {
}
}
}
- DefTyParam(..) | DefSelfTy(..) => {
+ Def::TyParam(..) | Def::SelfTy(..) => {
for rib in ribs {
match rib.kind {
NormalRibKind | MethodRibKind | ClosureRibKind(..) => {
if allowed == Everything {
// Look for a field with the same name in the current self_type.
match self.def_map.borrow().get(&node_id).map(|d| d.full_def()) {
- Some(DefTy(did, _)) |
- Some(DefStruct(did)) |
- Some(DefVariant(_, did, _)) => match self.structs.get(&did) {
+ Some(Def::Enum(did)) |
+ Some(Def::TyAlias(did)) |
+ Some(Def::Struct(did)) |
+ Some(Def::Variant(_, did)) => match self.structs.get(&did) {
None => {}
Some(fields) => {
if fields.iter().any(|&field_name| name == field_name) {
// Look for a method in the current self type's impl module.
if let Some(module) = get_module(self, path.span, &name_path) {
if let Some(binding) = module.children.borrow().get(&name) {
- if let Some(DefMethod(did)) = binding.value_ns.def() {
+ if let Some(Def::Method(did)) = binding.value_ns.def() {
if is_static_method(self, did) {
return StaticMethod(path_names_to_string(&path, 0));
}
// scopes looking for it.
if let Some(path_res) = resolution {
// Check if struct variant
- if let DefVariant(_, _, true) = path_res.base_def {
+ let is_struct_variant = if let Def::Variant(_, variant_id) = path_res.base_def {
+ self.structs.contains_key(&variant_id)
+ } else {
+ false
+ };
+ if is_struct_variant {
+ let _ = self.structs.contains_key(&path_res.base_def.def_id());
let path_name = path_names_to_string(path, 0);
let mut err = resolve_struct_error(self,
self.record_def(expr.id, err_path_resolution());
match type_res.map(|r| r.base_def) {
- Some(DefTy(struct_id, _)) if self.structs.contains_key(&struct_id) => {
+ Some(Def::Struct(..)) => {
let mut err = resolve_struct_error(self,
expr.span,
ResolutionError::StructVariantUsedAsFunction(&*path_name));
ExprLoop(_, Some(label)) | ExprWhile(_, _, Some(label)) => {
self.with_label_rib(|this| {
- let def_like = DlDef(DefLabel(expr.id));
+ let def_like = DlDef(Def::Label(expr.id));
{
let rib = this.label_ribs.last_mut().unwrap();
label.span,
ResolutionError::UndeclaredLabel(&label.node.name.as_str()))
}
- Some(DlDef(def @ DefLabel(_))) => {
+ Some(DlDef(def @ Def::Label(_))) => {
// Since this def is a label, it is never read.
self.record_def(expr.id,
PathResolution {
None => continue,
};
let trait_def_id = match def {
- DefTrait(trait_def_id) => trait_def_id,
+ Def::Trait(trait_def_id) => trait_def_id,
_ => continue,
};
if self.trait_item_map.contains_key(&(name, trait_def_id)) {
Some(ref target) => target,
};
let did = match target.binding.def() {
- Some(DefTrait(trait_def_id)) => trait_def_id,
+ Some(Def::Trait(trait_def_id)) => trait_def_id,
Some(..) | None => continue,
};
if self.trait_item_map.contains_key(&(name, did)) {
fn err_path_resolution() -> PathResolution {
PathResolution {
- base_def: DefErr,
+ base_def: Def::Err,
last_private: LastMod(AllPublic),
depth: 0,
}
if let Some(did) = target_module.def_id() {
self.resolver.def_map.borrow_mut().insert(id,
PathResolution {
- base_def: DefMod(did),
+ base_def: Def::Mod(did),
last_private: lp,
depth: 0,
});
if let Some(path) = env::var_os("PATH") {
new_path.extend(env::split_paths(&path));
}
+ if sess.target.target.options.is_like_msvc {
+ new_path.extend(msvc::host_dll_path());
+ }
env::join_paths(new_path).unwrap()
}
suffix))
}
config::CrateTypeStaticlib => {
- outputs.out_directory.join(&format!("lib{}.a", libname))
+ let (prefix, suffix) = (&sess.target.target.options.staticlib_prefix,
+ &sess.target.target.options.staticlib_suffix);
+ outputs.out_directory.join(&format!("{}{}{}", prefix, libname,
+ suffix))
}
config::CrateTypeExecutable => {
let suffix = &sess.target.target.options.exe_suffix;
fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); }
fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
fn args(&mut self, args: &[String]) { self.cmd.args(args); }
- fn build_dylib(&mut self, _out_filename: &Path) { self.cmd.arg("/DLL"); }
+
+ fn build_dylib(&mut self, out_filename: &Path) {
+ self.cmd.arg("/DLL");
+ let mut arg: OsString = "/IMPLIB:".into();
+ arg.push(out_filename.with_extension("dll.lib"));
+ self.cmd.arg(arg);
+ }
+
fn gc_sections(&mut self, _is_dylib: bool) { self.cmd.arg("/OPT:REF,ICF"); }
fn link_dylib(&mut self, lib: &str) {
// `foo.lib` file if the dll doesn't actually export any symbols, so we
// check to see if the file is there and just omit linking to it if it's
// not present.
- let name = format!("{}.lib", lib);
+ let name = format!("{}.dll.lib", lib);
if fs::metadata(&path.join(&name)).is_ok() {
self.cmd.arg(name);
}
//! paths/files is based on Microsoft's logic in their vcvars bat files, but
//! comments can also be found below leading through the various code paths.
-use std::process::Command;
-use session::Session;
-
#[cfg(windows)]
mod registry;
#[cfg(windows)]
-pub fn link_exe_cmd(sess: &Session) -> Command {
+mod platform {
use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{Path, PathBuf};
- use self::registry::{LOCAL_MACHINE};
-
- let arch = &sess.target.target.arch;
- let (binsub, libsub, vclibsub) =
- match (bin_subdir(arch), lib_subdir(arch), vc_lib_subdir(arch)) {
- (Some(x), Some(y), Some(z)) => (x, y, z),
- _ => return Command::new("link.exe"),
- };
+ use std::process::Command;
+ use session::Session;
+ use super::registry::{LOCAL_MACHINE};
- // First we need to figure out whether the environment is already correctly
- // configured by vcvars. We do this by looking at the environment variable
- // `VCINSTALLDIR` which is always set by vcvars, and unlikely to be set
- // otherwise. If it is defined, then we derive the path to `link.exe` from
- // that and trust that everything else is configured correctly.
- //
- // If `VCINSTALLDIR` wasn't defined (or we couldn't find the linker where it
- // claimed it should be), then we resort to finding everything ourselves.
- // First we find where the latest version of MSVC is installed and what
- // version it is. Then based on the version we find the appropriate SDKs.
- //
- // For MSVC 14 (VS 2015) we look for the Win10 SDK and failing that we look
- // for the Win8.1 SDK. We also look for the Universal CRT.
- //
- // For MSVC 12 (VS 2013) we look for the Win8.1 SDK.
- //
- // For MSVC 11 (VS 2012) we look for the Win8 SDK.
- //
- // For all other versions the user has to execute the appropriate vcvars bat
- // file themselves to configure the environment.
- //
- // If despite our best efforts we are still unable to find MSVC then we just
- // blindly call `link.exe` and hope for the best.
- return env::var_os("VCINSTALLDIR").and_then(|dir| {
- debug!("Environment already configured by user. Assuming it works.");
- let mut p = PathBuf::from(dir);
- p.push("bin");
- p.push(binsub);
- p.push("link.exe");
- if !p.is_file() { return None }
- Some(Command::new(p))
- }).or_else(|| {
- get_vc_dir().and_then(|(ver, vcdir)| {
- debug!("Found VC installation directory {:?}", vcdir);
- let mut linker = vcdir.clone();
- linker.push("bin");
- linker.push(binsub);
- linker.push("link.exe");
- if !linker.is_file() { return None }
- let mut cmd = Command::new(linker);
- add_lib(&mut cmd, &vcdir.join("lib").join(vclibsub));
- if ver == "14.0" {
- if let Some(dir) = get_ucrt_dir() {
- debug!("Found Universal CRT {:?}", dir);
- add_lib(&mut cmd, &dir.join("ucrt").join(libsub));
- }
- if let Some(dir) = get_sdk10_dir() {
- debug!("Found Win10 SDK {:?}", dir);
- add_lib(&mut cmd, &dir.join("um").join(libsub));
- } else if let Some(dir) = get_sdk81_dir() {
- debug!("Found Win8.1 SDK {:?}", dir);
- add_lib(&mut cmd, &dir.join("um").join(libsub));
- }
- } else if ver == "12.0" {
- if let Some(dir) = get_sdk81_dir() {
- debug!("Found Win8.1 SDK {:?}", dir);
- add_lib(&mut cmd, &dir.join("um").join(libsub));
- }
- } else { // ver == "11.0"
- if let Some(dir) = get_sdk8_dir() {
- debug!("Found Win8 SDK {:?}", dir);
- add_lib(&mut cmd, &dir.join("um").join(libsub));
- }
- }
- Some(cmd)
+ // Cross toolchains depend on dlls from the host toolchain
+ // We can't just add it to the Command's PATH in `link_exe_cmd` because it
+ // is later overridden so we publicly expose it here instead
+ pub fn host_dll_path() -> Option<PathBuf> {
+ get_vc_dir().and_then(|(_, vcdir)| {
+ host_dll_subdir().map(|sub| {
+ vcdir.join("bin").join(sub)
+ })
})
- }).unwrap_or_else(|| {
- debug!("Failed to locate linker.");
- Command::new("link.exe")
- });
+ }
+
+ pub fn link_exe_cmd(sess: &Session) -> Command {
+ let arch = &sess.target.target.arch;
+ let (binsub, libsub, vclibsub) =
+ match (bin_subdir(arch), lib_subdir(arch), vc_lib_subdir(arch)) {
+ (Some(x), Some(y), Some(z)) => (x, y, z),
+ _ => return Command::new("link.exe"),
+ };
+ // First we need to figure out whether the environment is already correctly
+ // configured by vcvars. We do this by looking at the environment variable
+ // `VCINSTALLDIR` which is always set by vcvars, and unlikely to be set
+ // otherwise. If it is defined, then we derive the path to `link.exe` from
+ // that and trust that everything else is configured correctly.
+ //
+ // If `VCINSTALLDIR` wasn't defined (or we couldn't find the linker where it
+ // claimed it should be), then we resort to finding everything ourselves.
+ // First we find where the latest version of MSVC is installed and what
+ // version it is. Then based on the version we find the appropriate SDKs.
+ //
+ // For MSVC 14 (VS 2015) we look for the Win10 SDK and failing that we look
+ // for the Win8.1 SDK. We also look for the Universal CRT.
+ //
+ // For MSVC 12 (VS 2013) we look for the Win8.1 SDK.
+ //
+ // For MSVC 11 (VS 2012) we look for the Win8 SDK.
+ //
+ // For all other versions the user has to execute the appropriate vcvars bat
+ // file themselves to configure the environment.
+ //
+ // If despite our best efforts we are still unable to find MSVC then we just
+ // blindly call `link.exe` and hope for the best.
+ return env::var_os("VCINSTALLDIR").and_then(|dir| {
+ debug!("Environment already configured by user. Assuming it works.");
+ let mut p = PathBuf::from(dir);
+ p.push("bin");
+ p.push(binsub);
+ p.push("link.exe");
+ if !p.is_file() { return None }
+ Some(Command::new(p))
+ }).or_else(|| {
+ get_vc_dir().and_then(|(ver, vcdir)| {
+ debug!("Found VC installation directory {:?}", vcdir);
+ let linker = vcdir.clone().join("bin").join(binsub).join("link.exe");
+ if !linker.is_file() { return None }
+ let mut cmd = Command::new(linker);
+ add_lib(&mut cmd, &vcdir.join("lib").join(vclibsub));
+ if ver == "14.0" {
+ if let Some(dir) = get_ucrt_dir() {
+ debug!("Found Universal CRT {:?}", dir);
+ add_lib(&mut cmd, &dir.join("ucrt").join(libsub));
+ }
+ if let Some(dir) = get_sdk10_dir() {
+ debug!("Found Win10 SDK {:?}", dir);
+ add_lib(&mut cmd, &dir.join("um").join(libsub));
+ } else if let Some(dir) = get_sdk81_dir() {
+ debug!("Found Win8.1 SDK {:?}", dir);
+ add_lib(&mut cmd, &dir.join("um").join(libsub));
+ }
+ } else if ver == "12.0" {
+ if let Some(dir) = get_sdk81_dir() {
+ debug!("Found Win8.1 SDK {:?}", dir);
+ add_lib(&mut cmd, &dir.join("um").join(libsub));
+ }
+ } else { // ver == "11.0"
+ if let Some(dir) = get_sdk8_dir() {
+ debug!("Found Win8 SDK {:?}", dir);
+ add_lib(&mut cmd, &dir.join("um").join(libsub));
+ }
+ }
+ Some(cmd)
+ })
+ }).unwrap_or_else(|| {
+ debug!("Failed to locate linker.");
+ Command::new("link.exe")
+ });
+ }
// A convenience function to make the above code simpler
fn add_lib(cmd: &mut Command, lib: &Path) {
let mut arg: OsString = "/LIBPATH:".into();
_ => None,
}
}
+ fn host_dll_subdir() -> Option<&'static str> {
+ if cfg!(target_arch = "x86_64") { Some("amd64") }
+ else if cfg!(target_arch = "x86") { Some("") }
+ else { None }
+ }
}
// If we're not on Windows, then there's no registry to search through and MSVC
// wouldn't be able to run, so we just call `link.exe` and hope for the best.
#[cfg(not(windows))]
-pub fn link_exe_cmd(_sess: &Session) -> Command {
- Command::new("link.exe")
+mod platform {
+ use std::path::PathBuf;
+ use std::process::Command;
+ use session::Session;
+ pub fn link_exe_cmd(_sess: &Session) -> Command {
+ Command::new("link.exe")
+ }
+ pub fn host_dll_path() -> Option<PathBuf> { None }
}
+pub use self::platform::*;
use session::Session;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::ty;
}
let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
match def {
- def::DefPrimTy(..) => None,
- def::DefSelfTy(..) => None,
+ Def::PrimTy(..) => None,
+ Def::SelfTy(..) => None,
_ => Some(def.def_id()),
}
}
}
let def = def_map.get(&ref_id).unwrap().full_def();
match def {
- def::DefMod(_) |
- def::DefForeignMod(_) => Some(recorder::ModRef),
- def::DefStruct(_) => Some(recorder::TypeRef),
- def::DefTy(..) |
- def::DefAssociatedTy(..) |
- def::DefTrait(_) => Some(recorder::TypeRef),
- def::DefStatic(_, _) |
- def::DefConst(_) |
- def::DefAssociatedConst(..) |
- def::DefLocal(..) |
- def::DefVariant(_, _, _) |
- def::DefUpvar(..) => Some(recorder::VarRef),
-
- def::DefFn(..) => Some(recorder::FnRef),
-
- def::DefSelfTy(..) |
- def::DefLabel(_) |
- def::DefTyParam(..) |
- def::DefMethod(..) |
- def::DefPrimTy(_) |
- def::DefErr => {
+ Def::Mod(_) |
+ Def::ForeignMod(_) => Some(recorder::ModRef),
+ Def::Struct(..) => Some(recorder::TypeRef),
+ Def::Enum(..) |
+ Def::TyAlias(..) |
+ Def::AssociatedTy(..) |
+ Def::Trait(_) => Some(recorder::TypeRef),
+ Def::Static(_, _) |
+ Def::Const(_) |
+ Def::AssociatedConst(..) |
+ Def::Local(..) |
+ Def::Variant(..) |
+ Def::Upvar(..) => Some(recorder::VarRef),
+
+ Def::Fn(..) => Some(recorder::FnRef),
+
+ Def::SelfTy(..) |
+ Def::Label(_) |
+ Def::TyParam(..) |
+ Def::Method(..) |
+ Def::PrimTy(_) |
+ Def::Err => {
self.sess.span_bug(span,
&format!("lookup_def_kind for unexpected item: {:?}", def));
}
qualname.push_str(name);
let val = self.span.snippet(variant.span);
- self.fmt.struct_variant_str(variant.span,
- self.span.span_for_first_ident(variant.span),
- variant.node.data.id(),
- variant.node.data.id(),
- &qualname,
- &enum_data.qualname,
- &val,
- enum_data.id);
+ match variant.node.data {
+ ast::VariantData::Struct(..) => {
+ self.fmt.struct_variant_str(variant.span,
+ self.span.span_for_first_ident(variant.span),
+ variant.node.data.id(),
+ &qualname,
+ &enum_data.qualname,
+ &val,
+ enum_data.scope);
+ }
+ _ => {
+ self.fmt.tuple_variant_str(variant.span,
+ self.span.span_for_first_ident(variant.span),
+ variant.node.data.id(),
+ name,
+ &qualname,
+ &enum_data.qualname,
+ &val,
+ enum_data.scope);
+ }
+ }
+
for field in variant.node.data.fields() {
self.process_struct_field_def(field, variant.node.data.id());
let def_map = self.tcx.def_map.borrow();
let def = def_map.get(&id).unwrap().full_def();
match def {
- def::DefMethod(did) => {
+ Def::Method(did) => {
let ti = self.tcx.impl_or_trait_item(did);
if let ty::MethodTraitItem(m) = ti {
if m.explicit_self == ty::ExplicitSelfCategory::Static {
}
}
}
- def::DefLocal(..) |
- def::DefStatic(_,_) |
- def::DefConst(..) |
- def::DefAssociatedConst(..) |
- def::DefStruct(_) |
- def::DefVariant(..) |
- def::DefFn(..) => self.write_sub_paths_truncated(path, false),
+ Def::Local(..) |
+ Def::Static(_,_) |
+ Def::Const(..) |
+ Def::AssociatedConst(..) |
+ Def::Struct(..) |
+ Def::Variant(..) |
+ Def::Fn(..) => self.write_sub_paths_truncated(path, false),
_ => {}
}
}
}
let def = def_map.get(&id).unwrap().full_def();
match def {
- def::DefLocal(_, id) => {
+ Def::Local(_, id) => {
let value = if immut == ast::MutImmutable {
self.span.snippet(p.span).to_string()
} else {
"qualified path for local variable def in arm");
self.fmt.variable_str(p.span, Some(p.span), id, &path_to_string(p), &value, "")
}
- def::DefVariant(..) | def::DefTy(..) | def::DefStruct(..) => {
+ Def::Variant(..) | Def::Enum(..) |
+ Def::TyAlias(..) | Def::Struct(..) => {
paths_to_process.push((id, p.clone(), Some(ref_kind)))
}
// FIXME(nrc) what are these doing here?
- def::DefStatic(_, _) |
- def::DefConst(..) |
- def::DefAssociatedConst(..) => {}
+ Def::Static(_, _) |
+ Def::Const(..) |
+ Def::AssociatedConst(..) => {}
_ => error!("unexpected definition kind when processing collected paths: {:?}",
def),
}
// except according to those terms.
use middle::ty;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use std::env;
let def = def_map.get(&id).unwrap().full_def();
let sub_span = self.span_utils.span_for_last_ident(path.span);
match def {
- def::DefUpvar(..) |
- def::DefLocal(..) |
- def::DefStatic(..) |
- def::DefConst(..) |
- def::DefAssociatedConst(..) |
- def::DefVariant(..) => {
+ Def::Upvar(..) |
+ Def::Local(..) |
+ Def::Static(..) |
+ Def::Const(..) |
+ Def::AssociatedConst(..) |
+ Def::Variant(..) => {
Some(Data::VariableRefData(VariableRefData {
name: self.span_utils.snippet(sub_span.unwrap()),
span: sub_span.unwrap(),
ref_id: def.def_id(),
}))
}
- def::DefStruct(def_id) |
- def::DefTy(def_id, _) |
- def::DefTrait(def_id) |
- def::DefTyParam(_, _, def_id, _) => {
+ Def::Struct(def_id) |
+ Def::Enum(def_id) |
+ Def::TyAlias(def_id) |
+ Def::Trait(def_id) |
+ Def::TyParam(_, _, def_id, _) => {
Some(Data::TypeRefData(TypeRefData {
span: sub_span.unwrap(),
ref_id: def_id,
scope: self.enclosing_scope(id),
}))
}
- def::DefMethod(decl_id) => {
+ Def::Method(decl_id) => {
let sub_span = self.span_utils.sub_span_for_meth_name(path.span);
let def_id = if decl_id.is_local() {
let ti = self.tcx.impl_or_trait_item(decl_id);
decl_id: Some(decl_id),
}))
}
- def::DefFn(def_id, _) => {
+ Def::Fn(def_id) => {
Some(Data::FunctionCallData(FunctionCallData {
ref_id: def_id,
span: sub_span.unwrap(),
scope: self.enclosing_scope(id),
}))
}
- def::DefMod(def_id) => {
+ Def::Mod(def_id) => {
Some(Data::ModRefData(ModRefData {
ref_id: def_id,
span: sub_span.unwrap(),
}
let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
match def {
- def::DefPrimTy(_) | def::DefSelfTy(..) => None,
+ Def::PrimTy(_) | Def::SelfTy(..) => None,
_ => Some(def.def_id()),
}
}
span: Span,
sub_span: Option<Span>,
id: NodeId,
- ctor_id: NodeId,
name: &str,
typ: &str,
val: &str,
scope_id: NodeId) {
let id = self.normalize_node_id(id);
+ let ctor_id = id;
let scope_id = self.normalize_node_id(scope_id);
- let ctor_id = self.normalize_node_id(ctor_id);
self.check_and_record(VariantStruct,
span,
sub_span,
use middle::check_match::StaticInliner;
use middle::check_match;
use middle::const_eval;
-use middle::def::{self, DefMap};
+use middle::def::{Def, DefMap};
use middle::def_id::DefId;
use middle::expr_use_visitor as euv;
use middle::infer;
// This is either an enum variant or a variable binding.
let opt_def = tcx.def_map.borrow().get(&cur.id).map(|d| d.full_def());
match opt_def {
- Some(def::DefVariant(enum_id, var_id, _)) => {
+ Some(Def::Variant(enum_id, var_id)) => {
let variant = tcx.lookup_adt_def(enum_id).variant_with_id(var_id);
Variant(Disr::from(variant.disr_val),
adt::represent_node(bcx, cur.id),
hir::PatTup(_) => true,
hir::PatStruct(..) => {
match tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(def::DefVariant(..)) => false,
+ Some(Def::Variant(..)) => false,
_ => true,
}
}
hir::PatEnum(..) | hir::PatIdent(_, _, None) => {
match tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(def::DefStruct(..)) => true,
+ Some(Def::Struct(..)) => true,
_ => false
}
}
fn is_discr_reassigned(bcx: Block, discr: &hir::Expr, body: &hir::Expr) -> bool {
let (vid, field) = match discr.node {
hir::ExprPath(..) => match bcx.def(discr.id) {
- def::DefLocal(_, vid) | def::DefUpvar(_, vid, _, _) => (vid, None),
+ Def::Local(_, vid) | Def::Upvar(_, vid, _, _) => (vid, None),
_ => return false
},
hir::ExprField(ref base, field) => {
let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
- Some(def::DefLocal(_, vid)) | Some(def::DefUpvar(_, vid, _, _)) => vid,
+ Some(Def::Local(_, vid)) | Some(Def::Upvar(_, vid, _, _)) => vid,
_ => return false
};
(vid, Some(mc::NamedField(field.node)))
},
hir::ExprTupField(ref base, field) => {
let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
- Some(def::DefLocal(_, vid)) | Some(def::DefUpvar(_, vid, _, _)) => vid,
+ Some(Def::Local(_, vid)) | Some(Def::Upvar(_, vid, _, _)) => vid,
_ => return false
};
(vid, Some(mc::PositionalField(field.node)))
hir::PatEnum(_, ref sub_pats) => {
let opt_def = bcx.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def());
match opt_def {
- Some(def::DefVariant(enum_id, var_id, _)) => {
+ Some(Def::Variant(enum_id, var_id)) => {
let repr = adt::represent_node(bcx, pat.id);
let vinfo = ccx.tcx().lookup_adt_def(enum_id).variant_with_id(var_id);
let args = extract_variant_args(bcx,
}
}
}
- Some(def::DefStruct(..)) => {
+ Some(Def::Struct(..)) => {
match *sub_pats {
None => {
// This is a unit-like struct. Nothing to do here.
// giving `trans_item` access to this item, so also record a read.
tcx.dep_graph.with_task(DepNode::TransCrateItem(def_id), || {
tcx.dep_graph.read(DepNode::Hir(def_id));
+
+ // We are going to be accessing various tables
+ // generated by TypeckItemBody; we also assume
+ // that the body passes type check. These tables
+ // are not individually tracked, so just register
+ // a read here.
+ tcx.dep_graph.read(DepNode::TypeckItemBody(def_id));
+
trans_item(self.ccx, i);
});
use back::link;
use llvm::{self, ValueRef, get_params};
use middle::cstore::LOCAL_CRATE;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::infer;
use middle::subst;
}
fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- def: def::Def,
+ def: Def,
ref_expr: &hir::Expr)
-> Callee<'blk, 'tcx> {
debug!("trans_def(def={:?}, ref_expr={:?})", def, ref_expr);
let expr_ty = common::node_id_type(bcx, ref_expr.id);
match def {
- def::DefFn(did, _) if {
+ Def::Fn(did) if {
let maybe_def_id = inline::get_local_instance(bcx.ccx(), did);
let maybe_ast_node = maybe_def_id.and_then(|def_id| {
let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
ty: expr_ty
}
}
- def::DefFn(did, _) if match expr_ty.sty {
+ Def::Fn(did) if match expr_ty.sty {
ty::TyBareFn(_, ref f) => f.abi == synabi::RustIntrinsic ||
f.abi == synabi::PlatformIntrinsic,
_ => false
let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
Callee { bcx: bcx, data: Intrinsic(node_id, substs), ty: expr_ty }
}
- def::DefFn(did, _) => {
+ Def::Fn(did) => {
fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
bcx.fcx.param_substs))
}
- def::DefMethod(meth_did) => {
+ Def::Method(meth_did) => {
let method_item = bcx.tcx().impl_or_trait_item(meth_did);
let fn_datum = match method_item.container() {
ty::ImplContainer(_) => {
};
fn_callee(bcx, fn_datum)
}
- def::DefVariant(tid, vid, _) => {
+ Def::Variant(tid, vid) => {
let vinfo = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
assert_eq!(vinfo.kind(), ty::VariantKind::Tuple);
ty: expr_ty
}
}
- def::DefStruct(_) => {
+ Def::Struct(..) => {
Callee {
bcx: bcx,
data: NamedTupleConstructor(Disr(0)),
ty: expr_ty
}
}
- def::DefStatic(..) |
- def::DefConst(..) |
- def::DefAssociatedConst(..) |
- def::DefLocal(..) |
- def::DefUpvar(..) => {
+ Def::Static(..) |
+ Def::Const(..) |
+ Def::AssociatedConst(..) |
+ Def::Local(..) |
+ Def::Upvar(..) => {
datum_callee(bcx, ref_expr)
}
- def::DefMod(..) | def::DefForeignMod(..) | def::DefTrait(..) |
- def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) |
- def::DefLabel(..) | def::DefTyParam(..) |
- def::DefSelfTy(..) | def::DefErr => {
+ Def::Mod(..) | Def::ForeignMod(..) | Def::Trait(..) |
+ Def::Enum(..) | Def::TyAlias(..) | Def::PrimTy(..) |
+ Def::AssociatedTy(..) | Def::Label(..) | Def::TyParam(..) |
+ Def::SelfTy(..) | Def::Err => {
bcx.tcx().sess.span_bug(
ref_expr.span,
&format!("cannot translate def {:?} \
use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef, TypeKind};
use llvm::{True, False, Bool};
use middle::cfg;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::infer;
use middle::lang_items::LangItem;
impl<'tcx> VariantInfo<'tcx> {
pub fn from_ty(tcx: &ty::ctxt<'tcx>,
ty: Ty<'tcx>,
- opt_def: Option<def::Def>)
+ opt_def: Option<Def>)
-> Self
{
match ty.sty {
self.tcx().map.node_to_string(id).to_string()
}
- pub fn def(&self, nid: ast::NodeId) -> def::Def {
+ pub fn def(&self, nid: ast::NodeId) -> Def {
match self.tcx().def_map.borrow().get(&nid) {
Some(v) => v.full_def(),
None => {
}
pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- node: ExprOrMethodCall,
- param_substs: &subst::Substs<'tcx>)
- -> subst::Substs<'tcx> {
+ node: ExprOrMethodCall,
+ param_substs: &subst::Substs<'tcx>)
+ -> subst::Substs<'tcx> {
let tcx = ccx.tcx();
let substs = match node {
};
if substs.types.needs_infer() {
- tcx.sess.bug(&format!("type parameters for node {:?} include inference types: {:?}",
- node, substs));
- }
+ tcx.sess.bug(&format!("type parameters for node {:?} include inference types: {:?}",
+ node, substs));
+ }
- monomorphize::apply_param_substs(tcx,
- param_substs,
- &substs.erase_regions())
+ monomorphize::apply_param_substs(tcx,
+ param_substs,
+ &substs.erase_regions())
}
pub fn langcall(bcx: Block,
use llvm;
use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
use llvm::{InternalLinkage, ValueRef, Bool, True};
-use middle::{check_const, def};
+use middle::const_qualif::ConstQualif;
use middle::cstore::LOCAL_CRATE;
use middle::const_eval::{self, ConstVal, ConstEvalErr};
use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg};
use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr};
use middle::const_eval::EvalHint::ExprTypeChecked;
use middle::const_eval::eval_const_expr_partial;
+use middle::def::Def;
use middle::def_id::DefId;
use trans::{adt, closure, debuginfo, expr, inline, machine};
use trans::base::{self, push_ctxt};
-> Result<ValueRef, ConstEvalFailure> {
let expr = get_const_expr(ccx, def_id, ref_expr, param_substs);
let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
- match get_const_expr_as_global(ccx, expr, check_const::ConstQualif::empty(),
- empty_substs, TrueConst::Yes) {
+ match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) {
Err(Runtime(err)) => {
ccx.tcx().sess.span_err(expr.span, &err.description());
Err(Compiletime(err))
pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
expr: &hir::Expr,
- qualif: check_const::ConstQualif,
+ qualif: ConstQualif,
param_substs: &'tcx Substs<'tcx>,
trueconst: TrueConst)
-> Result<ValueRef, ConstEvalFailure> {
// of just to get the `def` value
let def = ccx.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
match def {
- def::DefConst(def_id) | def::DefAssociatedConst(def_id) => {
+ Def::Const(def_id) | Def::AssociatedConst(def_id) => {
if !ccx.tcx().tables.borrow().adjustments.contains_key(&expr.id) {
debug!("get_const_expr_as_global ({:?}): found const {:?}",
expr.id, def_id);
}
let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs,
&ccx.tcx().expr_ty(expr));
- let val = if qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS) {
+ let val = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
// Avoid autorefs as they would create global instead of stack
// references, even when only the latter are correct.
try!(const_expr_unadjusted(ccx, expr, ty, param_substs, None, trueconst))
}
}
let opt_def = cx.tcx().def_map.borrow().get(&cur.id).map(|d| d.full_def());
- if let Some(def::DefStatic(def_id, _)) = opt_def {
+ if let Some(Def::Static(def_id, _)) = opt_def {
common::get_static_val(cx, def_id, ety)
} else {
// If this isn't the address of a static, then keep going through
hir::ExprPath(..) => {
let def = cx.tcx().def_map.borrow().get(&e.id).unwrap().full_def();
match def {
- def::DefLocal(_, id) => {
+ Def::Local(_, id) => {
if let Some(val) = fn_args.and_then(|args| args.get(&id).cloned()) {
val
} else {
cx.sess().span_bug(e.span, "const fn argument not found")
}
}
- def::DefFn(..) | def::DefMethod(..) => {
+ Def::Fn(..) | Def::Method(..) => {
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
}
- def::DefConst(def_id) | def::DefAssociatedConst(def_id) => {
+ Def::Const(def_id) | Def::AssociatedConst(def_id) => {
const_deref_ptr(cx, try!(get_const_val(cx, def_id, e, param_substs)))
}
- def::DefVariant(enum_did, variant_did, _) => {
+ Def::Variant(enum_did, variant_did) => {
let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);
match vinfo.kind() {
ty::VariantKind::Unit => {
}
}
}
- def::DefStruct(_) => {
+ Def::Struct(..) => {
if let ty::TyBareFn(..) = ety.sty {
// Tuple struct.
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
let def = cx.tcx().def_map.borrow()[&callee.id].full_def();
let arg_vals = try!(map_list(args));
match def {
- def::DefFn(did, _) | def::DefMethod(did) => {
+ Def::Fn(did) | Def::Method(did) => {
try!(const_fn_call(
cx,
ExprId(callee.id),
trueconst,
))
}
- def::DefStruct(_) => {
+ Def::Struct(..) => {
if ety.is_simd() {
C_vector(&arg_vals[..])
} else {
adt::trans_const(cx, &*repr, Disr(0), &arg_vals[..])
}
}
- def::DefVariant(enum_did, variant_did, _) => {
+ Def::Variant(enum_did, variant_did) => {
let repr = adt::represent_type(cx, ety);
let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);
adt::trans_const(cx,
// except according to those terms.
use llvm::ValueRef;
-use middle::def;
+use middle::def::Def;
use middle::lang_items::{PanicFnLangItem, PanicBoundsCheckFnLangItem};
use trans::base::*;
use trans::basic_block::BasicBlock;
None => fcx.top_loop_scope(),
Some(_) => {
match bcx.tcx().def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
- Some(def::DefLabel(loop_id)) => loop_id,
+ Some(Def::Label(loop_id)) => loop_id,
r => {
bcx.tcx().sess.bug(&format!("{:?} in def-map for label", r))
}
use back::abi;
use llvm::{self, ValueRef, TypeKind};
-use middle::check_const;
-use middle::def;
+use middle::const_qualif::ConstQualif;
+use middle::def::Def;
use middle::lang_items::CoerceUnsizedTraitLangItem;
use middle::subst::{Substs, VecPerParamSpace};
use middle::traits;
}
let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
- if !qualif.intersects(
- check_const::ConstQualif::NOT_CONST |
- check_const::ConstQualif::NEEDS_DROP
- ) {
- if !qualif.intersects(check_const::ConstQualif::PREFER_IN_PLACE) {
+ if !qualif.intersects(ConstQualif::NOT_CONST | ConstQualif::NEEDS_DROP) {
+ if !qualif.intersects(ConstQualif::PREFER_IN_PLACE) {
if let SaveIn(lldest) = dest {
match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
bcx.fcx.param_substs,
match expr.node {
hir::ExprPath(..) => {
match bcx.def(expr.id) {
- def::DefConst(did) => {
+ Def::Const(did) => {
let empty_substs = bcx.tcx().mk_substs(Substs::trans_empty());
let const_expr = consts::get_const_expr(bcx.ccx(), did, expr,
empty_substs);
let mut bcx = bcx;
let fcx = bcx.fcx;
let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
- let adjusted_global = !qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS);
- let global = if !qualif.intersects(
- check_const::ConstQualif::NOT_CONST |
- check_const::ConstQualif::NEEDS_DROP
- ) {
+ let adjusted_global = !qualif.intersects(ConstQualif::NON_STATIC_BORROWS);
+ let global = if !qualif.intersects(ConstQualif::NOT_CONST | ConstQualif::NEEDS_DROP) {
match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
bcx.fcx.param_substs,
consts::TrueConst::No) {
Ok(global) => {
- if qualif.intersects(check_const::ConstQualif::HAS_STATIC_BORROWS) {
+ if qualif.intersects(ConstQualif::HAS_STATIC_BORROWS) {
// Is borrowed as 'static, must return lvalue.
// Cast pointer to global, because constants have different types.
fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ref_expr: &hir::Expr,
- def: def::Def)
+ def: Def)
-> DatumBlock<'blk, 'tcx, Expr> {
//! Translates a reference to a path.
let _icx = push_ctxt("trans_def_lvalue");
match def {
- def::DefFn(..) | def::DefMethod(..) |
- def::DefStruct(_) | def::DefVariant(..) => {
+ Def::Fn(..) | Def::Method(..) |
+ Def::Struct(..) | Def::Variant(..) => {
let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def,
bcx.fcx.param_substs);
DatumBlock::new(bcx, datum.to_expr_datum())
}
- def::DefStatic(did, _) => {
+ Def::Static(did, _) => {
let const_ty = expr_ty(bcx, ref_expr);
let val = get_static_val(bcx.ccx(), did, const_ty);
let lval = Lvalue::new("expr::trans_def");
DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr(lval)))
}
- def::DefConst(_) => {
+ Def::Const(_) => {
bcx.sess().span_bug(ref_expr.span,
"constant expression should not reach expr::trans_def")
}
fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ref_expr: &hir::Expr,
- def: def::Def,
+ def: Def,
dest: Dest)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_def_dps_unadjusted");
};
match def {
- def::DefVariant(tid, vid, _) => {
+ Def::Variant(tid, vid) => {
let variant = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
if let ty::VariantKind::Tuple = variant.kind() {
// N-ary variant.
return bcx;
}
}
- def::DefStruct(_) => {
+ Def::Struct(..) => {
let ty = expr_ty(bcx, ref_expr);
match ty.sty {
ty::TyStruct(def, _) if def.has_dtor() => {
pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ref_expr: &hir::Expr,
- def: def::Def,
+ def: Def,
param_substs: &'tcx Substs<'tcx>)
-> Datum<'tcx, Rvalue> {
let _icx = push_ctxt("trans_def_datum_unadjusted");
match def {
- def::DefFn(did, _) |
- def::DefStruct(did) | def::DefVariant(_, did, _) => {
+ Def::Fn(did) |
+ Def::Struct(did) | Def::Variant(_, did) => {
callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs)
}
- def::DefMethod(method_did) => {
+ Def::Method(method_did) => {
match ccx.tcx().impl_or_trait_item(method_did).container() {
ty::ImplContainer(_) => {
callee::trans_fn_ref(ccx, method_did,
/// Translates a reference to a local variable or argument. This always results in an lvalue datum.
pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- def: def::Def)
+ def: Def)
-> Datum<'tcx, Lvalue> {
let _icx = push_ctxt("trans_local_var");
match def {
- def::DefUpvar(_, nid, _, _) => {
+ Def::Upvar(_, nid, _, _) => {
// Can't move upvars, so this is never a ZeroMemLastUse.
let local_ty = node_id_type(bcx, nid);
let lval = Lvalue::new_with_hint("expr::trans_local_var (upvar)",
}
}
}
- def::DefLocal(_, nid) => {
+ Def::Local(_, nid) => {
let datum = match bcx.fcx.lllocals.borrow().get(&nid) {
Some(&v) => v,
None => {
match expr.node {
hir::ExprPath(..) => {
match tcx.resolve_expr(expr) {
- def::DefStruct(_) | def::DefVariant(..) => {
+ Def::Struct(..) | Def::Variant(..) => {
if let ty::TyBareFn(..) = tcx.node_id_to_type(expr.id).sty {
// ctor function
ExprKind::RvalueDatum
}
}
- // Special case: A unit like struct's constructor must be called without () at the
- // end (like `UnitStruct`) which means this is an ExprPath to a DefFn. But in case
- // of unit structs this is should not be interpreted as function pointer but as
- // call to the constructor.
- def::DefFn(_, true) => ExprKind::RvalueDps,
-
// Fn pointers are just scalar values.
- def::DefFn(..) | def::DefMethod(..) => ExprKind::RvalueDatum,
+ Def::Fn(..) | Def::Method(..) => ExprKind::RvalueDatum,
// Note: there is actually a good case to be made that
// DefArg's, particularly those of immediate type, ought to
// considered rvalues.
- def::DefStatic(..) |
- def::DefUpvar(..) |
- def::DefLocal(..) => ExprKind::Lvalue,
+ Def::Static(..) |
+ Def::Upvar(..) |
+ Def::Local(..) => ExprKind::Lvalue,
- def::DefConst(..) |
- def::DefAssociatedConst(..) => ExprKind::RvalueDatum,
+ Def::Const(..) |
+ Def::AssociatedConst(..) => ExprKind::RvalueDatum,
def => {
tcx.sess.span_bug(
use middle::def_id::DefId;
use middle::infer;
use middle::subst::{Subst, Substs};
-use middle::subst::VecPerParamSpace;
use middle::subst;
use middle::traits;
use trans::base::*;
use trans::monomorphize;
use trans::type_::Type;
use trans::type_of::*;
-use middle::ty::{self, Ty, TypeFoldable};
+use middle::ty::{self, Ty};
use middle::ty::MethodCall;
use syntax::ast;
}
ty::TraitContainer(trait_def_id) => {
- let trait_substs = method.substs.clone().method_to_trait();
- let trait_substs = bcx.tcx().mk_substs(trait_substs);
- let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
-
+ let trait_ref = method.substs.to_trait_ref(bcx.tcx(), trait_def_id);
let trait_ref = ty::Binder(bcx.monomorphize(&trait_ref));
let span = bcx.tcx().map.span(method_call.expr_id);
debug!("method_call={:?} trait_ref={:?} trait_ref id={:?} substs={:?}",
trait_ref,
trait_ref.0.def_id,
trait_ref.0.substs);
- let origin = fulfill_obligation(bcx.ccx(),
- span,
- trait_ref.clone());
+ let origin = fulfill_obligation(bcx.ccx(), span, trait_ref);
debug!("origin = {:?}", origin);
trans_monomorphized_callee(bcx,
method_call,
// type parameters that belong to the trait but also some that
// belong to the method:
let rcvr_substs = node_id_substs(ccx, ExprId(expr_id), param_substs);
- let subst::SeparateVecsPerParamSpace {
- types: rcvr_type,
- selfs: rcvr_self,
- fns: rcvr_method
- } = rcvr_substs.types.split();
-
- // Lookup the precise impl being called. To do that, we need to
- // create a trait reference identifying the self type and other
- // input type parameters. To create that trait reference, we have
- // to pick apart the type parameters to identify just those that
- // pertain to the trait. This is easiest to explain by example:
- //
- // trait Convert {
- // fn from<U:Foo>(n: U) -> Option<Self>;
- // }
- // ...
- // let f = <Vec<i32> as Convert>::from::<String>(...)
- //
- // Here, in this call, which I've written with explicit UFCS
- // notation, the set of type parameters will be:
- //
- // rcvr_type: [] <-- nothing declared on the trait itself
- // rcvr_self: [Vec<i32>] <-- the self type
- // rcvr_method: [String] <-- method type parameter
- //
- // So we create a trait reference using the first two,
- // basically corresponding to `<Vec<i32> as Convert>`.
- // The remaining type parameters (`rcvr_method`) will be used below.
- let trait_substs =
- Substs::erased(VecPerParamSpace::new(rcvr_type,
- rcvr_self,
- Vec::new()));
- let trait_substs = tcx.mk_substs(trait_substs);
- debug!("trait_substs={:?}", trait_substs);
- let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, trait_substs));
- let vtbl = fulfill_obligation(ccx,
- DUMMY_SP,
- trait_ref);
+ debug!("rcvr_substs={:?}", rcvr_substs);
+ let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id));
+ let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
// Now that we know which impl is being used, we can dispatch to
// the actual function:
substs: impl_substs,
nested: _ }) =>
{
- assert!(!impl_substs.types.needs_infer());
-
- // Create the substitutions that are in scope. This combines
- // the type parameters from the impl with those declared earlier.
- // To see what I mean, consider a possible impl:
- //
- // impl<T> Convert for Vec<T> {
- // fn from<U:Foo>(n: U) { ... }
- // }
- //
- // Recall that we matched `<Vec<i32> as Convert>`. Trait
- // resolution will have given us a substitution
- // containing `impl_substs=[[T=i32],[],[]]` (the type
- // parameters defined on the impl). We combine
- // that with the `rcvr_method` from before, which tells us
- // the type parameters from the *method*, to yield
- // `callee_substs=[[T=i32],[],[U=String]]`.
- let subst::SeparateVecsPerParamSpace {
- types: impl_type,
- selfs: impl_self,
- fns: _
- } = impl_substs.types.split();
- let callee_substs =
- Substs::erased(VecPerParamSpace::new(impl_type,
- impl_self,
- rcvr_method));
-
+ let callee_substs = impl_substs.with_method_from(&rcvr_substs);
let mth = tcx.get_impl_method(impl_did, callee_substs, mname);
trans_fn_ref_with_substs(ccx, mth.method.def_id, ExprId(expr_id),
param_substs,
idx)
}
_ => {
+ // FIXME(#20847): handle at least VtableFnPointer
tcx.sess.bug(&format!("static call to invalid vtable: {:?}",
vtbl));
}
};
// create a concatenated set of substitutions which includes
// those from the impl and those from the method:
- let callee_substs =
- combine_impl_and_methods_tps(
- bcx, MethodCallKey(method_call), vtable_impl.substs);
-
- let mth = bcx.tcx().get_impl_method(impl_did, callee_substs, mname);
+ let meth_substs = node_id_substs(ccx,
+ MethodCallKey(method_call),
+ bcx.fcx.param_substs);
+ let impl_substs = vtable_impl.substs.with_method_from(&meth_substs);
+ let mth = bcx.tcx().get_impl_method(impl_did, impl_substs, mname);
// translate the function
let datum = trans_fn_ref_with_substs(bcx.ccx(),
mth.method.def_id,
}
}
- /// Creates a concatenated set of substitutions which includes those from the impl and those from
- /// the method. This are some subtle complications here. Statically, we have a list of type
- /// parameters like `[T0, T1, T2, M1, M2, M3]` where `Tn` are type parameters that appear on the
- /// receiver. For example, if the receiver is a method parameter `A` with a bound like
- /// `trait<B,C,D>` then `Tn` would be `[B,C,D]`.
- ///
- /// The weird part is that the type `A` might now be bound to any other type, such as `foo<X>`.
- /// In that case, the vector we want is: `[X, M1, M2, M3]`. Therefore, what we do now is to slice
- /// off the method type parameters and append them to the type parameters from the type that the
- /// receiver is mapped to.
-fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- node: ExprOrMethodCall,
- rcvr_substs: subst::Substs<'tcx>)
- -> subst::Substs<'tcx>
-{
- let ccx = bcx.ccx();
-
- let node_substs = node_id_substs(ccx, node, bcx.fcx.param_substs);
-
- debug!("rcvr_substs={:?}", rcvr_substs);
- debug!("node_substs={:?}", node_substs);
-
- // Break apart the type parameters from the node and type
- // parameters from the receiver.
- let node_method = node_substs.types.split().fns;
- let subst::SeparateVecsPerParamSpace {
- types: rcvr_type,
- selfs: rcvr_self,
- fns: rcvr_method
- } = rcvr_substs.types.clone().split();
- assert!(rcvr_method.is_empty());
- subst::Substs {
- regions: subst::ErasedRegions,
- types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method)
- }
-}
-
/// Create a method callee where the method is coming from a trait object (e.g., Box<Trait> type).
/// In this case, we must pull the fn pointer out of the vtable that is packaged up with the
/// object. Objects are represented as a pair, so we first evaluate the self expression and then
//! An analysis to determine which temporaries require allocas and
//! which do not.
-use rustc_data_structures::fnv::FnvHashSet;
+use rustc_data_structures::bitvec::BitVector;
use rustc::mir::repr as mir;
use rustc::mir::visit::{Visitor, LvalueContext};
use trans::common::{self, Block};
pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>,
mir: &mir::Mir<'tcx>)
- -> FnvHashSet<usize> {
- let mut analyzer = TempAnalyzer::new();
+ -> BitVector {
+ let mut analyzer = TempAnalyzer::new(mir.temp_decls.len());
analyzer.visit_mir(mir);
}
struct TempAnalyzer {
- lvalue_temps: FnvHashSet<usize>,
+ lvalue_temps: BitVector,
+ seen_assigned: BitVector
}
impl TempAnalyzer {
- fn new() -> TempAnalyzer {
- TempAnalyzer { lvalue_temps: FnvHashSet() }
+ fn new(temp_count: usize) -> TempAnalyzer {
+ TempAnalyzer {
+ lvalue_temps: BitVector::new(temp_count),
+ seen_assigned: BitVector::new(temp_count)
+ }
}
fn mark_as_lvalue(&mut self, temp: usize) {
debug!("marking temp {} as lvalue", temp);
self.lvalue_temps.insert(temp);
}
+
+ fn mark_assigned(&mut self, temp: usize) {
+ if !self.seen_assigned.insert(temp) {
+ self.mark_as_lvalue(temp);
+ }
+ }
}
impl<'tcx> Visitor<'tcx> for TempAnalyzer {
match *lvalue {
mir::Lvalue::Temp(index) => {
+ self.mark_assigned(index as usize);
if !rvalue::rvalue_creates_operand(rvalue) {
self.mark_as_lvalue(index as usize);
}
use rustc::middle::subst::Substs;
use rustc::middle::const_eval;
use rustc::middle::def_id::DefId;
-use rustc::middle::subst;
use rustc::middle::traits;
use rustc::mir::repr::ItemKind;
use trans::common::{Block, fulfill_obligation};
ItemKind::Function => self.trans_fn_ref(bcx, ty, substs, did),
ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() {
ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did),
- ty::TraitContainer(tdid) => self.trans_static_method(bcx, ty, did, tdid, substs)
+ ty::TraitContainer(tdid) => self.trans_trait_method(bcx, ty, did, tdid, substs)
},
ItemKind::Constant => {
let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
}
}
- /// Translates references to static methods.
+ /// Translates references to trait methods.
///
/// This is an adaptation of meth::trans_static_method_callee
- pub fn trans_static_method(&mut self,
- bcx: Block<'bcx, 'tcx>,
- ty: Ty<'tcx>,
- method_id: DefId,
- trait_id: DefId,
- substs: &'tcx Substs<'tcx>)
- -> OperandRef<'tcx> {
+ pub fn trans_trait_method(&mut self,
+ bcx: Block<'bcx, 'tcx>,
+ ty: Ty<'tcx>,
+ method_id: DefId,
+ trait_id: DefId,
+ substs: &'tcx Substs<'tcx>)
+ -> OperandRef<'tcx> {
debug!("trans_static_method(ty={:?}, method={}, trait={}, substs={:?})",
ty,
bcx.tcx().item_path_str(method_id),
let ccx = bcx.ccx();
let tcx = bcx.tcx();
- let subst::SeparateVecsPerParamSpace {
- types: rcvr_type,
- selfs: rcvr_self,
- fns: rcvr_method
- } = substs.clone().types.split();
- let trait_substs = Substs::erased(
- subst::VecPerParamSpace::new(rcvr_type, rcvr_self, Vec::new())
- );
- let trait_substs = tcx.mk_substs(trait_substs);
- let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, trait_substs));
+ let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
match vtbl {
- traits::VtableImpl(traits::VtableImplData { impl_def_id, substs: imp_substs, .. }) => {
- assert!(!imp_substs.types.needs_infer());
+ traits::VtableImpl(traits::VtableImplData {
+ impl_def_id, substs: impl_substs, ..
+ }) => {
+ assert!(!impl_substs.types.needs_infer());
let mname = tcx.item_name(method_id);
- let subst::SeparateVecsPerParamSpace {
- types: impl_type,
- selfs: impl_self,
- fns: _
- } = imp_substs.types.split();
- let callee_substs = Substs::erased(
- subst::VecPerParamSpace::new(impl_type, impl_self, rcvr_method)
- );
+ let callee_substs = impl_substs.with_method_from(substs);
let mth = tcx.get_impl_method(impl_def_id, callee_substs, mname);
- let mthsubsts = tcx.mk_substs(mth.substs);
- self.trans_fn_ref(bcx, ty, mthsubsts, mth.method.def_id)
+ let mth_substs = tcx.mk_substs(mth.substs);
+ self.trans_fn_ref(bcx, ty, mth_substs, mth.method.def_id)
},
traits::VtableClosure(data) => {
let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
let temps = mir.temp_decls.iter()
.map(|decl| bcx.monomorphize(&decl.ty))
.enumerate()
- .map(|(i, mty)| if lvalue_temps.contains(&i) {
+ .map(|(i, mty)| if lvalue_temps.contains(i) {
TempRef::Lvalue(LvalueRef::alloca(bcx,
mty,
&format!("temp{:?}", i)))
mir::Rvalue::Repeat(ref elem, ref count) => {
let elem = self.trans_operand(bcx, elem);
- let size = self.trans_constant(bcx, count).immediate();
+ let size = self.trans_constval(bcx, &count.value, count.ty).immediate();
let base = expr::get_dataptr(bcx, dest.llval);
tvec::iter_vec_raw(bcx, base, elem.ty, size, |bcx, llslot, _| {
self.store_operand(bcx, llslot, elem);
use middle::astconv_util::{prim_ty_to_ty, prohibit_type_params, prohibit_projection};
use middle::const_eval::{self, ConstVal};
use middle::const_eval::EvalHint::UncheckedExprHint;
-use middle::def;
+use middle::def::{self, Def};
use middle::def_id::DefId;
use middle::resolve_lifetime as rl;
use middle::privacy::{AllPublic, LastMod};
fn trait_def_id<'tcx>(this: &AstConv<'tcx>, trait_ref: &hir::TraitRef) -> DefId {
let path = &trait_ref.path;
match ::lookup_full_def(this.tcx(), path.span, trait_ref.ref_id) {
- def::DefTrait(trait_def_id) => trait_def_id,
- def::DefErr => {
+ Def::Trait(trait_def_id) => trait_def_id,
+ Def::Err => {
this.tcx().sess.fatal("cannot continue compilation due to previous error");
}
_ => {
_ => None
};
match def {
- Some(def::DefTrait(trait_def_id)) => {
+ Some(Def::Trait(trait_def_id)) => {
let mut projection_bounds = Vec::new();
let trait_ref = object_path_to_poly_trait_ref(this,
rscope,
fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
span: Span,
ty: Ty<'tcx>,
- ty_path_def: def::Def,
+ ty_path_def: Def,
item_segment: &hir::PathSegment)
- -> (Ty<'tcx>, def::Def)
+ -> (Ty<'tcx>, Def)
{
let tcx = this.tcx();
let assoc_name = item_segment.identifier.name;
// Find the type of the associated item, and the trait where the associated
// item is declared.
let bound = match (&ty.sty, ty_path_def) {
- (_, def::DefSelfTy(Some(trait_did), Some((impl_id, _)))) => {
+ (_, Def::SelfTy(Some(trait_did), Some((impl_id, _)))) => {
// `Self` in an impl of a trait - we have a concrete self type and a
// trait reference.
let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap();
Err(ErrorReported) => return (tcx.types.err, ty_path_def),
}
}
- (&ty::TyParam(_), def::DefSelfTy(Some(trait_did), None)) => {
+ (&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => {
let trait_node_id = tcx.map.as_local_node_id(trait_did).unwrap();
match find_bound_for_assoc_item(this,
trait_node_id,
Err(ErrorReported) => return (tcx.types.err, ty_path_def),
}
}
- (&ty::TyParam(_), def::DefTyParam(_, _, param_did, param_name)) => {
+ (&ty::TyParam(_), Def::TyParam(_, _, param_did, param_name)) => {
let param_node_id = tcx.map.as_local_node_id(param_did).unwrap();
match find_bound_for_assoc_item(this,
param_node_id,
item.expect("missing associated type").def_id()
};
- (ty, def::DefAssociatedTy(trait_did, item_did))
+ (ty, Def::AssociatedTy(trait_did, item_did))
}
fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
param_mode: PathParamMode,
- def: &def::Def,
+ def: &Def,
opt_self_ty: Option<Ty<'tcx>>,
base_segments: &[hir::PathSegment])
-> Ty<'tcx> {
let tcx = this.tcx();
match *def {
- def::DefTrait(trait_def_id) => {
+ Def::Trait(trait_def_id) => {
// N.B. this case overlaps somewhat with
// TyObjectSum, see that fn for details
let mut projection_bounds = Vec::new();
projection_bounds,
&[])
}
- def::DefTy(did, _) | def::DefStruct(did) => {
+ Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
prohibit_type_params(tcx, base_segments.split_last().unwrap().1);
ast_path_to_ty(this,
rscope,
did,
base_segments.last().unwrap())
}
- def::DefTyParam(space, index, _, name) => {
+ Def::TyParam(space, index, _, name) => {
prohibit_type_params(tcx, base_segments);
tcx.mk_param(space, index, name)
}
- def::DefSelfTy(_, Some((_, self_ty_id))) => {
+ Def::SelfTy(_, Some((_, self_ty_id))) => {
// Self in impl (we know the concrete type).
prohibit_type_params(tcx, base_segments);
if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&self_ty_id) {
tcx.sess.span_bug(span, "self type has not been fully resolved")
}
}
- def::DefSelfTy(Some(_), None) => {
+ Def::SelfTy(Some(_), None) => {
// Self in trait.
prohibit_type_params(tcx, base_segments);
tcx.mk_self_type()
}
- def::DefAssociatedTy(trait_did, _) => {
+ Def::AssociatedTy(trait_did, _) => {
prohibit_type_params(tcx, &base_segments[..base_segments.len()-2]);
qpath_to_ty(this,
rscope,
&base_segments[base_segments.len()-2],
base_segments.last().unwrap())
}
- def::DefMod(id) => {
+ Def::Mod(..) => {
// Used as sentinel by callers to indicate the `<T>::A::B::C` form.
// FIXME(#22519) This part of the resolution logic should be
// avoided entirely for that form, once we stop needed a Def
// resolve Self::Foo, at the moment we can't resolve the former because
// we don't have the trait information around, which is just sad.
- if !base_segments.is_empty() {
- let id_node = tcx.map.as_local_node_id(id).unwrap();
- span_err!(tcx.sess,
- span,
- E0247,
- "found module name used as a type: {}",
- tcx.map.node_to_user_string(id_node));
- return this.tcx().types.err;
- }
+ assert!(base_segments.is_empty());
opt_self_ty.expect("missing T in <T>::a::b::c")
}
- def::DefPrimTy(prim_ty) => {
+ Def::PrimTy(prim_ty) => {
prim_ty_to_ty(tcx, base_segments, prim_ty)
}
- def::DefErr => {
+ Def::Err => {
return this.tcx().types.err;
}
_ => {
- let id_node = tcx.map.as_local_node_id(def.def_id()).unwrap();
span_err!(tcx.sess, span, E0248,
"found value `{}` used as a type",
- tcx.map.path_to_string(id_node));
+ tcx.item_path_str(def.def_id()));
return this.tcx().types.err;
}
}
rscope: &RegionScope,
span: Span,
param_mode: PathParamMode,
- def: &def::Def,
+ def: &Def,
opt_self_ty: Option<Ty<'tcx>>,
base_segments: &[hir::PathSegment],
assoc_segments: &[hir::PathSegment])
} else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
// Create some fake resolution that can't possibly be a type.
def::PathResolution {
- base_def: def::DefMod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
+ base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
last_private: LastMod(AllPublic),
depth: path.segments.len()
}
match *ast_bound {
hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => {
match ::lookup_full_def(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) {
- def::DefTrait(trait_did) => {
+ Def::Trait(trait_did) => {
if tcx.try_add_builtin_trait(trait_did,
&mut builtin_bounds) {
let segments = &b.trait_ref.path.segments;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use middle::def;
+use middle::def::{self, Def};
use middle::infer::{self, TypeOrigin};
use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
use middle::pat_util::pat_is_resolved_const;
hir::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) {
- if d.base_def == def::DefErr {
+ if d.base_def == Def::Err {
fcx.write_error(pat.id);
return;
}
// This is just a sentinel for finish_resolving_def_to_ty.
let sentinel = fcx.tcx().map.local_def_id(ast::CRATE_NODE_ID);
def::PathResolution {
- base_def: def::DefMod(sentinel),
+ base_def: Def::Mod(sentinel),
last_private: LastMod(AllPublic),
depth: path.segments.len()
}
// subtyping.
}
-fn check_assoc_item_is_const(pcx: &pat_ctxt, def: def::Def, span: Span) -> bool {
+fn check_assoc_item_is_const(pcx: &pat_ctxt, def: Def, span: Span) -> bool {
match def {
- def::DefAssociatedConst(..) => true,
- def::DefMethod(..) => {
+ Def::AssociatedConst(..) => true,
+ Def::Method(..) => {
span_err!(pcx.fcx.ccx.tcx.sess, span, E0327,
"associated items in match patterns must be constants");
false
let tcx = pcx.fcx.ccx.tcx;
let path_res = match tcx.def_map.borrow().get(&pat.id) {
- Some(&path_res) if path_res.base_def != def::DefErr => path_res,
+ Some(&path_res) if path_res.base_def != Def::Err => path_res,
_ => {
fcx.write_error(pat.id);
let real_path_ty = fcx.node_ty(pat.id);
let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
- ty::TyEnum(enum_def, expected_substs)
- if def == def::DefVariant(enum_def.did, def.def_id(), false) =>
- {
+ ty::TyEnum(enum_def, expected_substs) => {
let variant = enum_def.variant_of_def(def);
+ if variant.kind() == ty::VariantKind::Struct {
+ report_bad_struct_kind(false);
+ return;
+ }
if is_tuple_struct_pat && variant.kind() != ty::VariantKind::Tuple {
// Matching unit variants with tuple variant patterns (`UnitVariant(..)`)
// is allowed for backward compatibility.
use CrateCtxt;
use middle::cstore::LOCAL_CRATE;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::infer;
use middle::ty::{self, LvaluePreference, Ty};
if let hir::ExprCall(ref expr, _) = call_expr.node {
let tcx = fcx.tcx();
if let Some(pr) = tcx.def_map.borrow().get(&expr.id) {
- if pr.depth == 0 && pr.base_def != def::DefErr {
+ if pr.depth == 0 && pr.base_def != Def::Err {
if let Some(span) = tcx.map.span_if_local(pr.def_id()) {
err.span_note(span, "defined here");
}
.generics.regions.get_slice(subst::FnSpace));
let subst::Substs { types, regions } = substs;
- let regions = regions.map(|r| r.with_vec(subst::FnSpace, method_regions));
+ let regions = regions.map(|r| r.with_slice(subst::FnSpace, &method_regions));
let mut final_substs = subst::Substs { types: types, regions: regions };
if num_supplied_types == 0 {
use astconv::AstConv;
use check::FnCtxt;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod};
use middle::subst;
method_name: ast::Name,
self_ty: ty::Ty<'tcx>,
expr_id: ast::NodeId)
- -> Result<(def::Def, LastPrivate), MethodError<'tcx>>
+ -> Result<(Def, LastPrivate), MethodError<'tcx>>
{
let mode = probe::Mode::Path;
let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
}
}
let def_result = match pick.item {
- ty::ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id),
- ty::ImplOrTraitItem::ConstTraitItem(..) => def::DefAssociatedConst(def_id),
+ ty::ImplOrTraitItem::MethodTraitItem(..) => Def::Method(def_id),
+ ty::ImplOrTraitItem::ConstTraitItem(..) => Def::AssociatedConst(def_id),
ty::ImplOrTraitItem::TypeTraitItem(..) => {
fcx.tcx().sess.span_bug(span, "resolve_ufcs: probe picked associated type");
}
use front::map as hir_map;
use middle::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
use middle::cstore::{self, CrateStore, DefLike};
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use middle::lang_items::FnOnceTraitLangItem;
use middle::subst::Substs;
cstore: &for<'a> cstore::CrateStore<'a>,
dl: cstore::DefLike) {
match dl {
- cstore::DlDef(def::DefTrait(did)) => {
+ cstore::DlDef(Def::Trait(did)) => {
traits.push(TraitInfo::new(did));
}
- cstore::DlDef(def::DefMod(did)) => {
+ cstore::DlDef(Def::Mod(did)) => {
if !external_mods.insert(did) {
return;
}
use fmt_macros::{Parser, Piece, Position};
use middle::astconv_util::prohibit_type_params;
use middle::cstore::LOCAL_CRATE;
-use middle::def;
+use middle::def::{self, Def};
use middle::def_id::DefId;
use middle::infer;
use middle::infer::{TypeOrigin, type_variable};
/// Return the dict-like variant corresponding to a given `Def`.
pub fn def_struct_variant(&self,
- def: def::Def,
+ def: Def,
span: Span)
-> Option<(ty::AdtDef<'tcx>, ty::VariantDef<'tcx>)>
{
let (adt, variant) = match def {
- def::DefVariant(enum_id, variant_id, _) => {
+ Def::Variant(enum_id, variant_id) => {
let adt = self.tcx().lookup_adt_def(enum_id);
(adt, adt.variant_with_id(variant_id))
}
- def::DefTy(did, _) | def::DefStruct(did) => {
+ Def::Struct(did) | Def::TyAlias(did) => {
let typ = self.tcx().lookup_item_type(did);
if let ty::TyStruct(adt, _) = typ.ty.sty {
(adt, adt.struct_variant())
// Find the relevant variant
let def = lookup_full_def(tcx, path.span, expr.id);
- if def == def::DefErr {
+ if def == Def::Err {
check_struct_fields_on_error(fcx, expr.id, fields, base_expr);
return;
}
} else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
// Create some fake resolution that can't possibly be a type.
def::PathResolution {
- base_def: def::DefMod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
+ base_def: Def::Mod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
last_private: LastMod(AllPublic),
depth: path.segments.len()
}
if let Some((opt_ty, segments, def)) =
resolve_ty_and_def_ufcs(fcx, path_res, opt_self_ty, path,
expr.span, expr.id) {
- if def != def::DefErr {
+ if def != Def::Err {
let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx,
expr.span,
def);
node_id: ast::NodeId)
-> Option<(Option<Ty<'tcx>>,
&'a [hir::PathSegment],
- def::Def)>
+ Def)>
{
// If fully resolved already, we don't have to do anything.
// Returns the type parameter count and the type for the given definition.
fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
sp: Span,
- defn: def::Def)
+ defn: Def)
-> (TypeScheme<'tcx>, GenericPredicates<'tcx>) {
match defn {
- def::DefLocal(_, nid) | def::DefUpvar(_, nid, _, _) => {
+ Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => {
let typ = fcx.local_ty(sp, nid);
(ty::TypeScheme { generics: ty::Generics::empty(), ty: typ },
ty::GenericPredicates::empty())
}
- def::DefFn(id, _) | def::DefMethod(id) |
- def::DefStatic(id, _) | def::DefVariant(_, id, _) |
- def::DefStruct(id) | def::DefConst(id) | def::DefAssociatedConst(id) => {
+ Def::Fn(id) | Def::Method(id) |
+ Def::Static(id, _) | Def::Variant(_, id) |
+ Def::Struct(id) | Def::Const(id) | Def::AssociatedConst(id) => {
(fcx.tcx().lookup_item_type(id), fcx.tcx().lookup_predicates(id))
}
- def::DefTrait(_) |
- def::DefTy(..) |
- def::DefAssociatedTy(..) |
- def::DefPrimTy(_) |
- def::DefTyParam(..) |
- def::DefMod(..) |
- def::DefForeignMod(..) |
- def::DefLabel(..) |
- def::DefSelfTy(..) |
- def::DefErr => {
+ Def::Trait(_) |
+ Def::Enum(..) |
+ Def::TyAlias(..) |
+ Def::AssociatedTy(..) |
+ Def::PrimTy(_) |
+ Def::TyParam(..) |
+ Def::Mod(..) |
+ Def::ForeignMod(..) |
+ Def::Label(..) |
+ Def::SelfTy(..) |
+ Def::Err => {
fcx.ccx.tcx.sess.span_bug(sp, &format!("expected value, found {:?}", defn));
}
}
type_scheme: TypeScheme<'tcx>,
type_predicates: &ty::GenericPredicates<'tcx>,
opt_self_ty: Option<Ty<'tcx>>,
- def: def::Def,
+ def: Def,
span: Span,
node_id: ast::NodeId) {
debug!("instantiate_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})",
let mut segment_spaces: Vec<_>;
match def {
// Case 1 and 1b. Reference to a *type* or *enum variant*.
- def::DefSelfTy(..) |
- def::DefStruct(..) |
- def::DefVariant(..) |
- def::DefTy(..) |
- def::DefAssociatedTy(..) |
- def::DefTrait(..) |
- def::DefPrimTy(..) |
- def::DefTyParam(..) => {
+ Def::SelfTy(..) |
+ Def::Struct(..) |
+ Def::Variant(..) |
+ Def::Enum(..) |
+ Def::TyAlias(..) |
+ Def::AssociatedTy(..) |
+ Def::Trait(..) |
+ Def::PrimTy(..) |
+ Def::TyParam(..) => {
// Everything but the final segment should have no
// parameters at all.
segment_spaces = vec![None; segments.len() - 1];
}
// Case 2. Reference to a top-level value.
- def::DefFn(..) |
- def::DefConst(..) |
- def::DefStatic(..) => {
+ Def::Fn(..) |
+ Def::Const(..) |
+ Def::Static(..) => {
segment_spaces = vec![None; segments.len() - 1];
segment_spaces.push(Some(subst::FnSpace));
}
// Case 3. Reference to a method.
- def::DefMethod(def_id) => {
+ Def::Method(def_id) => {
let container = fcx.tcx().impl_or_trait_item(def_id).container();
match container {
ty::TraitContainer(trait_did) => {
}
}
- def::DefAssociatedConst(def_id) => {
+ Def::AssociatedConst(def_id) => {
let container = fcx.tcx().impl_or_trait_item(def_id).container();
match container {
ty::TraitContainer(trait_did) => {
// Other cases. Various nonsense that really shouldn't show up
// here. If they do, an error will have been reported
// elsewhere. (I hope)
- def::DefMod(..) |
- def::DefForeignMod(..) |
- def::DefLocal(..) |
- def::DefLabel(..) |
- def::DefUpvar(..) |
- def::DefErr => {
+ Def::Mod(..) |
+ Def::ForeignMod(..) |
+ Def::Local(..) |
+ Def::Label(..) |
+ Def::Upvar(..) |
+ Def::Err => {
segment_spaces = vec![None; segments.len()];
}
}
// <id> nested anywhere inside the loop?
(block_query(b, |e| {
if let hir::ExprBreak(Some(_)) = e.node {
- lookup_full_def(cx, e.span, e.id) == def::DefLabel(id)
+ lookup_full_def(cx, e.span, e.id) == Def::Label(id)
} else {
false
}
use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region};
use lint;
-use middle::def;
+use middle::def::Def;
use middle::def_id::DefId;
use constrained_type_params as ctp;
use middle::lang_items::SizedTraitLangItem;
if let hir::TyPath(None, _) = ast_ty.node {
let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap();
match path_res.base_def {
- def::DefSelfTy(Some(def_id), None) => {
+ Def::SelfTy(Some(def_id), None) => {
path_res.depth == 0 && def_id == tcx.map.local_def_id(param_id)
}
- def::DefTyParam(_, _, def_id, _) => {
+ Def::TyParam(_, _, def_id, _) => {
path_res.depth == 0 && def_id == tcx.map.local_def_id(param_id)
}
_ => {
name: name,
disr_val: disr_val,
fields: fields,
- kind: match *def {
- hir::VariantData::Struct(..) => ty::VariantKind::Struct,
- hir::VariantData::Tuple(..) => ty::VariantKind::Tuple,
- hir::VariantData::Unit(..) => ty::VariantKind::Unit,
- }
+ kind: VariantKind::from_variant_data(def),
}
}
lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
param.id,
param.span,
- format!("defaults for type parameters are only allowed on type definitions, \
- like `struct` or `enum`"));
+ format!("defaults for type parameters are only allowed in `struct`, \
+ `enum`, `type`, or `trait` definitions."));
}
}
```
"##,
-//NB: not currently reachable
-E0247: r##"
-This error indicates an attempt to use a module name where a type is expected.
-For example:
-
-```
-mod MyMod {
- mod MySubMod { }
-}
-
-fn do_something(x: MyMod::MySubMod) { }
-```
-
-In this example, we're attempting to take a parameter of type `MyMod::MySubMod`
-in the do_something function. This is not legal: `MyMod::MySubMod` is a module
-name, not a type.
-"##,
-
E0248: r##"
This error indicates an attempt to use a value where a type is expected. For
example:
E0242, // internal error looking up a definition
E0245, // not a trait
// E0246, // invalid recursive type
+// E0247,
// E0319, // trait impls for defaulted traits allowed just for structs/enums
E0320, // recursive overflow during dropck
E0328, // cannot implement Unsize explicitly
pub use rustc::util;
use front::map as hir_map;
-use middle::def;
+use middle::def::Def;
use middle::infer::{self, TypeOrigin};
use middle::subst;
use middle::ty::{self, Ty, TypeFoldable};
}
}
-fn lookup_full_def(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) -> def::Def {
+fn lookup_full_def(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) -> Def {
match tcx.def_map.borrow().get(&id) {
Some(x) => x.full_def(),
None => {
use rustc_front::hir;
use rustc::middle::cstore::{self, CrateStore};
-use rustc::middle::def;
+use rustc::middle::def::Def;
use rustc::middle::def_id::DefId;
use rustc::middle::ty;
use rustc::middle::subst;
}
fn try_inline_def(cx: &DocContext, tcx: &ty::ctxt,
- def: def::Def) -> Option<Vec<clean::Item>> {
+ def: Def) -> Option<Vec<clean::Item>> {
let mut ret = Vec::new();
let did = def.def_id();
let inner = match def {
- def::DefTrait(did) => {
+ Def::Trait(did) => {
record_extern_fqn(cx, did, clean::TypeTrait);
clean::TraitItem(build_external_trait(cx, tcx, did))
}
- def::DefFn(did, false) => {
- // If this function is a tuple struct constructor, we just skip it
+ Def::Fn(did) => {
record_extern_fqn(cx, did, clean::TypeFunction);
clean::FunctionItem(build_external_function(cx, tcx, did))
}
- def::DefStruct(did) => {
+ Def::Struct(did)
+ // If this is a struct constructor, we skip it
+ if tcx.sess.cstore.tuple_struct_definition_if_ctor(did).is_none() => {
record_extern_fqn(cx, did, clean::TypeStruct);
ret.extend(build_impls(cx, tcx, did));
clean::StructItem(build_struct(cx, tcx, did))
}
- def::DefTy(did, false) => {
+ Def::TyAlias(did) => {
record_extern_fqn(cx, did, clean::TypeTypedef);
ret.extend(build_impls(cx, tcx, did));
build_type(cx, tcx, did)
}
- def::DefTy(did, true) => {
+ Def::Enum(did) => {
record_extern_fqn(cx, did, clean::TypeEnum);
ret.extend(build_impls(cx, tcx, did));
build_type(cx, tcx, did)
}
// Assume that the enum type is reexported next to the variant, and
// variants don't show up in documentation specially.
- def::DefVariant(..) => return Some(Vec::new()),
- def::DefMod(did) => {
+ Def::Variant(..) => return Some(Vec::new()),
+ Def::Mod(did) => {
record_extern_fqn(cx, did, clean::TypeModule);
clean::ModuleItem(build_module(cx, tcx, did))
}
- def::DefStatic(did, mtbl) => {
+ Def::Static(did, mtbl) => {
record_extern_fqn(cx, did, clean::TypeStatic);
clean::StaticItem(build_static(cx, tcx, did, mtbl))
}
- def::DefConst(did) | def::DefAssociatedConst(did) => {
+ Def::Const(did) | Def::AssociatedConst(did) => {
record_extern_fqn(cx, did, clean::TypeConst);
clean::ConstantItem(build_const(cx, tcx, did))
}
impls: &mut Vec<clean::Item>) {
match def {
cstore::DlImpl(did) => build_impl(cx, tcx, did, impls),
- cstore::DlDef(def::DefMod(did)) => {
+ cstore::DlDef(Def::Mod(did)) => {
for item in tcx.sess.cstore.item_children(did) {
populate_impls(cx, tcx, item.def, impls)
}
let mut visited = HashSet::new();
for item in tcx.sess.cstore.item_children(did) {
match item.def {
- cstore::DlDef(def::DefForeignMod(did)) => {
+ cstore::DlDef(Def::ForeignMod(did)) => {
fill_in(cx, tcx, did, items);
}
cstore::DlDef(def) if item.vis == hir::Public => {
use rustc_trans::back::link;
use rustc::middle::cstore::{self, CrateStore};
-use rustc::middle::def;
+use rustc::middle::def::Def;
use rustc::middle::def_id::{DefId, DefIndex};
use rustc::middle::subst::{self, ParamSpace, VecPerParamSpace};
use rustc::middle::ty;
cx.tcx_opt().map(|tcx| {
for item in tcx.sess.cstore.crate_top_level_items(self.0) {
let did = match item.def {
- cstore::DlDef(def::DefMod(did)) => did,
+ cstore::DlDef(Def::Mod(did)) => did,
_ => continue
};
let attrs = inline::load_attrs(cx, tcx, did);
debug!("resolve_type: def={:?}", def);
let is_generic = match def {
- def::DefPrimTy(p) => match p {
+ Def::PrimTy(p) => match p {
hir::TyStr => return Primitive(Str),
hir::TyBool => return Primitive(Bool),
hir::TyChar => return Primitive(Char),
hir::TyFloat(ast::TyF32) => return Primitive(F32),
hir::TyFloat(ast::TyF64) => return Primitive(F64),
},
- def::DefSelfTy(..) if path.segments.len() == 1 => {
+ Def::SelfTy(..) if path.segments.len() == 1 => {
return Generic(special_idents::type_self.name.to_string());
}
- def::DefSelfTy(..) | def::DefTyParam(..) => true,
+ Def::SelfTy(..) | Def::TyParam(..) => true,
_ => false,
};
let did = register_def(&*cx, def);
ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic }
}
-fn register_def(cx: &DocContext, def: def::Def) -> DefId {
+fn register_def(cx: &DocContext, def: Def) -> DefId {
debug!("register_def({:?})", def);
let (did, kind) = match def {
- def::DefFn(i, _) => (i, TypeFunction),
- def::DefTy(i, false) => (i, TypeTypedef),
- def::DefTy(i, true) => (i, TypeEnum),
- def::DefTrait(i) => (i, TypeTrait),
- def::DefStruct(i) => (i, TypeStruct),
- def::DefMod(i) => (i, TypeModule),
- def::DefStatic(i, _) => (i, TypeStatic),
- def::DefVariant(i, _, _) => (i, TypeEnum),
- def::DefSelfTy(Some(def_id), _) => (def_id, TypeTrait),
- def::DefSelfTy(_, Some((impl_id, _))) => return cx.map.local_def_id(impl_id),
+ Def::Fn(i) => (i, TypeFunction),
+ Def::TyAlias(i) => (i, TypeTypedef),
+ Def::Enum(i) => (i, TypeEnum),
+ Def::Trait(i) => (i, TypeTrait),
+ Def::Struct(i) => (i, TypeStruct),
+ Def::Mod(i) => (i, TypeModule),
+ Def::Static(i, _) => (i, TypeStatic),
+ Def::Variant(i, _) => (i, TypeEnum),
+ Def::SelfTy(Some(def_id), _) => (def_id, TypeTrait),
+ Def::SelfTy(_, Some((impl_id, _))) => return cx.map.local_def_id(impl_id),
_ => return def.def_id()
};
if did.is_local() { return did }
decl.decl)
}
clean::Tuple(ref typs) => {
- primitive_link(f, clean::PrimitiveTuple,
- &*match &**typs {
- [ref one] => format!("({},)", one),
- many => format!("({})", CommaSep(&many)),
- })
+ match &**typs {
+ [] => primitive_link(f, clean::PrimitiveTuple, "()"),
+ [ref one] => {
+ try!(primitive_link(f, clean::PrimitiveTuple, "("));
+ try!(write!(f, "{}", one));
+ primitive_link(f, clean::PrimitiveTuple, ")")
+ }
+ many => {
+ try!(primitive_link(f, clean::PrimitiveTuple, "("));
+ try!(write!(f, "{}", CommaSep(&many)));
+ primitive_link(f, clean::PrimitiveTuple, ")")
+ }
+ }
}
clean::Vector(ref t) => {
- primitive_link(f, clean::Slice, &format!("[{}]", **t))
+ try!(primitive_link(f, clean::Slice, &format!("[")));
+ try!(write!(f, "{}", t));
+ primitive_link(f, clean::Slice, &format!("]"))
}
clean::FixedVector(ref t, ref s) => {
+ try!(primitive_link(f, clean::PrimitiveType::Array, "["));
+ try!(write!(f, "{}", t));
primitive_link(f, clean::PrimitiveType::Array,
- &format!("[{}; {}]", **t, *s))
+ &format!("; {}]", *s))
}
clean::Bottom => f.write_str("!"),
clean::RawPointer(m, ref t) => {
- primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer,
- &format!("*{}{}", RawMutableSpace(m), **t))
+ match **t {
+ clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
+ primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer,
+ &format!("*{}{}", RawMutableSpace(m), t))
+ }
+ _ => {
+ try!(primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer,
+ &format!("*{}", RawMutableSpace(m))));
+ write!(f, "{}", t)
+ }
+ }
}
clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
let lt = match *l {
"".to_string()
} else {
format!("<a href='{}{}/index.html'>\
- <img src='{}' alt='' width='100'></a>",
+ <img src='{}' alt='logo' width='100'></a>",
page.root_path, layout.krate,
layout.logo)
},
}
.content span.enum, .content a.enum, .block a.current.enum { color: #5e9766; }
-.content span.struct, .content a.struct, .block a.current.struct { color: #e53700; }
+.content span.struct, .content a.struct, .block a.current.struct { color: #df3600; }
.content a.type { color: #e57300; }
.content a.macro { color: #068000; }
.block a.current.crate { font-weight: 500; }
}
.docblock a, .stability a {
- color: #4e8bca;
+ color: #3873AD;
}
a.test-arrow {
color: #f5f5f5;
}
-.content span.trait, .content a.trait, .block a.current.trait { color: #8866ff; }
+.content span.trait, .content a.trait, .block a.current.trait { color: #7c5af3; }
.search-input {
color: #555;
/// }
/// ```
///
+/// `HashMap` also implements an [`Entry API`](#method.entry), which allows
+/// for more complex methods of getting, setting, updating and removing keys and
+/// their values:
+///
+/// ```
+/// use std::collections::HashMap;
+///
+/// // type inference lets us omit an explicit type signature (which
+/// // would be `HashMap<&str, u8>` in this example).
+/// let mut player_stats = HashMap::new();
+///
+/// fn random_stat_buff() -> u8 {
+/// // could actually return some random value here - let's just return
+/// // some fixed value for now
+/// 42
+/// }
+///
+/// // insert a key only if it doesn't already exist
+/// player_stats.entry("health").or_insert(100);
+///
+/// // insert a key using a function that provides a new value only if it
+/// // doesn't already exist
+/// player_stats.entry("defence").or_insert_with(random_stat_buff);
+///
+/// // update a key, guarding against the key possibly not being set
+/// let stat = player_stats.entry("attack").or_insert(100);
+/// *stat += random_stat_buff();
+/// ```
+///
/// The easiest way to use `HashMap` with a custom type as key is to derive `Eq` and `Hash`.
/// We must also derive `PartialEq`.
///
}
}
+#[stable(feature = "str_parse_error2", since = "1.8.0")]
+impl Error for string::ParseError {
+ fn description(&self) -> &str {
+ match *self {}
+ }
+}
+
// copied from any.rs
impl Error + 'static {
/// Returns true if the boxed type is the same as `T`
/// # fn main() {
/// use std::ffi::CStr;
/// use std::os::raw::c_char;
- /// use std::str;
///
/// extern {
/// fn my_string() -> *const c_char;
///
/// unsafe {
/// let slice = CStr::from_ptr(my_string());
- /// println!("string returned: {}",
- /// str::from_utf8(slice.to_bytes()).unwrap());
+ /// println!("string returned: {}", slice.to_str().unwrap());
/// }
/// # }
/// ```
}
impl OpenOptions {
- /// Creates a blank net set of options ready for configuration.
+ /// Creates a blank new set of options ready for configuration.
///
/// All options are initially set to `false`.
///
/// ```no_run
/// use std::fs::OpenOptions;
///
- /// let file = OpenOptions::new().open("foo.txt");
+ /// let mut options = OpenOptions::new();
+ /// let file = options.read(true).open("foo.txt");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> OpenOptions {
/// This option, when true, will indicate that the file should be
/// `write`-able if opened.
///
+ /// If a file already exist, any write calls on the file will overwrite its
+ /// contents, without truncating it.
+ ///
/// # Examples
///
/// ```no_run
///
/// This option, when true, means that writes will append to a file instead
/// of overwriting previous contents.
+ /// Note that setting `.write(true).append(true)` has the same effect as
+ /// setting only `.append(true)`.
+ ///
+ /// For most filesystems the operating system guarantees all writes are
+ /// atomic: no writes get mangled because another process writes at the same
+ /// time.
+ ///
+ /// One maybe obvious note when using append-mode: make sure that all data
+ /// that belongs together, is written the the file in one operation. This
+ /// can be done by concatenating strings before passing them to `write()`,
+ /// or using a buffered writer (with a more than adequately sized buffer)
+ /// and calling `flush()` when the message is complete.
+ ///
+ /// If a file is opened with both read and append access, beware that after
+ /// opening and after every write the position for reading may be set at the
+ /// end of the file. So before writing save the current position (using
+ /// `seek(SeekFrom::Current(0))`, and restore it before the next read.
///
/// # Examples
///
/// ```no_run
/// use std::fs::OpenOptions;
///
- /// let file = OpenOptions::new().write(true).append(true).open("foo.txt");
+ /// let file = OpenOptions::new().append(true).open("foo.txt");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn append(&mut self, append: bool) -> &mut OpenOptions {
/// If a file is successfully opened with this option set it will truncate
/// the file to 0 length if it already exists.
///
+ /// The file must be opened with write access for truncate to work.
+ ///
/// # Examples
///
/// ```no_run
/// This option indicates whether a new file will be created if the file
/// does not yet already exist.
///
+ /// The file must be opened with write or append access in order to create
+ /// a new file.
+ ///
/// # Examples
///
/// ```no_run
/// use std::fs::OpenOptions;
///
- /// let file = OpenOptions::new().create(true).open("foo.txt");
+ /// let file = OpenOptions::new().write(true).create(true).open("foo.txt");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn create(&mut self, create: bool) -> &mut OpenOptions {
self.0.create(create); self
}
+ /// Sets the option to always create a new file.
+ ///
+ /// This option indicates whether a new file will be created.
+ /// No file is allowed to exist at the target location, also no (dangling)
+ /// symlink.
+ ///
+ /// This option is usefull because it as atomic. Otherwise between checking
+ /// whether a file exists and creating a new one, the file may have been
+ /// created by another process (a TOCTOU race condition / attack).
+ ///
+ /// If `.create_new(true)` is set, `.create()` and `.truncate()` are
+ /// ignored.
+ ///
+ /// The file must be opened with write or append access in order to create
+ /// a new file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(expand_open_options)]
+ /// use std::fs::OpenOptions;
+ ///
+ /// let file = OpenOptions::new().write(true)
+ /// .create_new(true)
+ /// .open("foo.txt");
+ /// ```
+ #[unstable(feature = "expand_open_options",
+ reason = "recently added",
+ issue = "30014")]
+ pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
+ self.0.create_new(create_new); self
+ }
+
/// Opens a file at `path` with the options specified by `self`.
///
/// # Errors
/// This function will return an error under a number of different
/// circumstances, to include but not limited to:
///
- /// * Opening a file that does not exist with read access.
+ /// * Opening a file that does not exist without setting `create` or
+ /// `create_new`.
/// * Attempting to open a file with access that the user lacks
/// permissions for
/// * Filesystem-level errors (full disk, etc)
+ /// * Invalid combinations of open options (truncate without write access,
+ /// no access mode set, etc)
///
/// # Examples
///
let mut r = OO::new(); r.read(true);
let mut w = OO::new(); w.write(true);
- let mut rw = OO::new(); rw.write(true).read(true);
-
- match r.open(&tmpdir.join("a")) {
- Ok(..) => panic!(), Err(..) => {}
- }
-
- // Perform each one twice to make sure that it succeeds the second time
- // (where the file exists)
- check!(c(&w).create(true).open(&tmpdir.join("b")));
- assert!(tmpdir.join("b").exists());
- check!(c(&w).create(true).open(&tmpdir.join("b")));
- check!(w.open(&tmpdir.join("b")));
-
+ let mut rw = OO::new(); rw.read(true).write(true);
+ let mut a = OO::new(); a.append(true);
+ let mut ra = OO::new(); ra.read(true).append(true);
+
+ let invalid_options = if cfg!(windows) { "The parameter is incorrect" }
+ else { "Invalid argument" };
+
+ // Test various combinations of creation modes and access modes.
+ //
+ // Allowed:
+ // creation mode | read | write | read-write | append | read-append |
+ // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:|
+ // not set (open existing) | X | X | X | X | X |
+ // create | | X | X | X | X |
+ // truncate | | X | X | | |
+ // create and truncate | | X | X | | |
+ // create_new | | X | X | X | X |
+ //
+ // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it.
+
+ // write-only
+ check!(c(&w).create_new(true).open(&tmpdir.join("a")));
+ check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a")));
+ check!(c(&w).truncate(true).open(&tmpdir.join("a")));
+ check!(c(&w).create(true).open(&tmpdir.join("a")));
+ check!(c(&w).open(&tmpdir.join("a")));
+
+ // read-only
+ error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options);
+ error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options);
+ error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options);
+ error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options);
+ check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only
+
+ // read-write
+ check!(c(&rw).create_new(true).open(&tmpdir.join("c")));
+ check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c")));
+ check!(c(&rw).truncate(true).open(&tmpdir.join("c")));
check!(c(&rw).create(true).open(&tmpdir.join("c")));
- assert!(tmpdir.join("c").exists());
- check!(c(&rw).create(true).open(&tmpdir.join("c")));
- check!(rw.open(&tmpdir.join("c")));
-
- check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
- assert!(tmpdir.join("d").exists());
- check!(c(&w).append(true).create(true).open(&tmpdir.join("d")));
- check!(c(&w).append(true).open(&tmpdir.join("d")));
-
- check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
- assert!(tmpdir.join("e").exists());
- check!(c(&rw).append(true).create(true).open(&tmpdir.join("e")));
- check!(c(&rw).append(true).open(&tmpdir.join("e")));
-
- check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
- assert!(tmpdir.join("f").exists());
- check!(c(&w).truncate(true).create(true).open(&tmpdir.join("f")));
- check!(c(&w).truncate(true).open(&tmpdir.join("f")));
-
- check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
- assert!(tmpdir.join("g").exists());
- check!(c(&rw).truncate(true).create(true).open(&tmpdir.join("g")));
- check!(c(&rw).truncate(true).open(&tmpdir.join("g")));
-
- check!(check!(File::create(&tmpdir.join("h"))).write("foo".as_bytes()));
+ check!(c(&rw).open(&tmpdir.join("c")));
+
+ // append
+ check!(c(&a).create_new(true).open(&tmpdir.join("d")));
+ error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options);
+ error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options);
+ check!(c(&a).create(true).open(&tmpdir.join("d")));
+ check!(c(&a).open(&tmpdir.join("d")));
+
+ // read-append
+ check!(c(&ra).create_new(true).open(&tmpdir.join("e")));
+ error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options);
+ error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options);
+ check!(c(&ra).create(true).open(&tmpdir.join("e")));
+ check!(c(&ra).open(&tmpdir.join("e")));
+
+ // Test opening a file without setting an access mode
+ let mut blank = OO::new();
+ error!(blank.create(true).open(&tmpdir.join("f")), invalid_options);
+
+ // Test write works
+ check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes()));
+
+ // Test write fails for read-only
check!(r.open(&tmpdir.join("h")));
{
let mut f = check!(r.open(&tmpdir.join("h")));
assert!(f.write("wut".as_bytes()).is_err());
}
+
+ // Test write overwrites
+ {
+ let mut f = check!(c(&w).open(&tmpdir.join("h")));
+ check!(f.write("baz".as_bytes()));
+ }
+ {
+ let mut f = check!(c(&r).open(&tmpdir.join("h")));
+ let mut b = vec![0; 6];
+ check!(f.read(&mut b));
+ assert_eq!(b, "bazbar".as_bytes());
+ }
+
+ // Test truncate works
+ {
+ let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
+ check!(f.write("foo".as_bytes()));
+ }
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
+
+ // Test append works
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
{
- let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
+ let mut f = check!(c(&a).open(&tmpdir.join("h")));
check!(f.write("bar".as_bytes()));
}
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
+
+ // Test .append(true) equals .write(true).append(true)
{
- let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
- check!(f.write("bar".as_bytes()));
+ let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
+ check!(f.write("baz".as_bytes()));
}
- assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
+ assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9);
+ }
+
+ #[test]
+ fn _assert_send_sync() {
+ fn _assert_send_sync<T: Send + Sync>() {}
+ _assert_send_sync::<OpenOptions>();
}
#[test]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufReader<R> {
inner: R,
- buf: Vec<u8>,
+ buf: Box<[u8]>,
pos: usize,
cap: usize,
}
pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
BufReader {
inner: inner,
- buf: vec![0; cap],
+ buf: vec![0; cap].into_boxed_slice(),
pos: 0,
cap: 0,
}
pub struct BufWriter<W: Write> {
inner: Option<W>,
buf: Vec<u8>,
+ // #30888: If the inner writer panics in a call to write, we don't want to
+ // write the buffered data a second time in BufWriter's destructor. This
+ // flag tells the Drop impl if it should skip the flush.
+ panicked: bool,
}
/// An error returned by `into_inner` which combines an error that
BufWriter {
inner: Some(inner),
buf: Vec::with_capacity(cap),
+ panicked: false,
}
}
let len = self.buf.len();
let mut ret = Ok(());
while written < len {
- match self.inner.as_mut().unwrap().write(&self.buf[written..]) {
+ self.panicked = true;
+ let r = self.inner.as_mut().unwrap().write(&self.buf[written..]);
+ self.panicked = false;
+
+ match r {
Ok(0) => {
ret = Err(Error::new(ErrorKind::WriteZero,
"failed to write the buffered data"));
try!(self.flush_buf());
}
if buf.len() >= self.buf.capacity() {
- self.inner.as_mut().unwrap().write(buf)
+ self.panicked = true;
+ let r = self.inner.as_mut().unwrap().write(buf);
+ self.panicked = false;
+ r
} else {
let amt = cmp::min(buf.len(), self.buf.capacity());
Write::write(&mut self.buf, &buf[..amt])
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> Drop for BufWriter<W> {
fn drop(&mut self) {
- if self.inner.is_some() {
+ if self.inner.is_some() && !self.panicked {
// dtors should not panic, so we ignore a failed flush
let _r = self.flush_buf();
}
use prelude::v1::*;
use io::prelude::*;
use io::{self, BufReader, BufWriter, LineWriter, SeekFrom};
+ use sync::atomic::{AtomicUsize, Ordering};
+ use thread;
use test;
/// A dummy reader intended at testing short-reads propagation.
panic!();
}
+ #[test]
+ fn panic_in_write_doesnt_flush_in_drop() {
+ static WRITES: AtomicUsize = AtomicUsize::new(0);
+
+ struct PanicWriter;
+
+ impl Write for PanicWriter {
+ fn write(&mut self, _: &[u8]) -> io::Result<usize> {
+ WRITES.fetch_add(1, Ordering::SeqCst);
+ panic!();
+ }
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+ }
+
+ thread::spawn(|| {
+ let mut writer = BufWriter::new(PanicWriter);
+ writer.write(b"hello world");
+ writer.flush();
+ }).join().err().unwrap();
+
+ assert_eq!(WRITES.load(Ordering::SeqCst), 1);
+ }
+
#[bench]
fn bench_buffered_reader(b: &mut test::Bencher) {
b.iter(|| {
#[cfg(not(target_os = "linux"))]
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
- haystack.iter().rposition(|&b| b == needle)
+ fallback::memrchr(needle, haystack)
}
memrchr_specific(needle, haystack)
///
/// If a new file is created as part of a `File::open_opts` call then this
/// specified `mode` will be used as the permission bits for the new file.
+ /// If no `mode` is set, the default of `0o666` will be used.
+ /// The operating system masks out bits with the systems `umask`, to produce
+ /// the final permissions.
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&mut self, mode: raw::mode_t) -> &mut Self;
+
+ /// Pass custom flags to the `flags` agument of `open`.
+ ///
+ /// The bits that define the access mode are masked out with `O_ACCMODE`, to
+ /// ensure they do not interfere with the access mode set by Rusts options.
+ ///
+ /// Custom flags can only set flags, not remove flags set by Rusts options.
+ /// This options overwrites any previously set custom flags.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// extern crate libc;
+ /// use std::fs::OpenOptions;
+ /// use std::os::unix::fs::OpenOptionsExt;
+ ///
+ /// let mut options = OpenOptions::new();
+ /// options.write(true);
+ /// if cfg!(unix) {
+ /// options.custom_flags(libc::O_NOFOLLOW);
+ /// }
+ /// let file = options.open("foo.txt");
+ /// ```
+ #[unstable(feature = "expand_open_options",
+ reason = "recently added",
+ issue = "30014")]
+ fn custom_flags(&mut self, flags: i32) -> &mut Self;
}
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&mut self, mode: raw::mode_t) -> &mut OpenOptions {
self.as_inner_mut().mode(mode); self
}
+
+ fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
+ self.as_inner_mut().custom_flags(flags); self
+ }
}
// Hm, why are there casts here to the returned type, shouldn't the types always
self
}
}
-
#[derive(Clone)]
pub struct OpenOptions {
- flags: c_int,
+ // generic
read: bool,
write: bool,
+ append: bool,
+ truncate: bool,
+ create: bool,
+ create_new: bool,
+ // system-specific
+ custom_flags: i32,
mode: mode_t,
}
impl OpenOptions {
pub fn new() -> OpenOptions {
OpenOptions {
- flags: libc::O_CLOEXEC,
+ // generic
read: false,
write: false,
+ append: false,
+ truncate: false,
+ create: false,
+ create_new: false,
+ // system-specific
+ custom_flags: 0,
mode: 0o666,
}
}
- pub fn read(&mut self, read: bool) {
- self.read = read;
- }
-
- pub fn write(&mut self, write: bool) {
- self.write = write;
- }
-
- pub fn append(&mut self, append: bool) {
- self.flag(libc::O_APPEND, append);
- }
-
- pub fn truncate(&mut self, truncate: bool) {
- self.flag(libc::O_TRUNC, truncate);
- }
-
- pub fn create(&mut self, create: bool) {
- self.flag(libc::O_CREAT, create);
- }
-
- pub fn mode(&mut self, mode: raw::mode_t) {
- self.mode = mode as mode_t;
+ pub fn read(&mut self, read: bool) { self.read = read; }
+ pub fn write(&mut self, write: bool) { self.write = write; }
+ pub fn append(&mut self, append: bool) { self.append = append; }
+ pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
+ pub fn create(&mut self, create: bool) { self.create = create; }
+ pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
+
+ pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; }
+ pub fn mode(&mut self, mode: raw::mode_t) { self.mode = mode as mode_t; }
+
+ fn get_access_mode(&self) -> io::Result<c_int> {
+ match (self.read, self.write, self.append) {
+ (true, false, false) => Ok(libc::O_RDONLY),
+ (false, true, false) => Ok(libc::O_WRONLY),
+ (true, true, false) => Ok(libc::O_RDWR),
+ (false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND),
+ (true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND),
+ (false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)),
+ }
}
- fn flag(&mut self, bit: c_int, on: bool) {
- if on {
- self.flags |= bit;
- } else {
- self.flags &= !bit;
+ fn get_creation_mode(&self) -> io::Result<c_int> {
+ match (self.write, self.append) {
+ (true, false) => {}
+ (false, false) =>
+ if self.truncate || self.create || self.create_new {
+ return Err(Error::from_raw_os_error(libc::EINVAL));
+ },
+ (_, true) =>
+ if self.truncate && !self.create_new {
+ return Err(Error::from_raw_os_error(libc::EINVAL));
+ },
}
+
+ Ok(match (self.create, self.truncate, self.create_new) {
+ (false, false, false) => 0,
+ (true, false, false) => libc::O_CREAT,
+ (false, true, false) => libc::O_TRUNC,
+ (true, true, false) => libc::O_CREAT | libc::O_TRUNC,
+ (_, _, true) => libc::O_CREAT | libc::O_EXCL,
+ })
}
}
}
pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
- let flags = opts.flags | match (opts.read, opts.write) {
- (true, true) => libc::O_RDWR,
- (false, true) => libc::O_WRONLY,
- (true, false) |
- (false, false) => libc::O_RDONLY,
- };
+ let flags = libc::O_CLOEXEC |
+ try!(opts.get_access_mode()) |
+ try!(opts.get_creation_mode()) |
+ (opts.custom_flags as c_int & !libc::O_ACCMODE);
let fd = try!(cvt_r(|| unsafe {
libc::open(path.as_ptr(), flags, opts.mode as c_int)
}));
pub const OPEN_ALWAYS: DWORD = 4;
pub const OPEN_EXISTING: DWORD = 3;
pub const TRUNCATE_EXISTING: DWORD = 5;
-pub const FILE_APPEND_DATA: DWORD = 0x00000004;
+
pub const FILE_READ_DATA: DWORD = 0x00000001;
pub const FILE_WRITE_DATA: DWORD = 0x00000002;
-pub const STANDARD_RIGHTS_READ: DWORD = 0x20000;
-pub const STANDARD_RIGHTS_WRITE: DWORD = 0x20000;
-pub const FILE_WRITE_EA: DWORD = 0x00000010;
+pub const FILE_APPEND_DATA: DWORD = 0x00000004;
pub const FILE_READ_EA: DWORD = 0x00000008;
-pub const SYNCHRONIZE: DWORD = 0x00100000;
-pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100;
+pub const FILE_WRITE_EA: DWORD = 0x00000010;
+pub const FILE_EXECUTE: DWORD = 0x00000020;
pub const FILE_READ_ATTRIBUTES: DWORD = 0x00000080;
+pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100;
+
+pub const DELETE: DWORD = 0x00008000;
+pub const READ_CONTROL: DWORD = 0x00020000;
+pub const WRITE_DAC: DWORD = 0x00040000;
+pub const WRITE_OWNER: DWORD = 0x00080000;
+pub const SYNCHRONIZE: DWORD = 0x00100000;
+
+pub const GENERIC_READ: DWORD = 0x80000000;
+pub const GENERIC_WRITE: DWORD = 0x40000000;
+pub const GENERIC_EXECUTE: DWORD = 0x20000000;
+pub const GENERIC_ALL: DWORD = 0x10000000;
+
+pub const STANDARD_RIGHTS_READ: DWORD = READ_CONTROL;
+pub const STANDARD_RIGHTS_WRITE: DWORD = READ_CONTROL;
+pub const STANDARD_RIGHTS_EXECUTE: DWORD = READ_CONTROL;
pub const FILE_GENERIC_READ: DWORD = STANDARD_RIGHTS_READ | FILE_READ_DATA |
FILE_READ_ATTRIBUTES |
FILE_READ_EA |
FILE_APPEND_DATA |
SYNCHRONIZE;
+pub const SECURITY_ANONYMOUS: DWORD = 0 << 16;
+pub const SECURITY_IDENTIFICATION: DWORD = 1 << 16;
+pub const SECURITY_IMPERSONATION: DWORD = 2 << 16;
+pub const SECURITY_DELEGATION: DWORD = 3 << 16;
+pub const SECURITY_CONTEXT_TRACKING: DWORD = 0x00040000;
+pub const SECURITY_EFFECTIVE_ONLY: DWORD = 0x00080000;
+pub const SECURITY_SQOS_PRESENT: DWORD = 0x00100000;
+
#[repr(C)]
#[derive(Copy)]
pub struct WIN32_FIND_DATAW {
pub trait OpenOptionsExt {
/// Overrides the `dwDesiredAccess` argument to the call to `CreateFile`
/// with the specified value.
- fn desired_access(&mut self, access: u32) -> &mut Self;
-
- /// Overrides the `dwCreationDisposition` argument to the call to
- /// `CreateFile` with the specified value.
///
- /// This will override any values of the standard `create` flags, for
- /// example.
- fn creation_disposition(&mut self, val: u32) -> &mut Self;
-
- /// Overrides the `dwFlagsAndAttributes` argument to the call to
- /// `CreateFile` with the specified value.
+ /// This will override the `read`, `write`, and `append` flags on the
+ /// `OpenOptions` structure. This method provides fine-grained control over
+ /// the permissions to read, write and append data, attributes (like hidden
+ /// and system) and extended attributes.
+ ///
+ /// # Examples
///
- /// This will override any values of the standard flags on the
- /// `OpenOptions` structure.
- fn flags_and_attributes(&mut self, val: u32) -> &mut Self;
+ /// ```no_run
+ /// #![feature(open_options_ext)]
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::fs::OpenOptionsExt;
+ ///
+ /// // Open without read and write permission, for example if you only need
+ /// // to call `stat()` on the file
+ /// let file = OpenOptions::new().access_mode(0).open("foo.txt");
+ /// ```
+ fn access_mode(&mut self, access: u32) -> &mut Self;
/// Overrides the `dwShareMode` argument to the call to `CreateFile` with
/// the specified value.
///
- /// This will override any values of the standard flags on the
- /// `OpenOptions` structure.
+ /// By default `share_mode` is set to
+ /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. Specifying
+ /// less permissions denies others to read from, write to and/or delete the
+ /// file while it is open.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(open_options_ext)]
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::fs::OpenOptionsExt;
+ ///
+ /// // Do not allow others to read or modify this file while we have it open
+ /// // for writing
+ /// let file = OpenOptions::new().write(true)
+ /// .share_mode(0)
+ /// .open("foo.txt");
+ /// ```
fn share_mode(&mut self, val: u32) -> &mut Self;
+
+ /// Sets extra flags for the `dwFileFlags` argument to the call to
+ /// `CreateFile2` (or combines it with `attributes` and `security_qos_flags`
+ /// to set the `dwFlagsAndAttributes` for `CreateFile`).
+ ///
+ /// Custom flags can only set flags, not remove flags set by Rusts options.
+ /// This options overwrites any previously set custom flags.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// extern crate winapi;
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::fs::OpenOptionsExt;
+ ///
+ /// let mut options = OpenOptions::new();
+ /// options.create(true).write(true);
+ /// if cfg!(windows) {
+ /// options.custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE);
+ /// }
+ /// let file = options.open("foo.txt");
+ /// ```
+ #[unstable(feature = "expand_open_options",
+ reason = "recently added",
+ issue = "30014")]
+ fn custom_flags(&mut self, flags: u32) -> &mut Self;
+
+ /// Sets the `dwFileAttributes` argument to the call to `CreateFile2` to
+ /// the specified value (or combines it with `custom_flags` and
+ /// `security_qos_flags` to set the `dwFlagsAndAttributes` for
+ /// `CreateFile`).
+ ///
+ /// If a _new_ file is created because it does not yet exist and
+ ///`.create(true)` or `.create_new(true)` are specified, the new file is
+ /// given the attributes declared with `.attributes()`.
+ ///
+ /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
+ /// existing attributes are preserved and combined with the ones declared
+ /// with `.attributes()`.
+ ///
+ /// In all other cases the attributes get ignored.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// #![feature(open_options_ext)]
+ /// extern crate winapi;
+ /// use std::fs::OpenOptions;
+ /// use std::os::windows::fs::OpenOptionsExt;
+ ///
+ /// let file = OpenOptions::new().write(true).create(true)
+ /// .attributes(winapi::FILE_ATTRIBUTE_HIDDEN)
+ /// .open("foo.txt");
+ /// ```
+ fn attributes(&mut self, val: u32) -> &mut Self;
+
+ /// Sets the `dwSecurityQosFlags` argument to the call to `CreateFile2` to
+ /// the specified value (or combines it with `custom_flags` and `attributes`
+ /// to set the `dwFlagsAndAttributes` for `CreateFile`).
+ fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions;
}
#[unstable(feature = "open_options_ext",
reason = "may require more thought/methods",
issue = "27720")]
impl OpenOptionsExt for OpenOptions {
- fn desired_access(&mut self, access: u32) -> &mut OpenOptions {
- self.as_inner_mut().desired_access(access); self
+ fn access_mode(&mut self, access: u32) -> &mut OpenOptions {
+ self.as_inner_mut().access_mode(access); self
}
- fn creation_disposition(&mut self, access: u32) -> &mut OpenOptions {
- self.as_inner_mut().creation_disposition(access); self
+
+ fn share_mode(&mut self, share: u32) -> &mut OpenOptions {
+ self.as_inner_mut().share_mode(share); self
}
- fn flags_and_attributes(&mut self, access: u32) -> &mut OpenOptions {
- self.as_inner_mut().flags_and_attributes(access); self
+
+ fn custom_flags(&mut self, flags: u32) -> &mut OpenOptions {
+ self.as_inner_mut().custom_flags(flags); self
}
- fn share_mode(&mut self, access: u32) -> &mut OpenOptions {
- self.as_inner_mut().share_mode(access); self
+
+ fn attributes(&mut self, attributes: u32) -> &mut OpenOptions {
+ self.as_inner_mut().attributes(attributes); self
+ }
+
+ fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions {
+ self.as_inner_mut().security_qos_flags(flags); self
}
}
data: c::WIN32_FIND_DATAW,
}
-#[derive(Clone, Default)]
+#[derive(Clone)]
pub struct OpenOptions {
- create: bool,
- append: bool,
+ // generic
read: bool,
write: bool,
+ append: bool,
truncate: bool,
- desired_access: Option<c::DWORD>,
- share_mode: Option<c::DWORD>,
- creation_disposition: Option<c::DWORD>,
- flags_and_attributes: Option<c::DWORD>,
- security_attributes: usize, // *mut T doesn't have a Default impl
+ create: bool,
+ create_new: bool,
+ // system-specific
+ custom_flags: u32,
+ access_mode: Option<c::DWORD>,
+ attributes: c::DWORD,
+ share_mode: c::DWORD,
+ security_qos_flags: c::DWORD,
+ security_attributes: usize, // FIXME: should be a reference
}
#[derive(Clone, PartialEq, Eq, Debug)]
}
impl OpenOptions {
- pub fn new() -> OpenOptions { Default::default() }
+ pub fn new() -> OpenOptions {
+ OpenOptions {
+ // generic
+ read: false,
+ write: false,
+ append: false,
+ truncate: false,
+ create: false,
+ create_new: false,
+ // system-specific
+ custom_flags: 0,
+ access_mode: None,
+ share_mode: c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE,
+ attributes: 0,
+ security_qos_flags: 0,
+ security_attributes: 0,
+ }
+ }
+
pub fn read(&mut self, read: bool) { self.read = read; }
pub fn write(&mut self, write: bool) { self.write = write; }
pub fn append(&mut self, append: bool) { self.append = append; }
- pub fn create(&mut self, create: bool) { self.create = create; }
pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
- pub fn creation_disposition(&mut self, val: u32) {
- self.creation_disposition = Some(val);
- }
- pub fn flags_and_attributes(&mut self, val: u32) {
- self.flags_and_attributes = Some(val);
- }
- pub fn desired_access(&mut self, val: u32) {
- self.desired_access = Some(val);
- }
- pub fn share_mode(&mut self, val: u32) {
- self.share_mode = Some(val);
- }
+ pub fn create(&mut self, create: bool) { self.create = create; }
+ pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
+
+ pub fn custom_flags(&mut self, flags: u32) { self.custom_flags = flags; }
+ pub fn access_mode(&mut self, access_mode: u32) { self.access_mode = Some(access_mode); }
+ pub fn share_mode(&mut self, share_mode: u32) { self.share_mode = share_mode; }
+ pub fn attributes(&mut self, attrs: u32) { self.attributes = attrs; }
+ pub fn security_qos_flags(&mut self, flags: u32) { self.security_qos_flags = flags; }
pub fn security_attributes(&mut self, attrs: c::LPSECURITY_ATTRIBUTES) {
self.security_attributes = attrs as usize;
}
- fn get_desired_access(&self) -> c::DWORD {
- self.desired_access.unwrap_or({
- let mut base = if self.read {c::FILE_GENERIC_READ} else {0} |
- if self.write {c::FILE_GENERIC_WRITE} else {0};
- if self.append {
- base &= !c::FILE_WRITE_DATA;
- base |= c::FILE_APPEND_DATA;
- }
- base
- })
+ fn get_access_mode(&self) -> io::Result<c::DWORD> {
+ const ERROR_INVALID_PARAMETER: i32 = 87;
+
+ match (self.read, self.write, self.append, self.access_mode) {
+ (_, _, _, Some(mode)) => Ok(mode),
+ (true, false, false, None) => Ok(c::GENERIC_READ),
+ (false, true, false, None) => Ok(c::GENERIC_WRITE),
+ (true, true, false, None) => Ok(c::GENERIC_READ | c::GENERIC_WRITE),
+ (false, _, true, None) => Ok(c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA),
+ (true, _, true, None) => Ok(c::GENERIC_READ |
+ (c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA)),
+ (false, false, false, None) => Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)),
+ }
}
- fn get_share_mode(&self) -> c::DWORD {
- // libuv has a good comment about this, but the basic idea is that
- // we try to emulate unix semantics by enabling all sharing by
- // allowing things such as deleting a file while it's still open.
- self.share_mode.unwrap_or(c::FILE_SHARE_READ |
- c::FILE_SHARE_WRITE |
- c::FILE_SHARE_DELETE)
- }
-
- fn get_creation_disposition(&self) -> c::DWORD {
- self.creation_disposition.unwrap_or({
- match (self.create, self.truncate) {
- (true, true) => c::CREATE_ALWAYS,
- (true, false) => c::OPEN_ALWAYS,
- (false, false) => c::OPEN_EXISTING,
- (false, true) => {
- if self.write && !self.append {
- c::CREATE_ALWAYS
- } else {
- c::TRUNCATE_EXISTING
- }
- }
- }
- })
+ fn get_creation_mode(&self) -> io::Result<c::DWORD> {
+ const ERROR_INVALID_PARAMETER: i32 = 87;
+
+ match (self.write, self.append) {
+ (true, false) => {}
+ (false, false) =>
+ if self.truncate || self.create || self.create_new {
+ return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER));
+ },
+ (_, true) =>
+ if self.truncate && !self.create_new {
+ return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER));
+ },
+ }
+
+ Ok(match (self.create, self.truncate, self.create_new) {
+ (false, false, false) => c::OPEN_EXISTING,
+ (true, false, false) => c::OPEN_ALWAYS,
+ (false, true, false) => c::TRUNCATE_EXISTING,
+ (true, true, false) => c::CREATE_ALWAYS,
+ (_, _, true) => c::CREATE_NEW,
+ })
}
fn get_flags_and_attributes(&self) -> c::DWORD {
- self.flags_and_attributes.unwrap_or(c::FILE_ATTRIBUTE_NORMAL)
+ self.custom_flags |
+ self.attributes |
+ self.security_qos_flags |
+ if self.security_qos_flags != 0 { c::SECURITY_SQOS_PRESENT } else { 0 } |
+ if self.create_new { c::FILE_FLAG_OPEN_REPARSE_POINT } else { 0 }
}
}
let mut opts = OpenOptions::new();
opts.read(!write);
opts.write(write);
- opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT |
- c::FILE_FLAG_BACKUP_SEMANTICS);
+ opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT |
+ c::FILE_FLAG_BACKUP_SEMANTICS);
File::open(path, &opts)
}
let path = try!(to_u16s(path));
let handle = unsafe {
c::CreateFileW(path.as_ptr(),
- opts.get_desired_access(),
- opts.get_share_mode(),
+ try!(opts.get_access_mode()),
+ opts.share_mode,
opts.security_attributes as *mut _,
- opts.get_creation_disposition(),
+ try!(opts.get_creation_mode()),
opts.get_flags_and_attributes(),
ptr::null_mut())
};
// metadata information is.
if attr.is_reparse_point() {
let mut opts = OpenOptions::new();
- opts.flags_and_attributes(c::FILE_FLAG_BACKUP_SEMANTICS);
+ // No read or write permissions are necessary
+ opts.access_mode(0);
+ // This flag is so we can open directories too
+ opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
let file = try!(File::open(p, &opts));
file.file_attr()
} else {
pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
let mut opts = OpenOptions::new();
- opts.read(true);
+ // No read or write permissions are necessary
+ opts.access_mode(0);
// This flag is so we can open directories too
- opts.flags_and_attributes(c::FILE_FLAG_BACKUP_SEMANTICS);
+ opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
let f = try!(File::open(p, &opts));
get_path(&f)
}
impl Encodable for Span {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- try!(s.emit_u32(self.lo.0));
- s.emit_u32(self.hi.0)
+ s.emit_struct("Span", 2, |s| {
+ try!(s.emit_struct_field("lo", 0, |s| {
+ self.lo.encode(s)
+ }));
+
+ s.emit_struct_field("hi", 1, |s| {
+ self.hi.encode(s)
+ })
+ })
}
}
impl Decodable for Span {
fn decode<D: Decoder>(d: &mut D) -> Result<Span, D::Error> {
- let lo = BytePos(try! { d.read_u32() });
- let hi = BytePos(try! { d.read_u32() });
- Ok(mk_sp(lo, hi))
+ d.read_struct("Span", 2, |d| {
+ let lo = try!(d.read_struct_field("lo", 0, |d| {
+ BytePos::decode(d)
+ }));
+
+ let hi = try!(d.read_struct_field("hi", 1, |d| {
+ BytePos::decode(d)
+ }));
+
+ Ok(mk_sp(lo, hi))
+ })
}
}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type="lib"]
+
+pub enum Foo {
+ FooV { data: () }
+}
--- /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::marker::PhantomData;
+
+pub struct Directed;
+pub struct Undirected;
+
+pub struct Graph<N, E, Ty = Directed> {
+ nodes: Vec<PhantomData<N>>,
+ edges: Vec<PhantomData<E>>,
+ ty: PhantomData<Ty>,
+}
+
+
+impl<N, E> Graph<N, E, Directed> {
+ pub fn new() -> Self {
+ Graph{nodes: Vec::new(), edges: Vec::new(), ty: PhantomData}
+ }
+}
+
+impl<N, E> Graph<N, E, Undirected> {
+ pub fn new_undirected() -> Self {
+ Graph{nodes: Vec::new(), edges: Vec::new(), ty: PhantomData}
+ }
+}
--- /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.
+
+pub enum XE {
+ XStruct { a: u8 },
+ XTuple(u8),
+ XUnit,
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-msvc everything is the system allocator on msvc
+// ignore-windows everything is the system allocator on windows
// ignore-musl no dylibs on musl yet
// ignore-bitrig no jemalloc on bitrig
// ignore-openbsd no jemalloc on openbsd
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-msvc everything is the system allocator on msvc
+// ignore-windows everything is the system allocator on windows
// ignore-musl no dylibs on musl right now
// ignore-bitrig no jemalloc on bitrig
// ignore-openbsd no jemalloc on openbsd
--- /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.
+
+// Test that when a trait impl changes, fns whose body uses that trait
+// must also be recompiled.
+
+// compile-flags: -Z incr-comp
+
+#![feature(rustc_attrs)]
+#![allow(warnings)]
+
+fn main() { }
+
+pub trait Foo: Sized {
+ type T;
+ fn method(self) { }
+}
+
+mod x {
+ use Foo;
+
+ #[rustc_if_this_changed]
+ impl Foo for char { type T = char; }
+
+ impl Foo for u32 { type T = u32; }
+}
+
+mod y {
+ use Foo;
+
+ #[rustc_then_this_would_need(TypeckItemBody)] //~ ERROR OK
+ #[rustc_then_this_would_need(TransCrateItem)] //~ ERROR OK
+ pub fn use_char_assoc() {
+ // Careful here: in the representation, <char as Foo>::T gets
+ // normalized away, so at a certain point we had no edge to
+ // trans. (But now trans just depends on typeck.)
+ let x: <char as Foo>::T = 'a';
+ }
+
+ pub fn take_foo<T:Foo>(t: T) { }
+}
char::method('a');
}
- // FIXME(#30741) tcx fulfillment cache not tracked
- #[rustc_then_this_would_need(TypeckItemBody)] //~ ERROR no path
- #[rustc_then_this_would_need(TransCrateItem)] //~ ERROR no path
+ #[rustc_then_this_would_need(TypeckItemBody)] //~ ERROR OK
+ #[rustc_then_this_would_need(TransCrateItem)] //~ ERROR OK
pub fn take_foo_with_char() {
take_foo::<char>('a');
}
u32::method(22);
}
- // FIXME(#30741) tcx fulfillment cache not tracked
- #[rustc_then_this_would_need(TypeckItemBody)] //~ ERROR no path
- #[rustc_then_this_would_need(TransCrateItem)] //~ ERROR no path
+ #[rustc_then_this_would_need(TypeckItemBody)] //~ ERROR OK
+ #[rustc_then_this_would_need(TransCrateItem)] //~ ERROR OK
pub fn take_foo_with_u32() {
take_foo::<u32>(22);
}
let e3 = E::Empty3; //~ ERROR `E::Empty3` is the name of a struct or struct variant
let e3 = E::Empty3(); //~ ERROR `E::Empty3` is the name of a struct or struct variant
- // FIXME: non-local struct kind should be known early (e.g. kept in `DefStruct`)
- // let xe1 = XEmpty1; // ERROR `XEmpty1` is the name of a struct or struct variant
- let xe1 = XEmpty1(); //~ ERROR expected function, found `empty_struct::XEmpty1`
+ let xe1 = XEmpty1; //~ ERROR `XEmpty1` is the name of a struct or struct variant
+ let xe1 = XEmpty1(); //~ ERROR `XEmpty1` is the name of a struct or struct variant
let xe3 = XE::Empty3; //~ ERROR no associated item named `Empty3` found for type
let xe3 = XE::Empty3(); //~ ERROR no associated item named `Empty3` found for type
}
XEmpty1 => () // Not an error, `XEmpty1` is interpreted as a new binding
}
match xe3 {
- XE::XEmpty3 => () //~ ERROR no associated item named `XEmpty3` found for type
+ XE::XEmpty3 => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct
}
}
Empty1(..) => () //~ ERROR unresolved enum variant, struct or const `Empty1`
}
match xe1 {
- XEmpty1(..) => () //~ ERROR `XEmpty1` does not name a tuple variant or a tuple struct
+ XEmpty1(..) => () //~ ERROR unresolved enum variant, struct or const `XEmpty1`
}
}
E::Empty3(..) => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
}
match xe3 {
- XE::XEmpty3(..) => () //~ ERROR no associated item named `XEmpty3` found for type
+ XE::XEmpty3(..) => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple
}
}
impl S { }
}
-fn foo(_: a::S) { //~ ERROR: type `S` is private
+fn foo(_: a::S) { //~ ERROR: struct `S` is private
}
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.
+
+// aux-build:issue_30123_aux.rs
+
+extern crate issue_30123_aux;
+use issue_30123_aux::*;
+
+fn main() {
+ let ug = Graph::<i32, i32>::new_undirected();
+ //~^ ERR no associated item named `new_undirected` found for type
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue-30535.rs
+
+extern crate issue_30535 as foo;
+
+fn bar(
+ _: foo::Foo::FooV //~ ERROR value `foo::Foo::FooV` used as a type
+) {}
+
+fn main() {}
}
fn main() {
- if 1 == 2 { forever(); }
}
--- /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 test1() {
+ // In this test the outer 'a loop may terminate without `x` getting initialised. Although the
+ // `x = loop { ... }` statement is reached, the value itself ends up never being computed and
+ // thus leaving `x` uninit.
+ let x: i32;
+ 'a: loop {
+ x = loop { break 'a };
+ }
+ println!("{:?}", x); //~ ERROR use of possibly uninitialized variable
+}
+
+// test2 and test3 should not fail.
+fn test2() {
+ // In this test the `'a` loop will never terminate thus making the use of `x` unreachable.
+ let x: i32;
+ 'a: loop {
+ x = loop { continue 'a };
+ }
+ println!("{:?}", x);
+}
+
+fn test3() {
+ let x: i32;
+ // Similarly, the use of variable `x` is unreachable.
+ 'a: loop {
+ x = loop { return };
+ }
+ println!("{:?}", x);
+}
+
+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 forever2() -> i32 {
+ let x: i32 = loop { break }; //~ ERROR mismatched types
+ x
+}
+
+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 forever2() -> ! { //~ ERROR computation may converge in a function marked as diverging
+ loop { break }
+}
+
+fn main() {}
// Even though the inner `A` struct is a publicly exported item (usable from
// external crates through `foo::foo`, it should not be accessible through
// its definition path (which has the private `i` module).
- use self::foo::i::A; //~ ERROR: type `A` is inaccessible
+ use self::foo::i::A; //~ ERROR: struct `A` is inaccessible
//~^ NOTE: module `i` is private
pub mod foo {
}
fn test(a: A, b: inner::A, c: inner::B, d: xc::A, e: xc::B) {
- //~^ ERROR: type `A` is private
+ //~^ ERROR: struct `A` is private
//~^^ ERROR: struct `A` is private
a.a;
--- /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:variant-namespacing.rs
+
+extern crate variant_namespacing;
+pub use variant_namespacing::XE::*;
+//~^ ERROR import `XStruct` conflicts with type in this module
+//~| ERROR import `XStruct` conflicts with value in this module
+//~| ERROR import `XTuple` conflicts with type in this module
+//~| ERROR import `XTuple` conflicts with value in this module
+//~| ERROR import `XUnit` conflicts with type in this module
+//~| ERROR import `XUnit` conflicts with value in this module
+pub use E::*;
+//~^ ERROR import `Struct` conflicts with type in this module
+//~| ERROR import `Struct` conflicts with value in this module
+//~| ERROR import `Tuple` conflicts with type in this module
+//~| ERROR import `Tuple` conflicts with value in this module
+//~| ERROR import `Unit` conflicts with type in this module
+//~| ERROR import `Unit` conflicts with value in this module
+
+enum E {
+ Struct { a: u8 },
+ Tuple(u8),
+ Unit,
+}
+
+type Struct = u8;
+type Tuple = u8;
+type Unit = u8;
+type XStruct = u8;
+type XTuple = u8;
+type XUnit = u8;
+
+const Struct: u8 = 0;
+const Tuple: u8 = 0;
+const Unit: u8 = 0;
+const XStruct: u8 = 0;
+const XTuple: u8 = 0;
+const XUnit: u8 = 0;
+
+fn main() {}
extern crate xcrate_unit_struct;
fn main() {
- let _ = xcrate_unit_struct::StructWithFields; //~ ERROR: unresolved name
+ let _ = xcrate_unit_struct::StructWithFields;
+ //~^ ERROR: `xcrate_unit_struct::StructWithFields` is the name of a struct or struct variant
let _ = xcrate_unit_struct::Struct;
}
ifdef IS_MSVC
$(TMPDIR)/$(call BIN,bar): $(call DYLIB,foo)
- $(CC) bar.c $(TMPDIR)/foo.lib $(call OUT_EXE,bar)
+ $(CC) bar.c $(TMPDIR)/foo.dll.lib $(call OUT_EXE,bar)
else
$(TMPDIR)/$(call BIN,bar): $(call DYLIB,foo)
$(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) -L $(TMPDIR)
ifneq ($(shell uname),FreeBSD)
all:
$(RUSTC) foo.rs
- cp $(TMPDIR)/libfoo.a $(call NATIVE_STATICLIB,foo2)
- $(CC) bar.c $(call NATIVE_STATICLIB,foo2) $(call OUT_EXE,bar) \
+ $(CC) bar.c $(call STATICLIB,foo) $(call OUT_EXE,bar) \
$(EXTRACFLAGS) $(EXTRACXXFLAGS)
$(call RUN,bar)
- rm $(call STATICLIB,foo*)
+ rm $(call STATICLIB,foo)
$(call RUN,bar)
else
all:
$(RUSTC) foo.rs -C lto
- $(CC) bar.c $(TMPDIR)/libfoo.a \
+ $(CC) bar.c $(call STATICLIB,foo) \
$(call OUT_EXE,bar) \
$(EXTRACFLAGS) $(EXTRACXXFLAGS)
$(call RUN,bar)
$(RUSTC) foo.rs --crate-type=rlib,dylib,staticlib
$(call REMOVE_RLIBS,bar)
$(call REMOVE_DYLIBS,bar)
- rm $(TMPDIR)/libbar.a
- rm -f $(TMPDIR)/bar.{exp,lib,pdb}
+ rm $(call STATICLIB,bar)
+ rm -f $(TMPDIR)/bar.{dll.exp,dll.lib,pdb}
# Check that $(TMPDIR) is empty.
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
rm $(TMPDIR)/$(call BIN,foo)
$(RUSTC) foo.rs --crate-type=dylib --emit=link=$(TMPDIR)/$(call BIN,foo)
rm $(TMPDIR)/$(call BIN,foo)
- rm -f $(TMPDIR)/foo.{exp,lib,pdb}
+ rm -f $(TMPDIR)/foo.{dll.exp,dll.lib,pdb}
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
$(RUSTC) foo.rs --crate-type=staticlib -o $(TMPDIR)/foo
rm $(TMPDIR)/bar.ll
rm $(TMPDIR)/bar.s
rm $(TMPDIR)/bar.o
- rm $(TMPDIR)/libbar.a
+ rm $(call STATICLIB,bar)
mv $(TMPDIR)/bar.bc $(TMPDIR)/foo.bc
# Don't check that the $(TMPDIR) is empty - we left `foo.bc` for later
# comparison.
TO_LINK := $(call DYLIB,bar)
ifdef IS_MSVC
-LINK_ARG = $(TO_LINK:dll=lib)
+LINK_ARG = $(TO_LINK:dll=dll.lib)
else
LINK_ARG = $(TO_LINK)
endif
#![feature(alloc_jemalloc, alloc_system)]
-#[cfg(not(any(target_env = "msvc", target_os = "bitrig", target_os = "openbsd")))]
+#[cfg(not(any(windows, target_os = "bitrig", target_os = "openbsd")))]
extern crate alloc_jemalloc;
-#[cfg(any(target_env = "msvc", target_os = "bitrig", target_os = "openbsd"))]
+#[cfg(any(windows, target_os = "bitrig", target_os = "openbsd"))]
extern crate alloc_system;
fn main() {
// except according to those terms.
// no-prefer-dynamic
-// ignore-msvc no jemalloc on msvc
+// ignore-windows no jemalloc on windows
// ignore-bitrig no jemalloc on bitrig
// ignore-openbsd no jemalloc on openbsd
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// aux-build:empty-struct.rs
+
#![feature(associated_consts)]
+extern crate empty_struct;
+use empty_struct::XEmpty2 as XFoo;
+
struct Foo;
enum Bar {
const THEBAR: Bar = Bar::Var1;
}
+impl HasBar for XFoo {
+ const THEBAR: Bar = Bar::Var1;
+}
+
fn main() {
// Inherent impl
assert!(match Bar::Var2 {
<Foo as HasBar>::THEBAR => true,
_ => false,
});
+ assert!(match Bar::Var1 {
+ XFoo::THEBAR => true,
+ _ => false,
+ });
+ assert!(match Bar::Var1 {
+ <XFoo>::THEBAR => true,
+ _ => false,
+ });
+ assert!(match Bar::Var1 {
+ <XFoo as HasBar>::THEBAR => true,
+ _ => false,
+ });
}
let e2: XEmpty2 = XEmpty2 {};
let e2: XEmpty2 = XEmpty2;
let e3: XE = XE::XEmpty3 {};
- // FIXME: Commented out tests are waiting for PR 30882 (fixes for variant namespaces)
- // let e4: XE = XE::XEmpty4 {};
+ let e4: XE = XE::XEmpty4 {};
let e4: XE = XE::XEmpty4;
match e1 {
XE::XEmpty3 {} => {}
_ => {}
}
- // match e4 {
- // XE::XEmpty4 {} => {}
- // _ => {}
- // }
+ match e4 {
+ XE::XEmpty4 {} => {}
+ _ => {}
+ }
match e1 {
XEmpty1 { .. } => {}
XE::XEmpty3 { .. } => {}
_ => {}
}
- // match e4 {
- // XE::XEmpty4 { .. } => {}
- // _ => {}
- // }
+ match e4 {
+ XE::XEmpty4 { .. } => {}
+ _ => {}
+ }
match e2 {
XEmpty2 => {}
}
- // match e4 {
- // XE::XEmpty4 => {}
- // _ => {}
- // }
+ match e4 {
+ XE::XEmpty4 => {}
+ _ => {}
+ }
let e11: XEmpty1 = XEmpty1 { ..e1 };
let e22: XEmpty2 = XEmpty2 { ..e2 };
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_attrs)]
+
+#[rustc_mir]
+fn test1(f: f32) -> bool {
+ // test that we properly promote temporaries to allocas when a temporary is assigned to
+ // multiple times (assignment is still happening once ∀ possible dataflows).
+ !(f.is_nan() || f.is_infinite())
+}
+
+fn main() {
+ assert_eq!(test1(0.0), true);
+}
--- /dev/null
+// Copyright 2013 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::collections::BinaryHeap;
+use std::iter::Iterator;
+
+fn main() {
+ const N: usize = 8;
+
+ for len in 0..N {
+ let mut tester = BinaryHeap::with_capacity(len);
+ assert_eq!(tester.len(), 0);
+ assert!(tester.capacity() >= len);
+ for bit in 0..len {
+ tester.push(());
+ }
+ assert_eq!(tester.len(), len);
+ assert_eq!(tester.iter().count(), len);
+ tester.clear();
+ }
+}
--- /dev/null
+// Copyright 2013 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::cmp::{Ord, Ordering, PartialOrd};
+use std::collections::BTreeMap;
+use std::iter::Iterator;
+
+#[derive(Eq, Hash, Debug, Ord, PartialEq, PartialOrd)]
+struct Zst;
+
+fn main() {
+ const N: usize = 8;
+
+ for len in 0..N {
+ let mut tester = BTreeMap::new();
+ assert_eq!(tester.len(), 0);
+ for bit in 0..len {
+ tester.insert(Zst, ());
+ }
+ assert_eq!(tester.len(), if len == 0 { 0 } else { 1 });
+ assert_eq!(tester.iter().count(), if len == 0 { 0 } else { 1 });
+ assert_eq!(tester.get(&Zst).is_some(), len > 0);
+ tester.clear();
+ }
+}
--- /dev/null
+// Copyright 2013 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::collections::LinkedList;
+use std::iter::Iterator;
+
+fn main() {
+ const N: usize = 8;
+
+ // Test that for all possible sequences of push_front / push_back,
+ // we end up with a LinkedList of the correct size
+
+ for len in 0..N {
+ let mut tester = LinkedList::new();
+ assert_eq!(tester.len(), 0);
+ assert_eq!(tester.front(), None);
+ for case in 0..(1 << len) {
+ assert_eq!(tester.len(), 0);
+ for bit in 0..len {
+ if case & (1 << bit) != 0 {
+ tester.push_front(());
+ } else {
+ tester.push_back(());
+ }
+ }
+ assert_eq!(tester.len(), len);
+ assert_eq!(tester.iter().count(), len);
+ tester.clear();
+ }
+ }
+}
--- /dev/null
+// Copyright 2013 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::iter::Iterator;
+use std::vec::Vec;
+
+fn main() {
+ const N: usize = 8;
+
+ for len in 0..N {
+ let mut tester = Vec::with_capacity(len);
+ assert_eq!(tester.len(), 0);
+ assert!(tester.capacity() >= len);
+ for bit in 0..len {
+ tester.push(());
+ }
+ assert_eq!(tester.len(), len);
+ assert_eq!(tester.iter().count(), len);
+ tester.clear();
+ }
+}