BOOM times 1!!!
```
-The TNT goes off before the firecracker does, because it was declared
+The `tnt` goes off before the `firecracker` does, because it was declared
afterwards. Last in, first out.
So what is `Drop` good for? Generally, `Drop` is used to clean up any resources
//! them cheap and safe to copy. For other types copies must be made
//! explicitly, by convention implementing the `Clone` trait and calling
//! the `clone` method.
+//!
+//! Basic usage example:
+//!
+//! ```
+//! let s = String::new(); // String type implements Clone
+//! let copy = s.clone(); // so we can clone it
+//! ```
+//!
+//! To easily implement the Clone trait, you can also use
+//! `#[derive(Clone)]`. Example:
+//!
+//! ```
+//! #[derive(Clone)] // we add the Clone trait to Morpheus struct
+//! struct Morpheus {
+//! blue_pill: f32,
+//! red_pill: i64,
+//! }
+//!
+//! fn main() {
+//! let f = Morpheus { blue_pill: 0.0, red_pill: 0 };
+//! let copy = f.clone(); // and now we can clone it!
+//! }
+//! ```
#![stable(feature = "rust1", since = "1.0.0")]
//! let msg = Some("howdy");
//!
//! // Take a reference to the contained string
-//! match msg {
-//! Some(ref m) => println!("{}", *m),
-//! None => (),
+//! if let Some(ref m) = msg {
+//! println!("{}", *m);
//! }
//!
//! // Remove the contained string, destroying the Option
-//! let unwrapped_msg = match msg {
-//! Some(m) => m,
-//! None => "default message",
-//! };
+//! let unwrapped_msg = msg.unwrap_or("default message");
//! ```
//!
//! Initialize a result to `None` before a loop:
"two overlapping inherent impls define an item with the same name were erroneously allowed"
}
+declare_lint! {
+ pub RENAMED_AND_REMOVED_LINTS,
+ Warn,
+ "lints that have been renamed or removed"
+}
+
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
CONST_ERR,
RAW_POINTER_DERIVE,
TRANSMUTE_FROM_FN_ITEM_TYPES,
- OVERLAPPING_INHERENT_IMPLS
+ OVERLAPPING_INHERENT_IMPLS,
+ RENAMED_AND_REMOVED_LINTS
)
}
}
}
}
-enum CheckLintNameResult<'a> {
+enum CheckLintNameResult {
Ok,
// Lint doesn't exist
NoLint,
- // The lint is either renamed or removed and a warning was
- // generated in the DiagnosticBuilder
- Mentioned(DiagnosticBuilder<'a>)
+ // The lint is either renamed or removed. This is the warning
+ // message.
+ Warning(String)
}
/// Checks the name of a lint for its existence, and whether it was
/// it emits non-fatal warnings and there are *two* lint passes that
/// inspect attributes, this is only run from the late pass to avoid
/// printing duplicate warnings.
-fn check_lint_name<'a>(sess: &'a Session,
- lint_cx: &LintStore,
- lint_name: &str,
- span: Option<Span>) -> CheckLintNameResult<'a> {
+fn check_lint_name(lint_cx: &LintStore,
+ lint_name: &str) -> CheckLintNameResult {
match lint_cx.by_name.get(lint_name) {
Some(&Renamed(ref new_name, _)) => {
- let warning = format!("lint {} has been renamed to {}",
- lint_name, new_name);
- let db = match span {
- Some(span) => sess.struct_span_warn(span, &warning[..]),
- None => sess.struct_warn(&warning[..]),
- };
- CheckLintNameResult::Mentioned(db)
+ CheckLintNameResult::Warning(
+ format!("lint {} has been renamed to {}", lint_name, new_name)
+ )
},
Some(&Removed(ref reason)) => {
- let warning = format!("lint {} has been removed: {}", lint_name, reason);
- let db = match span {
- Some(span) => sess.struct_span_warn(span, &warning[..]),
- None => sess.struct_warn(&warning[..])
- };
- CheckLintNameResult::Mentioned(db)
+ CheckLintNameResult::Warning(
+ format!("lint {} has been removed: {}", lint_name, reason)
+ )
},
None => {
match lint_cx.lint_groups.get(lint_name) {
continue;
}
Ok((lint_name, _, span)) => {
- match check_lint_name(&cx.tcx.sess, &cx.lints, &lint_name[..], Some(span)) {
+ match check_lint_name(&cx.lints,
+ &lint_name[..]) {
CheckLintNameResult::Ok => (),
- CheckLintNameResult::Mentioned(mut db) => {
- db.emit();
+ CheckLintNameResult::Warning(ref msg) => {
+ cx.span_lint(builtin::RENAMED_AND_REMOVED_LINTS,
+ span, msg);
}
CheckLintNameResult::NoLint => {
cx.span_lint(builtin::UNKNOWN_LINTS, span,
// Checks the validity of lint names derived from the command line
fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore,
lint_name: &str, level: Level) {
- let db = match check_lint_name(sess, lint_cx, lint_name, None) {
+ let db = match check_lint_name(lint_cx, lint_name) {
CheckLintNameResult::Ok => None,
- CheckLintNameResult::Mentioned(db) => Some(db),
+ CheckLintNameResult::Warning(ref msg) => {
+ Some(sess.struct_warn(msg))
+ },
CheckLintNameResult::NoLint => {
Some(sess.struct_err(&format!("unknown lint: `{}`", lint_name)))
}
// Type substitutions.
pub use self::ParamSpace::*;
-pub use self::RegionSubsts::*;
use middle::cstore;
use middle::def_id::DefId;
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Substs<'tcx> {
pub types: VecPerParamSpace<Ty<'tcx>>,
- pub regions: RegionSubsts,
-}
-
-/// Represents the values to use when substituting lifetime parameters.
-/// If the value is `ErasedRegions`, then this subst is occurring during
-/// trans, and all region parameters will be replaced with `ty::ReStatic`.
-#[derive(Clone, PartialEq, Eq, Hash)]
-pub enum RegionSubsts {
- ErasedRegions,
- NonerasedRegions(VecPerParamSpace<ty::Region>)
+ pub regions: VecPerParamSpace<ty::Region>,
}
impl<'tcx> Substs<'tcx> {
r: VecPerParamSpace<ty::Region>)
-> Substs<'tcx>
{
- Substs { types: t, regions: NonerasedRegions(r) }
+ Substs { types: t, regions: r }
}
pub fn new_type(t: Vec<Ty<'tcx>>,
VecPerParamSpace::new(r, Vec::new(), Vec::new()))
}
- pub fn erased(t: VecPerParamSpace<Ty<'tcx>>) -> Substs<'tcx>
- {
- Substs { types: t, regions: ErasedRegions }
- }
-
pub fn empty() -> Substs<'tcx> {
Substs {
types: VecPerParamSpace::empty(),
- regions: NonerasedRegions(VecPerParamSpace::empty()),
- }
- }
-
- pub fn trans_empty() -> Substs<'tcx> {
- Substs {
- types: VecPerParamSpace::empty(),
- regions: ErasedRegions
+ regions: VecPerParamSpace::empty(),
}
}
pub fn is_noop(&self) -> bool {
- let regions_is_noop = match self.regions {
- ErasedRegions => false, // may be used to canonicalize
- NonerasedRegions(ref regions) => regions.is_empty(),
- };
-
- regions_is_noop && self.types.is_empty()
+ self.regions.is_empty() && self.types.is_empty()
}
pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> {
}
pub fn erase_regions(self) -> Substs<'tcx> {
- let Substs { types, regions: _ } = self;
- Substs { types: types, regions: ErasedRegions }
- }
-
- /// Since ErasedRegions are only to be used in trans, most of the compiler can use this method
- /// to easily access the set of region substitutions.
- pub fn regions<'a>(&'a self) -> &'a VecPerParamSpace<ty::Region> {
- match self.regions {
- ErasedRegions => panic!("Erased regions only expected in trans"),
- NonerasedRegions(ref r) => r
- }
- }
-
- /// Since ErasedRegions are only to be used in trans, most of the compiler can use this method
- /// to easily access the set of region substitutions.
- pub fn mut_regions<'a>(&'a mut self) -> &'a mut VecPerParamSpace<ty::Region> {
- match self.regions {
- ErasedRegions => panic!("Erased regions only expected in trans"),
- NonerasedRegions(ref mut r) => r
- }
+ let Substs { types, regions } = self;
+ let regions = regions.map(|_| ty::ReStatic);
+ Substs { types: types, regions: regions }
}
pub fn with_method(self,
{
let Substs { types, regions } = self;
let types = types.with_slice(FnSpace, &m_types);
- let regions = regions.map(|r| r.with_slice(FnSpace, &m_regions));
+ let regions = regions.with_slice(FnSpace, &m_regions);
Substs { types: types, regions: regions }
}
{
let Substs { types, regions } = self.clone();
let types = types.with_slice(FnSpace, meth_substs.types.get_slice(FnSpace));
- let regions = regions.map(|r| {
- r.with_slice(FnSpace, meth_substs.regions().get_slice(FnSpace))
- });
+ let regions = regions.with_slice(FnSpace, meth_substs.regions.get_slice(FnSpace));
Substs { types: types, regions: regions }
}
pub fn with_method_from_subst(self, other: &Substs<'tcx>) -> Substs<'tcx> {
let Substs { types, regions } = self;
let types = types.with_slice(FnSpace, other.types.get_slice(FnSpace));
- let regions = regions.map(|r| {
- r.with_slice(FnSpace, other.regions().get_slice(FnSpace))
- });
+ let regions = regions.with_slice(FnSpace, other.regions.get_slice(FnSpace));
Substs { types: types, regions: regions }
}
/// Creates a trait-ref out of this substs, ignoring the FnSpace substs
pub fn to_trait_ref(&self, tcx: &TyCtxt<'tcx>, trait_id: DefId)
-> ty::TraitRef<'tcx> {
- let Substs { mut types, regions } = self.clone();
+ let Substs { mut types, mut regions } = self.clone();
types.truncate(FnSpace, 0);
- let regions = regions.map(|mut r| { r.truncate(FnSpace, 0); r });
+ regions.truncate(FnSpace, 0);
ty::TraitRef {
def_id: trait_id,
}
}
-impl RegionSubsts {
- pub fn map<F>(self, op: F) -> RegionSubsts where
- F: FnOnce(VecPerParamSpace<ty::Region>) -> VecPerParamSpace<ty::Region>,
- {
- match self {
- ErasedRegions => ErasedRegions,
- NonerasedRegions(r) => NonerasedRegions(op(r))
- }
- }
-
- pub fn is_erased(&self) -> bool {
- match *self {
- ErasedRegions => true,
- NonerasedRegions(_) => false,
- }
- }
-}
-
///////////////////////////////////////////////////////////////////////////
// ParamSpace
// the specialized routine `ty::replace_late_regions()`.
match r {
ty::ReEarlyBound(data) => {
- match self.substs.regions {
- ErasedRegions => ty::ReStatic,
- NonerasedRegions(ref regions) =>
- match regions.opt_get(data.space, data.index as usize) {
- Some(&r) => {
- self.shift_region_through_binders(r)
- }
- None => {
- let span = self.span.unwrap_or(DUMMY_SP);
- self.tcx().sess.span_bug(
- span,
- &format!("Type parameter out of range \
- when substituting in region {} (root type={:?}) \
- (space={:?}, index={})",
- data.name,
- self.root_ty,
- data.space,
- data.index));
- }
- }
+ match self.substs.regions.opt_get(data.space, data.index as usize) {
+ Some(&r) => {
+ self.shift_region_through_binders(r)
+ }
+ None => {
+ let span = self.span.unwrap_or(DUMMY_SP);
+ self.tcx().sess.span_bug(
+ span,
+ &format!("Region parameter out of range \
+ when substituting in region {} (root type={:?}) \
+ (space={:?}, index={})",
+ data.name,
+ self.root_ty,
+ data.space,
+ data.index));
+ }
}
}
_ => r
specialization_graph::Node::Trait(..) => source_trait_ref.substs.clone(),
};
- // retain erasure mode
- // NB: this must happen before inheriting method generics below
- let target_substs = if source_substs.regions.is_erased() {
- target_substs.erase_regions()
- } else {
- target_substs
- };
-
// directly inherent the method generics, since those do not vary across impls
infcx.tcx.mk_substs(target_substs.with_method_from_subst(source_substs))
}
fn add_substs(&mut self, substs: &subst::Substs) {
self.add_tys(substs.types.as_slice());
- match substs.regions {
- subst::ErasedRegions => {}
- subst::NonerasedRegions(ref regions) => {
- for &r in regions {
- self.add_region(r);
- }
- }
+ for &r in &substs.regions {
+ self.add_region(r);
}
}
fn fold_substs(&mut self,
substs: &subst::Substs<'tcx>)
-> subst::Substs<'tcx> {
- subst::Substs { regions: subst::ErasedRegions,
+ subst::Substs { regions: substs.regions.fold_with(self),
types: substs.types.fold_with(self) }
}
}
Substs {
types: types,
- regions: subst::NonerasedRegions(regions)
+ regions: regions,
}
}
//! type equality, etc.
use middle::def_id::DefId;
-use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs};
+use middle::subst::{ParamSpace, Substs};
use middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use middle::ty::error::{ExpectedFound, TypeError};
use std::rc::Rc;
substs.types.replace(space, tps);
}
- match (&a_subst.regions, &b_subst.regions) {
- (&ErasedRegions, _) | (_, &ErasedRegions) => {
- substs.regions = ErasedRegions;
- }
-
- (&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => {
- for &space in &ParamSpace::all() {
- let a_regions = a.get_slice(space);
- let b_regions = b.get_slice(space);
- let r_variances = variances.map(|v| v.regions.get_slice(space));
- let regions = relate_region_params(relation,
- r_variances,
- a_regions,
- b_regions)?;
- substs.mut_regions().replace(space, regions);
- }
- }
+ for &space in &ParamSpace::all() {
+ let a_regions = a_subst.regions.get_slice(space);
+ let b_regions = b_subst.regions.get_slice(space);
+ let r_variances = variances.map(|v| v.regions.get_slice(space));
+ let regions = relate_region_params(relation,
+ r_variances,
+ a_regions,
+ b_regions)?;
+ substs.regions.replace(space, regions);
}
Ok(substs)
impl<'tcx> TypeFoldable<'tcx> for subst::Substs<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
- let regions = match self.regions {
- subst::ErasedRegions => subst::ErasedRegions,
- subst::NonerasedRegions(ref regions) => {
- subst::NonerasedRegions(regions.fold_with(folder))
- }
- };
-
- subst::Substs { regions: regions,
+ subst::Substs { regions: self.regions.fold_with(folder),
types: self.types.fold_with(folder) }
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- self.types.visit_with(visitor) || match self.regions {
- subst::ErasedRegions => false,
- subst::NonerasedRegions(ref regions) => regions.visit_with(visitor),
- }
+ self.types.visit_with(visitor) || self.regions.visit_with(visitor)
}
}
TyTrait(ref obj) => {
let mut v = vec![obj.bounds.region_bound];
v.extend_from_slice(obj.principal.skip_binder()
- .substs.regions().as_slice());
+ .substs.regions.as_slice());
v
}
TyEnum(_, substs) |
TyStruct(_, substs) => {
- substs.regions().as_slice().to_vec()
+ substs.regions.as_slice().to_vec()
}
TyClosure(_, ref substs) => {
- substs.func_substs.regions().as_slice().to_vec()
+ substs.func_substs.regions.as_slice().to_vec()
}
TyProjection(ref data) => {
- data.trait_ref.substs.regions().as_slice().to_vec()
+ data.trait_ref.substs.regions.as_slice().to_vec()
}
TyFnDef(..) |
TyFnPtr(_) |
};
if verbose {
- match substs.regions {
- subst::ErasedRegions => {
- start_or_continue(f, "<", ", ")?;
- write!(f, "..")?;
- }
- subst::NonerasedRegions(ref regions) => {
- for region in regions {
- start_or_continue(f, "<", ", ")?;
- write!(f, "{:?}", region)?;
- }
- }
+ for region in &substs.regions {
+ start_or_continue(f, "<", ", ")?;
+ write!(f, "{:?}", region)?;
}
for &ty in &substs.types {
start_or_continue(f, "<", ", ")?;
}
}
- match substs.regions {
- subst::ErasedRegions => { }
- subst::NonerasedRegions(ref regions) => {
- for &r in regions {
- start_or_continue(f, "<", ", ")?;
- let s = r.to_string();
- if s.is_empty() {
- // This happens when the value of the region
- // parameter is not easily serialized. This may be
- // because the user omitted it in the first place,
- // or because it refers to some block in the code,
- // etc. I'm not sure how best to serialize this.
- write!(f, "'_")?;
- } else {
- write!(f, "{}", s)?;
- }
- }
+ for &r in &substs.regions {
+ start_or_continue(f, "<", ", ")?;
+ let s = r.to_string();
+ if s.is_empty() {
+ // This happens when the value of the region
+ // parameter is not easily serialized. This may be
+ // because the user omitted it in the first place,
+ // or because it refers to some block in the code,
+ // etc. I'm not sure how best to serialize this.
+ write!(f, "'_")?;
+ } else {
+ write!(f, "{}", s)?;
}
}
}
}
-impl fmt::Debug for subst::RegionSubsts {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- subst::ErasedRegions => write!(f, "erased"),
- subst::NonerasedRegions(ref regions) => write!(f, "{:?}", regions)
- }
- }
-}
-
impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// when printing out the debug representation, we don't need
use syntax::codemap::{self, Span};
use rustc_front::hir;
-use rustc_front::intravisit::{self, Visitor};
use rustc_front::util::is_shift_binop;
register_long_diagnostics! {
false
}
-fn ast_ty_to_normalized<'tcx>(tcx: &TyCtxt<'tcx>,
- id: ast::NodeId)
- -> Ty<'tcx> {
- let tty = match tcx.ast_ty_to_ty_cache.borrow().get(&id) {
- Some(&t) => t,
- None => panic!("ast_ty_to_ty_cache was incomplete after typeck!")
- };
- infer::normalize_associated_type(tcx, &tty)
-}
-
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// Check if the given type is "ffi-safe" (has a stable, well-defined
/// representation which can be exported to C code).
}
}
- fn check_def(&mut self, sp: Span, id: ast::NodeId) {
- let tty = ast_ty_to_normalized(self.cx.tcx, id);
+ fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
+ // it is only OK to use this function because extern fns cannot have
+ // any generic types right now:
+ let ty = infer::normalize_associated_type(self.cx.tcx, &ty);
- match ImproperCTypesVisitor::check_type_for_ffi(self, &mut FnvHashSet(), tty) {
+ match self.check_type_for_ffi(&mut FnvHashSet(), ty) {
FfiResult::FfiSafe => {}
FfiResult::FfiUnsafe(s) => {
self.cx.span_lint(IMPROPER_CTYPES, sp, s);
}
}
}
-}
-impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> {
- fn visit_ty(&mut self, ty: &hir::Ty) {
- match ty.node {
- hir::TyPath(..) |
- hir::TyBareFn(..) => self.check_def(ty.span, ty.id),
- hir::TyVec(..) => {
- self.cx.span_lint(IMPROPER_CTYPES, ty.span,
- "found Rust slice type in foreign module, consider \
- using a raw pointer instead");
- }
- hir::TyFixedLengthVec(ref ty, _) => self.visit_ty(ty),
- hir::TyTup(..) => {
- self.cx.span_lint(IMPROPER_CTYPES, ty.span,
- "found Rust tuple type in foreign module; \
- consider using a struct instead`")
+ fn check_foreign_fn(&mut self, id: ast::NodeId, decl: &hir::FnDecl) {
+ let def_id = self.cx.tcx.map.local_def_id(id);
+ let scheme = self.cx.tcx.lookup_item_type(def_id);
+ let sig = scheme.ty.fn_sig();
+ let sig = self.cx.tcx.erase_late_bound_regions(&sig);
+
+ for (&input_ty, input_hir) in sig.inputs.iter().zip(&decl.inputs) {
+ self.check_type_for_ffi_and_report_errors(input_hir.ty.span, &input_ty);
+ }
+
+ if let hir::Return(ref ret_hir) = decl.output {
+ let ret_ty = sig.output.unwrap();
+ if !ret_ty.is_nil() {
+ self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty);
}
- _ => intravisit::walk_ty(self, ty)
}
}
+
+ fn check_foreign_static(&mut self, id: ast::NodeId, span: Span) {
+ let def_id = self.cx.tcx.map.local_def_id(id);
+ let scheme = self.cx.tcx.lookup_item_type(def_id);
+ self.check_type_for_ffi_and_report_errors(span, scheme.ty);
+ }
}
#[derive(Copy, Clone)]
impl LateLintPass for ImproperCTypes {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
- fn check_ty(cx: &LateContext, ty: &hir::Ty) {
- let mut vis = ImproperCTypesVisitor { cx: cx };
- vis.visit_ty(ty);
- }
-
- fn check_foreign_fn(cx: &LateContext, decl: &hir::FnDecl) {
- for input in &decl.inputs {
- check_ty(cx, &input.ty);
- }
- if let hir::Return(ref ret_ty) = decl.output {
- let tty = ast_ty_to_normalized(cx.tcx, ret_ty.id);
- if !tty.is_nil() {
- check_ty(cx, &ret_ty);
- }
- }
- }
-
+ let mut vis = ImproperCTypesVisitor { cx: cx };
if let hir::ItemForeignMod(ref nmod) = it.node {
if nmod.abi != Abi::RustIntrinsic && nmod.abi != Abi::PlatformIntrinsic {
for ni in &nmod.items {
match ni.node {
- hir::ForeignItemFn(ref decl, _) => check_foreign_fn(cx, &decl),
- hir::ForeignItemStatic(ref t, _) => check_ty(cx, &t)
+ hir::ForeignItemFn(ref decl, _) => {
+ vis.check_foreign_fn(ni.id, decl);
+ }
+ hir::ForeignItemStatic(ref ty, _) => {
+ vis.check_foreign_static(ni.id, ty.span);
+ }
}
}
}
}
pub fn parse_substs(&mut self) -> subst::Substs<'tcx> {
- let regions = self.parse_region_substs();
+ let regions = self.parse_vec_per_param_space(|this| this.parse_region());
let types = self.parse_vec_per_param_space(|this| this.parse_ty());
subst::Substs { types: types, regions: regions }
}
- fn parse_region_substs(&mut self) -> subst::RegionSubsts {
- match self.next() {
- 'e' => subst::ErasedRegions,
- 'n' => {
- subst::NonerasedRegions(
- self.parse_vec_per_param_space(|this| this.parse_region()))
- }
- _ => panic!("parse_bound_region: bad input")
- }
- }
-
fn parse_bound_region(&mut self) -> ty::BoundRegion {
match self.next() {
'a' => {
pub fn enc_substs<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
substs: &subst::Substs<'tcx>) {
- enc_region_substs(w, cx, &substs.regions);
+ enc_vec_per_param_space(w, cx, &substs.regions,
+ |w, cx, &r| enc_region(w, cx, r));
enc_vec_per_param_space(w, cx, &substs.types,
|w, cx, &ty| enc_ty(w, cx, ty));
}
-fn enc_region_substs(w: &mut Cursor<Vec<u8>>, cx: &ctxt, substs: &subst::RegionSubsts) {
- match *substs {
- subst::ErasedRegions => {
- write!(w, "e");
- }
- subst::NonerasedRegions(ref regions) => {
- write!(w, "n");
- enc_vec_per_param_space(w, cx, regions,
- |w, cx, &r| enc_region(w, cx, r));
- }
- }
-}
-
pub fn enc_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, r: ty::Region) {
match r {
ty::ReLateBound(id, br) => {
source_ty: Ty<'tcx>,
target_ty: Ty<'tcx>)
-> CustomCoerceUnsized {
- let trait_substs = Substs::erased(subst::VecPerParamSpace::new(vec![target_ty],
- vec![source_ty],
- Vec::new()));
+ let trait_substs = Substs::new(subst::VecPerParamSpace::new(vec![target_ty],
+ vec![source_ty],
+ Vec::new()),
+ subst::VecPerParamSpace::empty());
+
let trait_ref = ty::Binder(ty::TraitRef {
def_id: ccx.tcx().lang_items.coerce_unsized_trait().unwrap(),
substs: ccx.tcx().mk_substs(trait_substs)
ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
if collector::collecting_debug_information(ccx) {
- ccx.record_translation_item_as_generated(TransItem::Fn(Instance {
- def: def_id,
- params: ¶m_substs.types
- }))
+ ccx.record_translation_item_as_generated(
+ TransItem::Fn(Instance::new(def_id, param_substs)));
}
let _icx = push_ctxt("trans_closure");
// compilation unit that references the item, so it will still get
// translated everywhere it's needed.
for (ref ccx, is_origin) in ccx.maybe_iter(!from_external && trans_everywhere) {
- let empty_substs = tcx.mk_substs(Substs::trans_empty());
let def_id = tcx.map.local_def_id(item.id);
+ let empty_substs = ccx.empty_substs_for_def_id(def_id);
let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
trans_fn(ccx, &decl, &body, llfn, empty_substs, item.id);
set_global_section(ccx, llfn, item);
if sig.generics.ty_params.is_empty() {
let trans_everywhere = attr::requests_inline(&impl_item.attrs);
for (ref ccx, is_origin) in ccx.maybe_iter(trans_everywhere) {
- let empty_substs = tcx.mk_substs(Substs::trans_empty());
let def_id = tcx.map.local_def_id(impl_item.id);
+ let empty_substs = ccx.empty_substs_for_def_id(def_id);
let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
trans_fn(ccx, &sig.decl, body, llfn, empty_substs, impl_item.id);
update_linkage(ccx, llfn, Some(impl_item.id),
Ok(id) => id,
Err(s) => ccx.sess().fatal(&s)
};
- let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
+ let empty_substs = ccx.tcx().mk_substs(Substs::empty());
let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx).val;
let args = {
let opaque_rust_main =
let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
//
- let empty_substs = tcx.mk_substs(Substs::trans_empty());
+ let empty_substs = tcx.mk_substs(Substs::empty());
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
block_arena = TypedArena::new();
fcx = FunctionContext::new(ccx, llfn, fn_ty, None, empty_substs, &block_arena);
// duplicate declarations
let tcx = ccx.tcx();
let substs = tcx.erase_regions(substs);
- let instance = Instance {
- def: closure_id,
- params: &substs.func_substs.types
- };
+ let instance = Instance::new(closure_id, &substs.func_substs);
if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
debug!("get_or_create_closure_declaration(): found closure {:?}: {:?}",
TransItem::Fn(instance) => {
1u8.hash(s);
instance.def.hash(s);
- (instance.params as *const _ as usize).hash(s);
+ (instance.substs as *const _ as usize).hash(s);
}
TransItem::Static(node_id) => {
2u8.hash(s);
mode: mode,
output: &mut roots,
enclosing_item: None,
- trans_empty_substs: ccx.tcx().mk_substs(Substs::trans_empty()),
};
ccx.tcx().map.krate().visit_all_items(&mut visitor);
ccx: ccx,
mir: &mir,
output: &mut neighbors,
- param_substs: ccx.tcx().mk_substs(Substs {
- types: instance.params.clone(),
- regions: subst::ErasedRegions
- })
+ param_substs: instance.substs
};
visitor.visit_mir(&mir);
let exchange_malloc_fn_trans_item =
create_fn_trans_item(self.ccx,
exchange_malloc_fn_def_id,
- &Substs::trans_empty(),
+ &Substs::empty(),
self.param_substs);
self.output.push(exchange_malloc_fn_trans_item);
let exchange_free_fn_trans_item =
create_fn_trans_item(ccx,
exchange_free_fn_def_id,
- &Substs::trans_empty(),
- &Substs::trans_empty());
+ &Substs::empty(),
+ &Substs::empty());
output.push(exchange_free_fn_trans_item);
}
.unwrap();
let self_type_substs = ccx.tcx().mk_substs(
- Substs::trans_empty().with_self_ty(ty));
+ Substs::empty().with_self_ty(ty));
let trait_ref = ty::TraitRef {
def_id: drop_trait_def_id,
let trans_item = create_fn_trans_item(ccx,
destructor_did,
substs,
- &Substs::trans_empty());
+ &Substs::empty());
output.push(trans_item);
}
}
fn_substs);
let concrete_substs = ccx.tcx().erase_regions(&concrete_substs);
- let trans_item = TransItem::Fn(Instance {
- def: def_id,
- params: &ccx.tcx().mk_substs(concrete_substs).types,
- });
+ let trans_item =
+ TransItem::Fn(Instance::new(def_id,
+ &ccx.tcx().mk_substs(concrete_substs)));
return trans_item;
}
Some(create_fn_trans_item(ccx,
impl_method.method.def_id,
&impl_method.substs,
- &Substs::trans_empty()))
+ &Substs::empty()))
} else {
None
}
mode: TransItemCollectionMode,
output: &'b mut Vec<TransItem<'tcx>>,
enclosing_item: Option<&'tcx hir::Item>,
- trans_empty_substs: &'tcx Substs<'tcx>
}
impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
if self.mode == TransItemCollectionMode::Eager {
create_trans_items_for_default_impls(self.ccx,
item,
- self.trans_empty_substs,
self.output);
}
}
fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
item: &'tcx hir::Item,
- trans_empty_substs: &'tcx Substs<'tcx>,
output: &mut Vec<TransItem<'tcx>>) {
match item.node {
hir::ItemImpl(_,
}
if can_have_local_instance(ccx, default_impl.def_id) {
+ let empty_substs = ccx.tcx().mk_substs(ccx.tcx().erase_regions(mth.substs));
let item = create_fn_trans_item(ccx,
default_impl.def_id,
callee_substs,
- trans_empty_substs);
+ empty_substs);
output.push(item);
}
}
instance: Instance<'tcx>,
output: &mut String) {
push_item_name(ccx, instance.def, output);
- push_type_params(ccx, instance.params, &[], output);
+ push_type_params(ccx, &instance.substs.types, &[], output);
}
fn def_id_to_string(ccx: &CrateContext, def_id: DefId) -> String {
TransItem::Fn(instance) => {
format!("Fn({:?}, {})",
instance.def,
- instance.params as *const _ as usize)
+ instance.substs as *const _ as usize)
}
TransItem::Static(id) => {
format!("Static({:?})", id)
param_substs: &'tcx Substs<'tcx>)
-> Result<ValueRef, ConstEvalFailure> {
let expr = get_const_expr(ccx, def_id, ref_expr, param_substs);
- let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
+ let empty_substs = ccx.tcx().mk_substs(Substs::empty());
match get_const_expr_as_global(ccx, expr, ConstQualif::empty(), empty_substs, TrueConst::Yes) {
Err(Runtime(err)) => {
ccx.tcx().sess.span_err(expr.span, &err.description());
let def_id = ccx.tcx().map.local_def_id(id);
let datum = get_static(ccx, def_id);
- let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
+ let empty_substs = ccx.tcx().mk_substs(Substs::empty());
let (v, _) = const_expr(
ccx,
expr,
use trans::monomorphize::Instance;
use trans::collector::{TransItem, TransItemState};
use trans::type_::{Type, TypeNames};
-use middle::subst::Substs;
+use middle::subst::{Substs, VecPerParamSpace};
use middle::ty::{self, Ty, TyCtxt};
use session::config::NoDebugInfo;
use session::Session;
self.local
}
-
/// Get a (possibly) different `CrateContext` from the same
/// `SharedCrateContext`.
pub fn rotate(&self) -> CrateContext<'b, 'tcx> {
codegen_items.insert(cgi, TransItemState::NotPredictedButGenerated);
}
}
+
+ /// Given the def-id of some item that has no type parameters, make
+ /// a suitable "empty substs" for it.
+ pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> {
+ let scheme = self.tcx().lookup_item_type(item_def_id);
+ self.empty_substs_for_scheme(&scheme)
+ }
+
+ pub fn empty_substs_for_scheme(&self, scheme: &ty::TypeScheme<'tcx>)
+ -> &'tcx Substs<'tcx> {
+ assert!(scheme.generics.types.is_empty());
+ self.tcx().mk_substs(
+ Substs::new(VecPerParamSpace::empty(),
+ scheme.generics.regions.map(|_| ty::ReStatic)))
+ }
}
pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>);
hir::ExprPath(..) => {
match bcx.def(expr.id) {
Def::Const(did) | Def::AssociatedConst(did) => {
- let empty_substs = bcx.tcx().mk_substs(Substs::trans_empty());
+ let empty_substs = bcx.tcx().mk_substs(Substs::empty());
let const_expr = consts::get_const_expr(bcx.ccx(), did, expr,
empty_substs);
// Temporarily get cleanup scopes out of the way,
let _s = StatRecorder::new(ccx, format!("drop {:?}", t));
- let empty_substs = tcx.mk_substs(Substs::trans_empty());
+ let empty_substs = ccx.tcx().mk_substs(Substs::empty());
let (arena, fcx): (TypedArena<_>, FunctionContext);
arena = TypedArena::new();
fcx = FunctionContext::new(ccx, llfn, fn_ty, None, empty_substs, &arena);
let trait_ref = ty::Binder(ty::TraitRef {
def_id: tcx.lang_items.drop_trait().unwrap(),
- substs: tcx.mk_substs(Substs::trans_empty().with_self_ty(t))
+ substs: tcx.mk_substs(Substs::empty().with_self_ty(t))
});
let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) {
traits::VtableImpl(data) => data,
// performance.
AvailableExternallyLinkage
};
- let empty_substs = tcx.mk_substs(Substs::trans_empty());
+ let empty_substs = tcx.mk_substs(Substs::empty());
let def_id = tcx.map.local_def_id(item.id);
let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
SetLinkage(llfn, linkage);
let impl_tpt = tcx.lookup_item_type(impl_did);
if impl_tpt.generics.types.is_empty() &&
sig.generics.ty_params.is_empty() {
- let empty_substs = tcx.mk_substs(Substs::trans_empty());
let def_id = tcx.map.local_def_id(impl_item.id);
+ let empty_substs = ccx.empty_substs_for_def_id(def_id);
let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
trans_fn(ccx,
&sig.decl,
sig: ty::Binder(sig)
});
let llfn = declare::define_internal_fn(ccx, name, rust_fn_ty);
- let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
+ let empty_substs = ccx.tcx().mk_substs(Substs::empty());
let (fcx, block_arena);
block_arena = TypedArena::new();
fcx = FunctionContext::new(ccx, llfn, fn_ty, None, empty_substs, &block_arena);
use llvm::{ValueRef, get_params};
use middle::def_id::DefId;
use middle::infer;
-use middle::subst::{Subst, Substs};
+use middle::subst::{FnSpace, Subst, Substs};
use middle::subst;
use middle::traits::{self, ProjectionMode};
use trans::abi::FnType;
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, method_ty, "object_shim");
let llfn = declare::define_internal_fn(ccx, &function_name, method_ty);
- let empty_substs = tcx.mk_substs(Substs::trans_empty());
+ let empty_substs = tcx.mk_substs(Substs::empty());
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
block_arena = TypedArena::new();
fcx = FunctionContext::new(ccx, llfn, fn_ty, None, empty_substs, &block_arena);
debug!("get_vtable_methods: trait_method_type={:?}",
trait_method_type);
+ // the method may have some early-bound lifetimes, add
+ // regions for those
+ let num_dummy_regions = trait_method_type.generics.regions.len(FnSpace);
+ let dummy_regions = vec![ty::ReStatic; num_dummy_regions];
+ let method_substs = substs.clone()
+ .with_method(vec![], dummy_regions);
+ let method_substs = tcx.mk_substs(method_substs);
+
// The substitutions we have are on the impl, so we grab
// the method type from the impl to substitute into.
- let mth = get_impl_method(tcx, impl_id, substs, name);
+ let mth = get_impl_method(tcx, impl_id, method_substs, name);
debug!("get_vtable_methods: mth={:?}", mth);
let _icx = push_ctxt("monomorphic_fn");
- let instance = Instance {
- def: fn_id,
- params: &psubsts.types
- };
+ let instance = Instance::new(fn_id, psubsts);
let item_ty = ccx.tcx().lookup_item_type(fn_id).ty;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Instance<'tcx> {
pub def: DefId,
- pub params: &'tcx subst::VecPerParamSpace<Ty<'tcx>>
+ pub substs: &'tcx Substs<'tcx>,
}
impl<'tcx> fmt::Display for Instance<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let substs = Substs {
- types: self.params.clone(),
- regions: subst::ErasedRegions
- };
- ppaux::parameterized(f, &substs, self.def, ppaux::Ns::Value, &[],
+ ppaux::parameterized(f, &self.substs, self.def, ppaux::Ns::Value, &[],
|tcx| tcx.lookup_item_type(self.def).generics)
}
}
impl<'tcx> Instance<'tcx> {
+ pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
+ -> Instance<'tcx> {
+ assert!(substs.regions.iter().all(|&r| r == ty::ReStatic));
+ Instance { def: def_id, substs: substs }
+ }
pub fn mono(tcx: &TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> {
- Instance {
- def: def_id,
- params: &tcx.mk_substs(Substs::trans_empty()).types
- }
+ Instance::new(def_id, &tcx.mk_substs(Substs::empty()))
}
}
decl_generics, self_ty, types_provided,
region_substs);
- assert_eq!(region_substs.regions().len(TypeSpace), decl_generics.regions.len(TypeSpace));
+ assert_eq!(region_substs.regions.len(TypeSpace), decl_generics.regions.len(TypeSpace));
assert!(region_substs.types.is_empty());
// Convert the type parameters supplied by the user.
trait_to_impl_substs
.subst(tcx, impl_to_skol_substs)
.with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
- impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
+ impl_to_skol_substs.regions.get_slice(subst::FnSpace).to_vec());
debug!("compare_impl_method: trait_to_skol_substs={:?}",
trait_to_skol_substs);
trait_to_impl_substs
.subst(tcx, impl_to_skol_substs)
.with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
- impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
+ impl_to_skol_substs.regions.get_slice(subst::FnSpace).to_vec());
debug!("compare_const_impl: trait_to_skol_substs={:?}",
trait_to_skol_substs);
.generics.regions.get_slice(subst::FnSpace));
let subst::Substs { types, regions } = substs;
- let regions = regions.map(|r| r.with_slice(subst::FnSpace, &method_regions));
+ let regions = regions.with_slice(subst::FnSpace, &method_regions);
let mut final_substs = subst::Substs { types: types, regions: regions };
if num_supplied_types == 0 {
assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
trait_ref.substs.types.get_slice(subst::TypeSpace).len());
assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
- trait_ref.substs.regions().get_slice(subst::TypeSpace).len());
+ trait_ref.substs.regions.get_slice(subst::TypeSpace).len());
assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
trait_ref.substs.types.get_slice(subst::SelfSpace).len());
assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
- trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
+ trait_ref.substs.regions.get_slice(subst::SelfSpace).len());
}
// Because this trait derives from a where-clause, it
// method yet. So create fresh variables here for those too,
// if there are any.
assert_eq!(substs.types.len(subst::FnSpace), 0);
- assert_eq!(substs.regions().len(subst::FnSpace), 0);
+ assert_eq!(substs.regions.len(subst::FnSpace), 0);
if self.mode == Mode::Path {
return impl_ty;
assert_eq!(substs.types.len(space), type_defs.len(space));
adjust_region_parameters(fcx, span, space, region_defs, &mut substs);
- assert_eq!(substs.regions().len(space), region_defs.len(space));
+ assert_eq!(substs.regions.len(space), region_defs.len(space));
}
// The things we are substituting into the type should not contain
let impl_scheme = fcx.tcx().lookup_item_type(impl_def_id);
assert_eq!(substs.types.len(subst::TypeSpace),
impl_scheme.generics.types.len(subst::TypeSpace));
- assert_eq!(substs.regions().len(subst::TypeSpace),
+ assert_eq!(substs.regions.len(subst::TypeSpace),
impl_scheme.generics.regions.len(subst::TypeSpace));
let impl_ty = fcx.instantiate_type_scheme(span, &substs, &impl_scheme.ty);
{
let region_count = region_defs.len(space);
- assert_eq!(substs.regions().len(space), 0);
+ assert_eq!(substs.regions.len(space), 0);
for (i, lifetime) in data.lifetimes.iter().enumerate() {
let r = ast_region_to_region(fcx.tcx(), lifetime);
if i < region_count {
- substs.mut_regions().push(space, r);
+ substs.regions.push(space, r);
} else if i == region_count {
span_err!(fcx.tcx().sess, lifetime.span, E0088,
"too many lifetime parameters provided: \
if region_count == 1 {""} else {"s"},
data.lifetimes.len(),
if data.lifetimes.len() == 1 {""} else {"s"});
- substs.mut_regions().truncate(space, 0);
+ substs.regions.truncate(space, 0);
break;
}
}
defs: &VecPerParamSpace<ty::RegionParameterDef>,
substs: &mut Substs)
{
- let provided_len = substs.mut_regions().len(space);
+ let provided_len = substs.regions.len(space);
let desired = defs.get_slice(space);
// Enforced by `push_explicit_parameters_from_segment_to_substs()`.
// If nothing was provided, just use inference variables.
if provided_len == 0 {
- substs.mut_regions().replace(
+ substs.regions.replace(
space,
fcx.infcx().region_vars_for_defs(span, desired));
return;
provided_len,
if provided_len == 1 {""} else {"s"});
- substs.mut_regions().replace(
+ substs.regions.replace(
space,
fcx.infcx().region_vars_for_defs(span, desired));
}
let origin = infer::ParameterInScope(origin, expr_span);
- for ®ion in substs.regions() {
+ for ®ion in &substs.regions {
rcx.fcx.mk_subr(origin.clone(), expr_region, region);
}
// edges, which winds up enforcing the same condition.
let needs_infer = {
projection_ty.trait_ref.substs.types.iter().any(|t| t.needs_infer()) ||
- projection_ty.trait_ref.substs.regions().iter().any(|r| r.needs_infer())
+ projection_ty.trait_ref.substs.regions.iter().any(|r| r.needs_infer())
};
if env_bounds.is_empty() && needs_infer {
debug!("projection_must_outlive: no declared bounds");
type_must_outlive(rcx, origin.clone(), component_ty, region);
}
- for &r in projection_ty.trait_ref.substs.regions() {
+ for &r in &projection_ty.trait_ref.substs.regions {
rcx.fcx.mk_subr(origin.clone(), region, r);
}
if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) {
let unique_bound = env_bounds[0];
debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound);
- if projection_ty.trait_ref.substs.regions()
+ if projection_ty.trait_ref.substs.regions
.iter()
.any(|r| env_bounds.contains(r))
{
}
fn parameters_for_regions_in_substs(substs: &subst::Substs) -> Vec<Parameter> {
- substs.regions()
+ substs.regions
.iter()
.filter_map(|r| parameters_for_region(r))
.collect()
self.declared_variance(p.def_id, def_id,
RegionParam, p.space, p.index as usize);
let variance_i = self.xform(variance, variance_decl);
- let substs_r = *substs.regions().get(p.space, p.index as usize);
+ let substs_r = *substs.regions.get(p.space, p.index as usize);
self.add_constraints_from_region(generics, substs_r, variance_i);
}
}
fn external_path_params(cx: &DocContext, trait_did: Option<DefId>,
bindings: Vec<TypeBinding>, substs: &subst::Substs) -> PathParameters {
- let lifetimes = substs.regions().get_slice(subst::TypeSpace)
+ let lifetimes = substs.regions.get_slice(subst::TypeSpace)
.iter()
.filter_map(|v| v.clean(cx))
.collect();
impl<'tcx> Clean<Option<Vec<TyParamBound>>> for subst::Substs<'tcx> {
fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
let mut v = Vec::new();
- v.extend(self.regions().iter().filter_map(|r| r.clean(cx)).map(RegionBound));
+ v.extend(self.regions.iter().filter_map(|r| r.clean(cx)).map(RegionBound));
v.extend(self.types.iter().map(|t| TraitBound(PolyTrait {
trait_: t.clean(cx),
lifetimes: vec![]
///
/// Each handle is a shared reference to a global buffer of input data to this
/// process. A handle can be `lock`'d to gain full access to [`BufRead`] methods
-/// (e.g. `.lines()`). Writes to this handle are otherwise locked with respect
-/// to other writes.
+/// (e.g. `.lines()`). Reads to this handle are otherwise locked with respect
+/// to other reads.
///
/// This handle implements the `Read` trait, but beware that concurrent reads
/// of `Stdin` must be executed with care.
// except according to those terms.
//! Temporal quantification.
+//!
+//! Example:
+//!
+//! ```
+//! use std::time::Duration;
+//!
+//! let five_seconds = Duration::new(5, 0);
+//! // both declarations are equivalent
+//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5));
+//! ```
#![stable(feature = "time", since = "1.3.0")]
/// no method to get "the number of seconds" from an instant. Instead, it only
/// allows measuring the duration between two instants (or comparing two
/// instants).
+///
+/// Example:
+///
+/// ```no_run
+/// use std::time::{Duration, Instant};
+/// use std::thread::sleep;
+///
+/// fn main() {
+/// let now = Instant::now();
+///
+/// // we sleep for 2 seconds
+/// sleep(Duration::new(2, 0));
+/// // it prints '2'
+/// println!("{}", now.elapsed().as_secs());
+/// }
+/// ```
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[stable(feature = "time2", since = "1.8.0")]
pub struct Instant(time::Instant);
/// information about a `SystemTime`. By calculating the duration from this
/// fixed point in time, a `SystemTime` can be converted to a human-readable time,
/// or perhaps some other string representation.
+///
+/// Example:
+///
+/// ```no_run
+/// use std::time::{Duration, SystemTime};
+/// use std::thread::sleep;
+///
+/// fn main() {
+/// let now = SystemTime::now();
+///
+/// // we sleep for 2 seconds
+/// sleep(Duration::new(2, 0));
+/// match now.elapsed() {
+/// Ok(elapsed) => {
+/// // it prints '2'
+/// println!("{}", elapsed.as_secs());
+/// }
+/// Err(e) => {
+/// // an error occured!
+/// println!("Error: {:?}", e);
+/// }
+/// }
+/// }
+/// ```
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[stable(feature = "time2", since = "1.8.0")]
pub struct SystemTime(time::SystemTime);
// FIXME spec the JSON output properly.
-use codemap::{MultiSpan, CodeMap};
+use codemap::{Span, MultiSpan, CodeMap};
use diagnostics::registry::Registry;
use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion};
use errors::emitter::Emitter;
/// 1-based, character offset.
column_start: usize,
column_end: usize,
+ /// Source text from the start of line_start to the end of line_end.
+ text: Vec<DiagnosticSpanLine>,
+}
+
+#[derive(RustcEncodable)]
+struct DiagnosticSpanLine {
+ text: String,
+ /// 1-based, character offset in self.text.
+ highlight_start: usize,
+ highlight_end: usize,
}
#[derive(RustcEncodable)]
line_end: end.line,
column_start: start.col.0 + 1,
column_end: end.col.0 + 1,
+ text: DiagnosticSpanLine::from_span(span, je),
}
}).collect()
}
line_end: end.line,
column_start: 0,
column_end: end.col.0 + 1,
+ text: DiagnosticSpanLine::from_span(span, je),
}
}).collect()
}
line_end: end.line,
column_start: 0,
column_end: 0,
+ text: DiagnosticSpanLine::from_span(span, je),
}
}).collect()
}
}
}
+impl DiagnosticSpanLine {
+ fn from_span(span: &Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> {
+ let lines = match je.cm.span_to_lines(*span) {
+ Ok(lines) => lines,
+ Err(_) => {
+ debug!("unprintable span");
+ return Vec::new();
+ }
+ };
+
+ let mut result = Vec::new();
+ let fm = &*lines.file;
+
+ for line in &lines.lines {
+ result.push(DiagnosticSpanLine {
+ text: fm.get_line(line.line_index).unwrap().to_owned(),
+ highlight_start: line.start_col.0 + 1,
+ highlight_end: line.end_col.0 + 1,
+ });
+ }
+
+ result
+ }
+}
+
impl DiagnosticCode {
fn map_opt_string(s: Option<String>, je: &JsonEmitter) -> Option<DiagnosticCode> {
s.map(|s| {
("unwind_attributes", "1.4.0", None, Active),
// allow the use of `#[naked]` on functions.
- ("naked_functions", "1.9.0", None, Active),
+ ("naked_functions", "1.9.0", Some(32408), Active),
// allow empty structs and enum variants with braces
("braced_empty_structs", "1.5.0", Some(29720), Accepted),
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// No warnings about removed lint when
+// allow(renamed_and_removed_lints)
+
+#[deny(raw_pointer_derive)]
+#[allow(renamed_and_removed_lints)]
+#[deny(unused_variables)]
+fn main() { let unused = (); } //~ ERR unused
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// The raw_pointer_derived lint only warns about its own removal
+// The raw_pointer_derived lint was removed, but is now reported by
+// the renamed_and_removed_lints lint, which means it's a warning by
+// default, and allowed in cargo dependency builds.
// cc #30346
#[deny(raw_pointer_derive)] //~ WARN raw_pointer_derive has been removed
-#[deny(warnings)]
+#[deny(unused_variables)]
fn main() { let unused = (); } //~ ERR unused
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// No warnings about renamed lint when
+// allow(renamed_and_removed_lints)
+
+#[deny(unknown_features)]
+#[allow(renamed_and_removed_lints)]
+#[deny(unused)]
+fn main() { let unused = (); } //~ ERR unused
cp foo.rs $(TMPDIR)
cd $(TMPDIR)
-$(RUSTC) -Z unstable-options --error-format=json foo.rs 2>$(LOG)
- grep -q '{"message":"unresolved name `y`","code":{"code":"E0425","explanation":"\\nAn unresolved name was used. Example of erroneous codes.*"},"level":"error","spans":\[{"file_name":"foo.rs","byte_start":496,"byte_end":497,"line_start":12,"line_end":12,"column_start":18,"column_end":19}\],"children":\[\]}' $(LOG)
- grep -q '{"message":".*","code":{"code":"E0277","explanation":"\\nYou tried.*"},"level":"error","spans":\[{.*}\],"children":\[{"message":"the .*","code":null,"level":"help","spans":\[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":0,"column_end":0}\],"children":\[\]},{"message":" <u8 as core::ops::Add>","code":null,"level":"help",' $(LOG)
+ grep -q '{"message":"unresolved name `y`","code":{"code":"E0425","explanation":"\\nAn unresolved name was used. Example of erroneous codes.*"},"level":"error","spans":\[{"file_name":"foo.rs","byte_start":496,"byte_end":497,"line_start":12,"line_end":12,"column_start":18,"column_end":19,"text":\[{"text":" let x = 42 + y;","highlight_start":18,"highlight_end":19}\]}\],"children":\[\]}' $(LOG)
+ grep -q '{"message":".*","code":{"code":"E0277","explanation":"\\nYou tried.*"},"level":"error","spans":\[{.*}\],"children":\[{"message":"the .*","code":null,"level":"help","spans":\[{"file_name":"foo.rs","byte_start":504,"byte_end":516,"line_start":14,"line_end":14,"column_start":0,"column_end":0,"text":\[{.*}\]}\],"children":\[\]},{"message":" <u8 as core::ops::Add>","code":null,"level":"help",' $(LOG)
#![deny(warnings)]
#![allow(unused_must_use)]
-#![allow(unknown_features)]
+#![allow(unused_features)]
#![feature(box_syntax)]
#![feature(question_mark)]