NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
rust_android_dummy.c
NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S
-ifeq ($$(findstring msvc,$(1)),msvc)
-ifeq ($$(findstring i686,$(1)),i686)
-NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_32.ll
-else
-NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_64.ll
-endif
-else
-NATIVE_DEPS_rustrt_native_$(1) += rust_try.ll
-endif
NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c
NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S
RT_OUTPUT_DIR_$(1) := $(1)/rt
-$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.ll $$(MKFILE_DEPS) \
- $$(LLVM_CONFIG_$$(CFG_BUILD))
- @mkdir -p $$(@D)
- @$$(call E, compile: $$@)
- $$(Q)$$(LLC_$$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) \
- -filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) \
- -relocation-model=pic -o $$@ $$<
-
$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS)
@mkdir -p $$(@D)
@$$(call E, compile: $$@)
OBJS_$(2)_$(1) := $$(NATIVE_DEPS_$(2)_$(1):%=$$(RT_OUTPUT_DIR_$(1))/%)
OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.c=.o)
OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.cpp=.o)
-OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.ll=.o)
OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.S=.o)
NATIVE_$(2)_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$(2))
$$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1)): $$(OBJS_$(2)_$(1))
Note that frameworks are only available on OSX targets.
The different `kind` values are meant to differentiate how the native library
-participates in linkage. From a linkage perspective, the rust compiler creates
+participates in linkage. From a linkage perspective, the Rust compiler creates
two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary).
Native dynamic library and framework dependencies are propagated to the final
artifact boundary, while static library dependencies are not propagated at
A few examples of how this model can be used are:
* A native build dependency. Sometimes some C/C++ glue is needed when writing
- some rust code, but distribution of the C/C++ code in a library format is just
+ some Rust code, but distribution of the C/C++ code in a library format is just
a burden. In this case, the code will be archived into `libfoo.a` and then the
- rust crate would declare a dependency via `#[link(name = "foo", kind =
+ Rust crate would declare a dependency via `#[link(name = "foo", kind =
"static")]`.
Regardless of the flavor of output for the crate, the native static library
* A normal dynamic dependency. Common system libraries (like `readline`) are
available on a large number of systems, and often a static copy of these
- libraries cannot be found. When this dependency is included in a rust crate,
+ libraries cannot be found. When this dependency is included in a Rust crate,
partial targets (like rlibs) will not link to the library, but when the rlib
is included in a final target (like a binary), the native library will be
linked in.
The first step to using Rust is to install it! There are a number of ways to
install Rust, but the easiest is to use the `rustup` script. If you're on Linux
-or a Mac, all you need to do is this:
+or a Mac, all you need to do is this:
> Note: you don't need to type in the `$`s, they just indicate the start of
> each command. You’ll see many tutorials and examples around the web that
[insecurity]: http://curlpipesh.tumblr.com
If you're on Windows, please download the appropriate [installer][install-page].
+**NOTE:** By default, the Windows installer will not add Rust to the %PATH%
+system variable. If this is the only version of Rust you are installing and you
+want to be able to run it from the command line, click on "Advanced" on the
+install dialog and on the "Product Features" page ensure "Add to PATH" is
+installed on the local hard drive.
+
[install-page]: http://www.rust-lang.org/install.html
If you did, Rust has been installed successfully! Congrats!
+If you didn't and you're on Windows, check that Rust is in your %PATH% system
+variable. If it isn't, run the installer again, select "Change" on the "Change,
+repair, or remove installation" page and ensure "Add to PATH" is installed on
+the local hard drive.
+
This installer also installs a copy of the documentation locally, so you can
read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location.
On Windows, it's in a `share/doc` directory, inside wherever you installed Rust
[irc]: irc://irc.mozilla.org/#rust
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
-[users]: http://users.rust-lang.org/
+[users]: http://users.rust-lang.org/
[stackoverflow]: http://stackoverflow.com/questions/tagged/rust
Additionally, testing against nightly can catch regressions even sooner, and so
if you don’t mind a third build, we’d appreciate testing against all channels.
+As an example, many Rust programmers use [Travis](https://travis-ci.org/) to
+test their crates, which is free for open source projects. Travis [supports
+Rust directly][travis], and you can use a `.travis.yml` file like this to
+test on all channels:
+
+```yaml
+language: rust
+rust:
+ - nightly
+ - beta
+ - stable
+
+matrix:
+ allow_failures:
+ - rust: nightly
+```
+
+[travis]: http://docs.travis-ci.com/user/languages/rust/
+
+With this configuration, Travis will test all three channels, but if something
+breaks on nightly, it won’t fail your build. A similar configuration is
+recommended for any CI system, check the documentation of the one you’re
+using for more details.
That’s it. It’s important that `unsafe` does not, for example, ‘turn off the
borrow checker’. Adding `unsafe` to some random Rust code doesn’t change its
-semantics, it won’t just start accepting anything.
+semantics, it won’t just start accepting anything. But it will let you write
+things that _do_ break some of the rules.
-But it will let you write things that _do_ break some of the rules. Let’s go
-over these three abilities in order.
+You will also encounter the `unsafe` keyword when writing bindings to foreign
+(non-Rust) interfaces. You're encouraged to write a safe, native Rust interface
+around the methods provided by the library.
+
+Let’s go over the basic three abilities listed, in order.
## Access or update a `static mut`
// allocate.
unsafe { core::intrinsics::abort() }
}
-
-// FIXME(#14344): When linking liballoc with libstd, this library will be linked
-// as an rlib (it only exists as an rlib). It turns out that an
-// optimized standard library doesn't actually use *any* symbols
-// from this library. Everything is inlined and optimized away.
-// This means that linkers will actually omit the object for this
-// file, even though it may be needed in the future.
-//
-// To get around this for now, we define a dummy symbol which
-// will never get inlined so the stdlib can call it. The stdlib's
-// reference to this symbol will cause this library's object file
-// to get linked in to libstd successfully (the linker won't
-// optimize it out).
-#[doc(hidden)]
-#[unstable(feature = "issue_14344_fixme")]
-#[cfg(stage0)]
-pub fn fixme_14344_be_sure_to_link_to_collections() {}
pub use btree::set::*;
}
-
-// FIXME(#14344) this shouldn't be necessary
-#[doc(hidden)]
-#[unstable(feature = "issue_14344_fixme")]
-#[cfg(stage0)]
-pub fn fixme_14344_be_sure_to_link_to_collections() {}
-
#[cfg(not(test))]
mod std {
pub use core::ops; // RangeFull
}
}
-#[cfg(not(stage0))]
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
impl ops::IndexMut<ops::Range<usize>> for String {
#[inline]
&mut self[..][index]
}
}
-#[cfg(not(stage0))]
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
impl ops::IndexMut<ops::RangeTo<usize>> for String {
#[inline]
&mut self[..][index]
}
}
-#[cfg(not(stage0))]
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
impl ops::IndexMut<ops::RangeFrom<usize>> for String {
#[inline]
/// Returns the value of the discriminant for the variant in 'v',
/// cast to a `u64`; if `T` has no discriminant, returns 0.
pub fn discriminant_value<T>(v: &T) -> u64;
+
+ /// Rust's "try catch" construct which invokes the function pointer `f` with
+ /// the data pointer `data`, returning the exception payload if an exception
+ /// is thrown (aka the thread panics).
+ #[cfg(not(stage0))]
+ pub fn try(f: fn(*mut u8), data: *mut u8) -> *mut u8;
}
#[unstable(feature = "iter_unfold")]
#[derive(Clone)]
#[deprecated(since = "1.2.0",
- reason = "has gained enough traction to retain its position \
+ reason = "has not gained enough traction to retain its position \
in the standard library")]
#[allow(deprecated)]
pub struct Unfold<St, F> {
#[unstable(feature = "iter_unfold")]
#[deprecated(since = "1.2.0",
- reason = "has gained enough traction to retain its position \
+ reason = "has not gained enough traction to retain its position \
in the standard library")]
#[allow(deprecated)]
impl<A, St, F> Unfold<St, F> where F: FnMut(&mut St) -> Option<A> {
/// from a given seed value.
#[unstable(feature = "iter_iterate")]
#[deprecated(since = "1.2.0",
- reason = "has gained enough traction to retain its position \
+ reason = "has not gained enough traction to retain its position \
in the standard library")]
#[allow(deprecated)]
pub type Iterate<T, F> = Unfold<IterateState<T, F>, fn(&mut IterateState<T, F>) -> Option<T>>;
/// repeated applications of the given function `f`.
#[unstable(feature = "iter_iterate")]
#[deprecated(since = "1.2.0",
- reason = "has gained enough traction to retain its position \
+ reason = "has not gained enough traction to retain its position \
in the standard library")]
#[allow(deprecated)]
pub fn iterate<T, F>(seed: T, f: F) -> Iterate<T, F> where
}
}
-#[doc(hidden)]
-#[cfg(stage0)]
-pub fn issue_14344_workaround() {} // FIXME #14344 force linkage to happen correctly
-
#[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows
remainder of a zero divisor) in a static or constant expression.
"##,
+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 => ...
+}
+```
+"##,
+
E0079: r##"
Enum variants which contain no data can be given a custom integer
representation. This error indicates that the value provided is not an
use middle::cast::{CastKind};
use middle::const_eval;
+use middle::const_eval::EvalHint::ExprTypeChecked;
use middle::def;
use middle::expr_use_visitor as euv;
use middle::infer;
use syntax::visit::{self, Visitor};
use std::collections::hash_map::Entry;
+use std::cmp::Ordering;
// Const qualification, from partial to completely promotable.
bitflags! {
ast::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.span_bug(
+ start.span, "literals of different types in range pat");
+ }
+ }
}
_ => visit::walk_pat(self, p)
}
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, None) {
+ match const_eval::eval_const_expr_partial(
+ self.tcx, ex, ExprTypeChecked) {
Ok(_) => {}
Err(msg) => {
span_err!(self.tcx.sess, msg.span, E0020,
use middle::const_eval::{compare_const_vals, ConstVal};
use middle::const_eval::{eval_const_expr, eval_const_expr_partial};
use middle::const_eval::{const_expr_to_pat, lookup_const_by_id};
+use middle::const_eval::EvalHint::ExprTypeChecked;
use middle::def::*;
use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Init};
use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode};
fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) {
ast_util::walk_pat(pat, |p| {
if let ast::PatLit(ref expr) = p.node {
- match eval_const_expr_partial(cx.tcx, &**expr, None) {
+ match eval_const_expr_partial(cx.tcx, &**expr, ExprTypeChecked) {
Ok(ConstVal::Float(f)) if f.is_nan() => {
span_warn!(cx.tcx.sess, p.span, E0003,
"unmatchable NaN in pattern, \
#![allow(non_camel_case_types)]
use self::ConstVal::*;
-
use self::ErrKind::*;
+use self::EvalHint::*;
use ast_map;
use ast_map::blocks::FnLikeNode;
Tuple(ast::NodeId),
}
+impl ConstVal {
+ pub fn description(&self) -> &'static str {
+ match *self {
+ Float(_) => "float",
+ Int(i) if i < 0 => "negative integer",
+ Int(_) => "positive integer",
+ Uint(_) => "unsigned integer",
+ Str(_) => "string literal",
+ Binary(_) => "binary array",
+ Bool(_) => "boolean",
+ Struct(_) => "struct",
+ Tuple(_) => "tuple",
+ }
+ }
+}
+
pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat> {
let pat = match expr.node {
ast::ExprTup(ref exprs) =>
}
pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> ConstVal {
- match eval_const_expr_partial(tcx, e, None) {
+ match eval_const_expr_partial(tcx, e, ExprTypeChecked) {
Ok(r) => r,
Err(s) => tcx.sess.span_fatal(s.span, &s.description())
}
InvalidOpForFloats(ast::BinOp_),
InvalidOpForIntUint(ast::BinOp_),
InvalidOpForUintInt(ast::BinOp_),
- NegateOnString,
- NegateOnBoolean,
- NegateOnBinary,
- NegateOnStruct,
- NegateOnTuple,
- NotOnFloat,
- NotOnString,
- NotOnBinary,
- NotOnStruct,
- NotOnTuple,
+ NegateOn(ConstVal),
+ NotOn(ConstVal),
NegateWithOverflow(i64),
AddiWithOverflow(i64, i64),
InvalidOpForFloats(_) => "can't do this op on floats".into_cow(),
InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(),
InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(),
- NegateOnString => "negate on string".into_cow(),
- NegateOnBoolean => "negate on boolean".into_cow(),
- NegateOnBinary => "negate on binary literal".into_cow(),
- NegateOnStruct => "negate on struct".into_cow(),
- NegateOnTuple => "negate on tuple".into_cow(),
- NotOnFloat => "not on float or string".into_cow(),
- NotOnString => "not on float or string".into_cow(),
- NotOnBinary => "not on binary literal".into_cow(),
- NotOnStruct => "not on struct".into_cow(),
- NotOnTuple => "not on tuple".into_cow(),
+ NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(),
+ NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(),
NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(),
AddiWithOverflow(..) => "attempted to add with overflow".into_cow(),
pub type EvalResult = Result<ConstVal, ConstEvalErr>;
pub type CastResult = Result<ConstVal, ErrKind>;
+// FIXME: Long-term, this enum should go away: trying to evaluate
+// an expression which hasn't been type-checked is a recipe for
+// disaster. That said, it's not clear how to fix ast_ty_to_ty
+// to avoid the ordering issue.
+
+/// Hint to determine how to evaluate constant expressions which
+/// might not be type-checked.
+#[derive(Copy, Clone, Debug)]
+pub enum EvalHint<'tcx> {
+ /// We have a type-checked expression.
+ ExprTypeChecked,
+ /// We have an expression which hasn't been type-checked, but we have
+ /// an idea of what the type will be because of the context. For example,
+ /// the length of an array is always `usize`. (This is referred to as
+ /// a hint because it isn't guaranteed to be consistent with what
+ /// type-checking would compute.)
+ UncheckedExprHint(Ty<'tcx>),
+ /// We have an expression which has not yet been type-checked, and
+ /// and we have no clue what the type will be.
+ UncheckedExprNoHint,
+}
+
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum IntTy { I8, I16, I32, I64 }
#[derive(Copy, Clone, PartialEq, Debug)]
uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
}}
-// After type checking, `eval_const_expr_partial` should always suffice. The
-// reason for providing `eval_const_expr_with_substs` is to allow
-// trait-associated consts to be evaluated *during* type checking, when the
-// substs for each expression have not been written into `tcx` yet.
+/// Evaluate a constant expression in a context where the expression isn't
+/// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
+/// but a few places need to evaluate constants during type-checking, like
+/// computing the length of an array. (See also the FIXME above EvalHint.)
pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
e: &Expr,
- ty_hint: Option<Ty<'tcx>>) -> EvalResult {
- eval_const_expr_with_substs(tcx, e, ty_hint, |id| {
- tcx.node_id_item_substs(id).substs
- })
-}
-
-pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
- e: &Expr,
- ty_hint: Option<Ty<'tcx>>,
- get_substs: S) -> EvalResult
- where S: Fn(ast::NodeId) -> subst::Substs<'tcx> {
+ ty_hint: EvalHint<'tcx>) -> EvalResult {
fn fromb(b: bool) -> ConstVal { Int(b as i64) }
- let ety = ty_hint.or_else(|| tcx.expr_ty_opt(e));
+ // Try to compute the type of the expression based on the EvalHint.
+ // (See also the definition of EvalHint, and the FIXME above EvalHint.)
+ let ety = match ty_hint {
+ ExprTypeChecked => {
+ // After type-checking, expr_ty is guaranteed to succeed.
+ Some(tcx.expr_ty(e))
+ }
+ UncheckedExprHint(ty) => {
+ // Use the type hint; it's not guaranteed to be right, but it's
+ // usually good enough.
+ Some(ty)
+ }
+ UncheckedExprNoHint => {
+ // This expression might not be type-checked, and we have no hint.
+ // Try to query the context for a type anyway; we might get lucky
+ // (for example, if the expression was imported from another crate).
+ tcx.expr_ty_opt(e)
+ }
+ };
// If type of expression itself is int or uint, normalize in these
// bindings so that isize/usize is mapped to a type with an
let result = match e.node {
ast::ExprUnary(ast::UnNeg, ref inner) => {
- match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
+ match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) {
Float(f) => Float(-f),
Int(n) => try!(const_int_checked_neg(n, e, expr_int_type)),
Uint(i) => {
try!(const_uint_checked_neg(i, e, expr_uint_type))
}
- Str(_) => signal!(e, NegateOnString),
- Bool(_) => signal!(e, NegateOnBoolean),
- Binary(_) => signal!(e, NegateOnBinary),
- Tuple(_) => signal!(e, NegateOnTuple),
- Struct(..) => signal!(e, NegateOnStruct),
+ const_val => signal!(e, NegateOn(const_val)),
}
}
ast::ExprUnary(ast::UnNot, ref inner) => {
- match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
+ match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) {
Int(i) => Int(!i),
Uint(i) => const_uint_not(i, expr_uint_type),
Bool(b) => Bool(!b),
- Str(_) => signal!(e, NotOnString),
- Float(_) => signal!(e, NotOnFloat),
- Binary(_) => signal!(e, NotOnBinary),
- Tuple(_) => signal!(e, NotOnTuple),
- Struct(..) => signal!(e, NotOnStruct),
+ const_val => signal!(e, NotOn(const_val)),
}
}
ast::ExprBinary(op, ref a, ref b) => {
let b_ty = match op.node {
- ast::BiShl | ast::BiShr => Some(tcx.types.usize),
- _ => ety
+ ast::BiShl | ast::BiShr => {
+ if let ExprTypeChecked = ty_hint {
+ ExprTypeChecked
+ } else {
+ UncheckedExprHint(tcx.types.usize)
+ }
+ }
+ _ => ty_hint
};
- match (try!(eval_const_expr_partial(tcx, &**a, ety)),
+ match (try!(eval_const_expr_partial(tcx, &**a, ty_hint)),
try!(eval_const_expr_partial(tcx, &**b, b_ty))) {
(Float(a), Float(b)) => {
match op.node {
}
}
ast::ExprCast(ref base, ref target_ty) => {
- // This tends to get called w/o the type actually having been
- // populated in the ctxt, which was causing things to blow up
- // (#5900). Fall back to doing a limited lookup to get past it.
let ety = ety.or_else(|| ast_ty_to_prim_ty(tcx, &**target_ty))
.unwrap_or_else(|| {
tcx.sess.span_fatal(target_ty.span,
"target type not found for const cast")
});
- // Prefer known type to noop, but always have a type hint.
- //
- // FIXME (#23833): the type-hint can cause problems,
- // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
- // type to the sum, and thus no overflow is signaled.
- let base_hint = tcx.expr_ty_opt(&**base).unwrap_or(ety);
- let val = try!(eval_const_expr_partial(tcx, &**base, Some(base_hint)));
+ let base_hint = if let ExprTypeChecked = ty_hint {
+ ExprTypeChecked
+ } else {
+ // FIXME (#23833): the type-hint can cause problems,
+ // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
+ // type to the sum, and thus no overflow is signaled.
+ match tcx.expr_ty_opt(&base) {
+ Some(t) => UncheckedExprHint(t),
+ None => ty_hint
+ }
+ };
+
+ let val = try!(eval_const_expr_partial(tcx, &**base, base_hint));
match cast_const(tcx, val, ety) {
Ok(val) => val,
Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
def::FromTrait(trait_id) => match tcx.map.find(def_id.node) {
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
ast::ConstTraitItem(ref ty, _) => {
- let substs = get_substs(e.id);
- (resolve_trait_associated_const(tcx,
- ti,
- trait_id,
- substs),
- Some(&**ty))
+ if let ExprTypeChecked = ty_hint {
+ let substs = tcx.node_id_item_substs(e.id).substs;
+ (resolve_trait_associated_const(tcx,
+ ti,
+ trait_id,
+ substs),
+ Some(&**ty))
+ } else {
+ (None, None)
+ }
}
_ => (None, None)
},
Some(actual_e) => actual_e,
None => signal!(e, NonConstPath)
};
- let ety = ety.or_else(|| const_ty.and_then(|ty| ast_ty_to_prim_ty(tcx, ty)));
- try!(eval_const_expr_partial(tcx, const_expr, ety))
+ let item_hint = if let UncheckedExprNoHint = ty_hint {
+ match const_ty {
+ Some(ty) => match ast_ty_to_prim_ty(tcx, ty) {
+ Some(ty) => UncheckedExprHint(ty),
+ None => UncheckedExprNoHint
+ },
+ None => UncheckedExprNoHint
+ }
+ } else {
+ ty_hint
+ };
+ try!(eval_const_expr_partial(tcx, const_expr, item_hint))
}
ast::ExprLit(ref lit) => {
lit_to_const(&**lit, ety)
}
- ast::ExprParen(ref e) => try!(eval_const_expr_partial(tcx, &**e, ety)),
+ ast::ExprParen(ref e) => try!(eval_const_expr_partial(tcx, &**e, ty_hint)),
ast::ExprBlock(ref block) => {
match block.expr {
- Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ety)),
+ Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint)),
None => Int(0)
}
}
ast::ExprTup(_) => Tuple(e.id),
ast::ExprStruct(..) => Struct(e.id),
ast::ExprTupField(ref base, index) => {
- if let Ok(c) = eval_const_expr_partial(tcx, base, None) {
+ let base_hint = if let ExprTypeChecked = ty_hint {
+ ExprTypeChecked
+ } else {
+ UncheckedExprNoHint
+ };
+ if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) {
if let Tuple(tup_id) = c {
if let ast::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
if index.node < fields.len() {
- return eval_const_expr_partial(tcx, &fields[index.node], None)
+ return eval_const_expr_partial(tcx, &fields[index.node], base_hint)
} else {
signal!(e, TupleIndexOutOfBounds);
}
}
ast::ExprField(ref base, field_name) => {
// Get the base expression if it is a struct and it is constant
- if let Ok(c) = eval_const_expr_partial(tcx, base, None) {
+ let base_hint = if let ExprTypeChecked = ty_hint {
+ ExprTypeChecked
+ } else {
+ UncheckedExprNoHint
+ };
+ if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) {
if let Struct(struct_id) = c {
if let ast::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node {
// Check that the given field exists and evaluate it
if let Some(f) = fields.iter().find(|f| f.ident.node.as_str()
== field_name.node.as_str()) {
- return eval_const_expr_partial(tcx, &*f.expr, None)
+ return eval_const_expr_partial(tcx, &*f.expr, base_hint)
} else {
signal!(e, MissingStructField);
}
})
}
-pub fn compare_lit_exprs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
- a: &Expr,
- b: &Expr,
- ty_hint: Option<Ty<'tcx>>,
- get_substs: S) -> Option<Ordering>
- where S: Fn(ast::NodeId) -> subst::Substs<'tcx> {
- let a = match eval_const_expr_with_substs(tcx, a, ty_hint,
- |id| {get_substs(id)}) {
+pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
+ a: &Expr,
+ b: &Expr) -> Option<Ordering> {
+ let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked) {
Ok(a) => a,
Err(e) => {
tcx.sess.span_err(a.span, &e.description());
return None;
}
};
- let b = match eval_const_expr_with_substs(tcx, b, ty_hint, get_substs) {
+ let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked) {
Ok(b) => b,
Err(e) => {
tcx.sess.span_err(b.span, &e.description());
if from_tc.interior_param() || to_tc.interior_param() {
span_err!(self.tcx.sess, span, E0139,
"cannot transmute to or from a type that contains \
- type parameters in its interior");
+ unsubstituted type parameters");
return;
}
StartFnLangItem, "start", start_fn;
EhPersonalityLangItem, "eh_personality", eh_personality;
+ EhPersonalityCatchLangItem, "eh_personality_catch", eh_personality_catch;
+ MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter;
ExchangeHeapLangItem, "exchange_heap", exchange_heap;
OwnedBoxLangItem, "owned_box", owned_box;
impl<'v, 'a> Visitor<'v> for GatherLabels<'a> {
fn visit_expr(&mut self, ex: &'v ast::Expr) {
+ // do not recurse into closures defined in the block
+ // since they are treated as separate fns from the POV of
+ // labels_in_fn
+ if let ast::ExprClosure(..) = ex.node {
+ return
+ }
if let Some(label) = expression_label(ex) {
for &(prior, prior_span) in &self.labels_in_fn[..] {
// FIXME (#24278): non-hygienic comparison
use middle::cast;
use middle::check_const;
use middle::const_eval::{self, ConstVal};
+use middle::const_eval::EvalHint::UncheckedExprHint;
use middle::def::{self, DefMap, ExportMap};
use middle::dependency_format;
use middle::fast_reject;
Some(ref e) => {
debug!("disr expr, checking {}", pprust::expr_to_string(&**e));
- // check_expr (from check_const pass) doesn't guarantee
- // that the expression is in a form that eval_const_expr can
- // handle, so we may still get an internal compiler error
- //
- // pnkfelix: The above comment was transcribed from
- // the version of this code taken from rustc_typeck.
- // Presumably the implication is that we need to deal
- // with such ICE's as they arise.
- //
- // Since this can be called from `ty::enum_variants`
- // anyway, best thing is to make `eval_const_expr`
- // more robust (on case-by-case basis).
-
- match const_eval::eval_const_expr_partial(self, &**e, Some(repr_type_ty)) {
+ let hint = UncheckedExprHint(repr_type_ty);
+ match const_eval::eval_const_expr_partial(self, &**e, hint) {
Ok(ConstVal::Int(val)) => current_disr_val = val as Disr,
Ok(ConstVal::Uint(val)) => current_disr_val = val as Disr,
Ok(_) => {
// Returns the repeat count for a repeating vector expression.
pub fn eval_repeat_count(&self, count_expr: &ast::Expr) -> usize {
- match const_eval::eval_const_expr_partial(self, count_expr, Some(self.types.usize)) {
+ let hint = UncheckedExprHint(self.types.usize);
+ match const_eval::eval_const_expr_partial(self, count_expr, hint) {
Ok(val) => {
let found = match val {
ConstVal::Uint(count) => return count as usize,
ConstVal::Int(count) if count >= 0 => return count as usize,
- ConstVal::Int(_) => "negative integer",
- ConstVal::Float(_) => "float",
- ConstVal::Str(_) => "string",
- ConstVal::Bool(_) => "boolean",
- ConstVal::Binary(_) => "binary array",
- ConstVal::Struct(..) => "struct",
- ConstVal::Tuple(_) => "tuple"
+ const_val => const_val.description(),
};
span_err!(self.sess, count_expr.span, E0306,
"expected positive integer for repeat count, found {}",
) }
weak_lang_items! {
- panic_fmt, PanicFmtLangItem, rust_begin_unwind;
+ panic_fmt, PanicFmtLangItem, rust_begin_unwind;
stack_exhausted, StackExhaustedLangItem, rust_stack_exhausted;
eh_personality, EhPersonalityLangItem, rust_eh_personality;
}
use middle::traits;
use middle::{def, pat_util, stability};
use middle::const_eval::{eval_const_expr_partial, ConstVal};
+use middle::const_eval::EvalHint::ExprTypeChecked;
use middle::cfg;
use rustc::ast_map;
use util::nodemap::{FnvHashMap, NodeSet};
if let ast::LitInt(shift, _) = lit.node { shift >= bits }
else { false }
} else {
- match eval_const_expr_partial(cx.tcx, &**r, Some(cx.tcx.types.usize)) {
+ match eval_const_expr_partial(cx.tcx, &**r, ExprTypeChecked) {
Ok(ConstVal::Int(shift)) => { shift as u64 >= bits },
Ok(ConstVal::Uint(shift)) => { shift >= bits },
_ => { false }
}
bitflags! {
- flags Attribute : u32 {
+ flags Attribute : u64 {
const ZExt = 1 << 0,
const SExt = 1 << 1,
const NoReturn = 1 << 2,
const ReturnsTwice = 1 << 29,
const UWTable = 1 << 30,
const NonLazyBind = 1 << 31,
+ const OptimizeNone = 1 << 42,
}
}
pub fn SetFunctionAttribute(fn_: ValueRef, attr: Attribute) {
unsafe {
- LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint, attr.bits() as uint64_t)
+ LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint,
+ attr.bits() as uint64_t)
}
}
use foo::MyTrait::do_something;
```
-In general, it's not legal to directly import methods belonging to a
-trait or concrete type.
+It's illegal to directly import methods belonging to a trait or concrete type.
"##,
E0255: r##"
on this topic:
http://doc.rust-lang.org/reference.html#use-declarations
-"##
+"##,
+
+E0403: r##"
+Some type parameters have the same name. Example of erroneous code:
+
+```
+fn foo<T, T>(s: T, u: T) {} // error: the name `T` is already used for a type
+ // parameter in this type parameter list
+```
+
+Please verify that none of the type parameterss are misspelled, and rename any
+clashing parameters. Example:
+
+```
+fn foo<T, Y>(s: T, u: Y) {} // ok!
+```
+"##,
+
+E0404: r##"
+You tried to implement something which was not a trait on an object. Example of
+erroneous code:
+
+```
+struct Foo;
+struct Bar;
+
+impl Foo for Bar {} // error: `Foo` is not a trait
+```
+
+Please verify that you didn't misspell the trait's name or otherwise use the
+wrong identifier. Example:
+
+```
+trait Foo {
+ // some functions
+}
+struct Bar;
+
+impl Foo for Bar { // ok!
+ // functions implementation
+}
+```
+"##,
+
+E0405: r##"
+An unknown trait was implemented. Example of erroneous code:
+
+```
+struct Foo;
+
+impl SomeTrait for Foo {} // error: use of undeclared trait name `SomeTrait`
+```
+
+Please verify that the name of the trait wasn't misspelled and ensure that it
+was imported. Example:
+
+```
+// solution 1:
+use some_file::SomeTrait;
+
+// solution 2:
+trait SomeTrait {
+ // some functions
+}
+
+struct Foo;
+
+impl SomeTrait for Foo { // ok!
+ // implements functions
+}
+```
+"##,
+
+E0407: r##"
+A definition of a method not in the implemented trait was given in a trait
+implementation. Example of erroneous code:
+
+```
+trait Foo {
+ fn a();
+}
+
+struct Bar;
+
+impl Foo for Bar {
+ fn a() {}
+ fn b() {} // error: method `b` is not a member of trait `Foo`
+}
+```
+
+Please verify you didn't misspell the method name and you used the correct
+trait. First example:
+
+```
+trait Foo {
+ fn a();
+ fn b();
+}
+
+struct Bar;
+
+impl Foo for Bar {
+ fn a() {}
+ fn b() {} // ok!
+}
+```
+
+Second example:
+
+```
+trait Foo {
+ fn a();
+}
+
+struct Bar;
+
+impl Foo for Bar {
+ fn a() {}
+}
+
+impl Bar {
+ fn b() {}
+}
+```
+"##,
+
+E0428: r##"
+A type or module has been defined more than once. Example of erroneous
+code:
+
+```
+struct Bar;
+struct Bar; // error: duplicate definition of value `Bar`
+```
+
+Please verify you didn't misspell the type/module's name or remove/rename the
+duplicated one. Example:
+
+```
+struct Bar;
+struct Bar2; // ok!
+```
+"##,
+
+E0433: r##"
+Invalid import. Example of erroneous code:
+
+```
+use something_which_doesnt_exist;
+// error: unresolved import `something_which_doesnt_exist`
+```
+
+Please verify you didn't misspell the import's name.
+"##,
}
E0258,
E0401, // can't use type parameters from outer function
E0402, // cannot use an outer type parameter in this context
- E0403, // the name `{}` is already used
- E0404, // is not a trait
- E0405, // use of undeclared trait name
E0406, // undeclared associated type
- E0407, // method is not a member of trait
E0408, // variable from pattern #1 is not bound in pattern #
E0409, // variable is bound with different mode in pattern # than in
// pattern #1
E0425, // unresolved name
E0426, // use of undeclared label
E0427, // cannot use `ref` binding mode with ...
- E0428, // duplicate definition of ...
E0429, // `self` imports are only allowed within a { } list
E0430, // `self` import can only appear once in the list
E0431, // `self` import can only appear in an import list with a non-empty
// prefix
E0432, // unresolved import
- E0433, // failed to resolve
E0434, // can't capture dynamic environment in a fn item
E0435, // attempt to use a non-constant value in a constant
E0437, // type is not a member of trait
let ctor_id = match def.ctor_id {
Some(node_id) => node_id,
- None => -1,
+ None => ast::DUMMY_NODE_ID,
};
let val = self.span.snippet(item.span);
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
ast::StructVariantKind(ref struct_def) => {
let ctor_id = match struct_def.ctor_id {
Some(node_id) => node_id,
- None => -1,
+ None => ast::DUMMY_NODE_ID,
};
self.fmt.struct_variant_str(variant.span,
self.span.span_for_first_ident(variant.span),
impl<'a> ConstantExpr<'a> {
fn eq(self, other: ConstantExpr<'a>, tcx: &ty::ctxt) -> bool {
- match const_eval::compare_lit_exprs(tcx, self.0, other.0, None,
- |id| {tcx.node_id_item_substs(id).substs}) {
+ match const_eval::compare_lit_exprs(tcx, self.0, other.0) {
Some(result) => result == Ordering::Equal,
None => panic!("compare_list_exprs: type mismatch"),
}
B(cx).landing_pad(ty, pers_fn, num_clauses, cx.fcx.llfn)
}
+pub fn AddClause(cx: Block, landing_pad: ValueRef, clause: ValueRef) {
+ B(cx).add_clause(landing_pad, clause)
+}
+
pub fn SetCleanup(cx: Block, landing_pad: ValueRef) {
B(cx).set_cleanup(landing_pad)
}
}
}
+ pub fn add_clause(&self, landing_pad: ValueRef, clause: ValueRef) {
+ unsafe {
+ llvm::LLVMAddClause(landing_pad, clause);
+ }
+ }
+
pub fn set_cleanup(&self, landing_pad: ValueRef) {
self.count_insn("setcleanup");
unsafe {
}, ArgVals(args), dest)
}
-/// This behemoth of a function translates function calls. Unfortunately, in order to generate more
-/// efficient LLVM output at -O0, it has quite a complex signature (refactoring this into two
-/// functions seems like a good idea).
+/// This behemoth of a function translates function calls. Unfortunately, in
+/// order to generate more efficient LLVM output at -O0, it has quite a complex
+/// signature (refactoring this into two functions seems like a good idea).
///
-/// In particular, for lang items, it is invoked with a dest of None, and in that case the return
-/// value contains the result of the fn. The lang item must not return a structural type or else
-/// all heck breaks loose.
+/// In particular, for lang items, it is invoked with a dest of None, and in
+/// that case the return value contains the result of the fn. The lang item must
+/// not return a structural type or else all heck breaks loose.
///
-/// For non-lang items, `dest` is always Some, and hence the result is written into memory
-/// somewhere. Nonetheless we return the actual return value of the function.
+/// For non-lang items, `dest` is always Some, and hence the result is written
+/// into memory somewhere. Nonetheless we return the actual return value of the
+/// function.
pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
debug_loc: DebugLoc,
get_callee: F,
use llvm::{BasicBlockRef, ValueRef};
use trans::base;
use trans::build;
-use trans::callee;
use trans::common;
-use trans::common::{Block, FunctionContext, ExprId, NodeIdAndSpan};
+use trans::common::{Block, FunctionContext, NodeIdAndSpan};
use trans::debuginfo::{DebugLoc, ToDebugLoc};
-use trans::declare;
use trans::glue;
use middle::region;
use trans::type_::Type;
&[Type::i8p(self.ccx), Type::i32(self.ccx)],
false);
- // The exception handling personality function.
- //
- // If our compilation unit has the `eh_personality` lang item somewhere
- // within it, then we just need to translate that. Otherwise, we're
- // building an rlib which will depend on some upstream implementation of
- // this function, so we just codegen a generic reference to it. We don't
- // specify any of the types for the function, we just make it a symbol
- // that LLVM can later use.
- //
- // Note that MSVC is a little special here in that we don't use the
- // `eh_personality` lang item at all. Currently LLVM has support for
- // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
- // *name of the personality function* to decide what kind of unwind side
- // tables/landing pads to emit. It looks like Dwarf is used by default,
- // injecting a dependency on the `_Unwind_Resume` symbol for resuming
- // an "exception", but for MSVC we want to force SEH. This means that we
- // can't actually have the personality function be our standard
- // `rust_eh_personality` function, but rather we wired it up to the
- // CRT's custom personality function, which forces LLVM to consider
- // landing pads as "landing pads for SEH".
- let target = &self.ccx.sess().target.target;
- let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() {
- Some(def_id) if !target.options.is_like_msvc => {
- callee::trans_fn_ref(pad_bcx.ccx(), def_id, ExprId(0),
- pad_bcx.fcx.param_substs).val
- }
- _ => {
- let mut personality = self.ccx.eh_personality().borrow_mut();
- match *personality {
- Some(llpersonality) => llpersonality,
- None => {
- let name = if !target.options.is_like_msvc {
- "rust_eh_personality"
- } else if target.arch == "x86" {
- "_except_handler3"
- } else {
- "__C_specific_handler"
- };
- let fty = Type::variadic_func(&[], &Type::i32(self.ccx));
- let f = declare::declare_cfn(self.ccx, name, fty,
- self.ccx.tcx().types.i32);
- *personality = Some(f);
- f
- }
- }
- }
- };
+ let llpersonality = pad_bcx.fcx.eh_personality();
// The only landing pad clause will be 'cleanup'
let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1);
mangle_internal_name_by_path_and_seq(path, "closure")
});
- // Currently there’s only a single user of get_or_create_declaration_if_closure and it
- // unconditionally defines the function, therefore we use define_* here.
- let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type).unwrap_or_else(||{
- ccx.sess().bug(&format!("symbol `{}` already defined", symbol));
- });
+ // Currently there’s only a single user of
+ // get_or_create_declaration_if_closure and it unconditionally defines the
+ // function, therefore we use define_* here.
+ let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type);
// set an inline hint for all closures
attributes::inline(llfn, attributes::InlineAttr::Hint);
// Create the by-value helper.
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim");
- let lloncefn = declare::define_internal_rust_fn(ccx, &function_name[..], llonce_fn_ty)
- .unwrap_or_else(||{
- ccx.sess().bug(&format!("symbol `{}` already defined", function_name));
- });
-
+ let lloncefn = declare::define_internal_rust_fn(ccx, &function_name,
+ llonce_fn_ty);
let sig = tcx.erase_late_bound_regions(&llonce_bare_fn_ty.sig);
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
block_arena = TypedArena::new();
use middle::subst::{self, Substs};
use trans::base;
use trans::build;
+use trans::callee;
use trans::cleanup;
use trans::consts;
use trans::datum;
pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
type_needs_drop_given_env(self.ccx.tcx(), ty, &self.param_env)
}
+
+ pub fn eh_personality(&self) -> ValueRef {
+ // The exception handling personality function.
+ //
+ // If our compilation unit has the `eh_personality` lang item somewhere
+ // within it, then we just need to translate that. Otherwise, we're
+ // building an rlib which will depend on some upstream implementation of
+ // this function, so we just codegen a generic reference to it. We don't
+ // specify any of the types for the function, we just make it a symbol
+ // that LLVM can later use.
+ //
+ // Note that MSVC is a little special here in that we don't use the
+ // `eh_personality` lang item at all. Currently LLVM has support for
+ // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
+ // *name of the personality function* to decide what kind of unwind side
+ // tables/landing pads to emit. It looks like Dwarf is used by default,
+ // injecting a dependency on the `_Unwind_Resume` symbol for resuming
+ // an "exception", but for MSVC we want to force SEH. This means that we
+ // can't actually have the personality function be our standard
+ // `rust_eh_personality` function, but rather we wired it up to the
+ // CRT's custom personality function, which forces LLVM to consider
+ // landing pads as "landing pads for SEH".
+ let target = &self.ccx.sess().target.target;
+ match self.ccx.tcx().lang_items.eh_personality() {
+ Some(def_id) if !target.options.is_like_msvc => {
+ callee::trans_fn_ref(self.ccx, def_id, ExprId(0),
+ self.param_substs).val
+ }
+ _ => {
+ let mut personality = self.ccx.eh_personality().borrow_mut();
+ match *personality {
+ Some(llpersonality) => llpersonality,
+ None => {
+ let name = if !target.options.is_like_msvc {
+ "rust_eh_personality"
+ } else if target.arch == "x86" {
+ "_except_handler3"
+ } else {
+ "__C_specific_handler"
+ };
+ let fty = Type::variadic_func(&[], &Type::i32(self.ccx));
+ let f = declare::declare_cfn(self.ccx, name, fty,
+ self.ccx.tcx().types.i32);
+ *personality = Some(f);
+ f
+ }
+ }
+ }
+ }
+ }
}
// Basic block context. We create a block context for each basic block
use middle::const_eval::{const_int_checked_rem, const_uint_checked_rem};
use middle::const_eval::{const_int_checked_shl, const_uint_checked_shl};
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 trans::{adt, closure, debuginfo, expr, inline, machine};
use trans::base::{self, push_ctxt};
use trans::common::*;
ast::ExprIndex(ref base, ref index) => {
let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
- let iv = match const_eval::eval_const_expr_partial(cx.tcx(), &**index, None) {
+ let iv = match eval_const_expr_partial(cx.tcx(), &index, ExprTypeChecked) {
Ok(ConstVal::Int(i)) => i as u64,
Ok(ConstVal::Uint(u)) => u,
_ => cx.sess().span_bug(index.span,
dbg_cx: Option<debuginfo::CrateDebugContext<'tcx>>,
eh_personality: RefCell<Option<ValueRef>>,
+ rust_try_fn: RefCell<Option<ValueRef>>,
intrinsics: RefCell<FnvHashMap<&'static str, ValueRef>>,
closure_vals: RefCell::new(FnvHashMap()),
dbg_cx: dbg_cx,
eh_personality: RefCell::new(None),
+ rust_try_fn: RefCell::new(None),
intrinsics: RefCell::new(FnvHashMap()),
n_llvm_insns: Cell::new(0),
trait_cache: RefCell::new(FnvHashMap()),
&self.local.eh_personality
}
+ pub fn rust_try_fn<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> {
+ &self.local.rust_try_fn
+ }
+
fn intrinsics<'a>(&'a self) -> &'a RefCell<FnvHashMap<&'static str, ValueRef>> {
&self.local.intrinsics
}
ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void);
ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
+ ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32);
// Some intrinsics were introduced in later versions of LLVM, but they have
// fallbacks in libc or libm and such.
/// return None if the name already has a definition associated with it. In that
/// case an error should be reported to the user, because it usually happens due
/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
-pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, fn_type: Type,
- output: ty::FnOutput) -> Option<ValueRef> {
+pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv,
+ fn_type: Type, output: ty::FnOutput) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
/// Declare a Rust function with an intention to define it.
///
/// Use this function when you intend to define a function. This function will
-/// return None if the name already has a definition associated with it. In that
-/// case an error should be reported to the user, because it usually happens due
-/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
-pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
- fn_type: ty::Ty<'tcx>) -> Option<ValueRef> {
+/// return panic if the name already has a definition associated with it. This
+/// can happen with #[no_mangle] or #[export_name], for example.
+pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ name: &str,
+ fn_type: ty::Ty<'tcx>) -> ValueRef {
if get_defined_value(ccx, name).is_some() {
- None
+ ccx.sess().fatal(&format!("symbol `{}` already defined", name))
} else {
- Some(declare_internal_rust_fn(ccx, name, fn_type))
+ declare_internal_rust_fn(ccx, name, fn_type)
}
}
-/// Get defined or externally defined (AvailableExternally linkage) value by name.
+/// Get defined or externally defined (AvailableExternally linkage) value by
+/// name.
fn get_defined_value(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
debug!("get_defined_value(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
ccx.tcx().map.path_to_string(id),
id, t);
- let llfn = declare::define_internal_rust_fn(ccx, &ps[..], t).unwrap_or_else(||{
- ccx.sess().bug(&format!("symbol `{}` already defined", ps));
- });
+ let llfn = declare::define_internal_rust_fn(ccx, &ps, t);
attributes::from_fn_attrs(ccx, attrs, llfn);
base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]);
llfn
#![allow(non_upper_case_globals)]
+use arena::TypedArena;
use llvm;
use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind};
use middle::subst;
use trans::common::*;
use trans::datum::*;
use trans::debuginfo::DebugLoc;
+use trans::declare;
use trans::expr;
use trans::glue;
use trans::type_of::*;
use trans::machine::llsize_of;
use trans::type_::Type;
use middle::ty::{self, Ty, HasTypeFlags};
-use syntax::abi::RustIntrinsic;
+use middle::subst::Substs;
+use syntax::abi::{self, RustIntrinsic};
use syntax::ast;
use syntax::parse::token;
}
}
+ let call_debug_location = DebugLoc::At(call_info.id, call_info.span);
+
+ // For `try` we need some custom control flow
+ if &name[..] == "try" {
+ if let callee::ArgExprs(ref exprs) = args {
+ let (func, data) = if exprs.len() != 2 {
+ ccx.sess().bug("expected two exprs as arguments for \
+ `try` intrinsic");
+ } else {
+ (&exprs[0], &exprs[1])
+ };
+
+ // translate arguments
+ let func = unpack_datum!(bcx, expr::trans(bcx, func));
+ let func = unpack_datum!(bcx, func.to_rvalue_datum(bcx, "func"));
+ let data = unpack_datum!(bcx, expr::trans(bcx, data));
+ let data = unpack_datum!(bcx, data.to_rvalue_datum(bcx, "data"));
+
+ let dest = match dest {
+ expr::SaveIn(d) => d,
+ expr::Ignore => alloc_ty(bcx, tcx.mk_mut_ptr(tcx.types.i8),
+ "try_result"),
+ };
+
+ // do the invoke
+ bcx = try_intrinsic(bcx, func.val, data.val, dest,
+ call_debug_location);
+
+ fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
+ return Result::new(bcx, dest);
+ } else {
+ ccx.sess().bug("expected two exprs as arguments for \
+ `try` intrinsic");
+ }
+ }
+
// Push the arguments.
let mut llargs = Vec::new();
bcx = callee::trans_args(bcx,
fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
- let call_debug_location = DebugLoc::At(call_info.id, call_info.span);
-
// These are the only intrinsic functions that diverge.
if &name[..] == "abort" {
let llfn = ccx.get_intrinsic(&("llvm.trap"));
ret
}
}
+
+fn try_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ func: ValueRef,
+ data: ValueRef,
+ dest: ValueRef,
+ dloc: DebugLoc) -> Block<'blk, 'tcx> {
+ if bcx.sess().no_landing_pads() {
+ Call(bcx, func, &[data], None, dloc);
+ Store(bcx, C_null(Type::i8p(bcx.ccx())), dest);
+ bcx
+ } else if bcx.sess().target.target.options.is_like_msvc {
+ trans_msvc_try(bcx, func, data, dest, dloc)
+ } else {
+ trans_gnu_try(bcx, func, data, dest, dloc)
+ }
+}
+
+// MSVC's definition of the `rust_try` function. The exact implementation here
+// is a little different than the GNU (standard) version below, not only because
+// of the personality function but also because of the other fiddly bits about
+// SEH. LLVM also currently requires us to structure this a very particular way
+// as explained below.
+//
+// Like with the GNU version we generate a shim wrapper
+fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ func: ValueRef,
+ data: ValueRef,
+ dest: ValueRef,
+ dloc: DebugLoc) -> Block<'blk, 'tcx> {
+ let llfn = get_rust_try_fn(bcx.fcx, &mut |try_fn_ty, output| {
+ let ccx = bcx.ccx();
+ let dloc = DebugLoc::None;
+ let rust_try = declare::define_internal_rust_fn(ccx, "__rust_try",
+ try_fn_ty);
+ let (fcx, block_arena);
+ block_arena = TypedArena::new();
+ fcx = new_fn_ctxt(ccx, rust_try, ast::DUMMY_NODE_ID, false,
+ output, ccx.tcx().mk_substs(Substs::trans_empty()),
+ None, &block_arena);
+ let bcx = init_function(&fcx, true, output);
+ let then = fcx.new_temp_block("then");
+ let catch = fcx.new_temp_block("catch");
+ let catch_return = fcx.new_temp_block("catch-return");
+ let catch_resume = fcx.new_temp_block("catch-resume");
+ let personality = fcx.eh_personality();
+
+ let eh_typeid_for = ccx.get_intrinsic(&"llvm.eh.typeid.for");
+ let rust_try_filter = match bcx.tcx().lang_items.msvc_try_filter() {
+ Some(did) => callee::trans_fn_ref(ccx, did, ExprId(0),
+ bcx.fcx.param_substs).val,
+ None => bcx.sess().bug("msvc_try_filter not defined"),
+ };
+
+ // Type indicator for the exception being thrown, not entirely sure
+ // what's going on here but it's what all the examples in LLVM use.
+ let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)],
+ false);
+
+ llvm::SetFunctionAttribute(rust_try, llvm::Attribute::NoInline);
+ llvm::SetFunctionAttribute(rust_try, llvm::Attribute::OptimizeNone);
+ let func = llvm::get_param(rust_try, 0);
+ let data = llvm::get_param(rust_try, 1);
+
+ // Invoke the function, specifying our two temporary landing pads as the
+ // ext point. After the invoke we've terminated our basic block.
+ Invoke(bcx, func, &[data], then.llbb, catch.llbb, None, dloc);
+
+ // All the magic happens in this landing pad, and this is basically the
+ // only landing pad in rust tagged with "catch" to indicate that we're
+ // catching an exception. The other catch handlers in the GNU version
+ // below just catch *all* exceptions, but that's because most exceptions
+ // are already filtered out by the gnu personality function.
+ //
+ // For MSVC we're just using a standard personality function that we
+ // can't customize (e.g. _except_handler3 or __C_specific_handler), so
+ // we need to do the exception filtering ourselves. This is currently
+ // performed by the `__rust_try_filter` function. This function,
+ // specified in the landingpad instruction, will be invoked by Windows
+ // SEH routines and will return whether the exception in question can be
+ // caught (aka the Rust runtime is the one that threw the exception).
+ //
+ // To get this to compile (currently LLVM segfaults if it's not in this
+ // particular structure), when the landingpad is executing we test to
+ // make sure that the ID of the exception being thrown is indeed the one
+ // that we were expecting. If it's not, we resume the exception, and
+ // otherwise we return the pointer that we got Full disclosure: It's not
+ // clear to me what this `llvm.eh.typeid` stuff is doing *other* then
+ // just allowing LLVM to compile this file without segfaulting. I would
+ // expect the entire landing pad to just be:
+ //
+ // %vals = landingpad ...
+ // %ehptr = extractvalue { i8*, i32 } %vals, 0
+ // ret i8* %ehptr
+ //
+ // but apparently LLVM chokes on this, so we do the more complicated
+ // thing to placate it.
+ let vals = LandingPad(catch, lpad_ty, personality, 1);
+ let rust_try_filter = BitCast(catch, rust_try_filter, Type::i8p(ccx));
+ AddClause(catch, vals, rust_try_filter);
+ let ehptr = ExtractValue(catch, vals, 0);
+ let sel = ExtractValue(catch, vals, 1);
+ let filter_sel = Call(catch, eh_typeid_for, &[rust_try_filter], None,
+ dloc);
+ let is_filter = ICmp(catch, llvm::IntEQ, sel, filter_sel, dloc);
+ CondBr(catch, is_filter, catch_return.llbb, catch_resume.llbb, dloc);
+
+ // Our "catch-return" basic block is where we've determined that we
+ // actually need to catch this exception, in which case we just return
+ // the exception pointer.
+ Ret(catch_return, ehptr, dloc);
+
+ // The "catch-resume" block is where we're running this landing pad but
+ // we actually need to not catch the exception, so just resume the
+ // exception to return.
+ Resume(catch_resume, vals);
+
+ // On the successful branch we just return null.
+ Ret(then, C_null(Type::i8p(ccx)), dloc);
+
+ return rust_try
+ });
+
+ // Note that no invoke is used here because by definition this function
+ // can't panic (that's what it's catching).
+ let ret = Call(bcx, llfn, &[func, data], None, dloc);
+ Store(bcx, ret, dest);
+ return bcx;
+}
+
+// Definition of the standard "try" function for Rust using the GNU-like model
+// of exceptions (e.g. the normal semantics of LLVM's landingpad and invoke
+// instructions).
+//
+// This translation is a little surprising for two reasons:
+//
+// 1. We always call a shim function instead of inlining the call to `invoke`
+// manually here. This is done because in LLVM we're only allowed to have one
+// personality per function definition. The call to the `try` intrinsic is
+// being inlined into the function calling it, and that function may already
+// have other personality functions in play. By calling a shim we're
+// guaranteed that our shim will have the right personality function.
+//
+// 2. Instead of making one shim (explained above), we make two shims! The
+// reason for this has to do with the technical details about the
+// implementation of unwinding in the runtime, but the tl;dr; is that the
+// outer shim's personality function says "catch rust exceptions" and the
+// inner shim's landing pad will not `resume` the exception being thrown.
+// This means that the outer shim's landing pad is never run and the inner
+// shim's return value is the return value of the whole call.
+//
+// The double-shim aspect is currently done for implementation ease on the
+// runtime side of things, and more info can be found in
+// src/libstd/rt/unwind/gcc.rs.
+fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ func: ValueRef,
+ data: ValueRef,
+ dest: ValueRef,
+ dloc: DebugLoc) -> Block<'blk, 'tcx> {
+ let llfn = get_rust_try_fn(bcx.fcx, &mut |try_fn_ty, output| {
+ let ccx = bcx.ccx();
+ let dloc = DebugLoc::None;
+
+ // Type indicator for the exception being thrown, not entirely sure
+ // what's going on here but it's what all the examples in LLVM use.
+ let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)],
+ false);
+
+ // Define the "inner try" shim
+ let rust_try_inner = declare::define_internal_rust_fn(ccx,
+ "__rust_try_inner",
+ try_fn_ty);
+ trans_rust_try(ccx, rust_try_inner, lpad_ty, bcx.fcx.eh_personality(),
+ output, dloc, &mut |bcx, then, catch| {
+ let func = llvm::get_param(rust_try_inner, 0);
+ let data = llvm::get_param(rust_try_inner, 1);
+ Invoke(bcx, func, &[data], then.llbb, catch.llbb, None, dloc);
+ C_null(Type::i8p(ccx))
+ });
+
+ // Define the "outer try" shim.
+ let rust_try = declare::define_internal_rust_fn(ccx, "__rust_try",
+ try_fn_ty);
+ let catch_pers = match bcx.tcx().lang_items.eh_personality_catch() {
+ Some(did) => callee::trans_fn_ref(ccx, did, ExprId(0),
+ bcx.fcx.param_substs).val,
+ None => bcx.tcx().sess.bug("eh_personality_catch not defined"),
+ };
+ trans_rust_try(ccx, rust_try, lpad_ty, catch_pers, output, dloc,
+ &mut |bcx, then, catch| {
+ let func = llvm::get_param(rust_try, 0);
+ let data = llvm::get_param(rust_try, 1);
+ Invoke(bcx, rust_try_inner, &[func, data], then.llbb, catch.llbb,
+ None, dloc)
+ });
+ return rust_try
+ });
+
+ // Note that no invoke is used here because by definition this function
+ // can't panic (that's what it's catching).
+ let ret = Call(bcx, llfn, &[func, data], None, dloc);
+ Store(bcx, ret, dest);
+ return bcx;
+
+ // Translates both the inner and outer shims described above. The only
+ // difference between these two is the function invoked and the personality
+ // involved, so a common routine is shared.
+ //
+ // bcx:
+ // invoke %func(%args...) normal %normal unwind %unwind
+ //
+ // normal:
+ // ret null
+ //
+ // unwind:
+ // (ptr, _) = landingpad
+ // br (ptr != null), done, reraise
+ //
+ // done:
+ // ret ptr
+ //
+ // reraise:
+ // resume
+ //
+ // Note that the branch checking for `null` here isn't actually necessary,
+ // it's just an unfortunate hack to make sure that LLVM doesn't optimize too
+ // much. If this were not present, then LLVM would correctly deduce that our
+ // inner shim should be tagged with `nounwind` (as it catches all
+ // exceptions) and then the outer shim's `invoke` will be translated to just
+ // a simple call, destroying that entry for the personality function.
+ //
+ // To ensure that both shims always have an `invoke` this check against null
+ // confuses LLVM enough to the point that it won't infer `nounwind` and
+ // we'll proceed as normal.
+ fn trans_rust_try<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ llfn: ValueRef,
+ lpad_ty: Type,
+ personality: ValueRef,
+ output: ty::FnOutput<'tcx>,
+ dloc: DebugLoc,
+ invoke: &mut FnMut(Block, Block, Block) -> ValueRef) {
+ let (fcx, block_arena);
+ block_arena = TypedArena::new();
+ fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, false,
+ output, ccx.tcx().mk_substs(Substs::trans_empty()),
+ None, &block_arena);
+ let bcx = init_function(&fcx, true, output);
+ let then = bcx.fcx.new_temp_block("then");
+ let catch = bcx.fcx.new_temp_block("catch");
+ let reraise = bcx.fcx.new_temp_block("reraise");
+ let catch_return = bcx.fcx.new_temp_block("catch-return");
+
+ let invoke_ret = invoke(bcx, then, catch);
+ Ret(then, invoke_ret, dloc);
+ let vals = LandingPad(catch, lpad_ty, personality, 1);
+ AddClause(catch, vals, C_null(Type::i8p(ccx)));
+ let ptr = ExtractValue(catch, vals, 0);
+ let valid = ICmp(catch, llvm::IntNE, ptr, C_null(Type::i8p(ccx)), dloc);
+ CondBr(catch, valid, catch_return.llbb, reraise.llbb, dloc);
+ Ret(catch_return, ptr, dloc);
+ Resume(reraise, vals);
+ }
+}
+
+// Helper to generate the `Ty` associated with `rust_Try`
+fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
+ f: &mut FnMut(Ty<'tcx>,
+ ty::FnOutput<'tcx>) -> ValueRef)
+ -> ValueRef {
+ let ccx = fcx.ccx;
+ if let Some(llfn) = *ccx.rust_try_fn().borrow() {
+ return llfn
+ }
+
+ // Define the types up front for the signatures of the rust_try and
+ // rust_try_inner functions.
+ let tcx = ccx.tcx();
+ let i8p = tcx.mk_mut_ptr(tcx.types.i8);
+ let fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
+ unsafety: ast::Unsafety::Unsafe,
+ abi: abi::Rust,
+ sig: ty::Binder(ty::FnSig {
+ inputs: vec![i8p],
+ output: ty::FnOutput::FnConverging(tcx.mk_nil()),
+ variadic: false,
+ }),
+ });
+ let fn_ty = tcx.mk_fn(None, fn_ty);
+ let output = ty::FnOutput::FnConverging(i8p);
+ let try_fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
+ unsafety: ast::Unsafety::Unsafe,
+ abi: abi::Rust,
+ sig: ty::Binder(ty::FnSig {
+ inputs: vec![fn_ty, i8p],
+ output: output,
+ variadic: false,
+ }),
+ });
+ let rust_try = f(tcx.mk_fn(None, try_fn_ty), output);
+ *ccx.rust_try_fn().borrow_mut() = Some(rust_try);
+ return rust_try
+}
let shim_fn_ty = tcx.mk_fn(None, fty);
let method_bare_fn_ty = tcx.mk_fn(None, method_ty);
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim");
- let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty).unwrap_or_else(||{
- ccx.sess().bug(&format!("symbol `{}` already defined", function_name));
- });
+ let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty);
let sig = ccx.tcx().erase_late_bound_regions(&fty.sig);
let lldecl = if abi != abi::Rust {
foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..])
} else {
- // FIXME(nagisa): perhaps needs a more fine grained selection? See setup_lldecl below.
- declare::define_internal_rust_fn(ccx, &s[..], mono_ty).unwrap_or_else(||{
- ccx.sess().bug(&format!("symbol `{}` already defined", s));
- })
+ // FIXME(nagisa): perhaps needs a more fine grained selection? See
+ // setup_lldecl below.
+ declare::define_internal_rust_fn(ccx, &s, mono_ty)
};
ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl);
use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS};
use middle::const_eval::{self, ConstVal};
+use middle::const_eval::EvalHint::UncheckedExprHint;
use middle::def;
use middle::implicator::object_region_bounds;
use middle::resolve_lifetime as rl;
use middle::traits;
use middle::ty::{self, RegionEscape, Ty, ToPredicate, HasTypeFlags};
use middle::ty_fold;
+use require_c_abi_if_variadic;
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope,
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
ElisionFailureInfo, ElidedLifetime};
}
ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ),
ast::TyBareFn(ref bf) => {
- if bf.decl.variadic && bf.abi != abi::C {
- span_err!(tcx.sess, ast_ty.span, E0045,
- "variadic function must have C calling convention");
- }
+ require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl);
tcx.mk_fn(None, tcx.mk_bare_fn(bare_fn))
}
ty
}
ast::TyFixedLengthVec(ref ty, ref e) => {
- match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.usize)) {
+ let hint = UncheckedExprHint(tcx.types.usize);
+ match const_eval::eval_const_expr_partial(tcx, &e, hint) {
Ok(r) => {
match r {
ConstVal::Int(i) =>
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use middle::const_eval;
use middle::def;
use middle::infer;
use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
use require_same_types;
use util::nodemap::FnvHashMap;
-use std::cmp::{self, Ordering};
+use std::cmp;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use syntax::ast;
use syntax::ast_util;
fcx.write_ty(pat.id, common_type);
- // Finally we evaluate the constants and check that the range is non-empty.
- let get_substs = |id| fcx.item_substs()[&id].substs.clone();
- match const_eval::compare_lit_exprs(tcx, begin, end, Some(&common_type), get_substs) {
- Some(Ordering::Less) |
- Some(Ordering::Equal) => {}
- Some(Ordering::Greater) => {
- span_err!(tcx.sess, begin.span, E0030,
- "lower range bound must be less than or equal to upper");
- }
- None => tcx.sess.span_bug(begin.span, "literals of different types in range pat")
- }
-
// subtyping doesn't matter here, as the value is some kind of scalar
demand::eqtype(fcx, pat.span, expected, lhs_ty);
}
use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty};
use middle::ty::{MethodCall, MethodCallee};
use middle::ty_fold::{TypeFolder, TypeFoldable};
+use require_c_abi_if_variadic;
use rscope::{ElisionFailureInfo, RegionScope};
use session::Session;
use {CrateCtxt, lookup_full_def, require_same_types};
}
if let ast::ForeignItemFn(ref fn_decl, _) = item.node {
- if fn_decl.variadic && m.abi != abi::C {
- span_err!(ccx.tcx.sess, item.span, E0045,
- "variadic function must have C calling convention");
- }
+ require_c_abi_if_variadic(ccx.tcx, fn_decl, m.abi, item.span);
}
}
}
ty::BrAnon(0))),
param(ccx, 0))], tcx.types.u64),
+ "try" => {
+ let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
+ let fn_ty = ty::BareFnTy {
+ unsafety: ast::Unsafety::Normal,
+ abi: abi::Rust,
+ sig: ty::Binder(FnSig {
+ inputs: vec![mut_u8],
+ output: ty::FnOutput::FnConverging(tcx.mk_nil()),
+ variadic: false,
+ }),
+ };
+ let fn_ty = tcx.mk_bare_fn(fn_ty);
+ (0, vec![tcx.mk_fn(None, fn_ty), mut_u8], mut_u8)
+ }
+
ref other => {
span_err!(tcx.sess, it.span, E0093,
"unrecognized intrinsic function: `{}`", *other);
```
"##,
-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 => ...
-}
-```
-"##,
-
E0033: r##"
This error indicates that a pointer to a trait type cannot be implicitly
dereferenced by a pattern. Every trait defines a type, but because the
diverging function (such as `panic!()`).
"##,
+E0172: r##"
+This error means that an attempt was made to specify the type of a variable with
+a combination of a concrete type and a trait. Consider the following example:
+
+```
+fn foo(bar: i32+std::fmt::Display) {}
+```
+
+The code is trying to specify that we want to receive a signed 32-bit integer
+which also implements `Display`. This doesn't make sense: when we pass `i32`, a
+concrete type, it implicitly includes all of the traits that it implements.
+This includes `Display`, `Debug`, `Clone`, and a host of others.
+
+If `i32` implements the trait we desire, there's no need to specify the trait
+separately. If it does not, then we need to `impl` the trait for `i32` before
+passing it into `foo`. Either way, a fixed definition for `foo` will look like
+the following:
+
+```
+fn foo(bar: i32) {}
+```
+
+To learn more about traits, take a look at the Book:
+
+https://doc.rust-lang.org/book/traits.html
+"##,
+
E0178: r##"
In types, the `+` type operator has low precedence, so it is often necessary
to use parentheses.
E0164,
E0167,
E0168,
- E0172,
E0173, // manual implementations of unboxed closure traits are experimental
E0174, // explicit use of unboxed closure methods are experimental
E0182,
}
}
+fn require_c_abi_if_variadic(tcx: &ty::ctxt,
+ decl: &ast::FnDecl,
+ abi: abi::Abi,
+ span: Span) {
+ if decl.variadic && abi != abi::C {
+ span_err!(tcx.sess, span, E0045,
+ "variadic function must have C calling convention");
+ }
+}
+
fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>,
t1_is_expected: bool,
}
}
-/// Wraps a Writer and buffers output to it.
+/// Wraps a writer and buffers its output.
///
-/// It can be excessively inefficient to work directly with a `Write`. For
-/// example, every call to `write` on `TcpStream` results in a system call. A
-/// `BufWriter` keeps an in memory buffer of data and writes it to the
-/// underlying `Write` in large, infrequent batches.
+/// It can be excessively inefficient to work directly with something that
+/// implements `Write`. For example, every call to `write` on `TcpStream`
+/// results in a system call. A `BufWriter` keeps an in-memory buffer of data
+/// and writes it to an underlying writer in large, infrequent batches.
///
/// The buffer will be written out when the writer is dropped.
+///
+/// # Examples
+///
+/// Let's write the numbers one through ten to a `TcpStream`:
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::net::TcpStream;
+///
+/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+///
+/// for i in 1..10 {
+/// stream.write(&[i]).unwrap();
+/// }
+/// ```
+///
+/// Because we're not buffering, we write each one in turn, incurring the
+/// overhead of a system call per byte written. We can fix this with a
+/// `BufWriter`:
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::BufWriter;
+/// use std::net::TcpStream;
+///
+/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+///
+/// for i in 1..10 {
+/// stream.write(&[i]).unwrap();
+/// }
+/// ```
+///
+/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped
+/// together by the buffer, and will all be written out in one system call when
+/// the `stream` is dropped.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufWriter<W: Write> {
inner: Option<W>,
/// An error returned by `into_inner` which combines an error that
/// happened while writing out the buffer, and the buffered writer object
/// which may be used to recover from the condition.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::BufWriter;
+/// use std::net::TcpStream;
+///
+/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+///
+/// // do stuff with the stream
+///
+/// // we want to get our `TcpStream` back, so let's try:
+///
+/// let stream = match stream.into_inner() {
+/// Ok(s) => s,
+/// Err(e) => {
+/// // Here, e is an IntoInnerError
+/// panic!("An error occurred");
+/// }
+/// };
+/// ```
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoInnerError<W>(W, Error);
impl<W: Write> BufWriter<W> {
/// Creates a new `BufWriter` with a default buffer capacity.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(inner: W) -> BufWriter<W> {
BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
}
/// Creates a new `BufWriter` with the specified buffer capacity.
+ ///
+ /// # Examples
+ ///
+ /// Creating a buffer with a buffer of a hundred bytes.
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+ /// let mut buffer = BufWriter::with_capacity(100, stream);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(cap: usize, inner: W) -> BufWriter<W> {
BufWriter {
}
/// Gets a reference to the underlying writer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ ///
+ /// // we can use reference just like buffer
+ /// let reference = buffer.get_ref();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() }
/// # Warning
///
/// It is inadvisable to directly write to the underlying writer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ ///
+ /// // we can use reference just like buffer
+ /// let reference = buffer.get_mut();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() }
/// Unwraps this `BufWriter`, returning the underlying writer.
///
/// The buffer is written out before returning the writer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ ///
+ /// // unwrap the TcpStream and flush the buffer
+ /// let stream = buffer.into_inner().unwrap();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
match self.flush_buf() {
}
impl<W> IntoInnerError<W> {
- /// Returns the error which caused the call to `into_inner` to fail.
+ /// Returns the error which caused the call to `into_inner()` to fail.
///
/// This error was returned when attempting to write the internal buffer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ ///
+ /// // do stuff with the stream
+ ///
+ /// // we want to get our `TcpStream` back, so let's try:
+ ///
+ /// let stream = match stream.into_inner() {
+ /// Ok(s) => s,
+ /// Err(e) => {
+ /// // Here, e is an IntoInnerError, let's log the inner error.
+ /// //
+ /// // We'll just 'log' to stdout for this example.
+ /// println!("{}", e.error());
+ ///
+ /// panic!("An unexpected error occurred.");
+ /// }
+ /// };
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn error(&self) -> &Error { &self.1 }
///
/// The returned object can be used for error recovery, such as
/// re-inspecting the buffer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::io::BufWriter;
+ /// use std::net::TcpStream;
+ ///
+ /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+ ///
+ /// // do stuff with the stream
+ ///
+ /// // we want to get our `TcpStream` back, so let's try:
+ ///
+ /// let stream = match stream.into_inner() {
+ /// Ok(s) => s,
+ /// Err(e) => {
+ /// // Here, e is a IntoInnerError, let's re-examine the buffer:
+ /// let buffer = e.into_inner();
+ ///
+ /// // do stuff to try to recover
+ ///
+ /// // afterwards, let's just return the stream
+ /// buffer.into_inner().unwrap()
+ /// }
+ /// };
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_inner(self) -> W { self.0 }
}
}
}
-/// Wraps a Writer and buffers output to it, flushing whenever a newline
+/// Wraps a writer and buffers output to it, flushing whenever a newline
/// (`0x0a`, `'\n'`) is detected.
///
-/// The buffer will be written out when the writer is dropped.
+/// The [`BufWriter`][bufwriter] struct wraps a writer and buffers its output.
+/// But it only does this batched write when it goes out of scope, or when the
+/// internal buffer is full. Sometimes, you'd prefer to write each line as it's
+/// completed, rather than the entire buffer at once. Enter `LineWriter`. It
+/// does exactly that.
+///
+/// [bufwriter]: struct.BufWriter.html
+///
+/// If there's still a partial line in the buffer when the `LineWriter` is
+/// dropped, it will flush those contents.
+///
+/// # Examples
+///
+/// We can use `LineWriter` to write one line at a time, significantly
+/// reducing the number of actual writes to the file.
+///
+/// ```
+/// use std::fs::File;
+/// use std::io::prelude::*;
+/// use std::io::LineWriter;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let road_not_taken = b"I shall be telling this with a sigh
+/// Somewhere ages and ages hence:
+/// Two roads diverged in a wood, and I -
+/// I took the one less traveled by,
+/// And that has made all the difference.";
+///
+/// let file = try!(File::create("poem.txt"));
+/// let mut file = LineWriter::new(file);
+///
+/// for &byte in road_not_taken.iter() {
+/// file.write(&[byte]).unwrap();
+/// }
+///
+/// // let's check we did the right thing.
+/// let mut file = try!(File::open("poem.txt"));
+/// let mut contents = String::new();
+///
+/// try!(file.read_to_string(&mut contents));
+///
+/// assert_eq!(contents.as_bytes(), &road_not_taken[..]);
+/// # Ok(())
+/// # }
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LineWriter<W: Write> {
inner: BufWriter<W>,
}
impl<W: Write> LineWriter<W> {
- /// Creates a new `LineWriter`
+ /// Creates a new `LineWriter`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::File;
+ /// use std::io::LineWriter;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let file = try!(File::create("poem.txt"));
+ /// let file = LineWriter::new(file);
+ /// # Ok(())
+ /// # }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(inner: W) -> LineWriter<W> {
// Lines typically aren't that long, don't use a giant buffer
/// Creates a new `LineWriter` with a specified capacity for the internal
/// buffer.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::File;
+ /// use std::io::LineWriter;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let file = try!(File::create("poem.txt"));
+ /// let file = LineWriter::with_capacity(100, file);
+ /// # Ok(())
+ /// # }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(cap: usize, inner: W) -> LineWriter<W> {
LineWriter { inner: BufWriter::with_capacity(cap, inner) }
}
/// Gets a reference to the underlying writer.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::File;
+ /// use std::io::LineWriter;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let file = try!(File::create("poem.txt"));
+ /// let file = LineWriter::new(file);
+ ///
+ /// let reference = file.get_ref();
+ /// # Ok(())
+ /// # }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_ref(&self) -> &W { self.inner.get_ref() }
///
/// Caution must be taken when calling methods on the mutable reference
/// returned as extra writes could corrupt the output stream.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::File;
+ /// use std::io::LineWriter;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let file = try!(File::create("poem.txt"));
+ /// let mut file = LineWriter::new(file);
+ ///
+ /// // we can use reference just like file
+ /// let reference = file.get_mut();
+ /// # Ok(())
+ /// # }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() }
/// Unwraps this `LineWriter`, returning the underlying writer.
///
/// The internal buffer is written out before returning the writer.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::File;
+ /// use std::io::LineWriter;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let file = try!(File::create("poem.txt"));
+ ///
+ /// let writer: LineWriter<File> = LineWriter::new(file);
+ ///
+ /// let file: File = try!(writer.into_inner());
+ /// # Ok(())
+ /// # }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
self.inner.into_inner().map_err(|IntoInnerError(buf, e)| {
use io::{self, SeekFrom, Error, ErrorKind};
use slice;
-/// A `Cursor` is a type which wraps a non-I/O object to provide a `Seek`
+/// A `Cursor` wraps another type and provides it with a [`Seek`][seek]
/// implementation.
///
-/// Cursors are typically used with memory buffer objects in order to allow
-/// `Seek`, `Read`, and `Write` implementations. For example, common cursor types
-/// include `Cursor<Vec<u8>>` and `Cursor<&[u8]>`.
+/// [seek]: trait.Seek.html
///
-/// Implementations of the I/O traits for `Cursor<T>` are currently not generic
-/// over `T` itself. Instead, specific implementations are provided for various
-/// in-memory buffer types like `Vec<u8>` and `&[u8]`.
+/// Cursors are typically used with in-memory buffers to allow them to
+/// implement `Read` and/or `Write`, allowing these buffers to be used
+/// anywhere you might use a reader or writer that does actual I/O.
+///
+/// The standard library implements some I/O traits on various types which
+/// are commonly used as a buffer, like `Cursor<Vec<u8>>` and `Cursor<&[u8]>`.
+///
+/// # Examples
+///
+/// We may want to write bytes to a [`File`][file] in our production
+/// code, but use an in-memory buffer in our tests. We can do this with
+/// `Cursor`:
+///
+/// [file]: ../fs/struct.File.html
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::{self, SeekFrom};
+/// use std::fs::File;
+///
+/// // a library function we've written
+/// fn write_ten_bytes_at_end<W: Write + Seek>(writer: &mut W) -> io::Result<()> {
+/// try!(writer.seek(SeekFrom::End(-10)));
+///
+/// for i in 0..10 {
+/// try!(writer.write(&[i]));
+/// }
+///
+/// // all went well
+/// Ok(())
+/// }
+///
+/// # fn foo() -> io::Result<()> {
+/// // Here's some code that uses this library function.
+/// //
+/// // We might want to use a BufReader here for efficiency, but let's
+/// // keep this example focused.
+/// let mut file = try!(File::create("foo.txt"));
+///
+/// try!(write_ten_bytes_at_end(&mut file));
+/// # Ok(())
+/// # }
+///
+/// // now let's write a test
+/// #[test]
+/// fn test_writes_bytes() {
+/// // setting up a real File is much more slow than an in-memory buffer,
+/// // let's use a cursor instead
+/// use std::io::Cursor;
+/// let mut buff = Cursor::new(vec![0; 15]);
+///
+/// write_ten_bytes(&mut buff).unwrap();
+///
+/// assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+/// }
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone, Debug)]
pub struct Cursor<T> {
impl<T> Cursor<T> {
/// Creates a new cursor wrapping the provided underlying I/O object.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::Cursor;
+ ///
+ /// let buff = Cursor::new(Vec::new());
+ /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+ /// # force_inference(&buff);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(inner: T) -> Cursor<T> {
Cursor { pos: 0, inner: inner }
}
/// Consumes this cursor, returning the underlying value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::Cursor;
+ ///
+ /// let buff = Cursor::new(Vec::new());
+ /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+ /// # force_inference(&buff);
+ ///
+ /// let vec = buff.into_inner();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_inner(self) -> T { self.inner }
/// Gets a reference to the underlying value in this cursor.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::Cursor;
+ ///
+ /// let buff = Cursor::new(Vec::new());
+ /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+ /// # force_inference(&buff);
+ ///
+ /// let reference = buff.get_ref();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_ref(&self) -> &T { &self.inner }
///
/// Care should be taken to avoid modifying the internal I/O state of the
/// underlying value as it may corrupt this cursor's position.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::Cursor;
+ ///
+ /// let mut buff = Cursor::new(Vec::new());
+ /// # fn force_inference(_: &Cursor<Vec<u8>>) {}
+ /// # force_inference(&buff);
+ ///
+ /// let reference = buff.get_mut();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self) -> &mut T { &mut self.inner }
- /// Returns the current value of this cursor
+ /// Returns the current position of this cursor.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::Cursor;
+ /// use std::io::prelude::*;
+ /// use std::io::SeekFrom;
+ ///
+ /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
+ ///
+ /// assert_eq!(buff.position(), 0);
+ ///
+ /// buff.seek(SeekFrom::Current(2)).unwrap();
+ /// assert_eq!(buff.position(), 2);
+ ///
+ /// buff.seek(SeekFrom::Current(-1)).unwrap();
+ /// assert_eq!(buff.position(), 1);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn position(&self) -> u64 { self.pos }
- /// Sets the value of this cursor
+ /// Sets the position of this cursor.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io::Cursor;
+ ///
+ /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
+ ///
+ /// assert_eq!(buff.position(), 0);
+ ///
+ /// buff.set_position(2);
+ /// assert_eq!(buff.position(), 2);
+ ///
+ /// buff.set_position(4);
+ /// assert_eq!(buff.position(), 4);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn set_position(&mut self, pos: u64) { self.pos = pos; }
}
/// A `Write` adaptor which will write data to multiple locations.
///
-/// For more information, see `Write::broadcast`.
+/// This struct is generally created by calling [`broadcast()`][broadcast] on a
+/// writer. Please see the documentation of `broadcast()` for more details.
+///
+/// [broadcast]: trait.Write.html#method.broadcast
#[unstable(feature = "io", reason = "awaiting stability of Write::broadcast")]
pub struct Broadcast<T, U> {
first: T,
}
}
-/// Adaptor to chain together two instances of `Read`.
+/// Adaptor to chain together two readers.
+///
+/// This struct is generally created by calling [`chain()`][chain] on a reader.
+/// Please see the documentation of `chain()` for more details.
///
-/// For more information, see `Read::chain`.
+/// [chain]: trait.Read.html#method.chain
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Chain<T, U> {
first: T,
/// Reader adaptor which limits the bytes read from an underlying reader.
///
-/// For more information, see `Read::take`.
+/// This struct is generally created by calling [`take()`][take] on a reader.
+/// Please see the documentation of `take()` for more details.
+///
+/// [take]: trait.Read.html#method.take
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Take<T> {
inner: T,
/// An adaptor which will emit all read data to a specified writer as well.
///
-/// For more information see `Read::tee`
+/// This struct is generally created by calling [`tee()`][tee] on a reader.
+/// Please see the documentation of `tee()` for more details.
+///
+/// [tee]: trait.Read.html#method.tee
#[unstable(feature = "io", reason = "awaiting stability of Read::tee")]
pub struct Tee<R, W> {
reader: R,
}
}
-/// A bridge from implementations of `Read` to an `Iterator` of `u8`.
+/// An iterator over `u8` values of a reader.
///
-/// See `Read::bytes` for more information.
+/// This struct is generally created by calling [`bytes()`][bytes] on a reader.
+/// Please see the documentation of `bytes()` for more details.
+///
+/// [bytes]: trait.Read.html#method.bytes
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Bytes<R> {
inner: R,
}
}
-/// A bridge from implementations of `Read` to an `Iterator` of `char`.
+/// An iterator over the `char`s of a reader.
+///
+/// This struct is generally created by calling [`chars()`][chars] on a reader.
+/// Please see the documentation of `chars()` for more details.
///
-/// See `Read::chars` for more information.
+/// [chars]: trait.Read.html#method.chars
#[unstable(feature = "io", reason = "awaiting stability of Read::chars")]
pub struct Chars<R> {
inner: R,
/// An iterator over the contents of an instance of `BufRead` split on a
/// particular byte.
///
-/// See `BufRead::split` for more information.
+/// This struct is generally created by calling [`split()`][split] on a
+/// `BufRead`. Please see the documentation of `split()` for more details.
+///
+/// [split]: trait.BufRead.html#method.split
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Split<B> {
buf: B,
}
}
-/// An iterator over the lines of an instance of `BufRead` split on a newline
-/// byte.
+/// An iterator over the lines of an instance of `BufRead`.
+///
+/// This struct is generally created by calling [`lines()`][lines] on a
+/// `BufRead`. Please see the documentation of `lines()` for more details.
///
-/// See `BufRead::lines` for more information.
+/// [lines]: trait.BufRead.html#method.lines
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Lines<B> {
buf: B,
}
/// A reader which is always at EOF.
+///
+/// This struct is generally created by calling [`empty()`][empty]. Please see
+/// the documentation of `empty()` for more details.
+///
+/// [empty]: fn.empty.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Empty { _priv: () }
fn consume(&mut self, _n: usize) {}
}
-/// A reader which infinitely yields one byte.
+/// A reader which yields one byte over and over and over and over and over and...
+///
+/// This struct is generally created by calling [`repeat()`][repeat]. Please
+/// see the documentation of `repeat()` for more details.
+///
+/// [empty]: fn.repeat.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Repeat { byte: u8 }
}
/// A writer which will move data into the void.
+///
+/// This struct is generally created by calling [`sink()`][sink]. Please
+/// see the documentation of `sink()` for more details.
+///
+/// [empty]: fn.sink.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Sink { _priv: () }
// own fault handlers if we hit it.
sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom,
my_stack_top);
- sys::thread::guard::init();
+ let main_guard = sys::thread::guard::init();
sys::stack_overflow::init();
// Next, set up the current Thread with the guard information we just
// but we just do this to name the main thread and to give it correct
// info about the stack bounds.
let thread: Thread = NewThread::new(Some("<main>".to_string()));
- thread_info::set(sys::thread::guard::main(), thread);
+ thread_info::set(main_guard, thread);
// By default, some platforms will send a *signal* when a EPIPE error
// would otherwise be delivered. This runtime doesn't install a SIGPIPE
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(private_no_mangle_fns)]
+
use prelude::v1::*;
use any::Any;
-use libc::c_void;
use rt::libunwind as uw;
struct Exception {
}
}
-pub unsafe fn cleanup(ptr: *mut c_void) -> Box<Any + Send + 'static> {
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
let my_ep = ptr as *mut Exception;
rtdebug!("caught {}", (*my_ep).uwe.exception_class);
let cause = (*my_ep).cause.take();
use rt::libunwind as uw;
use libc::c_int;
- extern "C" {
+ extern {
fn __gcc_personality_v0(version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
-> uw::_Unwind_Reason_Code;
}
- #[lang="eh_personality"]
- #[no_mangle] // referenced from rust_try.ll
- #[allow(private_no_mangle_fns)]
+ #[lang = "eh_personality"]
+ #[no_mangle]
extern fn rust_eh_personality(
version: c_int,
actions: uw::_Unwind_Action,
}
}
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality_catch(
+ #[cfg_attr(not(stage0), lang = "eh_personality_catch")]
+ #[no_mangle]
+ pub extern fn rust_eh_personality_catch(
_version: c_int,
actions: uw::_Unwind_Action,
_exception_class: uw::_Unwind_Exception_Class,
use rt::libunwind as uw;
use libc::c_int;
- extern "C" {
+ extern {
fn __gcc_personality_sj0(version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
-> uw::_Unwind_Reason_Code;
}
- #[lang="eh_personality"]
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality(
+ #[lang = "eh_personality"]
+ #[no_mangle]
+ pub extern fn rust_eh_personality(
version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
}
}
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality_catch(
+ #[cfg_attr(not(stage0), lang = "eh_personality_catch")]
+ #[no_mangle]
+ pub extern fn rust_eh_personality_catch(
_version: c_int,
actions: uw::_Unwind_Action,
_exception_class: uw::_Unwind_Exception_Class,
use rt::libunwind as uw;
use libc::c_int;
- extern "C" {
+ extern {
fn __gcc_personality_v0(state: uw::_Unwind_State,
ue_header: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code;
}
- #[lang="eh_personality"]
- #[no_mangle] // referenced from rust_try.ll
- #[allow(private_no_mangle_fns)]
- extern "C" fn rust_eh_personality(
+ #[lang = "eh_personality"]
+ #[no_mangle]
+ extern fn rust_eh_personality(
state: uw::_Unwind_State,
ue_header: *mut uw::_Unwind_Exception,
context: *mut uw::_Unwind_Context
}
}
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality_catch(
+ #[cfg_attr(not(stage0), lang = "eh_personality_catch")]
+ #[no_mangle]
+ pub extern fn rust_eh_personality_catch(
state: uw::_Unwind_State,
_ue_header: *mut uw::_Unwind_Exception,
_context: *mut uw::_Unwind_Context
}
type _Unwind_Personality_Fn =
- extern "C" fn(
+ extern fn(
version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
context: *mut uw::_Unwind_Context
) -> uw::_Unwind_Reason_Code;
- extern "C" {
+ extern {
fn __gcc_personality_seh0(
exceptionRecord: *mut EXCEPTION_RECORD,
establisherFrame: *mut c_void,
) -> EXCEPTION_DISPOSITION;
}
- #[lang="eh_personality"]
- #[no_mangle] // referenced from rust_try.ll
- #[allow(private_no_mangle_fns)]
- extern "C" fn rust_eh_personality(
+ #[lang = "eh_personality"]
+ #[no_mangle]
+ extern fn rust_eh_personality(
exceptionRecord: *mut EXCEPTION_RECORD,
establisherFrame: *mut c_void,
contextRecord: *mut CONTEXT,
}
}
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality_catch(
+ #[cfg_attr(not(stage0), lang = "eh_personality_catch")]
+ #[no_mangle]
+ pub extern fn rust_eh_personality_catch(
exceptionRecord: *mut EXCEPTION_RECORD,
establisherFrame: *mut c_void,
contextRecord: *mut CONTEXT,
dispatcherContext: *mut DISPATCHER_CONTEXT
) -> EXCEPTION_DISPOSITION
{
- extern "C" fn inner(
+ extern fn inner(
_version: c_int,
actions: uw::_Unwind_Action,
_exception_class: uw::_Unwind_Exception_Class,
use panicking;
use fmt;
use intrinsics;
-use libc::c_void;
use mem;
use sync::atomic::{self, Ordering};
use sys_common::mutex::Mutex;
/// run.
pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
let mut f = Some(f);
- return inner_try(try_fn::<F>, &mut f as *mut _ as *mut c_void);
+ return inner_try(try_fn::<F>, &mut f as *mut _ as *mut u8);
// If an inner function were not used here, then this generic function `try`
// uses the native symbol `rust_try`, for which the code is statically
// `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll`
// files and instead just have this non-generic shim the compiler can take
// care of exposing correctly.
- unsafe fn inner_try(f: extern fn(*mut c_void), data: *mut c_void)
+ #[cfg(not(stage0))]
+ unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
-> Result<(), Box<Any + Send>> {
let prev = PANICKING.with(|s| s.get());
PANICKING.with(|s| s.set(false));
- let ep = rust_try(f, data);
+ let ep = intrinsics::try(f, data);
PANICKING.with(|s| s.set(prev));
if ep.is_null() {
Ok(())
Err(imp::cleanup(ep))
}
}
+ #[cfg(stage0)]
+ unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
+ -> Result<(), Box<Any + Send>> {
+ Ok(f(data))
+ }
- extern fn try_fn<F: FnOnce()>(opt_closure: *mut c_void) {
+ fn try_fn<F: FnOnce()>(opt_closure: *mut u8) {
let opt_closure = opt_closure as *mut Option<F>;
unsafe { (*opt_closure).take().unwrap()(); }
}
// When f(...) returns normally, the return value is null.
// When f(...) throws, the return value is a pointer to the caught
// exception object.
- fn rust_try(f: extern fn(*mut c_void),
- data: *mut c_void) -> *mut c_void;
+ fn rust_try(f: extern fn(*mut u8),
+ data: *mut u8) -> *mut u8;
}
}
rtabort!("could not unwind stack");
}
-pub unsafe fn cleanup(ptr: *mut c_void) -> Box<Any + Send + 'static> {
+pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> {
// The `ptr` here actually corresponds to the code of the exception, and our
// real data is stored in our thread local.
rtassert!(ptr as DWORD == RUST_PANIC);
// to ensure that it's code is RUST_PANIC, which was set by the call to
// `RaiseException` above in the `panic` function.
#[no_mangle]
+#[lang = "msvc_try_filter"]
pub extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS,
- _rbp: *mut c_void) -> i32 {
+ _rbp: *mut u8) -> i32 {
unsafe {
((*(*eh_ptrs).ExceptionRecord).ExceptionCode == RUST_PANIC) as i32
}
use thread::LocalKeyState;
struct ThreadInfo {
- stack_guard: usize,
+ stack_guard: Option<usize>,
thread: Thread,
}
THREAD_INFO.with(move |c| {
if c.borrow().is_none() {
*c.borrow_mut() = Some(ThreadInfo {
- stack_guard: 0,
+ stack_guard: None,
thread: NewThread::new(None),
})
}
}
pub fn stack_guard() -> Option<usize> {
- ThreadInfo::with(|info| info.stack_guard)
+ ThreadInfo::with(|info| info.stack_guard).and_then(|o| o)
}
-pub fn set(stack_guard: usize, thread: Thread) {
+pub fn set(stack_guard: Option<usize>, thread: Thread) {
THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{
stack_guard: stack_guard,
not(target_os = "netbsd"),
not(target_os = "openbsd")))]
pub mod guard {
- pub unsafe fn current() -> usize { 0 }
- pub unsafe fn main() -> usize { 0 }
- pub unsafe fn init() {}
+ use prelude::v1::*;
+
+ pub unsafe fn current() -> Option<usize> { None }
+ pub unsafe fn init() -> Option<usize> { None }
}
target_os = "openbsd"))]
#[allow(unused_imports)]
pub mod guard {
+ use prelude::v1::*;
+
use libc::{self, pthread_t};
use libc::funcs::posix88::mman::mmap;
use libc::consts::os::posix88::{PROT_NONE,
use super::{pthread_self, pthread_attr_destroy};
use sys::os;
- // These are initialized in init() and only read from after
- static mut GUARD_PAGE: usize = 0;
-
#[cfg(any(target_os = "macos",
target_os = "bitrig",
target_os = "netbsd",
target_os = "openbsd"))]
- unsafe fn get_stack_start() -> *mut libc::c_void {
- current() as *mut libc::c_void
+ unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+ current().map(|s| s as *mut libc::c_void)
}
#[cfg(any(target_os = "linux", target_os = "android"))]
- unsafe fn get_stack_start() -> *mut libc::c_void {
+ unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+ use super::pthread_attr_init;
+
+ let mut ret = None;
let mut attr: libc::pthread_attr_t = mem::zeroed();
- assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
- let mut stackaddr = ptr::null_mut();
- let mut stacksize = 0;
- assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0);
+ assert_eq!(pthread_attr_init(&mut attr), 0);
+ if pthread_getattr_np(pthread_self(), &mut attr) == 0 {
+ let mut stackaddr = ptr::null_mut();
+ let mut stacksize = 0;
+ assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr,
+ &mut stacksize), 0);
+ ret = Some(stackaddr);
+ }
assert_eq!(pthread_attr_destroy(&mut attr), 0);
- stackaddr
+ ret
}
- pub unsafe fn init() {
+ pub unsafe fn init() -> Option<usize> {
let psize = os::page_size();
- let mut stackaddr = get_stack_start();
+ let mut stackaddr = match get_stack_start() {
+ Some(addr) => addr,
+ None => return None,
+ };
// Ensure stackaddr is page aligned! A parent process might
// have reset RLIMIT_STACK to be non-page aligned. The
let offset = if cfg!(target_os = "linux") {2} else {1};
- GUARD_PAGE = stackaddr as usize + offset * psize;
- }
-
- pub unsafe fn main() -> usize {
- GUARD_PAGE
+ Some(stackaddr as usize + offset * psize)
}
#[cfg(target_os = "macos")]
- pub unsafe fn current() -> usize {
+ pub unsafe fn current() -> Option<usize> {
extern {
fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut libc::c_void;
fn pthread_get_stacksize_np(thread: pthread_t) -> libc::size_t;
}
- (pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
- pthread_get_stacksize_np(pthread_self())) as usize
+ Some((pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
+ pthread_get_stacksize_np(pthread_self())) as usize)
}
#[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "bitrig"))]
- pub unsafe fn current() -> usize {
+ pub unsafe fn current() -> Option<usize> {
#[repr(C)]
struct stack_t {
ss_sp: *mut libc::c_void,
assert_eq!(pthread_stackseg_np(pthread_self(), &mut current_stack), 0);
let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
- if pthread_main_np() == 1 {
+ Some(if pthread_main_np() == 1 {
// main thread
current_stack.ss_sp as usize - current_stack.ss_size as usize + extra
} else {
// new thread
current_stack.ss_sp as usize - current_stack.ss_size as usize
- }
+ })
}
#[cfg(any(target_os = "linux", target_os = "android"))]
- pub unsafe fn current() -> usize {
+ pub unsafe fn current() -> Option<usize> {
+ use super::pthread_attr_init;
+
+ let mut ret = None;
let mut attr: libc::pthread_attr_t = mem::zeroed();
- assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0);
- let mut guardsize = 0;
- assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0);
- if guardsize == 0 {
- panic!("there is no guard page");
+ assert_eq!(pthread_attr_init(&mut attr), 0);
+ if pthread_getattr_np(pthread_self(), &mut attr) == 0 {
+ let mut guardsize = 0;
+ assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0);
+ if guardsize == 0 {
+ panic!("there is no guard page");
+ }
+ let mut stackaddr = ptr::null_mut();
+ let mut size = 0;
+ assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);
+
+ ret = Some(stackaddr as usize + guardsize as usize);
}
- let mut stackaddr = ptr::null_mut();
- let mut size = 0;
- assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);
assert_eq!(pthread_attr_destroy(&mut attr), 0);
-
- stackaddr as usize + guardsize as usize
+ return ret
}
#[cfg(any(target_os = "linux", target_os = "android"))]
}
pub mod guard {
- pub unsafe fn main() -> usize { 0 }
- pub unsafe fn current() -> usize { 0 }
- pub unsafe fn init() {}
+ use prelude::v1::*;
+
+ pub unsafe fn current() -> Option<usize> { None }
+ pub unsafe fn init() -> Option<usize> { None }
}
LPVOID) =
on_tls_callback;
-#[cfg(target_env = "msvc")]
+#[cfg(all(target_env = "msvc", target_pointer_width = "64"))]
#[link_args = "/INCLUDE:_tls_used"]
extern {}
+#[cfg(all(target_env = "msvc", target_pointer_width = "32"))]
+#[link_args = "/INCLUDE:__tls_used"]
+extern {}
#[allow(warnings)]
unsafe extern "system" fn on_tls_callback(h: LPVOID,
imp::Thread::sleep(dur)
}
-/// Blocks unless or until the current thread's token is made available (may wake spuriously).
+/// Blocks unless or until the current thread's token is made available.
///
-/// See the module doc for more detail.
+/// Every thread is equipped with some basic low-level blocking support, via
+/// the `park()` function and the [`unpark()`][unpark] method. These can be
+/// used as a more CPU-efficient implementation of a spinlock.
+///
+/// [unpark]: struct.Thread.html#method.unpark
+///
+/// The API is typically used by acquiring a handle to the current thread,
+/// placing that handle in a shared data structure so that other threads can
+/// find it, and then parking (in a loop with a check for the token actually
+/// being acquired).
+///
+/// A call to `park` does not guarantee that the thread will remain parked
+/// forever, and callers should be prepared for this possibility.
+///
+/// See the [module documentation][thread] for more detail.
+///
+/// [thread]: index.html
//
// The implementation currently uses the trivial strategy of a Mutex+Condvar
// with wakeup flag, which does not actually allow spurious wakeups. In the
+++ /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.
-
-; Rust's try-catch
-; When f(...) returns normally, the return value is null.
-; When f(...) throws, the return value is a pointer to the caught exception object.
-
-; See also: libstd/rt/unwind/mod.rs
-
-define i8* @rust_try(void (i8*)* %f, i8* %env)
- personality i8* bitcast (i32 (...)* @rust_eh_personality_catch to i8*)
-{
-
- %1 = invoke i8* @rust_try_inner(void (i8*)* %f, i8* %env)
- to label %normal
- unwind label %catch
-
-normal:
- ret i8* %1
-
-catch:
- landingpad { i8*, i32 } catch i8* null
- ; rust_try_inner's landing pad does not resume unwinds, so execution will
- ; never reach here
- ret i8* null
-}
-
-define internal i8* @rust_try_inner(void (i8*)* %f, i8* %env)
- personality i8* bitcast (i32 (...)* @rust_eh_personality to i8*)
-{
-
- invoke void %f(i8* %env)
- to label %normal
- unwind label %catch
-
-normal:
- ret i8* null
-
-catch:
- %1 = landingpad { i8*, i32 } catch i8* null
- ; extract and return pointer to the exception object
- %2 = extractvalue { i8*, i32 } %1, 0
- ret i8* %2
-}
-
-declare i32 @rust_eh_personality(...)
-declare i32 @rust_eh_personality_catch(...)
+++ /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.
-
-; For more comments about what's going on here see rust_try_msvc_64.ll. The only
-; difference between that and this file is the personality function used as it's
-; different for 32-bit MSVC than it is for 64-bit.
-
-define i8* @rust_try(void (i8*)* %f, i8* %env)
- personality i8* bitcast (i32 (...)* @_except_handler3 to i8*)
-{
- invoke void %f(i8* %env)
- to label %normal
- unwind label %catch
-
-normal:
- ret i8* null
-catch:
- %vals = landingpad { i8*, i32 }
- catch i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*)
- %ehptr = extractvalue { i8*, i32 } %vals, 0
- %sel = extractvalue { i8*, i32 } %vals, 1
- %filter_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*))
- %is_filter = icmp eq i32 %sel, %filter_sel
- br i1 %is_filter, label %catch-return, label %catch-resume
-
-catch-return:
- ret i8* %ehptr
-
-catch-resume:
- resume { i8*, i32 } %vals
-}
-
-declare i32 @_except_handler3(...)
-declare i32 @__rust_try_filter(i8*, i8*)
-declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind
+++ /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.
-
-; 64-bit MSVC's definition of the `rust_try` function. This function can't be
-; defined in Rust as it's a "try-catch" block that's not expressible in Rust's
-; syntax, so we're using LLVM to produce an object file with the associated
-; handler.
-;
-; To use the correct system implementation details, this file is separate from
-; the standard rust_try.ll as we need specifically use the __C_specific_handler
-; personality function or otherwise LLVM doesn't emit SEH handling tables.
-; There's also a few fiddly bits about SEH right now in LLVM that require us to
-; structure this a fairly particular way!
-;
-; See also: src/libstd/rt/unwind/seh.rs
-
-define i8* @rust_try(void (i8*)* %f, i8* %env)
- personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
-{
- invoke void %f(i8* %env)
- to label %normal
- unwind label %catch
-
-normal:
- ret i8* null
-
-; Here's where most of the magic happens, this is the only landing pad in rust
-; tagged with "catch" to indicate that we're catching an exception. The other
-; catch handlers in rust_try.ll just catch *all* exceptions, but that's because
-; most exceptions are already filtered out by their personality function.
-;
-; For MSVC we're just using a standard personality function that we can't
-; customize, so we need to do the exception filtering ourselves, and this is
-; currently performed by the `__rust_try_filter` function. This function,
-; specified in the landingpad instruction, will be invoked by Windows SEH
-; routines and will return whether the exception in question can be caught (aka
-; the Rust runtime is the one that threw the exception).
-;
-; To get this to compile (currently LLVM segfaults if it's not in this
-; particular structure), when the landingpad is executing we test to make sure
-; that the ID of the exception being thrown is indeed the one that we were
-; expecting. If it's not, we resume the exception, and otherwise we return the
-; pointer that we got
-;
-; Full disclosure: It's not clear to me what this `llvm.eh.typeid` stuff is
-; doing *other* then just allowing LLVM to compile this file without
-; segfaulting. I would expect the entire landing pad to just be:
-;
-; %vals = landingpad ...
-; %ehptr = extractvalue { i8*, i32 } %vals, 0
-; ret i8* %ehptr
-;
-; but apparently LLVM chokes on this, so we do the more complicated thing to
-; placate it.
-catch:
- %vals = landingpad { i8*, i32 }
- catch i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*)
- %ehptr = extractvalue { i8*, i32 } %vals, 0
- %sel = extractvalue { i8*, i32 } %vals, 1
- %filter_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*))
- %is_filter = icmp eq i32 %sel, %filter_sel
- br i1 %is_filter, label %catch-return, label %catch-resume
-
-catch-return:
- ret i8* %ehptr
-
-catch-resume:
- resume { i8*, i32 } %vals
-}
-
-declare i32 @__C_specific_handler(...)
-declare i32 @__rust_try_filter(i8*, i8*)
-declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind
idx, B)));
}
-extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64_t Val) {
+extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index,
+ uint64_t Val) {
Function *A = unwrap<Function>(Fn);
AttrBuilder B;
B.addRawValue(Val);
+S 2015-07-17 d4432b3
+ linux-i386 93f6216a35d3bed3cedf244c9aff4cd716336bd9
+ linux-x86_64 d8f4967fc71a153c925faecf95a7feadf7e463a4
+ macos-i386 29852c4d4b5a851f16d627856a279cae5bf9bd01
+ macos-x86_64 1a20259899321062a0325edb1d22990f05d18708
+ winnt-i386 df50210f41db9a6f2968be5773b8e3bae32bb823
+ winnt-x86_64 d7774b724988485652781a804bdf8e05d28ead48
+
S 2015-05-24 ba0e1cd
bitrig-x86_64 2a710e16e3e3ef3760df1f724d66b3af34c1ef3f
freebsd-x86_64 370db40613f5c08563ed7e38357826dd42d4e0f8
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct X { x: i32 }
+
+fn main() {
+ let mut b: Vec<X> = vec![];
+ b.sort();
+ //~^ ERROR the trait `core::cmp::Ord` is not implemented for the type `X`
+}
fn foo<'a, T: Trait<'a>>(value: T::A) {
let new: T::B = unsafe { std::mem::transmute(value) };
-//~^ ERROR: cannot transmute to or from a type that contains type parameters in its interior [E0139]
+//~^ ERROR: cannot transmute to or from a type that contains unsubstituted type parameters [E0139]
}
fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(negate_unsigned)]
#![deny(exceeding_bitshifts)]
#![allow(unused_variables)]
#![allow(dead_code)]
-#![feature(num_bits_bytes, negate_unsigned)]
+#![feature(num_bits_bytes)]
fn main() {
let n = 1u8 << 7;
let n = 1_isize << std::isize::BITS; //~ ERROR: bitshift exceeds the type's number of bits
let n = 1_usize << std::usize::BITS; //~ ERROR: bitshift exceeds the type's number of bits
+
+
+ let n = 1i8<<(1isize+-1);
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ match 5 {
+ 6 ... 1 => { }
+ _ => { }
+ };
+ //~^^^ ERROR lower range bound must be less than or equal to upper
+
+ match 5u64 {
+ 0xFFFF_FFFF_FFFF_FFFF ... 1 => { }
+ _ => { }
+ };
+ //~^^^ ERROR lower range bound must be less than or equal to upper
+}
// except according to those terms.
fn main() {
- match 5 {
- 6 ... 1 => { }
- _ => { }
- };
- //~^^^ ERROR lower range bound must be less than or equal to upper
-
match "wow" {
"bar" ... "foo" => { }
};
fn main() {
let n = 1;
- let a = [0; n]; //~ ERROR expected constant integer for repeat count, found variable
+ let a = [0; n];
+ //~^ ERROR expected constant integer for repeat count, found variable [E0307]
let b = [0; ()];
-//~^ ERROR mismatched types
-//~| expected `usize`
-//~| found `()`
-//~| expected usize
-//~| found ()
-//~| ERROR expected positive integer for repeat count, found tuple
+ //~^ ERROR mismatched types
+ //~| expected `usize`
+ //~| found `()`
+ //~| expected usize
+ //~| found ()) [E0308]
+ //~| ERROR expected positive integer for repeat count, found tuple [E0306]
let c = [0; true];
//~^ ERROR mismatched types
//~| expected `usize`
//~| found `bool`
//~| expected usize
- //~| found bool
- //~| ERROR expected positive integer for repeat count, found boolean
+ //~| found bool) [E0308]
+ //~| ERROR expected positive integer for repeat count, found boolean [E0306]
let d = [0; 0.5];
//~^ ERROR mismatched types
//~| expected `usize`
//~| found `_`
//~| expected usize
- //~| found floating-point variable
- //~| ERROR expected positive integer for repeat count, found float
+ //~| found floating-point variable) [E0308]
+ //~| ERROR expected positive integer for repeat count, found float [E0306]
let e = [0; "foo"];
//~^ ERROR mismatched types
//~| expected `usize`
//~| found `&'static str`
//~| expected usize
- //~| found &-ptr
- //~| ERROR expected positive integer for repeat count, found string
+ //~| found &-ptr) [E0308]
+ //~| ERROR expected positive integer for repeat count, found string literal [E0306]
let f = [0; -4_isize];
//~^ ERROR mismatched types
//~| expected `usize`
//~| found `isize`
//~| expected usize
- //~| found isize
- //~| ERROR expected positive integer for repeat count, found negative integer
+ //~| found isize) [E0308]
+ //~| ERROR expected positive integer for repeat count, found negative integer [E0306]
let f = [0_usize; -1_isize];
//~^ ERROR mismatched types
//~| expected `usize`
//~| found `isize`
//~| expected usize
- //~| found isize
- //~| ERROR expected positive integer for repeat count, found negative integer
+ //~| found isize) [E0308]
+ //~| ERROR expected positive integer for repeat count, found negative integer [E0306]
+ struct G {
+ g: (),
+ }
+ let g = [0; G { g: () }];
+ //~^ ERROR mismatched types
+ //~| expected `usize`
+ //~| found `main::G`
+ //~| expected usize
+ //~| found struct `main::G`) [E0308]
+ //~| ERROR expected positive integer for repeat count, found struct [E0306]
}
--- /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.
+
+// This test exercises cases where cyclic structure is legal,
+// including when the cycles go through data-structures such
+// as `Vec` or `TypedArena`.
+//
+// The intent is to cover as many such cases as possible, ensuring
+// that if the compiler did not complain circa Rust 1.x (1.2 as of
+// this writing), then it will continue to not complain in the future.
+//
+// Note that while some of the tests are only exercising using the
+// given collection as a "backing store" for a set of nodes that hold
+// the actual cycle (and thus the cycle does not go through the
+// collection itself in such cases), in general we *do* want to make
+// sure to have at least one example exercising a cycle that goes
+// through the collection, for every collection type that supports
+// this.
+
+#![feature(vecmap)]
+
+use std::cell::Cell;
+use std::cmp::Ordering;
+use std::collections::BinaryHeap;
+use std::collections::HashMap;
+use std::collections::LinkedList;
+use std::collections::VecDeque;
+use std::collections::VecMap;
+use std::collections::btree_map::BTreeMap;
+use std::collections::btree_set::BTreeSet;
+use std::hash::{Hash, Hasher};
+
+const PRINT: bool = false;
+
+pub fn main() {
+ let c_orig = ContextData {
+ curr_depth: 0,
+ max_depth: 3,
+ visited: 0,
+ max_visits: 1000,
+ skipped: 0,
+ curr_mark: 0,
+ saw_prev_marked: false,
+ };
+
+ // Cycle 1: { v[0] -> v[1], v[1] -> v[0] };
+ // does not exercise `v` itself
+ let v: Vec<S> = vec![Named::new("s0"),
+ Named::new("s1")];
+ v[0].next.set(Some(&v[1]));
+ v[1].next.set(Some(&v[0]));
+
+ let mut c = c_orig.clone();
+ c.curr_mark = 10;
+ assert!(!c.saw_prev_marked);
+ v[0].for_each_child(&mut c);
+ assert!(c.saw_prev_marked);
+
+ if PRINT { println!(""); }
+
+ // Cycle 2: { v[0] -> v, v[1] -> v }
+ let v: V = Named::new("v");
+ v.contents[0].set(Some(&v));
+ v.contents[1].set(Some(&v));
+
+ let mut c = c_orig.clone();
+ c.curr_mark = 20;
+ assert!(!c.saw_prev_marked);
+ v.for_each_child(&mut c);
+ assert!(c.saw_prev_marked);
+
+ if PRINT { println!(""); }
+
+ // Cycle 3: { hk0 -> hv0, hv0 -> hk0, hk1 -> hv1, hv1 -> hk1 };
+ // does not exercise `h` itself
+
+ let mut h: HashMap<H,H> = HashMap::new();
+ h.insert(Named::new("hk0"), Named::new("hv0"));
+ h.insert(Named::new("hk1"), Named::new("hv1"));
+ for (key, val) in h.iter() {
+ val.next.set(Some(key));
+ key.next.set(Some(val));
+ }
+
+ let mut c = c_orig.clone();
+ c.curr_mark = 30;
+ for (key, _) in h.iter() {
+ c.curr_mark += 1;
+ c.saw_prev_marked = false;
+ key.for_each_child(&mut c);
+ assert!(c.saw_prev_marked);
+ }
+
+ if PRINT { println!(""); }
+
+ // Cycle 4: { h -> (hmk0,hmv0,hmk1,hmv1), {hmk0,hmv0,hmk1,hmv1} -> h }
+
+ let mut h: HashMap<HM,HM> = HashMap::new();
+ h.insert(Named::new("hmk0"), Named::new("hmv0"));
+ h.insert(Named::new("hmk0"), Named::new("hmv0"));
+ for (key, val) in h.iter() {
+ val.contents.set(Some(&h));
+ key.contents.set(Some(&h));
+ }
+
+ let mut c = c_orig.clone();
+ c.max_depth = 2;
+ c.curr_mark = 40;
+ for (key, _) in h.iter() {
+ c.curr_mark += 1;
+ c.saw_prev_marked = false;
+ key.for_each_child(&mut c);
+ assert!(c.saw_prev_marked);
+ // break;
+ }
+
+ if PRINT { println!(""); }
+
+ // Cycle 5: { vd[0] -> vd[1], vd[1] -> vd[0] };
+ // does not exercise vd itself
+ let mut vd: VecDeque<S> = VecDeque::new();
+ vd.push_back(Named::new("d0"));
+ vd.push_back(Named::new("d1"));
+ vd[0].next.set(Some(&vd[1]));
+ vd[1].next.set(Some(&vd[0]));
+
+ let mut c = c_orig.clone();
+ c.curr_mark = 50;
+ assert!(!c.saw_prev_marked);
+ vd[0].for_each_child(&mut c);
+ assert!(c.saw_prev_marked);
+
+ if PRINT { println!(""); }
+
+ // Cycle 6: { vd -> (vd0, vd1), {vd0, vd1} -> vd }
+ let mut vd: VecDeque<VD> = VecDeque::new();
+ vd.push_back(Named::new("vd0"));
+ vd.push_back(Named::new("vd1"));
+ vd[0].contents.set(Some(&vd));
+ vd[1].contents.set(Some(&vd));
+
+ let mut c = c_orig.clone();
+ c.curr_mark = 60;
+ assert!(!c.saw_prev_marked);
+ vd[0].for_each_child(&mut c);
+ assert!(c.saw_prev_marked);
+
+ if PRINT { println!(""); }
+
+ // Cycle 7: { vm -> (vm0, vm1), {vm0, vm1} -> vm }
+ let mut vm: VecMap<VM> = VecMap::new();
+ vm.insert(0, Named::new("vm0"));
+ vm.insert(1, Named::new("vm1"));
+ vm[0].contents.set(Some(&vm));
+ vm[1].contents.set(Some(&vm));
+
+ let mut c = c_orig.clone();
+ c.curr_mark = 70;
+ assert!(!c.saw_prev_marked);
+ vm[0].for_each_child(&mut c);
+ assert!(c.saw_prev_marked);
+
+ if PRINT { println!(""); }
+
+ // Cycle 8: { ll -> (ll0, ll1), {ll0, ll1} -> ll }
+ let mut ll: LinkedList<LL> = LinkedList::new();
+ ll.push_back(Named::new("ll0"));
+ ll.push_back(Named::new("ll1"));
+ for e in &ll {
+ e.contents.set(Some(&ll));
+ }
+
+ let mut c = c_orig.clone();
+ c.curr_mark = 80;
+ for e in &ll {
+ c.curr_mark += 1;
+ c.saw_prev_marked = false;
+ e.for_each_child(&mut c);
+ assert!(c.saw_prev_marked);
+ // break;
+ }
+
+ if PRINT { println!(""); }
+
+ // Cycle 9: { bh -> (bh0, bh1), {bh0, bh1} -> bh }
+ let mut bh: BinaryHeap<BH> = BinaryHeap::new();
+ bh.push(Named::new("bh0"));
+ bh.push(Named::new("bh1"));
+ for b in bh.iter() {
+ b.contents.set(Some(&bh));
+ }
+
+ let mut c = c_orig.clone();
+ c.curr_mark = 90;
+ for b in &bh {
+ c.curr_mark += 1;
+ c.saw_prev_marked = false;
+ b.for_each_child(&mut c);
+ assert!(c.saw_prev_marked);
+ // break;
+ }
+
+ if PRINT { println!(""); }
+
+ // Cycle 10: { btm -> (btk0, btv1), {bt0, bt1} -> btm }
+ let mut btm: BTreeMap<BTM, BTM> = BTreeMap::new();
+ btm.insert(Named::new("btk0"), Named::new("btv0"));
+ btm.insert(Named::new("btk1"), Named::new("btv1"));
+ for (k, v) in btm.iter() {
+ k.contents.set(Some(&btm));
+ v.contents.set(Some(&btm));
+ }
+
+ let mut c = c_orig.clone();
+ c.curr_mark = 100;
+ for (k, _) in &btm {
+ c.curr_mark += 1;
+ c.saw_prev_marked = false;
+ k.for_each_child(&mut c);
+ assert!(c.saw_prev_marked);
+ // break;
+ }
+
+ if PRINT { println!(""); }
+
+ // Cycle 10: { bts -> (bts0, bts1), {bts0, bts1} -> btm }
+ let mut bts: BTreeSet<BTS> = BTreeSet::new();
+ bts.insert(Named::new("bts0"));
+ bts.insert(Named::new("bts1"));
+ for v in bts.iter() {
+ v.contents.set(Some(&bts));
+ }
+
+ let mut c = c_orig.clone();
+ c.curr_mark = 100;
+ for b in &bts {
+ c.curr_mark += 1;
+ c.saw_prev_marked = false;
+ b.for_each_child(&mut c);
+ assert!(c.saw_prev_marked);
+ // break;
+ }
+}
+
+trait Named {
+ fn new(&'static str) -> Self;
+ fn name(&self) -> &str;
+}
+
+trait Marked<M> {
+ fn mark(&self) -> M;
+ fn set_mark(&self, mark: M);
+}
+
+struct S<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ next: Cell<Option<&'a S<'a>>>,
+}
+
+impl<'a> Named for S<'a> {
+ fn new<'b>(name: &'static str) -> S<'b> {
+ S { name: name, mark: Cell::new(0), next: Cell::new(None) }
+ }
+ fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for S<'a> {
+ fn mark(&self) -> u32 { self.mark.get() }
+ fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+struct V<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ contents: Vec<Cell<Option<&'a V<'a>>>>,
+}
+
+impl<'a> Named for V<'a> {
+ fn new<'b>(name: &'static str) -> V<'b> {
+ V { name: name,
+ mark: Cell::new(0),
+ contents: vec![Cell::new(None), Cell::new(None)]
+ }
+ }
+ fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for V<'a> {
+ fn mark(&self) -> u32 { self.mark.get() }
+ fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+#[derive(Eq)]
+struct H<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ next: Cell<Option<&'a H<'a>>>,
+}
+
+impl<'a> Named for H<'a> {
+ fn new<'b>(name: &'static str) -> H<'b> {
+ H { name: name, mark: Cell::new(0), next: Cell::new(None) }
+ }
+ fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for H<'a> {
+ fn mark(&self) -> u32 { self.mark.get() }
+ fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+impl<'a> PartialEq for H<'a> {
+ fn eq(&self, rhs: &H<'a>) -> bool {
+ self.name == rhs.name
+ }
+}
+
+impl<'a> Hash for H<'a> {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.name.hash(state)
+ }
+}
+
+#[derive(Eq)]
+struct HM<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ contents: Cell<Option<&'a HashMap<HM<'a>, HM<'a>>>>,
+}
+
+impl<'a> Named for HM<'a> {
+ fn new<'b>(name: &'static str) -> HM<'b> {
+ HM { name: name,
+ mark: Cell::new(0),
+ contents: Cell::new(None)
+ }
+ }
+ fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for HM<'a> {
+ fn mark(&self) -> u32 { self.mark.get() }
+ fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+impl<'a> PartialEq for HM<'a> {
+ fn eq(&self, rhs: &HM<'a>) -> bool {
+ self.name == rhs.name
+ }
+}
+
+impl<'a> Hash for HM<'a> {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.name.hash(state)
+ }
+}
+
+
+struct VD<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ contents: Cell<Option<&'a VecDeque<VD<'a>>>>,
+}
+
+impl<'a> Named for VD<'a> {
+ fn new<'b>(name: &'static str) -> VD<'b> {
+ VD { name: name,
+ mark: Cell::new(0),
+ contents: Cell::new(None)
+ }
+ }
+ fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for VD<'a> {
+ fn mark(&self) -> u32 { self.mark.get() }
+ fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+struct VM<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ contents: Cell<Option<&'a VecMap<VM<'a>>>>,
+}
+
+impl<'a> Named for VM<'a> {
+ fn new<'b>(name: &'static str) -> VM<'b> {
+ VM { name: name,
+ mark: Cell::new(0),
+ contents: Cell::new(None)
+ }
+ }
+ fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for VM<'a> {
+ fn mark(&self) -> u32 { self.mark.get() }
+ fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+struct LL<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ contents: Cell<Option<&'a LinkedList<LL<'a>>>>,
+}
+
+impl<'a> Named for LL<'a> {
+ fn new<'b>(name: &'static str) -> LL<'b> {
+ LL { name: name,
+ mark: Cell::new(0),
+ contents: Cell::new(None)
+ }
+ }
+ fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for LL<'a> {
+ fn mark(&self) -> u32 { self.mark.get() }
+ fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+struct BH<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ contents: Cell<Option<&'a BinaryHeap<BH<'a>>>>,
+}
+
+impl<'a> Named for BH<'a> {
+ fn new<'b>(name: &'static str) -> BH<'b> {
+ BH { name: name,
+ mark: Cell::new(0),
+ contents: Cell::new(None)
+ }
+ }
+ fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for BH<'a> {
+ fn mark(&self) -> u32 { self.mark.get() }
+ fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+impl<'a> Eq for BH<'a> { }
+
+impl<'a> PartialEq for BH<'a> {
+ fn eq(&self, rhs: &BH<'a>) -> bool {
+ self.name == rhs.name
+ }
+}
+
+impl<'a> PartialOrd for BH<'a> {
+ fn partial_cmp(&self, rhs: &BH<'a>) -> Option<Ordering> {
+ Some(self.cmp(rhs))
+ }
+}
+
+impl<'a> Ord for BH<'a> {
+ fn cmp(&self, rhs: &BH<'a>) -> Ordering {
+ self.name.cmp(rhs.name)
+ }
+}
+
+struct BTM<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ contents: Cell<Option<&'a BTreeMap<BTM<'a>, BTM<'a>>>>,
+}
+
+impl<'a> Named for BTM<'a> {
+ fn new<'b>(name: &'static str) -> BTM<'b> {
+ BTM { name: name,
+ mark: Cell::new(0),
+ contents: Cell::new(None)
+ }
+ }
+ fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for BTM<'a> {
+ fn mark(&self) -> u32 { self.mark.get() }
+ fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+impl<'a> Eq for BTM<'a> { }
+
+impl<'a> PartialEq for BTM<'a> {
+ fn eq(&self, rhs: &BTM<'a>) -> bool {
+ self.name == rhs.name
+ }
+}
+
+impl<'a> PartialOrd for BTM<'a> {
+ fn partial_cmp(&self, rhs: &BTM<'a>) -> Option<Ordering> {
+ Some(self.cmp(rhs))
+ }
+}
+
+impl<'a> Ord for BTM<'a> {
+ fn cmp(&self, rhs: &BTM<'a>) -> Ordering {
+ self.name.cmp(rhs.name)
+ }
+}
+
+struct BTS<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ contents: Cell<Option<&'a BTreeSet<BTS<'a>>>>,
+}
+
+impl<'a> Named for BTS<'a> {
+ fn new<'b>(name: &'static str) -> BTS<'b> {
+ BTS { name: name,
+ mark: Cell::new(0),
+ contents: Cell::new(None)
+ }
+ }
+ fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for BTS<'a> {
+ fn mark(&self) -> u32 { self.mark.get() }
+ fn set_mark(&self, mark: u32) { self.mark.set(mark); }
+}
+
+impl<'a> Eq for BTS<'a> { }
+
+impl<'a> PartialEq for BTS<'a> {
+ fn eq(&self, rhs: &BTS<'a>) -> bool {
+ self.name == rhs.name
+ }
+}
+
+impl<'a> PartialOrd for BTS<'a> {
+ fn partial_cmp(&self, rhs: &BTS<'a>) -> Option<Ordering> {
+ Some(self.cmp(rhs))
+ }
+}
+
+impl<'a> Ord for BTS<'a> {
+ fn cmp(&self, rhs: &BTS<'a>) -> Ordering {
+ self.name.cmp(rhs.name)
+ }
+}
+
+
+trait Context {
+ fn should_act(&self) -> bool;
+ fn increase_visited(&mut self);
+ fn increase_skipped(&mut self);
+ fn increase_depth(&mut self);
+ fn decrease_depth(&mut self);
+}
+
+trait PrePost<T> {
+ fn pre(&mut self, &T);
+ fn post(&mut self, &T);
+ fn hit_limit(&mut self, &T);
+}
+
+trait Children<'a> {
+ fn for_each_child<C>(&self, context: &mut C)
+ where C: Context + PrePost<Self>, Self: Sized;
+
+ fn descend_into_self<C>(&self, context: &mut C)
+ where C: Context + PrePost<Self>, Self: Sized
+ {
+ context.pre(self);
+ if context.should_act() {
+ context.increase_visited();
+ context.increase_depth();
+ self.for_each_child(context);
+ context.decrease_depth();
+ } else {
+ context.hit_limit(self);
+ context.increase_skipped();
+ }
+ context.post(self);
+ }
+
+ fn descend<'b, C>(&self, c: &Cell<Option<&'b Self>>, context: &mut C)
+ where C: Context + PrePost<Self>, Self: Sized
+ {
+ if let Some(r) = c.get() {
+ r.descend_into_self(context);
+ }
+ }
+}
+
+impl<'a> Children<'a> for S<'a> {
+ fn for_each_child<C>(&self, context: &mut C)
+ where C: Context + PrePost<S<'a>>
+ {
+ self.descend(&self.next, context);
+ }
+}
+
+impl<'a> Children<'a> for V<'a> {
+ fn for_each_child<C>(&self, context: &mut C)
+ where C: Context + PrePost<V<'a>>
+ {
+ for r in &self.contents {
+ self.descend(r, context);
+ }
+ }
+}
+
+impl<'a> Children<'a> for H<'a> {
+ fn for_each_child<C>(&self, context: &mut C)
+ where C: Context + PrePost<H<'a>>
+ {
+ self.descend(&self.next, context);
+ }
+}
+
+impl<'a> Children<'a> for HM<'a> {
+ fn for_each_child<C>(&self, context: &mut C)
+ where C: Context + PrePost<HM<'a>>
+ {
+ if let Some(ref hm) = self.contents.get() {
+ for (k, v) in hm.iter() {
+ for r in &[k, v] {
+ r.descend_into_self(context);
+ }
+ }
+ }
+ }
+}
+
+impl<'a> Children<'a> for VD<'a> {
+ fn for_each_child<C>(&self, context: &mut C)
+ where C: Context + PrePost<VD<'a>>
+ {
+ if let Some(ref vd) = self.contents.get() {
+ for r in vd.iter() {
+ r.descend_into_self(context);
+ }
+ }
+ }
+}
+
+impl<'a> Children<'a> for VM<'a> {
+ fn for_each_child<C>(&self, context: &mut C)
+ where C: Context + PrePost<VM<'a>>
+ {
+ if let Some(ref vd) = self.contents.get() {
+ for (_idx, r) in vd.iter() {
+ r.descend_into_self(context);
+ }
+ }
+ }
+}
+
+impl<'a> Children<'a> for LL<'a> {
+ fn for_each_child<C>(&self, context: &mut C)
+ where C: Context + PrePost<LL<'a>>
+ {
+ if let Some(ref ll) = self.contents.get() {
+ for r in ll.iter() {
+ r.descend_into_self(context);
+ }
+ }
+ }
+}
+
+impl<'a> Children<'a> for BH<'a> {
+ fn for_each_child<C>(&self, context: &mut C)
+ where C: Context + PrePost<BH<'a>>
+ {
+ if let Some(ref bh) = self.contents.get() {
+ for r in bh.iter() {
+ r.descend_into_self(context);
+ }
+ }
+ }
+}
+
+impl<'a> Children<'a> for BTM<'a> {
+ fn for_each_child<C>(&self, context: &mut C)
+ where C: Context + PrePost<BTM<'a>>
+ {
+ if let Some(ref bh) = self.contents.get() {
+ for (k, v) in bh.iter() {
+ for r in &[k, v] {
+ r.descend_into_self(context);
+ }
+ }
+ }
+ }
+}
+
+impl<'a> Children<'a> for BTS<'a> {
+ fn for_each_child<C>(&self, context: &mut C)
+ where C: Context + PrePost<BTS<'a>>
+ {
+ if let Some(ref bh) = self.contents.get() {
+ for r in bh.iter() {
+ r.descend_into_self(context);
+ }
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+struct ContextData {
+ curr_depth: usize,
+ max_depth: usize,
+ visited: usize,
+ max_visits: usize,
+ skipped: usize,
+ curr_mark: u32,
+ saw_prev_marked: bool,
+}
+
+impl Context for ContextData {
+ fn should_act(&self) -> bool {
+ self.curr_depth < self.max_depth && self.visited < self.max_visits
+ }
+ fn increase_visited(&mut self) { self.visited += 1; }
+ fn increase_skipped(&mut self) { self.skipped += 1; }
+ fn increase_depth(&mut self) { self.curr_depth += 1; }
+ fn decrease_depth(&mut self) { self.curr_depth -= 1; }
+}
+
+impl<T:Named+Marked<u32>> PrePost<T> for ContextData {
+ fn pre(&mut self, t: &T) {
+ for _ in 0..self.curr_depth {
+ if PRINT { print!(" "); }
+ }
+ if PRINT { println!("prev {}", t.name()); }
+ if t.mark() == self.curr_mark {
+ for _ in 0..self.curr_depth {
+ if PRINT { print!(" "); }
+ }
+ if PRINT { println!("(probably previously marked)"); }
+ self.saw_prev_marked = true;
+ }
+ t.set_mark(self.curr_mark);
+ }
+ fn post(&mut self, t: &T) {
+ for _ in 0..self.curr_depth {
+ if PRINT { print!(" "); }
+ }
+ if PRINT { println!("post {}", t.name()); }
+ }
+ fn hit_limit(&mut self, t: &T) {
+ for _ in 0..self.curr_depth {
+ if PRINT { print!(" "); }
+ }
+ if PRINT { println!("LIMIT {}", t.name()); }
+ }
+}
--- /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 works<T>(x: T) -> Vec<T> { vec![x] }
+
+fn also_works<T: Clone>(x: T) -> Vec<T> { vec![x] }
+
+fn main() {
+ let _: Vec<usize> = works(0);
+ let _: Vec<usize> = also_works(0);
+ let _ = works(0);
+ let _ = also_works(0);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo: Sized {
+ fn foo(self) {}
+}
+
+trait Bar: Sized {
+ fn bar(self) {}
+}
+
+struct S;
+
+impl<'l> Foo for &'l S {}
+
+impl<T: Foo> Bar for T {}
+
+fn main() {
+ let s = S;
+ s.foo();
+ (&s).bar();
+ s.bar();
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[derive(Debug)]
+struct Matrix4<S>(S);
+trait POrd<S> {}
+
+fn translate<S: POrd<S>>(s: S) -> Matrix4<S> { Matrix4(s) }
+
+impl POrd<f32> for f32 {}
+impl POrd<f64> for f64 {}
+
+fn main() {
+ let x = 1.0;
+ let m : Matrix4<f32> = translate(x);
+ println!("m: {:?}", m);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(reflect_marker)]
+
+use std::any::TypeId;
+use std::marker::Reflect;
+use std::rc::Rc;
+
+type Fp<T> = Rc<T>;
+
+struct Engine;
+
+trait Component: 'static + Reflect {}
+impl Component for Engine {}
+
+trait Env {
+ fn get_component_type_id(&self, type_id: TypeId) -> Option<Fp<Component>>;
+}
+
+impl<'a> Env+'a {
+ fn get_component<T: Component>(&self) -> Option<Fp<T>> {
+ let x = self.get_component_type_id(TypeId::of::<T>());
+ None
+ }
+}
+
+trait Figment {
+ fn init(&mut self, env: &Env);
+}
+
+struct MyFigment;
+
+impl Figment for MyFigment {
+ fn init(&mut self, env: &Env) {
+ let engine = env.get_component::<Engine>();
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ || {
+ 'label: loop {
+ }
+ };
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+enum FooMode {
+ Check = 0x1001,
+}
+
+enum BarMode {
+ Check = 0x2001,
+}
+
+enum Mode {
+ Foo(FooMode),
+ Bar(BarMode),
+}
+
+#[inline(never)]
+fn broken(mode: &Mode) -> u32 {
+ for _ in 0..1 {
+ if let Mode::Foo(FooMode::Check) = *mode { return 17 }
+ if let Mode::Bar(BarMode::Check) = *mode { return 19 }
+ }
+ return 42;
+}
+
+fn main() {
+ let mode = Mode::Bar(BarMode::Check);
+ assert_eq!(broken(&mode), 19);
+}