See #14646 (tracking issue) and rust-lang/rfcs#69.
This does not close the tracking issue, as the `bytes!()` macro still needs to be removed. It will be later, after a snapshot is made with the changes in this PR, so that the new syntax can be used when bootstrapping the compiler.
### Static-only attributes
-- `address_insignificant` - references to this static may alias with
- references to other statics, potentially of unrelated type.
- `thread_local` - on a `static mut`, this signals that the value of this
static may change depending on the current thread. The exact consequences of
this are implementation-defined.
### Inline attributes
The inline attribute is used to suggest to the compiler to perform an inline
-expansion and place a copy of the function in the caller rather than generating
-code to call the function where it is defined.
+expansion and place a copy of the function or static in the caller rather than
+generating code to call the function or access the static where it is defined.
The compiler automatically inlines functions based on internal heuristics.
Incorrectly inlining functions can actually making the program slower, so it
should be used with care.
+Immutable statics are always considered inlineable
+unless marked with `#[inline(never)]`.
+It is undefined
+whether two different inlineable statics
+have the same memory address.
+In other words,
+the compiler is free
+to collapse duplicate inlineable statics together.
+
`#[inline]` and `#[inline(always)]` always causes the function to be serialized
into crate metadata to allow cross-crate inlining.
assert_eq!(next(st), '[');
let def = parse_def(st, NominalType, |x,y| conv(x,y));
let substs = parse_substs(st, |x,y| conv(x,y));
- let store = parse_trait_store(st, |x,y| conv(x,y));
let bounds = parse_bounds(st, |x,y| conv(x,y));
assert_eq!(next(st), ']');
- return ty::mk_trait(st.tcx, def, substs, store, bounds.builtin_bounds);
+ return ty::mk_trait(st.tcx, def, substs, bounds.builtin_bounds);
}
'p' => {
let did = parse_def(st, TypeParameter, |x,y| conv(x,y));
ty::ty_trait(box ty::TyTrait {
def_id,
ref substs,
- store,
bounds
}) => {
mywrite!(w, "x[{}|", (cx.ds)(def_id));
enc_substs(w, cx, substs);
- enc_trait_store(w, cx, store);
let bounds = ty::ParamBounds {builtin_bounds: bounds,
trait_bounds: Vec::new()};
enc_bounds(w, cx, &bounds);
fn check_trait_cast(cx: &mut Context, source_ty: ty::t, target_ty: ty::t, span: Span) {
check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
match ty::get(target_ty).sty {
- ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
- check_trait_cast_bounds(cx, span, source_ty, bounds);
- }
+ ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => match ty::get(ty).sty {
+ ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
+ check_trait_cast_bounds(cx, span, source_ty, bounds);
+ }
+ _ => {}
+ },
_ => {}
}
}
{
// Determine what type we are casting to; if it is not a trait, then no
// worries.
- match ty::get(target_ty).sty {
- ty::ty_trait(..) => {}
- _ => { return; }
+ if !ty::type_is_trait(target_ty) {
+ return;
}
// Collect up the regions that appear in the target type. We want to
n_box += 1;
}
ty::ty_uniq(_) |
- ty::ty_trait(box ty::TyTrait {
- store: ty::UniqTraitStore, ..
- }) |
ty::ty_closure(box ty::ClosureTy {
store: ty::UniqTraitStore,
..
// FIXME: #14406 these are processed in trans, which happens after the
// lint pass
- "address_insignificant",
"cold",
"inline",
"link",
pub fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
match ty::get(t).sty {
ty::ty_uniq(_) |
- ty::ty_trait(box ty::TyTrait { store: ty::UniqTraitStore, .. }) |
ty::ty_closure(box ty::ClosureTy {store: ty::UniqTraitStore, ..}) => {
Some(deref_ptr(OwnedPtr))
}
let kind = ty::BorrowKind::from_mutbl(mt.mutbl);
Some(deref_ptr(BorrowedPtr(kind, r)))
}
- ty::ty_trait(box ty::TyTrait {
- store: ty::RegionTraitStore(r, mutbl),
- ..
- }) => {
- let kind = ty::BorrowKind::from_mutbl(mutbl);
- Some(deref_ptr(BorrowedPtr(kind, r)))
- }
ty::ty_closure(box ty::ClosureTy {
store: ty::RegionTraitStore(r, _),
use syntax::abi;
use syntax::ast;
use syntax::ast_map;
-use syntax::ast_util::{is_local};
+use syntax::ast_util::is_local;
+use syntax::ast_util;
+use syntax::attr::{InlineAlways, InlineHint, InlineNever, InlineNone};
use syntax::attr;
use syntax::visit::Visitor;
use syntax::visit;
// Returns true if the given set of attributes contains the `#[inline]`
// attribute.
fn attributes_specify_inlining(attrs: &[ast::Attribute]) -> bool {
- attr::contains_name(attrs, "inline")
+ match attr::find_inline_attr(attrs) {
+ InlineNone | InlineNever => false,
+ InlineAlways | InlineHint => true,
+ }
}
// Returns true if the given set of generics implies that the item it's
match def {
// If this path leads to a static, then we may have
// to do some work to figure out whether the static
- // is indeed reachable (address_insignificant
- // statics are *never* reachable).
+ // is indeed reachable. (Inlineable statics are
+ // never reachable.)
def::DefStatic(..) => {
self.worklist.push(def_id.node);
}
// Statics with insignificant addresses are not reachable
// because they're inlined specially into all other crates.
- ast::ItemStatic(_, _, ref init) => {
- if attr::contains_name(item.attrs.as_slice(),
- "address_insignificant") {
+ ast::ItemStatic(_, mutbl, ref init) => {
+ if !ast_util::static_has_significant_address(
+ mutbl,
+ item.attrs.as_slice()) {
self.reachable_symbols.remove(&search_item);
}
visit::walk_expr(self, &**init, ());
fn find_ptr(&self) -> Option<uint> {
self.tys.iter().position(|&ty| {
match ty::get(ty).sty {
- ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
- ty::ty_vec(_, None) | ty::ty_str => false,
+ ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
+ ty::ty_vec(_, None) | ty::ty_str| ty::ty_trait(..) => false,
_ => true,
},
- ty::ty_uniq(..) | ty::ty_box(..) |
- ty::ty_bare_fn(..) => true,
+ ty::ty_box(..) | ty::ty_bare_fn(..) => true,
// Is that everything? Would closures or slices qualify?
_ => false
}
match ty::get(ret_ty).sty {
// `~` pointer return values never alias because ownership
// is transferred
+ ty::ty_uniq(it) if match ty::get(it).sty {
+ ty::ty_str | ty::ty_vec(..) | ty::ty_trait(..) => true, _ => false
+ } => {}
ty::ty_uniq(_) => {
attrs.push((lib::llvm::ReturnIndex as uint, lib::llvm::NoAliasAttribute as u64));
}
// We can also mark the return value as `nonnull` in certain cases
match ty::get(ret_ty).sty {
// These are not really pointers but pairs, (pointer, len)
- ty::ty_rptr(_, ty::mt { ty: it, .. }) |
+ ty::ty_uniq(it) |
ty::ty_rptr(_, ty::mt { ty: it, .. }) if match ty::get(it).sty {
- ty::ty_str | ty::ty_vec(..) => true, _ => false
+ ty::ty_str | ty::ty_vec(..) | ty::ty_trait(..) => true, _ => false
} => {}
ty::ty_uniq(_) | ty::ty_rptr(_, _) => {
attrs.push((lib::llvm::ReturnIndex as uint, lib::llvm::NonNullAttribute as u64));
let sym = exported_name(ccx, id, ty, i.attrs.as_slice());
let v = match i.node {
- ast::ItemStatic(_, _, ref expr) => {
+ ast::ItemStatic(_, mutbl, ref expr) => {
// If this static came from an external crate, then
// we need to get the symbol from csearch instead of
// using the current crate's name/version
// Apply the `unnamed_addr` attribute if
// requested
- if attr::contains_name(i.attrs.as_slice(),
- "address_insignificant") {
- if ccx.reachable.contains(&id) {
- ccx.sess().span_bug(i.span,
- "insignificant static is reachable");
- }
+ if !ast_util::static_has_significant_address(
+ mutbl,
+ i.attrs.as_slice()) {
lib::llvm::SetUnnamedAddr(g, true);
// This is a curious case where we must make
// all of these statics inlineable. If a
- // global is tagged as
- // address_insignificant, then LLVM won't
- // coalesce globals unless they have an
- // internal linkage type. This means that
+ // global is not tagged as `#[inline(never)]`,
+ // then LLVM won't coalesce globals unless they
+ // have an internal linkage type. This means that
// external crates cannot use this global.
// This is a problem for things like inner
// statics in generic functions, because the
// crate and then attempt to link to the
// static in the original crate, only to
// find that it's not there. On the other
- // side of inlininig, the crates knows to
+ // side of inlining, the crates knows to
// not declare this static as
// available_externally (because it isn't)
inlineable = true;
ty::type_is_unique(ty) || ty::type_is_region_ptr(ty) ||
type_is_newtype_immediate(ccx, ty) || ty::type_is_bot(ty) ||
ty::type_is_simd(tcx, ty);
- if simple {
+ if simple && !ty::type_is_trait(ty) {
return true;
}
match ty::get(ty).sty {
let dv = match ty::get(t).sty {
ty::ty_ptr(mt) | ty::ty_rptr(_, mt) => {
match ty::get(mt.ty).sty {
- ty::ty_vec(_, None) | ty::ty_str => cx.sess().bug("unexpected slice"),
+ ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => {
+ cx.sess().bug("unexpected unsized type")
+ }
_ => const_deref_ptr(cx, v),
}
}
* on whether type is immediate or not.
*/
- if type_is_zero_size(ccx, ty) {
- ByValue
- } else if type_is_immediate(ccx, ty) {
+ if type_is_immediate(ccx, ty) {
ByValue
} else {
ByRef
// unique ptr (~) -> {~ :pointee-uid:}
// @-ptr (@) -> {@ :pointee-uid:}
// sized vec ([T, ..x]) -> {[:size:] :element-uid:}
- // vec slice (&[T]) -> {&<mut> [] :element-uid:}
- // trait (~ | &[mut] T) -> {:sigil: trait_:svh: / :node-id:_<(:param-uid:),*> }
+ // unsized vec ([T]) -> {[] :element-uid:}
+ // trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> }
// closure -> {<unsafe_> <once_> :store-sigil: |(:param-uid:),* <,_...>| -> \
// :return-type-uid: : (:bounds:)*}
// function -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(inner_type_id.as_slice());
},
- ty::ty_vec(ty::mt { ty: inner_type, mutbl }, optional_length) => {
+ ty::ty_vec(ty::mt { ty: inner_type, .. }, optional_length) => {
match optional_length {
Some(len) => {
unique_type_id.push_str(format!("[{}]", len).as_slice());
}
None => {
- unique_type_id.push_char('&');
-
- if mutbl == ast::MutMutable {
- unique_type_id.push_str("mut");
- }
-
unique_type_id.push_str("[]");
}
};
unique_type_id.push_str(inner_type_id.as_slice());
},
ty::ty_trait(ref trait_data) => {
- match trait_data.store {
- ty::UniqTraitStore => unique_type_id.push_char('~'),
- ty::RegionTraitStore(_, ast::MutMutable) => unique_type_id.push_str("&mut"),
- ty::RegionTraitStore(_, ast::MutImmutable) => unique_type_id.push_char('&'),
- };
-
unique_type_id.push_str("trait ");
from_def_id_and_substs(self,
let i8_t = ty::mk_i8();
heap_vec_metadata(cx, pointee_type, i8_t, unique_type_id, usage_site_span)
}
+ ty::ty_trait(box ty::TyTrait {
+ def_id,
+ ref substs,
+ ref bounds
+ }) => {
+ MetadataCreationResult::new(
+ trait_metadata(cx, def_id, t, substs, ty::UniqTraitStore,
+ bounds, unique_type_id),
+ false)
+ }
_ => {
let pointee_metadata = type_metadata(cx, pointee_type, usage_site_span);
return_if_created_in_meantime!();
ty::ty_str => {
vec_slice_metadata(cx, t, ty::mk_i8(), unique_type_id, usage_site_span)
}
+ ty::ty_trait(box ty::TyTrait {
+ def_id,
+ ref substs,
+ ref bounds
+ }) => {
+ MetadataCreationResult::new(
+ trait_metadata(cx, def_id, t, substs,
+ ty::RegionTraitStore(ty::ReStatic, mt.mutbl),
+ bounds, unique_type_id),
+ false)
+ }
_ => {
let pointee = type_metadata(cx, mt.ty, usage_site_span);
return_if_created_in_meantime!();
ty::ty_closure(ref closurety) => {
subroutine_type_metadata(cx, unique_type_id, &closurety.sig, usage_site_span)
}
- ty::ty_trait(box ty::TyTrait {
- def_id,
- ref substs,
- store,
- ref bounds
- }) => {
- MetadataCreationResult::new(
- trait_metadata(cx, def_id, t, substs, store, bounds, unique_type_id),
- false)
- }
ty::ty_struct(def_id, ref substs) => {
prepare_struct_metadata(cx,
t,
}
ast::ExprCast(ref val, _) => {
// DPS output mode means this is a trait cast:
- match ty::get(node_id_type(bcx, expr.id)).sty {
- ty::ty_trait(..) => {
- let datum = unpack_datum!(bcx, trans(bcx, &**val));
- meth::trans_trait_cast(bcx, datum, expr.id, dest)
- }
- _ => {
- bcx.tcx().sess.span_bug(expr.span,
- "expr_cast of non-trait");
- }
+ if ty::type_is_trait(node_id_type(bcx, expr.id)) {
+ let datum = unpack_datum!(bcx, trans(bcx, &**val));
+ meth::trans_trait_cast(bcx, datum, expr.id, dest)
+ } else {
+ bcx.tcx().sess.span_bug(expr.span,
+ "expr_cast of non-trait");
}
}
ast::ExprAssignOp(op, ref dst, ref src) => {
ty::ty_float(..) => cast_float,
ty::ty_ptr(..) => cast_pointer,
ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty{
- ty::ty_vec(_, None) | ty::ty_str => cast_other,
+ ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => cast_other,
_ => cast_pointer,
},
ty::ty_bare_fn(..) => cast_pointer,
let r = match ty::get(datum.ty).sty {
ty::ty_uniq(content_ty) => {
match ty::get(content_ty).sty {
- ty::ty_vec(_, None) | ty::ty_str
- => bcx.tcx().sess.span_bug(expr.span, "unexpected ~[T]"),
+ ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..)
+ => bcx.tcx().sess.span_bug(expr.span, "unexpected unsized box"),
_ => deref_owned_pointer(bcx, expr, datum, content_ty),
}
}
ty::ty_ptr(ty::mt { ty: content_ty, .. }) |
ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => {
match ty::get(content_ty).sty {
- ty::ty_vec(_, None) | ty::ty_str
- => bcx.tcx().sess.span_bug(expr.span, "unexpected &[T]"),
+ ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..)
+ => bcx.tcx().sess.span_bug(expr.span, "unexpected unsized reference"),
_ => {
assert!(!ty::type_needs_drop(bcx.tcx(), datum.ty));
ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ) => {
match ty::get(typ).sty {
- ty::ty_vec(_, None) | ty::ty_str => t,
+ ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => t,
_ => {
let llty = sizing_type_of(ccx, typ);
// `Box<ZeroSizeType>` does not allocate.
decr_refcnt_maybe_free(bcx, v0, body_ty)
}
ty::ty_uniq(content_ty) => {
- let llbox = Load(bcx, v0);
- let not_null = IsNotNull(bcx, llbox);
match ty::get(content_ty).sty {
ty::ty_vec(mt, None) => {
+ let llbox = Load(bcx, v0);
+ let not_null = IsNotNull(bcx, llbox);
with_cond(bcx, not_null, |bcx| {
let bcx = tvec::make_drop_glue_unboxed(bcx, llbox, mt.ty);
// FIXME: #13994: the old `Box<[T]>` will not support sized deallocation
})
}
ty::ty_str => {
+ let llbox = Load(bcx, v0);
+ let not_null = IsNotNull(bcx, llbox);
with_cond(bcx, not_null, |bcx| {
let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
let bcx = tvec::make_drop_glue_unboxed(bcx, llbox, unit_ty);
trans_exchange_free(bcx, llbox, 0, 8)
})
}
+ ty::ty_trait(..) => {
+ let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
+ // Only drop the value when it is non-null
+ with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue)), |bcx| {
+ let dtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
+ let dtor = Load(bcx, dtor_ptr);
+ Call(bcx,
+ dtor,
+ [PointerCast(bcx, lluniquevalue, Type::i8p(bcx.ccx()))],
+ []);
+ bcx
+ })
+ }
_ => {
+ let llbox = Load(bcx, v0);
+ let not_null = IsNotNull(bcx, llbox);
with_cond(bcx, not_null, |bcx| {
let bcx = drop_ty(bcx, llbox, content_ty);
trans_exchange_free_ty(bcx, llbox, content_ty)
}
}
}
- ty::ty_trait(box ty::TyTrait { store: ty::UniqTraitStore, .. }) => {
- let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
- // Only drop the value when it is non-null
- with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue)), |bcx| {
- let dtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
- let dtor = Load(bcx, dtor_ptr);
- Call(bcx, dtor, [PointerCast(bcx, lluniquevalue, Type::i8p(bcx.ccx()))], []);
- bcx
- })
- }
ty::ty_closure(ref f) if f.store == ty::UniqTraitStore => {
let box_cell_v = GEPi(bcx, v0, [0u, abi::fn_field_box]);
let env = Load(bcx, box_cell_v);
use syntax::ast;
use syntax::ast_util::local_def;
-use syntax::attr;
+use syntax::ast_util;
pub fn maybe_instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId)
-> ast::DefId {
// however, so we use the available_externally linkage which llvm
// provides
match item.node {
- ast::ItemStatic(..) => {
+ ast::ItemStatic(_, mutbl, _) => {
let g = get_item_val(ccx, item.id);
// see the comment in get_item_val() as to why this check is
// performed here.
- if !attr::contains_name(item.attrs.as_slice(),
- "address_insignificant") {
+ if ast_util::static_has_significant_address(
+ mutbl,
+ item.attrs.as_slice()) {
SetLinkage(g, AvailableExternallyLinkage);
}
}
let extra = extra.append(self.c_mt(mt).as_slice());
self.visit("evec_fixed", extra.as_slice())
}
- ty::ty_vec(..) | ty::ty_str => fail!("unexpected unsized type"),
+ ty::ty_vec(..) | ty::ty_str | ty::ty_trait(..) => fail!("unexpected unsized type"),
// Should remove mt from box and uniq.
ty::ty_box(typ) => {
let extra = self.c_mt(&ty::mt {
self.visit("evec_uniq", extra.as_slice())
}
ty::ty_str => self.visit("estr_uniq", &[]),
+ ty::ty_trait(..) => {
+ let extra = [
+ self.c_slice(token::intern_and_get_ident(
+ ty_to_str(tcx, t).as_slice()))
+ ];
+ self.visit("trait", extra);
+ }
_ => {
let extra = self.c_mt(&ty::mt {
ty: typ,
extra.as_slice())
}
ty::ty_str => self.visit("estr_slice", &[]),
+ ty::ty_trait(..) => {
+ let extra = [
+ self.c_slice(token::intern_and_get_ident(
+ ty_to_str(tcx, t).as_slice()))
+ ];
+ self.visit("trait", extra);
+ }
_ => {
let extra = self.c_mt(mt);
self.visit("rptr", extra.as_slice())
})
}
- ty::ty_trait(..) => {
- let extra = [
- self.c_slice(token::intern_and_get_ident(
- ty_to_str(tcx, t).as_slice()))
- ];
- self.visit("trait", extra);
- }
-
// Miscellaneous extra types
ty::ty_infer(_) => self.leaf("infer"),
ty::ty_err => self.leaf("err"),
ty::ty_float(t) => Type::float_from_ty(cx, t),
ty::ty_box(..) |
- ty::ty_uniq(..) |
ty::ty_ptr(..) => Type::i8p(cx),
+ ty::ty_uniq(ty) => {
+ match ty::get(ty).sty {
+ ty::ty_trait(..) => Type::opaque_trait(cx),
+ _ => Type::i8p(cx),
+ }
+ }
ty::ty_rptr(_, mt) => {
match ty::get(mt.ty).sty {
ty::ty_vec(_, None) | ty::ty_str => {
Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false)
}
+ ty::ty_trait(..) => Type::opaque_trait(cx),
_ => Type::i8p(cx),
}
}
ty::ty_bare_fn(..) => Type::i8p(cx),
ty::ty_closure(..) => Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false),
- ty::ty_trait(..) => Type::opaque_trait(cx),
ty::ty_vec(mt, Some(size)) => {
Type::array(&sizing_type_of(cx, mt.ty), size as u64)
}
ty::ty_infer(..) | ty::ty_param(..) |
- ty::ty_err(..) | ty::ty_vec(_, None) | ty::ty_str => {
+ ty::ty_err(..) | ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => {
cx.sess().bug(format!("fictitious type {:?} in sizing_type_of()",
ty::get(t).sty).as_slice())
}
match ty::get(typ).sty {
ty::ty_vec(mt, None) => Type::vec(cx, &type_of(cx, mt.ty)).ptr_to(),
ty::ty_str => Type::vec(cx, &Type::i8(cx)).ptr_to(),
+ ty::ty_trait(..) => Type::opaque_trait(cx),
_ => type_of(cx, typ).ptr_to(),
}
}
// This means we get a nicer name in the output
cx.tn.find_type("str_slice").unwrap()
}
+ ty::ty_trait(..) => Type::opaque_trait(cx),
_ => type_of(cx, mt.ty).ptr_to(),
}
}
let fn_ty = type_of_fn_from_ty(cx, t).ptr_to();
Type::struct_(cx, [fn_ty, Type::i8p(cx)], false)
}
- ty::ty_trait(..) => Type::opaque_trait(cx),
ty::ty_tup(..) => {
let repr = adt::represent_type(cx, t);
adt::type_of(cx, &*repr)
ty::ty_vec(_, None) => cx.sess().bug("type_of with unsized ty_vec"),
ty::ty_str => cx.sess().bug("type_of with unsized (bare) ty_str"),
+ ty::ty_trait(..) => cx.sess().bug("type_of with unsized ty_trait"),
ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"),
ty::ty_param(..) => cx.sess().bug("type_of with ty_param"),
ty::ty_err(..) => cx.sess().bug("type_of with ty_err")
pub struct TyTrait {
pub def_id: DefId,
pub substs: Substs,
- pub store: TraitStore,
pub bounds: BuiltinBounds
}
&ty_enum(_, ref substs) | &ty_struct(_, ref substs) => {
flags |= sflags(substs);
}
- &ty_trait(box ty::TyTrait { ref substs, store, .. }) => {
+ &ty_trait(box ty::TyTrait { ref substs, .. }) => {
flags |= sflags(substs);
- match store {
- RegionTraitStore(r, _) => {
- flags |= rflags(r);
- }
- _ => {}
- }
}
&ty_box(tt) | &ty_uniq(tt) => {
flags |= get(tt).flags
pub fn mk_trait(cx: &ctxt,
did: ast::DefId,
substs: Substs,
- store: TraitStore,
bounds: BuiltinBounds)
-> t {
// take a copy of substs so that we own the vectors inside
let inner = box TyTrait {
def_id: did,
substs: substs,
- store: store,
bounds: bounds
};
mk_t(cx, ty_trait(inner))
pub fn type_is_structural(ty: t) -> bool {
match get(ty).sty {
- ty_struct(..) | ty_tup(_) | ty_enum(..) | ty_closure(_) | ty_trait(..) |
+ ty_struct(..) | ty_tup(_) | ty_enum(..) | ty_closure(_) |
ty_vec(_, Some(_)) => true,
- _ => type_is_slice(ty)
+ _ => type_is_slice(ty) | type_is_trait(ty)
}
}
ty_rptr(_, mt) => match get(mt.ty).sty {
// FIXME(nrc, DST) slices weren't regarded as rptrs, so we preserve this
// odd behaviour for now. (But ~[] were unique. I have no idea why).
- ty_vec(_, None) | ty_str => false,
+ ty_vec(_, None) | ty_str | ty_trait(..) => false,
_ => true
},
_ => false
pub fn type_is_unique(ty: t) -> bool {
match get(ty).sty {
- ty_uniq(_) => true,
+ ty_uniq(_) => match get(ty).sty {
+ ty_trait(..) => false,
+ _ => true
+ },
_ => false
}
}
}
}
- ty_trait(box ty::TyTrait { store, bounds, .. }) => {
- object_contents(cx, store, bounds)
+ ty_trait(box ty::TyTrait { bounds, .. }) => {
+ object_contents(cx, bounds)
}
ty_ptr(ref mt) => {
fn closure_contents(cx: &ctxt, cty: &ClosureTy) -> TypeContents {
// Closure contents are just like trait contents, but with potentially
// even more stuff.
- let st = object_contents(cx, cty.store, cty.bounds);
+ let st = object_contents(cx, cty.bounds);
+
+ let st = match cty.store {
+ UniqTraitStore => {
+ st.owned_pointer()
+ }
+ RegionTraitStore(r, mutbl) => {
+ st.reference(borrowed_contents(r, mutbl))
+ }
+ };
// This also prohibits "@once fn" from being copied, which allows it to
// be called. Neither way really makes much sense.
}
fn object_contents(cx: &ctxt,
- store: TraitStore,
bounds: BuiltinBounds)
-> TypeContents {
// These are the type contents of the (opaque) interior
- let contents = kind_bounds_to_contents(cx, bounds, []);
-
- match store {
- UniqTraitStore => {
- contents.owned_pointer()
- }
- RegionTraitStore(r, mutbl) => {
- contents.reference(borrowed_contents(r, mutbl))
- }
- }
+ kind_bounds_to_contents(cx, bounds, [])
}
fn kind_bounds_to_contents(cx: &ctxt,
pub fn type_is_trait(ty: t) -> bool {
match get(ty).sty {
+ ty_uniq(ty) | ty_rptr(_, mt { ty, ..}) => match get(ty).sty {
+ ty_trait(..) => true,
+ _ => false
+ },
ty_trait(..) => true,
_ => false
}
match get(t).sty {
ty_box(typ) | ty_uniq(typ) => match get(typ).sty {
// Don't deref ~[] etc., might need to generalise this to all DST.
- ty_vec(_, None) | ty_str => None,
+ ty_vec(_, None) | ty_str | ty_trait(..) => None,
_ => Some(mt {
ty: typ,
mutbl: ast::MutImmutable,
},
ty_rptr(_, mt) => match get(mt.ty).sty {
// Don't deref &[], might need to generalise this to all DST.
- ty_vec(_, None) | ty_str => None,
+ ty_vec(_, None) | ty_str | ty_trait(..) => None,
_ => Some(mt),
},
ty_ptr(mt) if explicit => Some(mt),
}
AutoObject(store, bounds, def_id, ref substs) => {
- mk_trait(cx, def_id, substs.clone(), store, bounds)
+
+ let tr = mk_trait(cx, def_id, substs.clone(), bounds);
+ match store {
+ UniqTraitStore => {
+ mk_uniq(cx, tr)
+ }
+ RegionTraitStore(r, m) => {
+ mk_rptr(cx, r, mt {
+ ty: tr,
+ mutbl: m
+ })
+ }
+ }
}
}
}
fn borrow_obj(cx: &ctxt, span: Span, r: Region,
m: ast::Mutability, ty: ty::t) -> ty::t {
match get(ty).sty {
- ty_trait(box ty::TyTrait {def_id, ref substs, bounds, .. }) => {
- ty::mk_trait(cx, def_id, substs.clone(),
- RegionTraitStore(r, m), bounds)
- }
+ ty_uniq(t) | ty_rptr(_, mt{ty: t, ..}) => match get(t).sty {
+ ty_trait(box ty::TyTrait {def_id, ref substs, bounds, .. }) => {
+ mk_rptr(cx, r, mt {
+ ty: ty::mk_trait(cx, def_id, substs.clone(), bounds),
+ mutbl: m
+ })
+ }
+ _ => {
+ cx.sess.span_bug(
+ span,
+ format!("borrow-trait-obj associated with bad sty: {:?}",
+ get(ty).sty).as_slice());
+ }
+ },
ref s => {
cx.sess.span_bug(
span,
let substs = Substs::empty();
let trait_ref = Rc::new(TraitRef { def_id: trait_lang_item, substs: substs });
Ok((trait_ref.clone(),
- mk_trait(tcx,
- trait_ref.def_id,
- trait_ref.substs.clone(),
- RegionTraitStore(region, ast::MutMutable),
- empty_builtin_bounds())))
+ mk_rptr(tcx, region, mt {mutbl: ast::MutMutable,
+ ty: mk_trait(tcx,
+ trait_ref.def_id,
+ trait_ref.substs.clone(),
+ empty_builtin_bounds()) })))
}
pub fn item_variances(tcx: &ctxt, item_id: ast::DefId) -> Rc<ItemVariances> {
}
}
}
- ty_trait(box ty::TyTrait { def_id: d, store, bounds, .. }) => {
+ ty_trait(box ty::TyTrait { def_id: d, bounds, .. }) => {
byte!(17);
did(&mut state, d);
- match store {
- UniqTraitStore => byte!(0),
- RegionTraitStore(r, m) => {
- byte!(1)
- region(&mut state, r);
- hash!(m);
- }
- }
hash!(bounds);
}
ty_struct(d, _) => {
ty::ty_trait(box ty::TyTrait {
def_id,
ref substs,
- store,
bounds
}) => {
ty::ty_trait(box ty::TyTrait {
def_id: def_id,
substs: substs.fold_with(this),
- store: store.fold_with(this),
bounds: bounds
})
}
return constr(ty::mk_vec(tcx, mt, None));
}
ast::TyUnboxedFn(ref unboxed_function) => {
- let trait_store = match ptr_ty {
- Uniq => ty::UniqTraitStore,
+ let ty::TraitRef {
+ def_id,
+ substs
+ } = trait_ref_for_unboxed_function(this,
+ rscope,
+ &**unboxed_function,
+ None);
+ let tr = ty::mk_trait(this.tcx(),
+ def_id,
+ substs,
+ ty::empty_builtin_bounds());
+ match ptr_ty {
+ Uniq => {
+ return ty::mk_uniq(this.tcx(), tr);
+ }
RPtr(r) => {
- ty::RegionTraitStore(r, a_seq_ty.mutbl)
+ return ty::mk_rptr(this.tcx(),
+ r,
+ ty::mt {mutbl: a_seq_ty.mutbl, ty: tr});
}
_ => {
tcx.sess.span_err(
forms of casting-to-trait");
return ty::mk_err();
}
- };
- let ty::TraitRef {
- def_id,
- substs
- } = trait_ref_for_unboxed_function(this,
- rscope,
- &**unboxed_function,
- None);
- return ty::mk_trait(this.tcx(),
- def_id,
- substs,
- trait_store,
- ty::empty_builtin_bounds());
+
+ }
}
ast::TyPath(ref path, ref bounds, id) => {
// Note that the "bounds must be empty if path is not a trait"
path.span,
bounds,
trait_store);
- return ty::mk_trait(tcx,
- result.def_id,
- result.substs.clone(),
- trait_store,
- bounds);
+ let tr = ty::mk_trait(tcx,
+ result.def_id,
+ result.substs.clone(),
+ bounds);
+ // We could just match on ptr_ty, but we need to pass a trait
+ // store to conv_builtin_bounds, so mathc twice for now.
+ return match trait_store {
+ ty::UniqTraitStore => {
+ return ty::mk_uniq(tcx, tr);
+ }
+ ty::RegionTraitStore(r, m) => {
+ return ty::mk_rptr(tcx, r, ty::mt{mutbl: m, ty: tr});
+ }
+ }
}
_ => {}
}
fcx.write_ty(pat_id, expected);
};
match *structure_of(fcx, span, expected) {
- ty::ty_uniq(e_inner) if pointer_kind == Send => {
+ ty::ty_uniq(e_inner) if pointer_kind == Send && !ty::type_is_trait(e_inner) => {
check_inner(e_inner);
}
- ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed => {
+ ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed && !ty::type_is_trait(e_inner.ty) => {
check_inner(e_inner.ty);
}
_ => {
match ty::get(transformed_self_ty).sty {
ty::ty_rptr(r, mt) => { // must be SelfRegion
let r = r.subst(tcx, rcvr_substs); // handle Early-Bound lifetime
- ty::mk_trait(tcx, trait_def_id, obj_substs,
- RegionTraitStore(r, mt.mutbl),
- ty::empty_builtin_bounds())
+ let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
+ ty::empty_builtin_bounds());
+ ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: mt.mutbl })
}
ty::ty_uniq(_) => { // must be SelfUniq
- ty::mk_trait(tcx, trait_def_id, obj_substs,
- UniqTraitStore,
- ty::empty_builtin_bounds())
+ let tr = ty::mk_trait(tcx, trait_def_id, obj_substs,
+ ty::empty_builtin_bounds());
+ ty::mk_uniq(tcx, tr)
}
_ => {
tcx.sess.span_bug(span,
let span = self.self_expr.map_or(self.span, |e| e.span);
check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
match get(self_ty).sty {
- ty_trait(box TyTrait { def_id, ref substs, .. }) => {
- self.push_inherent_candidates_from_object(def_id, substs);
- self.push_inherent_impl_candidates_for_type(def_id);
- }
+ ty_uniq(ty) | ty_rptr(_, mt {ty, ..}) => match get(ty).sty{
+ ty_trait(box TyTrait { def_id, ref substs, .. }) => {
+ self.push_inherent_candidates_from_object(def_id, substs);
+ self.push_inherent_impl_candidates_for_type(def_id);
+ }
+ _ => {}
+ },
ty_enum(did, _) | ty_struct(did, _) => {
if self.check_traits == CheckTraitsAndInherentMethods {
self.push_inherent_impl_candidates_for_type(did);
let (extra_derefs, auto) = match ty::get(self_mt.ty).sty {
ty::ty_vec(_, None) => (0, ty::AutoBorrowVec(region, self_mt.mutbl)),
ty::ty_str => (0, ty::AutoBorrowVec(region, self_mt.mutbl)),
+ ty::ty_trait(..) => (0, ty::AutoBorrowObj(region, self_mt.mutbl)),
_ => (1, ty::AutoPtr(region, self_mt.mutbl)),
};
(ty::mk_rptr(tcx, region, self_mt),
autoderefs: autoderefs + extra_derefs,
autoref: Some(auto)})
}
-
- ty::ty_trait(box ty::TyTrait {
- def_id, ref substs, store: ty::RegionTraitStore(_, mutbl), bounds
- }) => {
- let region =
- self.infcx().next_region_var(infer::Autoref(self.span));
- (ty::mk_trait(tcx, def_id, substs.clone(),
- ty::RegionTraitStore(region, mutbl), bounds),
- ty::AutoDerefRef {
- autoderefs: autoderefs,
- autoref: Some(ty::AutoBorrowObj(region, mutbl))})
- }
_ => {
(self_ty,
ty::AutoDerefRef {
})
}
+ // Coerce Box/&Trait instances to &Trait.
+ fn auto_slice_trait(&self, ty: ty::t, autoderefs: uint) -> Option<MethodCallee> {
+ match ty::get(ty).sty {
+ ty_trait(box ty::TyTrait {
+ def_id: trt_did,
+ substs: ref trt_substs,
+ bounds: b,
+ .. }) => {
+ let tcx = self.tcx();
+ self.search_for_some_kind_of_autorefd_method(
+ AutoBorrowObj, autoderefs, [MutImmutable, MutMutable],
+ |m, r| {
+ let tr = ty::mk_trait(tcx, trt_did, trt_substs.clone(), b);
+ ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: m })
+ })
+ }
+ _ => fail!("Expected ty_trait in auto_slice_trait")
+ }
+ }
+
fn search_for_autosliced_method(&self,
self_ty: ty::t,
autoderefs: uint)
* `~[]` to `&[]`.
*/
- let tcx = self.tcx();
- debug!("search_for_autosliced_method {}", ppaux::ty_to_str(tcx, self_ty));
+ debug!("search_for_autosliced_method {}", ppaux::ty_to_str(self.tcx(), self_ty));
let sty = ty::get(self_ty).sty.clone();
match sty {
ty_rptr(_, mt) => match ty::get(mt.ty).sty {
ty_vec(mt, None) => self.auto_slice_vec(mt, autoderefs),
+ ty_trait(..) => self.auto_slice_trait(mt.ty, autoderefs),
_ => None
},
ty_uniq(t) => match ty::get(t).sty {
ty_vec(mt, None) => self.auto_slice_vec(mt, autoderefs),
ty_str => self.auto_slice_str(autoderefs),
+ ty_trait(..) => self.auto_slice_trait(t, autoderefs),
_ => None
},
ty_vec(mt, Some(_)) => self.auto_slice_vec(mt, autoderefs),
- ty_trait(box ty::TyTrait {
- def_id: trt_did,
- substs: trt_substs,
- bounds: b,
- ..
- }) => {
- // Coerce Box/&Trait instances to &Trait.
-
- self.search_for_some_kind_of_autorefd_method(
- AutoBorrowObj, autoderefs, [MutImmutable, MutMutable],
- |m, r| {
- ty::mk_trait(tcx, trt_did, trt_substs.clone(),
- RegionTraitStore(r, m), b)
- })
- }
-
ty_closure(..) => {
// This case should probably be handled similarly to
// Trait instances.
ty::ty_rptr(_, mt) => {
match ty::get(mt.ty).sty {
ty::ty_vec(_, None) | ty::ty_str => false,
+ ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => {
+ mutability_matches(mt.mutbl, m) &&
+ rcvr_matches_object(self_did, candidate)
+ }
_ => mutability_matches(mt.mutbl, m) &&
rcvr_matches_ty(self.fcx, mt.ty, candidate),
}
}
- ty::ty_trait(box ty::TyTrait {
- def_id: self_did, store: RegionTraitStore(_, self_m), ..
- }) => {
- mutability_matches(self_m, m) &&
- rcvr_matches_object(self_did, candidate)
- }
_ => false
}
ty::ty_uniq(typ) => {
match ty::get(typ).sty {
ty::ty_vec(_, None) | ty::ty_str => false,
+ ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => {
+ rcvr_matches_object(self_did, candidate)
+ }
_ => rcvr_matches_ty(self.fcx, typ, candidate),
}
}
- ty::ty_trait(box ty::TyTrait {
- def_id: self_did, store: UniqTraitStore, ..
- }) => {
- rcvr_matches_object(self_did, candidate)
- }
-
_ => false
}
}
else {
match ty::get(t_1).sty {
// This will be looked up later on
- ty::ty_trait(..) => (),
+ _ if ty::type_is_trait(t_1) => {},
_ => {
if ty::type_is_nil(t_e) {
// explaining how it goes about doing that.
let target_ty = rcx.resolve_node_type(expr.id);
match ty::get(target_ty).sty {
- ty::ty_trait(box ty::TyTrait {
- store: ty::RegionTraitStore(trait_region, _), ..
- }) => {
- let source_ty = rcx.resolve_expr_type_adjusted(&**source);
- constrain_regions_in_type(
- rcx,
- trait_region,
- infer::RelateObjectBound(expr.span),
- source_ty);
+ ty::ty_rptr(trait_region, ty::mt{ty, ..}) => {
+ match ty::get(ty).sty {
+ ty::ty_trait(..) => {
+ let source_ty = rcx.resolve_expr_type_adjusted(&**source);
+ constrain_regions_in_type(
+ rcx,
+ trait_region,
+ infer::RelateObjectBound(expr.span),
+ source_ty);
+ }
+ _ => {}
+ }
}
_ => ()
}
trait_ref: Rc<ty::TraitRef>,
is_early: bool)
-> Option<vtable_origin> {
+ debug!("nrc - search_for_vtable");
let tcx = vcx.tcx();
let mut found = Vec::new();
// use a dummy type just to package up the substs that need fixing up
let t = ty::mk_trait(tcx,
id, substs,
- ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
ty::empty_builtin_bounds());
fixup_ty(vcx, span, t, is_early).map(|t_f| {
match ty::get(t_f).sty {
}
pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
+ fn mutability_allowed(a_mutbl: ast::Mutability,
+ b_mutbl: ast::Mutability) -> bool {
+ a_mutbl == b_mutbl ||
+ (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
+ }
+
debug!("vtable: early_resolve_expr() ex with id {:?} (early: {}): {}",
ex.id, is_early, expr_to_str(ex));
let _indent = indenter();
let cx = fcx.ccx;
let resolve_object_cast = |src: &ast::Expr, target_ty: ty::t| {
- match ty::get(target_ty).sty {
- // Bounds of type's contents are not checked here, but in kind.rs.
- ty::ty_trait(box ty::TyTrait {
- def_id: target_def_id, substs: ref target_substs, store, ..
- }) => {
- fn mutability_allowed(a_mutbl: ast::Mutability,
- b_mutbl: ast::Mutability) -> bool {
- a_mutbl == b_mutbl ||
- (a_mutbl == ast::MutMutable && b_mutbl == ast::MutImmutable)
- }
- // Look up vtables for the type we're casting to,
- // passing in the source and target type. The source
- // must be a pointer type suitable to the object sigil,
- // e.g.: `&x as &Trait` or `box x as Box<Trait>`
- let ty = structurally_resolved_type(fcx, ex.span,
- fcx.expr_ty(src));
- match (&ty::get(ty).sty, store) {
- (&ty::ty_rptr(_, mt), ty::RegionTraitStore(_, mutbl))
- if !mutability_allowed(mt.mutbl, mutbl) => {
+ // Look up vtables for the type we're casting to,
+ // passing in the source and target type. The source
+ // must be a pointer type suitable to the object sigil,
+ // e.g.: `&x as &Trait` or `box x as Box<Trait>`
+ // Bounds of type's contents are not checked here, but in kind.rs.
+ let src_ty = structurally_resolved_type(fcx, ex.span,
+ fcx.expr_ty(src));
+ match (&ty::get(target_ty).sty, &ty::get(src_ty).sty) {
+ (&ty::ty_rptr(_, ty::mt{ty, mutbl}), &ty::ty_rptr(_, mt))
+ if !mutability_allowed(mt.mutbl, mutbl) => {
+ match ty::get(ty).sty {
+ ty::ty_trait(..) => {
fcx.tcx()
.sess
.span_err(ex.span, "types differ in mutability");
}
+ _ => {}
+ }
+ }
- (&ty::ty_uniq(..), ty::UniqTraitStore) |
- (&ty::ty_rptr(..), ty::RegionTraitStore(..)) => {
- let typ = match &ty::get(ty).sty {
- &ty::ty_box(typ) | &ty::ty_uniq(typ) => typ,
- &ty::ty_rptr(_, mt) => mt.ty,
- _ => fail!("shouldn't get here"),
- };
+ (&ty::ty_uniq(ty), &ty::ty_uniq(..) ) |
+ (&ty::ty_rptr(_, ty::mt{ty, ..}), &ty::ty_rptr(..)) => {
+ match ty::get(ty).sty {
+ ty::ty_trait(box ty::TyTrait {
+ def_id: target_def_id, substs: ref target_substs, ..
+ }) => {
+ debug!("nrc correct path");
+ let typ = match &ty::get(src_ty).sty {
+ &ty::ty_uniq(typ) => typ,
+ &ty::ty_rptr(_, mt) => mt.ty,
+ _ => fail!("shouldn't get here"),
+ };
let vcx = fcx.vtable_context();
// Now, if this is &trait, we need to link the
// regions.
- match (&ty::get(ty).sty, store) {
- (&ty::ty_rptr(ra, _),
- ty::RegionTraitStore(rb, _)) => {
+ match (&ty::get(src_ty).sty, &ty::get(target_ty).sty) {
+ (&ty::ty_rptr(ra, _), &ty::ty_rptr(rb, _)) => {
+ debug!("nrc - make subr");
infer::mk_subr(fcx.infcx(),
false,
- infer::RelateObjectBound(
- ex.span),
+ infer::RelateObjectBound(ex.span),
rb,
ra);
}
_ => {}
}
}
+ _ => {}
+ }
+ }
- (_, ty::UniqTraitStore) => {
+ (&ty::ty_uniq(ty), _) => {
+ match ty::get(ty).sty {
+ ty::ty_trait(..) => {
fcx.ccx.tcx.sess.span_err(
ex.span,
format!("can only cast an boxed pointer \
to a boxed object, not a {}",
- ty::ty_sort_str(fcx.tcx(), ty)).as_slice());
+ ty::ty_sort_str(fcx.tcx(), src_ty)).as_slice());
}
+ _ => {}
+ }
- (_, ty::RegionTraitStore(..)) => {
+ }
+ (&ty::ty_rptr(_, ty::mt{ty, ..}), _) => {
+ match ty::get(ty).sty {
+ ty::ty_trait(..) => {
fcx.ccx.tcx.sess.span_err(
ex.span,
format!("can only cast an &-pointer \
to an &-object, not a {}",
- ty::ty_sort_str(fcx.tcx(), ty)).as_slice());
+ ty::ty_sort_str(fcx.tcx(), src_ty)).as_slice());
}
+ _ => {}
}
}
- _ => { /* not a cast to a trait; ignore */ }
+
+ _ => {}
}
};
match ex.node {
ex.repr(fcx.tcx()),
is_early);
- let object_ty = ty::mk_trait(cx.tcx, def_id,
- substs.clone(),
- store, bounds);
+ let trait_ty = ty::mk_trait(cx.tcx,
+ def_id,
+ substs.clone(),
+ bounds);
+ let object_ty = match store {
+ ty::UniqTraitStore => ty::mk_uniq(cx.tcx, trait_ty),
+ ty::RegionTraitStore(r, m) => {
+ ty::mk_rptr(cx.tcx, r, ty::mt {ty: trait_ty, mutbl: m})
+ }
+ };
+
resolve_object_cast(ex, object_ty);
}
AutoAddEnv(..) => {}
}
match get(resolved_type).sty {
- ty_enum(..) | ty_trait(..) | ty_struct(..) => {
+ ty_enum(..) | ty_struct(..) => {
debug!("(getting base type) found base type");
Some(resolved_type)
}
+ // FIXME(14865) I would prefere to use `_` here, but that causes a
+ // compiler error.
+ ty_uniq(_) | ty_rptr(_, _) | ty_trait(..) if ty::type_is_trait(resolved_type) => {
+ debug!("(getting base type) found base type (trait)");
+ Some(resolved_type)
+ }
ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
get(original_type).sty);
None
}
+ ty_trait(..) => fail!("should have been caught")
}
}
found_nominal = true;
}
}
- ty_trait(box ty::TyTrait { def_id, ref store, .. }) => {
+ ty_trait(box ty::TyTrait { def_id, .. }) => {
if def_id.krate == ast::LOCAL_CRATE {
found_nominal = true;
}
- if *store == ty::UniqTraitStore {
- match tcx.lang_items.owned_box() {
- Some(did) if did.krate == ast::LOCAL_CRATE => {
- found_nominal = true;
- }
- _ => {}
- }
- }
}
ty_uniq(..) => {
match tcx.lang_items.owned_box() {
original_type: t)
-> Option<DefId> {
match get_base_type(inference_context, span, original_type) {
- None => {
- return None;
- }
+ None => None,
Some(base_type) => {
match get(base_type).sty {
ty_enum(def_id, _) |
- ty_struct(def_id, _) |
- ty_trait(box ty::TyTrait { def_id, .. }) => {
- return Some(def_id);
+ ty_struct(def_id, _) => {
+ Some(def_id)
}
+ ty_rptr(_, ty::mt {ty, ..}) | ty_uniq(ty) => match ty::get(ty).sty {
+ ty_trait(box ty::TyTrait { def_id, .. }) => {
+ Some(def_id)
+ }
+ _ => {
+ fail!("get_base_type() returned a type that wasn't an \
+ enum, struct, or trait");
+ }
+ },
_ => {
fail!("get_base_type() returned a type that wasn't an \
enum, struct, or trait");
// Note: does not attempt to resolve type variables we encounter.
// See above for details.
match ty::get(b).sty {
- ty::ty_rptr(_, mt_b) => {
+ ty::ty_rptr(r_b, mt_b) => {
match ty::get(mt_b.ty).sty {
ty::ty_vec(mt_b, None) => {
return self.unpack_actual_value(a, |sty_a| {
self.coerce_borrowed_string(a, sty_a, b)
});
}
+
+ ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => {
+ let result = self.unpack_actual_value(a, |sty_a| {
+ match *sty_a {
+ ty::ty_rptr(_, mt_a) => match ty::get(mt_a.ty).sty {
+ ty::ty_trait(..) => {
+ self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl)
+ }
+ _ => self.coerce_object(a, sty_a, b, def_id, substs,
+ ty::RegionTraitStore(r_b, mt_b.mutbl),
+ bounds)
+ },
+ _ => self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl)
+ }
+ });
+
+ match result {
+ Ok(t) => return Ok(t),
+ Err(..) => {}
+ }
+ }
+
_ => {
return self.unpack_actual_value(a, |sty_a| {
self.coerce_borrowed_pointer(a, sty_a, b, mt_b)
};
}
+ ty::ty_uniq(t_b) => {
+ match ty::get(t_b).sty {
+ ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => {
+ let result = self.unpack_actual_value(a, |sty_a| {
+ match *sty_a {
+ ty::ty_uniq(t_a) => match ty::get(t_a).sty {
+ ty::ty_trait(..) => {
+ Err(ty::terr_mismatch)
+ }
+ _ => self.coerce_object(a, sty_a, b, def_id, substs,
+ ty::UniqTraitStore, bounds)
+ },
+ _ => Err(ty::terr_mismatch)
+ }
+ });
+
+ match result {
+ Ok(t) => return Ok(t),
+ Err(..) => {}
+ }
+ }
+ _ => {}
+ }
+ }
+
ty::ty_closure(box ty::ClosureTy {
store: ty::RegionTraitStore(..),
..
});
}
- ty::ty_trait(box ty::TyTrait {
- def_id, ref substs, store: ty::UniqTraitStore, bounds
- }) => {
- let result = self.unpack_actual_value(a, |sty_a| {
- match *sty_a {
- ty::ty_uniq(..) => {
- self.coerce_object(a, sty_a, b, def_id, substs,
- ty::UniqTraitStore, bounds)
- }
- _ => Err(ty::terr_mismatch)
- }
- });
-
- match result {
- Ok(t) => return Ok(t),
- Err(..) => {}
- }
- }
-
- ty::ty_trait(box ty::TyTrait {
- def_id, ref substs, store: ty::RegionTraitStore(region, m), bounds
- }) => {
- let result = self.unpack_actual_value(a, |sty_a| {
- match *sty_a {
- ty::ty_rptr(..) => {
- self.coerce_object(a, sty_a, b, def_id, substs,
- ty::RegionTraitStore(region, m), bounds)
- }
- _ => self.coerce_borrowed_object(a, sty_a, b, m)
- }
- });
-
- match result {
- Ok(t) => return Ok(t),
- Err(..) => {}
- }
- }
-
_ => {}
}
let r_a = self.get_ref().infcx.next_region_var(coercion);
let a_borrowed = match *sty_a {
- ty::ty_trait(box ty::TyTrait {
- def_id,
- ref substs,
- bounds,
- ..
- }) => {
- ty::mk_trait(tcx, def_id, substs.clone(),
- ty::RegionTraitStore(r_a, b_mutbl), bounds)
- }
+ ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
+ ty::ty_trait(box ty::TyTrait {
+ def_id,
+ ref substs,
+ bounds,
+ ..
+ }) => {
+ let tr = ty::mk_trait(tcx, def_id, substs.clone(), bounds);
+ ty::mk_rptr(tcx, r_a, ty::mt{ mutbl: b_mutbl, ty: tr })
+ }
+ _ => {
+ return self.subtype(a, b);
+ }
+ },
_ => {
return self.subtype(a, b);
}
// so, for example, &T and &[U] should not unify. In fact the only thing
// &[U] should unify with is &[T]. We preserve that behaviour with this
// check.
- fn check_ptr_to_vec<C:Combine>(this: &C,
- a: ty::t,
- b: ty::t,
- a_inner: ty::t,
- b_inner: ty::t,
- result: ty::t) -> cres<ty::t> {
+ fn check_ptr_to_unsized<C:Combine>(this: &C,
+ a: ty::t,
+ b: ty::t,
+ a_inner: ty::t,
+ b_inner: ty::t,
+ result: ty::t) -> cres<ty::t> {
match (&ty::get(a_inner).sty, &ty::get(b_inner).sty) {
(&ty::ty_vec(_, None), &ty::ty_vec(_, None)) |
- (&ty::ty_str, &ty::ty_str) => Ok(result),
+ (&ty::ty_str, &ty::ty_str) |
+ (&ty::ty_trait(..), &ty::ty_trait(..)) => Ok(result),
(&ty::ty_vec(_, None), _) | (_, &ty::ty_vec(_, None)) |
- (&ty::ty_str, _) | (_, &ty::ty_str)
+ (&ty::ty_str, _) | (_, &ty::ty_str) |
+ (&ty::ty_trait(..), _) | (_, &ty::ty_trait(..))
=> Err(ty::terr_sorts(expected_found(this, a, b))),
_ => Ok(result),
}
if a_.def_id == b_.def_id => {
debug!("Trying to match traits {:?} and {:?}", a, b);
let substs = if_ok!(this.substs(a_.def_id, &a_.substs, &b_.substs));
- let s = if_ok!(this.trait_stores(ty::terr_trait, a_.store, b_.store));
let bounds = if_ok!(this.bounds(a_.bounds, b_.bounds));
Ok(ty::mk_trait(tcx,
a_.def_id,
substs.clone(),
- s,
bounds))
}
(&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => {
let typ = if_ok!(this.tys(a_inner, b_inner));
- check_ptr_to_vec(this, a, b, a_inner, b_inner, ty::mk_uniq(tcx, typ))
+ check_ptr_to_unsized(this, a, b, a_inner, b_inner, ty::mk_uniq(tcx, typ))
}
(&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => {
let mt = if_ok!(this.mts(a_mt, b_mt));
- check_ptr_to_vec(this, a, b, a_mt.ty, b_mt.ty, ty::mk_ptr(tcx, mt))
+ check_ptr_to_unsized(this, a, b, a_mt.ty, b_mt.ty, ty::mk_ptr(tcx, mt))
}
(&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => {
let r = if_ok!(this.contraregions(a_r, b_r));
- let mt = if_ok!(this.mts(a_mt, b_mt));
- check_ptr_to_vec(this, a, b, a_mt.ty, b_mt.ty, ty::mk_rptr(tcx, r, mt))
+ // FIXME(14985) If we have mutable references to trait objects, we
+ // used to use covariant subtyping. I have preserved this behaviour,
+ // even though it is probably incorrect. So don't go down the usual
+ // path which would require invariance.
+ let mt = match (&ty::get(a_mt.ty).sty, &ty::get(b_mt.ty).sty) {
+ (&ty::ty_trait(..), &ty::ty_trait(..)) if a_mt.mutbl == b_mt.mutbl => {
+ let ty = if_ok!(this.tys(a_mt.ty, b_mt.ty));
+ ty::mt { ty: ty, mutbl: a_mt.mutbl }
+ }
+ _ => if_ok!(this.mts(a_mt, b_mt))
+ };
+ check_ptr_to_unsized(this, a, b, a_mt.ty, b_mt.ty, ty::mk_rptr(tcx, r, mt))
}
(&ty::ty_vec(ref a_mt, sz_a), &ty::ty_vec(ref b_mt, sz_b)) => {
let dummy0 = ty::mk_trait(self.tcx,
trait_ref.def_id,
trait_ref.substs.clone(),
- ty::UniqTraitStore,
ty::empty_builtin_bounds());
let dummy1 = self.resolve_type_vars_if_possible(dummy0);
match ty::get(dummy1).sty {
parameterized(cx, base.as_slice(), substs, &generics)
}
ty_trait(box ty::TyTrait {
- def_id: did, ref substs, store, ref bounds
+ def_id: did, ref substs, ref bounds
}) => {
let base = ty::item_path_str(cx, did);
let trait_def = ty::lookup_trait_def(cx, did);
substs, &trait_def.generics);
let bound_sep = if bounds.is_empty() { "" } else { ":" };
let bound_str = bounds.repr(cx);
- format!("{}{}{}{}",
- trait_store_to_str(cx, store),
+ format!("{}{}{}",
ty,
bound_sep,
bound_str)
use std::fmt;
use std::io::MemWriter;
use std::io;
-use std::mem::swap;
+use std::mem::{swap,transmute};
use std::num;
use std::str::ScalarValue;
use std::str;
pub fn buffer_encode<T:Encodable<Encoder<'a>, io::IoError>>(to_encode_object: &T) -> Vec<u8> {
//Serialize the object in a string using a writer
let mut m = MemWriter::new();
- {
+ // FIXME(14302) remove the transmute and unsafe block.
+ unsafe {
let mut encoder = Encoder::new(&mut m as &mut io::Writer);
// MemWriter never Errs
- let _ = to_encode_object.encode(&mut encoder);
+ let _ = to_encode_object.encode(transmute(&mut encoder));
}
m.unwrap()
}
// ref #12967, make sure to wrap a key in double quotes,
// in the event that its of a type that omits them (eg numbers)
let mut buf = MemWriter::new();
- let mut check_encoder = Encoder::new(&mut buf);
- try!(f(&mut check_encoder));
+ // FIXME(14302) remove the transmute and unsafe block.
+ unsafe {
+ let mut check_encoder = Encoder::new(&mut buf);
+ try!(f(transmute(&mut check_encoder)));
+ }
let buf = buf.unwrap();
let out = from_utf8(buf.as_slice()).unwrap();
let needs_wrapping = out.char_at(0) != '"' &&
// ref #12967, make sure to wrap a key in double quotes,
// in the event that its of a type that omits them (eg numbers)
let mut buf = MemWriter::new();
- let mut check_encoder = PrettyEncoder::new(&mut buf);
- try!(f(&mut check_encoder));
+ // FIXME(14302) remove the transmute and unsafe block.
+ unsafe {
+ let mut check_encoder = PrettyEncoder::new(&mut buf);
+ try!(f(transmute(&mut check_encoder)));
+ }
let buf = buf.unwrap();
let out = from_utf8(buf.as_slice()).unwrap();
let needs_wrapping = out.char_at(0) != '"' &&
use ast::*;
use ast;
use ast_util;
+use attr::{InlineNever, InlineNone};
+use attr;
use codemap;
use codemap::Span;
use owned_slice::OwnedSlice;
}
}
+/// Returns true if the static with the given mutability and attributes
+/// has a significant address and false otherwise.
+pub fn static_has_significant_address(mutbl: ast::Mutability,
+ attrs: &[ast::Attribute])
+ -> bool {
+ if mutbl == ast::MutMutable {
+ return true
+ }
+ let inline = attr::find_inline_attr(attrs);
+ inline == InlineNever || inline == InlineNone
+}
#[cfg(test)]
mod test {
}).collect()
}
-/**
- * From a list of crate attributes get only the meta_items that affect crate
- * linkage
- */
-pub fn find_linkage_metas(attrs: &[Attribute]) -> Vec<Gc<MetaItem>> {
- let mut result = Vec::new();
- for attr in attrs.iter().filter(|at| at.check_name("link")) {
- match attr.meta().node {
- MetaList(_, ref items) => result.push_all(items.as_slice()),
- _ => ()
- }
- }
- result
-}
-
pub fn find_crateid(attrs: &[Attribute]) -> Option<CrateId> {
match first_attr_value_str_by_name(attrs, "crate_id") {
None => None,
/// These attributes are applied to all statics that this syntax extension
/// will generate.
fn static_attrs(&self) -> Vec<ast::Attribute> {
- // Flag statics as `address_insignificant` so LLVM can merge duplicate
- // globals as much as possible (which we're generating a whole lot of).
- let unnamed = self.ecx
- .meta_word(self.fmtsp,
- InternedString::new(
- "address_insignificant"));
- let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
-
// Do not warn format string as dead code
let dead_code = self.ecx.meta_word(self.fmtsp,
InternedString::new("dead_code"));
InternedString::new("allow"),
vec!(dead_code));
let allow_dead_code = self.ecx.attribute(self.fmtsp, allow_dead_code);
- return vec!(unnamed, allow_dead_code);
+ return vec!(allow_dead_code);
}
fn rtpath(&self, s: &str) -> Vec<ast::Ident> {
use serialize::{json, Encodable};
use std::io;
use std::io::MemWriter;
+ use std::mem::transmute;
use std::str;
use std::gc::GC;
use codemap::{Span, BytePos, Spanned};
fn to_json_str<'a, E: Encodable<json::Encoder<'a>, io::IoError>>(val: &E) -> String {
let mut writer = MemWriter::new();
- let mut encoder = json::Encoder::new(&mut writer as &mut io::Writer);
- let _ = val.encode(&mut encoder);
+ // FIXME(14302) remove the transmute and unsafe block.
+ unsafe {
+ let mut encoder = json::Encoder::new(&mut writer as &mut io::Writer);
+ let _ = val.encode(transmute(&mut encoder));
+ }
str::from_utf8(writer.unwrap().as_slice()).unwrap().to_string()
}
// except according to those terms.
pub fn foo<T>() -> int {
- #[address_insignificant]
static a: int = 3;
a
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#[inline(never)]
pub static global: int = 3;
+#[inline(never)]
static global0: int = 4;
+
+#[inline(never)]
pub static global2: &'static int = &global0;
pub fn verify_same(a: &'static int) {