of builtin bounds.
Fixes #10834.
Fixes #11385.
cc #5922.
use std::cell::{Cell, RefCell};
use std::num;
use std::ptr;
+use std::kinds::marker;
use std::mem;
use std::rt::global_heap;
use std::uint;
// different chunks than objects without destructors. This reduces
// overhead when initializing plain-old-data and means we don't need
// to waste time running the destructors of POD.
-#[no_freeze]
pub struct Arena {
// The head is separated out from the list as a unbenchmarked
// microoptimization, to avoid needing to case on the list to
priv head: Chunk,
priv pod_head: Chunk,
priv chunks: RefCell<@List<Chunk>>,
+ priv no_freeze: marker::NoFreeze,
}
impl Arena {
head: chunk(initial_size, false),
pod_head: chunk(initial_size, true),
chunks: RefCell::new(@Nil),
+ no_freeze: marker::NoFreeze,
}
}
}
use sync::{Mutex, RWLock};
use std::cast;
+use std::kinds::marker;
use std::sync::arc::UnsafeArc;
use std::task;
struct MutexArcInner<T> { lock: Mutex, failed: bool, data: T }
/// An Arc with mutable data protected by a blocking mutex.
-#[no_freeze]
-pub struct MutexArc<T> { priv x: UnsafeArc<MutexArcInner<T>> }
-
+pub struct MutexArc<T> {
+ priv x: UnsafeArc<MutexArcInner<T>>,
+ priv marker: marker::NoFreeze,
+}
impl<T:Send> Clone for MutexArc<T> {
/// Duplicate a mutex-protected Arc. See arc::clone for more details.
fn clone(&self) -> MutexArc<T> {
// NB: Cloning the underlying mutex is not necessary. Its reference
// count would be exactly the same as the shared state's.
- MutexArc { x: self.x.clone() }
+ MutexArc { x: self.x.clone(),
+ marker: marker::NoFreeze, }
}
}
lock: Mutex::new_with_condvars(num_condvars),
failed: false, data: user_data
};
- MutexArc { x: UnsafeArc::new(data) }
+ MutexArc { x: UnsafeArc::new(data),
+ marker: marker::NoFreeze, }
}
/**
*
* Unlike mutex_arcs, rw_arcs are safe, because they cannot be nested.
*/
-#[no_freeze]
pub struct RWArc<T> {
priv x: UnsafeArc<RWArcInner<T>>,
+ priv marker: marker::NoFreeze,
}
impl<T:Freeze + Send> Clone for RWArc<T> {
/// Duplicate a rwlock-protected Arc. See arc::clone for more details.
#[inline]
fn clone(&self) -> RWArc<T> {
- RWArc { x: self.x.clone() }
+ RWArc { x: self.x.clone(),
+ marker: marker::NoFreeze, }
}
}
lock: RWLock::new_with_condvars(num_condvars),
failed: false, data: user_data
};
- RWArc { x: UnsafeArc::new(data), }
+ RWArc { x: UnsafeArc::new(data),
+ marker: marker::NoFreeze, }
}
/**
37, ManagedHeapLangItem, "managed_heap", managed_heap;
38, ExchangeHeapLangItem, "exchange_heap", exchange_heap;
39, GcLangItem, "gc", gc;
+
+ 40, CovariantTypeItem, "covariant_type", covariant_type;
+ 41, ContravariantTypeItem, "contravariant_type", contravariant_type;
+ 42, InvariantTypeItem, "invariant_type", invariant_type;
+
+ 43, CovariantLifetimeItem, "covariant_lifetime", covariant_lifetime;
+ 44, ContravariantLifetimeItem, "contravariant_lifetime", contravariant_lifetime;
+ 45, InvariantLifetimeItem, "invariant_lifetime", invariant_lifetime;
+
+ 46, NoFreezeItem, "no_freeze_bound", no_freeze_bound;
+ 47, NoSendItem, "no_send_bound", no_send_bound;
+ 48, NoPodItem, "no_pod_bound", no_pod_bound;
+ 49, ManagedItem, "managed_bound", managed_bound;
}
"thread_local", // for statics
"allow", "deny", "forbid", "warn", // lint options
"deprecated", "experimental", "unstable", "stable", "locked", "frozen", //item stability
- "crate_map", "cfg", "doc", "export_name", "link_section", "no_freeze",
- "no_mangle", "no_send", "static_assert", "unsafe_no_drop_flag", "packed",
+ "crate_map", "cfg", "doc", "export_name", "link_section",
+ "no_mangle", "static_assert", "unsafe_no_drop_flag", "packed",
"simd", "repr", "deriving", "unsafe_destructor", "link", "phase",
"macro_export", "must_use",
// malloc_raw_dyn: allocates a box to contain a given type, but with a
// potentially dynamic size.
pub fn malloc_raw_dyn<'a>(
- bcx: &'a Block,
+ bcx: &'a Block<'a>,
t: ty::t,
heap: heap,
size: ValueRef)
}
}
-pub fn malloc_general<'a>(bcx: &'a Block, t: ty::t, heap: heap)
+pub fn malloc_general<'a>(bcx: &'a Block<'a>, t: ty::t, heap: heap)
-> MallocResult<'a> {
let ty = type_of(bcx.ccx(), t);
assert!(heap != heap_exchange);
//
// Be warned! You must call `init_function` before doing anything with the
// returned function context.
-pub fn new_fn_ctxt_detailed(ccx: @CrateContext,
- path: ast_map::Path,
- llfndecl: ValueRef,
- id: ast::NodeId,
- has_env: bool,
- output_type: ty::t,
- param_substs: Option<@param_substs>,
- sp: Option<Span>)
- -> FunctionContext {
+pub fn new_fn_ctxt<'a>(ccx: @CrateContext,
+ path: ast_map::Path,
+ llfndecl: ValueRef,
+ id: ast::NodeId,
+ has_env: bool,
+ output_type: ty::t,
+ param_substs: Option<@param_substs>,
+ sp: Option<Span>,
+ block_arena: &'a TypedArena<Block<'a>>)
+ -> FunctionContext<'a> {
for p in param_substs.iter() { p.validate(); }
- debug!("new_fn_ctxt_detailed(path={},
+ debug!("new_fn_ctxt(path={},
id={:?}, \
param_substs={})",
path_str(ccx.sess, path),
let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl);
let mut fcx = FunctionContext {
- llfn: llfndecl,
- llenv: None,
- llretptr: Cell::new(None),
- entry_bcx: RefCell::new(None),
- alloca_insert_pt: Cell::new(None),
- llreturn: Cell::new(None),
- personality: Cell::new(None),
- caller_expects_out_pointer: uses_outptr,
- llargs: RefCell::new(HashMap::new()),
- lllocals: RefCell::new(HashMap::new()),
- llupvars: RefCell::new(HashMap::new()),
- id: id,
- param_substs: param_substs,
- span: sp,
- path: path,
- block_arena: TypedArena::new(),
- ccx: ccx,
- debug_context: debug_context,
- scopes: RefCell::new(~[])
+ llfn: llfndecl,
+ llenv: None,
+ llretptr: Cell::new(None),
+ entry_bcx: RefCell::new(None),
+ alloca_insert_pt: Cell::new(None),
+ llreturn: Cell::new(None),
+ personality: Cell::new(None),
+ caller_expects_out_pointer: uses_outptr,
+ llargs: RefCell::new(HashMap::new()),
+ lllocals: RefCell::new(HashMap::new()),
+ llupvars: RefCell::new(HashMap::new()),
+ id: id,
+ param_substs: param_substs,
+ span: sp,
+ path: path,
+ block_arena: block_arena,
+ ccx: ccx,
+ debug_context: debug_context,
+ scopes: RefCell::new(~[])
};
if has_env {
}
}
-pub fn new_fn_ctxt(ccx: @CrateContext,
- path: ast_map::Path,
- llfndecl: ValueRef,
- has_env: bool,
- output_type: ty::t,
- sp: Option<Span>)
- -> FunctionContext {
- // FIXME(#11385): Do not call `init_function` here; it will typecheck
- // but segfault.
- new_fn_ctxt_detailed(ccx, path, llfndecl, -1, has_env, output_type, None, sp)
-}
-
// NB: must keep 4 fns in sync:
//
// - type_of_fn
// Ties up the llstaticallocas -> llloadenv -> lltop edges,
// and builds the return block.
-pub fn finish_fn(fcx: &FunctionContext, last_bcx: &Block) {
+pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>,
+ last_bcx: &'a Block<'a>) {
let _icx = push_ctxt("finish_fn");
let ret_cx = match fcx.llreturn.get() {
id: ast::NodeId,
_attributes: &[ast::Attribute],
output_type: ty::t,
- maybe_load_env: |&'a Block<'a>| -> &'a Block<'a>) {
+ maybe_load_env: <'b> |&'b Block<'b>| -> &'b Block<'b>) {
ccx.stats.n_closures.set(ccx.stats.n_closures.get() + 1);
let _icx = push_ctxt("trans_closure");
_ => false
};
- let fcx = new_fn_ctxt_detailed(ccx, path, llfndecl, id, has_env, output_type,
- param_substs, Some(body.span));
+ let arena = TypedArena::new();
+ let fcx = new_fn_ctxt(ccx,
+ path,
+ llfndecl,
+ id,
+ has_env,
+ output_type,
+ param_substs,
+ Some(body.span),
+ &arena);
init_function(&fcx, false, output_type, param_substs);
// cleanup scope for the incoming arguments
ty_to_str(ccx.tcx, ctor_ty)))
};
- let fcx = new_fn_ctxt_detailed(ccx, ~[], llfndecl, ctor_id, false,
- result_ty, param_substs, None);
+ let arena = TypedArena::new();
+ let fcx = new_fn_ctxt(ccx,
+ ~[],
+ llfndecl,
+ ctor_id,
+ false,
+ result_ty,
+ param_substs,
+ None,
+ &arena);
init_function(&fcx, false, result_ty, param_substs);
let arg_tys = ty::ty_fn_args(ctor_ty);
self.ccx.tcx.sess.bug("No loop scope found");
}
- fn normal_exit_block(&self,
+ fn normal_exit_block(&'a self,
cleanup_scope: ast::NodeId,
exit: uint) -> BasicBlockRef {
/*!
self.trans_cleanups_to_exit_scope(LoopExit(cleanup_scope, exit))
}
- fn return_exit_block(&self) -> BasicBlockRef {
+ fn return_exit_block(&'a self) -> BasicBlockRef {
/*!
* Returns a block to branch to which will perform all pending
* cleanups and then return from this function
scopes.get().iter().rev().any(|s| s.needs_invoke())
}
- fn get_landing_pad(&self) -> BasicBlockRef {
+ fn get_landing_pad(&'a self) -> BasicBlockRef {
/*!
* Returns a basic block to branch to in the event of a failure.
* This block will run the failure cleanups and eventually
f(scopes.get().last().unwrap())
}
- fn trans_cleanups_to_exit_scope(&self,
+ fn trans_cleanups_to_exit_scope(&'a self,
label: EarlyExitLabel)
-> BasicBlockRef {
/*!
prev_llbb
}
- fn get_or_create_landing_pad(&self) -> BasicBlockRef {
+ fn get_or_create_landing_pad(&'a self) -> BasicBlockRef {
/*!
* Creates a landing pad for the top scope, if one does not
* exist. The landing pad will perform all cleanups necessary
custom_scope: CustomScopeIndex)
-> &'a Block<'a>;
fn top_loop_scope(&self) -> ast::NodeId;
- fn normal_exit_block(&self,
+ fn normal_exit_block(&'a self,
cleanup_scope: ast::NodeId,
exit: uint) -> BasicBlockRef;
- fn return_exit_block(&self) -> BasicBlockRef;
+ fn return_exit_block(&'a self) -> BasicBlockRef;
fn schedule_drop_mem(&self,
cleanup_scope: ScopeId,
val: ValueRef,
custom_scope: CustomScopeIndex,
cleanup: ~Cleanup);
fn needs_invoke(&self) -> bool;
- fn get_landing_pad(&self) -> BasicBlockRef;
+ fn get_landing_pad(&'a self) -> BasicBlockRef;
}
trait CleanupHelperMethods<'a> {
fn trans_scope_cleanups(&self,
bcx: &'a Block<'a>,
scope: &CleanupScope<'a>) -> &'a Block<'a>;
- fn trans_cleanups_to_exit_scope(&self,
+ fn trans_cleanups_to_exit_scope(&'a self,
label: EarlyExitLabel)
-> BasicBlockRef;
- fn get_or_create_landing_pad(&self) -> BasicBlockRef;
+ fn get_or_create_landing_pad(&'a self) -> BasicBlockRef;
fn scopes_len(&self) -> uint;
fn push_scope(&self, scope: CleanupScope<'a>);
fn pop_scope(&self) -> CleanupScope<'a>;
use util::ppaux::Repr;
use util::ppaux::ty_to_str;
+use arena::TypedArena;
use std::vec;
use syntax::ast;
use syntax::ast_map::PathName;
};
let ClosureResult {llbox, cdata_ty, bcx} = build_closure(bcx, cap_vars, sigil);
trans_closure(ccx, sub_path, decl, body, llfn,
- bcx.fcx.param_substs, user_id,
- [], ty::ty_fn_ret(fty),
- |bcx| load_environment(bcx, cdata_ty, cap_vars, sigil));
+ bcx.fcx.param_substs, user_id,
+ [], ty::ty_fn_ret(fty),
+ |bcx| load_environment(bcx, cdata_ty, cap_vars, sigil));
fill_fn_pair(bcx, dest_addr, llfn, llbox);
bcx
let _icx = push_ctxt("closure::get_wrapper_for_bare_fn");
- let fcx = new_fn_ctxt(ccx, ~[], llfn, true, f.sig.output, None);
+ let arena = TypedArena::new();
+ let fcx = new_fn_ctxt(ccx, ~[], llfn, -1, true, f.sig.output, None, None,
+ &arena);
init_function(&fcx, true, f.sig.output, None);
let bcx = fcx.entry_bcx.get().unwrap();
path: Path,
// The arena that blocks are allocated from.
- block_arena: TypedArena<Block<'a>>,
+ block_arena: &'a TypedArena<Block<'a>>,
// This function's enclosing crate context.
ccx: @CrateContext,
use middle::trans::type_::Type;
+use arena::TypedArena;
use std::c_str::ToCStr;
use std::cell::Cell;
use std::libc::c_uint;
return llfn;
}
-pub type glue_helper<'a> =
- 'a |&'a Block<'a>, ValueRef, ty::t| -> &'a Block<'a>;
-
-fn make_generic_glue(ccx: @CrateContext, t: ty::t, llfn: ValueRef,
- helper: glue_helper, name: &str) -> ValueRef {
+fn make_generic_glue(ccx: @CrateContext,
+ t: ty::t,
+ llfn: ValueRef,
+ helper: <'a> |&'a Block<'a>, ValueRef, ty::t|
+ -> &'a Block<'a>,
+ name: &str)
+ -> ValueRef {
let _icx = push_ctxt("make_generic_glue");
let glue_name = format!("glue {} {}", name, ty_to_short_str(ccx.tcx, t));
let _s = StatRecorder::new(ccx, glue_name);
- let fcx = new_fn_ctxt(ccx, ~[], llfn, false, ty::mk_nil(), None);
+ let arena = TypedArena::new();
+ let fcx = new_fn_ctxt(ccx, ~[], llfn, -1, false, ty::mk_nil(), None, None,
+ &arena);
+
init_function(&fcx, false, ty::mk_nil(), None);
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
let bcx = fcx.entry_bcx.get().unwrap();
let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, fcx.arg_pos(0) as c_uint) };
let bcx = helper(bcx, llrawptr0, t);
-
finish_fn(&fcx, bcx);
llfn
#[allow(non_uppercase_pattern_statics)];
+use arena::TypedArena;
use back::abi;
use lib::llvm::{SequentiallyConsistent, Acquire, Release, Xchg};
use lib::llvm::{ValueRef, Pointer, Array, Struct};
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, item.id));
- let fcx = new_fn_ctxt_detailed(ccx, path, decl, item.id, false, output_type,
- Some(substs), Some(item.span));
+ let arena = TypedArena::new();
+ let fcx = new_fn_ctxt(ccx,
+ path,
+ decl,
+ item.id,
+ false,
+ output_type,
+ Some(substs),
+ Some(item.span),
+ &arena);
init_function(&fcx, true, output_type, Some(substs));
set_always_inline(fcx.llfn);
use middle::ty;
use util::ppaux::ty_to_str;
+use arena::TypedArena;
use std::libc::c_uint;
use std::option::{Some,None};
use std::vec;
sub_path,
"get_disr");
- let llfdecl = decl_internal_rust_fn(ccx, false,
- [opaqueptrty],
- ty::mk_u64(), sym);
- let fcx = new_fn_ctxt(ccx, ~[], llfdecl, false, ty::mk_u64(), None);
+ let llfdecl = decl_internal_rust_fn(ccx, false, [opaqueptrty], ty::mk_u64(), sym);
+ let arena = TypedArena::new();
+ let fcx = new_fn_ctxt(ccx,
+ ~[],
+ llfdecl,
+ -1, // id
+ false,
+ ty::mk_u64(),
+ None,
+ None,
+ &arena);
init_function(&fcx, false, ty::mk_u64(), None);
let arg = unsafe {
// Things that prevent values from being considered sized
Nonsized = 0b0000__00000000__0001,
- // Things that make values considered not POD (same as `Moves`)
+ // Things that make values considered not POD (would be same
+ // as `Moves`, but for the fact that managed data `@` is
+ // not considered POD)
Nonpod = 0b0000__00001111__0000,
// Bits to set when a managed value is encountered
if ty::has_dtor(cx, did) {
res = res | TC::OwnsDtor;
}
- apply_attributes(cx, did, res)
+ apply_lang_items(cx, did, res)
}
ty_tup(ref tys) => {
tc_ty(cx, *arg_ty, cache)
})
});
- apply_attributes(cx, did, res)
+ apply_lang_items(cx, did, res)
}
ty_param(p) => {
mc | tc_ty(cx, mt.ty, cache)
}
- fn apply_attributes(cx: ctxt,
+ fn apply_lang_items(cx: ctxt,
did: ast::DefId,
tc: TypeContents)
-> TypeContents {
- tc |
- TC::ReachesMutable.when(has_attr(cx, did, "no_freeze")) |
- TC::ReachesNonsendAnnot.when(has_attr(cx, did, "no_send"))
+ if Some(did) == cx.lang_items.no_freeze_bound() {
+ tc | TC::ReachesMutable
+ } else if Some(did) == cx.lang_items.no_send_bound() {
+ tc | TC::ReachesNonsendAnnot
+ } else if Some(did) == cx.lang_items.managed_bound() {
+ tc | TC::Managed
+ } else if Some(did) == cx.lang_items.no_pod_bound() {
+ tc | TC::OwnsAffine
+ } else {
+ tc
+ }
}
fn borrowed_contents(region: ty::Region,
struct ConstraintContext<'a> {
terms_cx: TermsContext<'a>,
+ // These are the def-id of the std::kinds::marker::InvariantType,
+ // std::kinds::marker::InvariantLifetime, and so on. The arrays
+ // are indexed by the `ParamKind` (type, lifetime, self). Note
+ // that there are no marker types for self, so the entries for
+ // self are always None.
+ invariant_lang_items: [Option<ast::DefId>, ..3],
+ covariant_lang_items: [Option<ast::DefId>, ..3],
+ contravariant_lang_items: [Option<ast::DefId>, ..3],
+
// These are pointers to common `ConstantTerm` instances
covariant: VarianceTermPtr<'a>,
contravariant: VarianceTermPtr<'a>,
fn add_constraints_from_crate<'a>(terms_cx: TermsContext<'a>,
crate: &ast::Crate)
-> ConstraintContext<'a> {
+ let mut invariant_lang_items = [None, ..3];
+ let mut covariant_lang_items = [None, ..3];
+ let mut contravariant_lang_items = [None, ..3];
+
+ covariant_lang_items[TypeParam as uint] =
+ terms_cx.tcx.lang_items.covariant_type();
+ covariant_lang_items[RegionParam as uint] =
+ terms_cx.tcx.lang_items.covariant_lifetime();
+
+ contravariant_lang_items[TypeParam as uint] =
+ terms_cx.tcx.lang_items.contravariant_type();
+ contravariant_lang_items[RegionParam as uint] =
+ terms_cx.tcx.lang_items.contravariant_lifetime();
+
+ invariant_lang_items[TypeParam as uint] =
+ terms_cx.tcx.lang_items.invariant_type();
+ invariant_lang_items[RegionParam as uint] =
+ terms_cx.tcx.lang_items.invariant_lifetime();
+
let covariant = terms_cx.arena.alloc(|| ConstantTerm(ty::Covariant));
let contravariant = terms_cx.arena.alloc(|| ConstantTerm(ty::Contravariant));
let invariant = terms_cx.arena.alloc(|| ConstantTerm(ty::Invariant));
let bivariant = terms_cx.arena.alloc(|| ConstantTerm(ty::Bivariant));
let mut constraint_cx = ConstraintContext {
terms_cx: terms_cx,
+
+ invariant_lang_items: invariant_lang_items,
+ covariant_lang_items: covariant_lang_items,
+ contravariant_lang_items: contravariant_lang_items,
+
covariant: covariant,
contravariant: contravariant,
invariant: invariant,
*/
assert_eq!(param_def_id.crate, item_def_id.crate);
- if param_def_id.crate == ast::LOCAL_CRATE {
+
+ if self.invariant_lang_items[kind as uint] == Some(item_def_id) {
+ self.invariant
+ } else if self.covariant_lang_items[kind as uint] == Some(item_def_id) {
+ self.covariant
+ } else if self.contravariant_lang_items[kind as uint] == Some(item_def_id) {
+ self.contravariant
+ } else if param_def_id.crate == ast::LOCAL_CRATE {
// Parameter on an item defined within current crate:
// variance not yet inferred, so return a symbolic
// variance.
use container::Container;
use iter::{Iterator, range};
use libc;
+use kinds::marker;
use ops::Drop;
use option::{Option, Some, None};
use ptr::RawPtr;
pub fn iter<'a>(&'a self) -> CChars<'a> {
CChars {
ptr: self.buf,
- lifetime: unsafe { cast::transmute(self.buf) },
+ marker: marker::ContravariantLifetime,
}
}
}
/// Use with the `std::iter` module.
pub struct CChars<'a> {
priv ptr: *libc::c_char,
- priv lifetime: &'a libc::c_char, // FIXME: #5922
+ priv marker: marker::ContravariantLifetime<'a>,
}
impl<'a> Iterator<libc::c_char> for CChars<'a> {
use prelude::*;
use cast;
use util::NonCopyable;
+use kinds::{marker,Pod};
/// A mutable memory location that admits only `Pod` data.
-#[no_freeze]
-#[deriving(Clone)]
pub struct Cell<T> {
priv value: T,
+ priv marker1: marker::InvariantType<T>,
+ priv marker2: marker::NoFreeze,
}
-impl<T: ::kinds::Pod> Cell<T> {
+impl<T:Pod> Cell<T> {
/// Creates a new `Cell` containing the given value.
pub fn new(value: T) -> Cell<T> {
Cell {
value: value,
+ marker1: marker::InvariantType::<T>,
+ marker2: marker::NoFreeze,
}
}
}
}
+impl<T:Pod> Clone for Cell<T> {
+ fn clone(&self) -> Cell<T> {
+ Cell::new(self.get())
+ }
+}
+
/// A mutable memory location with dynamically checked borrow rules
-#[no_freeze]
pub struct RefCell<T> {
priv value: T,
priv borrow: BorrowFlag,
- priv nc: NonCopyable
+ priv nc: NonCopyable,
+ priv marker1: marker::InvariantType<T>,
+ priv marker2: marker::NoFreeze,
}
// Values [1, MAX-1] represent the number of `Ref` active
/// Create a new `RefCell` containing `value`
pub fn new(value: T) -> RefCell<T> {
RefCell {
+ marker1: marker::InvariantType::<T>,
+ marker2: marker::NoFreeze,
value: value,
borrow: UNUSED,
nc: NonCopyable
use container::Container;
use int;
use iter::Iterator;
+use kinds::marker;
use kinds::Send;
use ops::Drop;
use option::{Option, Some, None};
/// The receiving-half of Rust's channel type. This half can only be owned by
/// one task
-#[no_freeze] // can't share ports in an arc
pub struct Port<T> {
priv queue: Consumer<T>,
+
+ // can't share in an arc
+ priv marker: marker::NoFreeze,
}
/// An iterator over messages received on a port, this iterator will block
/// The sending-half of Rust's channel type. This half can only be owned by one
/// task
-#[no_freeze] // can't share chans in an arc
pub struct Chan<T> {
priv queue: spsc::Producer<T, Packet>,
+
+ // can't share in an arc
+ priv marker: marker::NoFreeze,
}
/// The sending-half of Rust's channel type. This half can be shared among many
/// tasks by creating copies of itself through the `clone` method.
-#[no_freeze] // technically this implementation is shareable, but it shouldn't
- // be required to be shareable in an arc
pub struct SharedChan<T> {
priv queue: mpsc::Producer<T, Packet>,
+
+ // can't share in an arc -- technically this implementation is
+ // shareable, but it shouldn't be required to be shareable in an
+ // arc
+ priv marker: marker::NoFreeze,
}
/// This enumeration is the list of the possible reasons that try_recv could not
// maximum buffer size
let (c, p) = spsc::queue(128, Packet::new());
let c = SPSC(c);
- (Port { queue: c }, Chan { queue: p })
+ (Port { queue: c, marker: marker::NoFreeze },
+ Chan { queue: p, marker: marker::NoFreeze })
}
/// Sends a value along this channel to be received by the corresponding
pub fn new() -> (Port<T>, SharedChan<T>) {
let (c, p) = mpsc::queue(Packet::new());
let c = MPSC(c);
- (Port { queue: c }, SharedChan { queue: p })
+ (Port { queue: c, marker: marker::NoFreeze },
+ SharedChan { queue: p, marker: marker::NoFreeze })
}
/// Equivalent method to `send` on the `Chan` type (using the same
impl<T: Send> Clone for SharedChan<T> {
fn clone(&self) -> SharedChan<T> {
unsafe { (*self.queue.packet()).channels.fetch_add(1, SeqCst); }
- SharedChan { queue: self.queue.clone() }
+ SharedChan { queue: self.queue.clone(), marker: marker::NoFreeze }
}
}
use cast;
use comm;
use iter::Iterator;
+use kinds::marker;
use kinds::Send;
use ops::Drop;
use option::{Some, None, Option};
/// The "port set" of the select interface. This structure is used to manage a
/// set of ports which are being selected over.
-#[no_freeze]
-#[no_send]
pub struct Select {
priv head: *mut Packet,
priv tail: *mut Packet,
priv next_id: uint,
+ priv marker1: marker::NoSend,
+ priv marker2: marker::NoFreeze,
}
/// A handle to a port which is currently a member of a `Select` set of ports.
head: 0 as *mut Packet,
tail: 0 as *mut Packet,
next_id: 1,
+ marker1: marker::NoSend,
+ marker2: marker::NoFreeze,
}
}
#[allow(experimental)];
+use kinds::marker;
use kinds::Send;
use clone::{Clone, DeepClone};
use managed;
/// Immutable garbage-collected pointer type
#[lang="gc"]
#[cfg(not(test))]
-#[no_send]
#[experimental = "Gc is currently based on reference-counting and will not collect cycles until \
task annihilation. For now, cycles need to be broken manually by using `Rc<T>` \
with a non-owning `Weak<T>` pointer. A tracing garbage collector is planned."]
pub struct Gc<T> {
- priv ptr: @T
+ priv ptr: @T,
+ priv marker: marker::NoSend,
}
#[cfg(test)]
#[no_send]
pub struct Gc<T> {
- priv ptr: @T
+ priv ptr: @T,
+ priv marker: marker::NoSend,
}
impl<T: 'static> Gc<T> {
/// Construct a new garbage-collected box
#[inline]
pub fn new(value: T) -> Gc<T> {
- Gc { ptr: @value }
+ Gc { ptr: @value, marker: marker::NoSend }
}
/// Borrow the value contained in the garbage-collected box
/// Clone the pointer only
#[inline]
fn clone(&self) -> Gc<T> {
- Gc{ ptr: self.ptr }
+ Gc{ ptr: self.ptr, marker: marker::NoSend }
}
}
// Empty.
}
+/// Marker types are special types that are used with unsafe code to
+/// inform the compiler of special constraints. Marker types should
+/// only be needed when you are creating an abstraction that is
+/// implemented using unsafe code. In that case, you may want to embed
+/// some of the marker types below into your type.
+pub mod marker {
+
+ /// A marker type whose type parameter `T` is considered to be
+ /// covariant with respect to the type itself. This is (typically)
+ /// used to indicate that an instance of the type `T` is being stored
+ /// into memory and read from, even though that may not be apparent.
+ ///
+ /// For more information about variance, refer to this Wikipedia
+ /// article <http://en.wikipedia.org/wiki/Variance_%28computer_science%29>.
+ ///
+ /// *Note:* It is very unusual to have to add a covariant constraint.
+ /// If you are not sure, you probably want to use `InvariantType`.
+ ///
+ /// # Example
+ ///
+ /// Given a struct `S` that includes a type parameter `T`
+ /// but does not actually *reference* that type parameter:
+ ///
+ /// ```
+ /// struct S<T> { x: *() }
+ /// fn get<T>(s: &S<T>) -> T {
+ /// unsafe {
+ /// let x: *T = cast::transmute(s.x);
+ /// *x
+ /// }
+ /// }
+ /// ```
+ ///
+ /// The type system would currently infer that the value of
+ /// the type parameter `T` is irrelevant, and hence a `S<int>` is
+ /// a subtype of `S<~[int]>` (or, for that matter, `S<U>` for
+ /// for any `U`). But this is incorrect because `get()` converts the
+ /// `*()` into a `*T` and reads from it. Therefore, we should include the
+ /// a marker field `CovariantType<T>` to inform the type checker that
+ /// `S<T>` is a subtype of `S<U>` if `T` is a a subtype of `U`
+ /// (for example, `S<&'static int>` is a subtype of `S<&'a int>`
+ /// for some lifetime `'a`, but not the other way around).
+ #[lang="covariant_type"]
+ #[deriving(Eq,Clone)]
+ pub struct CovariantType<T>;
+
+ /// A marker type whose type parameter `T` is considered to be
+ /// contravariant with respect to the type itself. This is (typically)
+ /// used to indicate that an instance of the type `T` will be consumed
+ /// (but not read from), even though that may not be apparent.
+ ///
+ /// For more information about variance, refer to this Wikipedia
+ /// article <http://en.wikipedia.org/wiki/Variance_%28computer_science%29>.
+ ///
+ /// *Note:* It is very unusual to have to add a contravariant constraint.
+ /// If you are not sure, you probably want to use `InvariantType`.
+ ///
+ /// # Example
+ ///
+ /// Given a struct `S` that includes a type parameter `T`
+ /// but does not actually *reference* that type parameter:
+ ///
+ /// ```
+ /// struct S<T> { x: *() }
+ /// fn get<T>(s: &S<T>, v: T) {
+ /// unsafe {
+ /// let x: fn(T) = cast::transmute(s.x);
+ /// x(v)
+ /// }
+ /// }
+ /// ```
+ ///
+ /// The type system would currently infer that the value of
+ /// the type parameter `T` is irrelevant, and hence a `S<int>` is
+ /// a subtype of `S<~[int]>` (or, for that matter, `S<U>` for
+ /// for any `U`). But this is incorrect because `get()` converts the
+ /// `*()` into a `fn(T)` and then passes a value of type `T` to it.
+ ///
+ /// Supplying a `ContravariantType` marker would correct the
+ /// problem, because it would mark `S` so that `S<T>` is only a
+ /// subtype of `S<U>` if `U` is a subtype of `T`; given that the
+ /// function requires arguments of type `T`, it must also accept
+ /// arguments of type `U`, hence such a conversion is safe.
+ #[lang="contravariant_type"]
+ #[deriving(Eq,Clone)]
+ pub struct ContravariantType<T>;
+
+ /// A marker type whose type parameter `T` is considered to be
+ /// invariant with respect to the type itself. This is (typically)
+ /// used to indicate that instances of the type `T` may be read or
+ /// written, even though that may not be apparent.
+ ///
+ /// For more information about variance, refer to this Wikipedia
+ /// article <http://en.wikipedia.org/wiki/Variance_%28computer_science%29>.
+ ///
+ /// # Example
+ ///
+ /// The Cell type is an example which uses unsafe code to achieve
+ /// "interior" mutability:
+ ///
+ /// ```
+ /// struct Cell<T> { priv value: T }
+ /// ```
+ ///
+ /// The type system would infer that `value` is only read here and
+ /// never written, but in fact `Cell` uses unsafe code to achieve
+ /// interior mutability.
+ #[lang="invariant_type"]
+ #[deriving(Eq,Clone)]
+ pub struct InvariantType<T>;
+
+ /// As `CovariantType`, but for lifetime parameters. Using
+ /// `CovariantLifetime<'a>` indicates that it is ok to substitute
+ /// a *longer* lifetime for `'a` than the one you originally
+ /// started with (e.g., you could convert any lifetime `'foo` to
+ /// `'static`). You almost certainly want `ContravariantLifetime`
+ /// instead, or possibly `InvariantLifetime`. The only case where
+ /// it would be appropriate is that you have a (type-casted, and
+ /// hence hidden from the type system) function pointer with a
+ /// signature like `fn(&'a T)` (and no other uses of `'a`). In
+ /// this case, it is ok to substitute a larger lifetime for `'a`
+ /// (e.g., `fn(&'static T)`), because the function is only
+ /// becoming more selective in terms of what it accepts as
+ /// argument.
+ ///
+ /// For more information about variance, refer to this Wikipedia
+ /// article <http://en.wikipedia.org/wiki/Variance_%28computer_science%29>.
+ #[lang="covariant_lifetime"]
+ #[deriving(Eq,Clone)]
+ pub struct CovariantLifetime<'a>;
+
+ /// As `ContravariantType`, but for lifetime parameters. Using
+ /// `ContravariantLifetime<'a>` indicates that it is ok to
+ /// substitute a *shorter* lifetime for `'a` than the one you
+ /// originally started with (e.g., you could convert `'static` to
+ /// any lifetime `'foo`). This is appropriate for cases where you
+ /// have an unsafe pointer that is actually a pointer into some
+ /// memory with lifetime `'a`, and thus you want to limit the
+ /// lifetime of your data structure to `'a`. An example of where
+ /// this is used is the iterator for vectors.
+ ///
+ /// For more information about variance, refer to this Wikipedia
+ /// article <http://en.wikipedia.org/wiki/Variance_%28computer_science%29>.
+ #[lang="contravariant_lifetime"]
+ #[deriving(Eq,Clone)]
+ pub struct ContravariantLifetime<'a>;
+
+ /// As `InvariantType`, but for lifetime parameters. Using
+ /// `InvariantLifetime<'a>` indicates that it is not ok to
+ /// substitute any other lifetime for `'a` besides its original
+ /// value. This is appropriate for cases where you have an unsafe
+ /// pointer that is actually a pointer into memory with lifetime `'a`,
+ /// and this pointer is itself stored in an inherently mutable
+ /// location (such as a `Cell`).
+ #[lang="invariant_lifetime"]
+ #[deriving(Eq,Clone)]
+ pub struct InvariantLifetime<'a>;
+
+ /// A type which is considered "not freezable", meaning that
+ /// its contents could change even if stored in an immutable
+ /// context or it is the referent of an `&T` pointer. This is
+ /// typically embedded in other types, such as `Cell`.
+ #[lang="no_freeze_bound"]
+ #[deriving(Eq,Clone)]
+ pub struct NoFreeze;
+
+ /// A type which is considered "not sendable", meaning that it cannot
+ /// be safely sent between tasks, even if it is owned. This is
+ /// typically embedded in other types, such as `Gc`, to ensure that
+ /// their instances remain thread-local.
+ #[lang="no_send_bound"]
+ #[deriving(Eq,Clone)]
+ pub struct NoSend;
+
+ /// A type which is considered "not POD", meaning that it is not
+ /// implicitly copyable. This is typically embedded in other types to
+ /// ensure that they are never copied, even if they lack a destructor.
+ #[lang="no_pod_bound"]
+ #[deriving(Eq,Clone)]
+ pub struct NoPod;
+
+ /// A type which is considered managed by the GC. This is typically
+ /// embedded in other types.
+ #[lang="managed_bound"]
+ #[deriving(Eq,Clone)]
+ pub struct Managed;
+}
use cmp::Ord;
use container::Container;
use iter::{Iterator, range};
+use kinds::marker;
use local_data;
use prelude::*;
use str;
static TASK_RNG_RESEED_THRESHOLD: uint = 32_768;
type TaskRngInner = reseeding::ReseedingRng<StdRng, TaskRngReseeder>;
/// The task-local RNG.
-#[no_send]
pub struct TaskRng {
// This points into TLS (specifically, it points to the endpoint
// of a ~ stored in TLS, to make it robust against TLS moving
// The use of unsafe code here is OK if the invariants above are
// satisfied; and it allows us to avoid (unnecessarily) using a
// GC'd or RC'd pointer.
- priv rng: *mut TaskRngInner
+ priv rng: *mut TaskRngInner,
+ priv marker: marker::NoSend,
}
// used to make space in TLS for a random number generator
local_data::set(TASK_RNG_KEY, rng);
- TaskRng { rng: ptr }
+ TaskRng { rng: ptr, marker: marker::NoSend }
}
- Some(rng) => TaskRng { rng: &mut **rng }
+ Some(rng) => TaskRng { rng: &mut **rng, marker: marker::NoSend }
})
}
use ops::Drop;
use cmp::{Eq, Ord};
use clone::{Clone, DeepClone};
+use kinds::marker;
use rt::global_heap::exchange_free;
use ptr::read_ptr;
use option::{Option, Some, None};
/// Immutable reference counted pointer type
#[unsafe_no_drop_flag]
-#[no_send]
pub struct Rc<T> {
- priv ptr: *mut RcBox<T>
+ priv ptr: *mut RcBox<T>,
+ priv marker: marker::NoSend
}
impl<T> Rc<T> {
/// Construct a new reference-counted box
pub fn new(value: T) -> Rc<T> {
unsafe {
- Rc { ptr: transmute(~RcBox { value: value, strong: 1, weak: 0 }) }
+ Rc {
+ ptr: transmute(~RcBox { value: value, strong: 1, weak: 0 }),
+ marker: marker::NoSend,
+ }
}
}
}
pub fn downgrade(&self) -> Weak<T> {
unsafe {
(*self.ptr).weak += 1;
- Weak { ptr: self.ptr }
+ Weak { ptr: self.ptr, marker: marker::NoSend }
}
}
}
fn clone(&self) -> Rc<T> {
unsafe {
(*self.ptr).strong += 1;
- Rc { ptr: self.ptr }
+ Rc { ptr: self.ptr, marker: marker::NoSend }
}
}
}
/// Weak reference to a reference-counted box
#[unsafe_no_drop_flag]
-#[no_send]
pub struct Weak<T> {
- priv ptr: *mut RcBox<T>
+ priv ptr: *mut RcBox<T>,
+ priv marker: marker::NoSend
}
impl<T> Weak<T> {
None
} else {
(*self.ptr).strong += 1;
- Some(Rc { ptr: self.ptr })
+ Some(Rc { ptr: self.ptr, marker: marker::NoSend })
}
}
}
fn clone(&self) -> Weak<T> {
unsafe {
(*self.ptr).weak += 1;
- Weak { ptr: self.ptr }
+ Weak { ptr: self.ptr, marker: marker::NoSend }
}
}
}
use rt::global_heap::{malloc_raw, realloc_raw, exchange_free};
use mem;
use mem::size_of;
+use kinds::marker;
use uint;
use unstable::finally::Finally;
use unstable::intrinsics;
let p = self.as_ptr();
if mem::size_of::<T>() == 0 {
Items{ptr: p,
- end: (p as uint + self.len()) as *T,
- lifetime: None}
+ end: (p as uint + self.len()) as *T,
+ marker: marker::ContravariantLifetime::<'a>}
} else {
Items{ptr: p,
- end: p.offset(self.len() as int),
- lifetime: None}
+ end: p.offset(self.len() as int),
+ marker: marker::ContravariantLifetime::<'a>}
}
}
}
let p = self.as_mut_ptr();
if mem::size_of::<T>() == 0 {
MutItems{ptr: p,
- end: (p as uint + self.len()) as *mut T,
- lifetime: None}
+ end: (p as uint + self.len()) as *mut T,
+ marker: marker::ContravariantLifetime::<'a>}
} else {
MutItems{ptr: p,
- end: p.offset(self.len() as int),
- lifetime: None}
+ end: p.offset(self.len() as int),
+ marker: marker::ContravariantLifetime::<'a>}
}
}
}
pub struct $name<'a, T> {
priv ptr: $ptr,
priv end: $ptr,
- priv lifetime: Option<$elem> // FIXME: #5922
+ priv marker: marker::ContravariantLifetime<'a>,
}
impl<'a, T> Iterator<$elem> for $name<'a, T> {
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::kinds::marker;
+
+fn foo<P:Freeze>(p: P) { }
+
+fn main()
+{
+ foo(marker::NoFreeze); //~ ERROR does not fulfill `Freeze`
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::kinds::marker;
+
+fn foo<P:Pod>(p: P) { }
+
+fn main()
+{
+ foo(marker::NoPod); //~ ERROR does not fulfill `Pod`
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::kinds::marker;
+
+fn foo<P:Send>(p: P) { }
+
+fn main()
+{
+ foo(marker::NoSend); //~ ERROR does not fulfill `Send`
+}
// Tests that an `&` pointer to something inherently mutable is itself
// to be considered mutable.
-#[no_freeze]
-enum Foo { A }
+use std::kinds::marker;
+
+enum Foo { A(marker::NoFreeze) }
fn bar<T: Freeze>(_: T) {}
fn main() {
- let x = A;
+ let x = A(marker::NoFreeze);
bar(&x); //~ ERROR type parameter with an incompatible type
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[no_freeze]
-enum Foo { A }
+use std::kinds::marker;
+
+enum Foo { A(marker::NoFreeze) }
fn bar<T: Freeze>(_: T) {}
fn main() {
- let x = A;
+ let x = A(marker::NoFreeze);
bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Freeze`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[no_freeze]
-struct Foo { a: int }
+use std::kinds::marker;
+
+struct Foo { a: int, m: marker::NoFreeze }
fn bar<T: Freeze>(_: T) {}
fn main() {
- let x = Foo { a: 5 };
+ let x = Foo { a: 5, m: marker::NoFreeze };
bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Freeze`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[no_send]
-enum Foo { A }
+use std::kinds::marker;
+
+enum Foo {
+ A(marker::NoSend)
+}
fn bar<T: Send>(_: T) {}
fn main() {
- let x = A;
+ let x = A(marker::NoSend);
bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Send`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[no_send]
-struct Foo { a: int }
+use std::kinds::marker;
+
+struct Foo {
+ a: int,
+ ns: marker::NoSend
+}
fn bar<T: Send>(_: T) {}
fn main() {
- let x = Foo { a: 5 };
+ let x = Foo { a: 5, ns: marker::NoSend };
bar(x); //~ ERROR instantiating a type parameter with an incompatible type `Foo`, which does not fulfill `Send`
}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that a type which is contravariant with respect to its region
+// parameter yields an error when used in a covariant way.
+//
+// Note: see variance-regions-*.rs for the tests that check that the
+// variance inference works in the first place.
+
+use std::kinds::marker;
+
+// This is contravariant with respect to 'a, meaning that
+// Contravariant<'foo> <: Contravariant<'static> because
+// 'foo <= 'static
+struct Contravariant<'a> {
+ marker: marker::ContravariantLifetime<'a>
+}
+
+fn use_<'short,'long>(c: Contravariant<'short>,
+ s: &'short int,
+ l: &'long int,
+ _where:Option<&'short &'long ()>) {
+
+ // Test whether Contravariant<'short> <: Contravariant<'long>. Since
+ // 'short <= 'long, this would be true if the Contravariant type were
+ // covariant with respect to its parameter 'a.
+
+ let _: Contravariant<'long> = c; //~ ERROR mismatched types
+ //~^ ERROR cannot infer an appropriate lifetime
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that a type which is covariant with respect to its region
+// parameter yields an error when used in a contravariant way.
+//
+// Note: see variance-regions-*.rs for the tests that check that the
+// variance inference works in the first place.
+
+use std::kinds::marker;
+
+struct Covariant<'a> {
+ marker: marker::CovariantLifetime<'a>
+}
+
+fn use_<'short,'long>(c: Covariant<'long>,
+ s: &'short int,
+ l: &'long int,
+ _where:Option<&'short &'long ()>) {
+
+ // Test whether Covariant<'long> <: Covariant<'short>. Since
+ // 'short <= 'long, this would be true if the Covariant type were
+ // contravariant with respect to its parameter 'a.
+
+ let _: Covariant<'short> = c; //~ ERROR mismatched types
+ //~^ ERROR cannot infer an appropriate lifetime
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::kinds::marker;
+
+struct invariant<'a> {
+ marker: marker::InvariantLifetime<'a>
+}
+
+fn to_same_lifetime<'r>(bi: invariant<'r>) {
+ let bj: invariant<'r> = bi;
+}
+
+fn to_longer_lifetime<'r>(bi: invariant<'r>) -> invariant<'static> {
+ bi //~ ERROR mismatched types
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that Cell is considered invariant with respect to its
+// type.
+
+use std::cell::Cell;
+
+struct Foo<'a> {
+ x: Cell<Option<&'a int>>,
+}
+
+fn use_<'short,'long>(c: Foo<'short>,
+ s: &'short int,
+ l: &'long int,
+ _where:Option<&'short &'long ()>) {
+ let _: Foo<'long> = c; //~ ERROR mismatched types
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cell::Cell;
+
+struct Foo {
+ x: int
+}
+
+impl Clone for Foo {
+ fn clone(&self) -> Foo {
+ // Using Cell in any way should never cause clone() to be
+ // invoked -- after all, that would permit evil user code to
+ // abuse `Cell` and trigger crashes.
+
+ fail!();
+ }
+}
+
+pub fn main() {
+ let x = Cell::new(Foo { x: 22 });
+ let _y = x.get();
+ let _z = x.clone();
+}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that a type whose lifetime parameters is never used is
+// inferred to be bivariant.
+
+use std::kinds::marker;
+
+struct Bivariant<'a>;
+
+fn use1<'short,'long>(c: Bivariant<'short>,
+ _where:Option<&'short &'long ()>) {
+ let _: Bivariant<'long> = c;
+}
+
+fn use2<'short,'long>(c: Bivariant<'long>,
+ _where:Option<&'short &'long ()>) {
+ let _: Bivariant<'short> = c;
+}
+
+pub fn main() {}