diff --git a/configure b/configure index 7df98d1bd565d..f284d13ee3bbd 100755 --- a/configure +++ b/configure @@ -1051,7 +1051,7 @@ then esac else case $CFG_CLANG_VERSION in - (3.2* | 3.3* | 3.4* | 3.5* | 3.6* | 3.7* | 3.8*) + (3.2* | 3.3* | 3.4* | 3.5* | 3.6* | 3.7* | 3.8* | 3.9*) step_msg "found ok version of CLANG: $CFG_CLANG_VERSION" ;; (*) diff --git a/src/doc/book/error-handling.md b/src/doc/book/error-handling.md index 9b1d16170b97f..40891dbe191e9 100644 --- a/src/doc/book/error-handling.md +++ b/src/doc/book/error-handling.md @@ -1512,7 +1512,7 @@ and [`rustc-serialize`](https://crates.io/crates/rustc-serialize) crates. We're not going to spend a lot of time on setting up a project with Cargo because it is already covered well in [the Cargo -section](../book/hello-cargo.html) and [Cargo's documentation][14]. +section](getting-started.html#hello-cargo) and [Cargo's documentation][14]. To get started from scratch, run `cargo new --bin city-pop` and make sure your `Cargo.toml` looks something like this: diff --git a/src/doc/book/getting-started.md b/src/doc/book/getting-started.md index 18d5ca5be1ae3..d7b6e15794ef4 100644 --- a/src/doc/book/getting-started.md +++ b/src/doc/book/getting-started.md @@ -167,6 +167,10 @@ variable. If it isn't, run the installer again, select "Change" on the "Change, repair, or remove installation" page and ensure "Add to PATH" is installed on the local hard drive. +Rust does not do its own linking, and so you’ll need to have a linker +installed. Doing so will depend on your specific system, consult its +documentation for more details. + If not, there are a number of places where we can get help. The easiest is [the #rust IRC channel on irc.mozilla.org][irc], which we can access through [Mibbit][mibbit]. Click that link, and we'll be chatting with other Rustaceans @@ -511,15 +515,17 @@ programming languages. For complex projects composed of multiple crates, it’s much easier to let Cargo coordinate the build. Using Cargo, you can run `cargo build`, and it should work the right way. -## Building for Release +### Building for Release -When your project is finally ready for release, you can use `cargo build +When your project is ready for release, you can use `cargo build --release` to compile your project with optimizations. These optimizations make your Rust code run faster, but turning them on makes your program take longer to compile. This is why there are two different profiles, one for development, and one for building the final program you’ll give to a user. -Running this command also causes Cargo to create a new file called +### What Is That `Cargo.lock`? + +Running `cargo build` also causes Cargo to create a new file called *Cargo.lock*, which looks like this: ```toml @@ -602,11 +608,11 @@ This chapter covered the basics that will serve you well through the rest of this book, and the rest of your time with Rust. Now that you’ve got the tools down, we'll cover more about the Rust language itself. -You have two options: Dive into a project with ‘[Learn Rust][learnrust]’, or +You have two options: Dive into a project with ‘[Tutorial: Guessing Game][guessinggame]’, or start from the bottom and work your way up with ‘[Syntax and Semantics][syntax]’. More experienced systems programmers will probably prefer -‘Learn Rust’, while those from dynamic backgrounds may enjoy either. Different +‘Tutorial: Guessing Game’, while those from dynamic backgrounds may enjoy either. Different people learn differently! Choose whatever’s right for you. -[learnrust]: learn-rust.html +[guessinggame]: guessing-game.html [syntax]: syntax-and-semantics.html diff --git a/src/doc/book/learn-rust.md b/src/doc/book/learn-rust.md deleted file mode 100644 index 7be7fa4f039a7..0000000000000 --- a/src/doc/book/learn-rust.md +++ /dev/null @@ -1,9 +0,0 @@ -% Learn Rust - -Welcome! This chapter has a few tutorials that teach you Rust through building -projects. You’ll get a high-level overview, but we’ll skim over the details. - -If you’d prefer a more ‘from the ground up’-style experience, check -out [Syntax and Semantics][ss]. - -[ss]: syntax-and-semantics.html diff --git a/src/doc/book/loops.md b/src/doc/book/loops.md index 68bb49d2c2966..5b08c2fb04dbd 100644 --- a/src/doc/book/loops.md +++ b/src/doc/book/loops.md @@ -195,7 +195,7 @@ for x in 0..10 { You may also encounter situations where you have nested loops and need to specify which one your `break` or `continue` statement is for. Like most other languages, by default a `break` or `continue` will apply to innermost -loop. In a situation where you would like to a `break` or `continue` for one +loop. In a situation where you would like to `break` or `continue` for one of the outer loops, you can use labels to specify which loop the `break` or `continue` statement applies to. This will only print when both `x` and `y` are odd: diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 789b75836d0a7..6041355e9dbc0 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -414,7 +414,9 @@ impl RefCell { /// /// let c = RefCell::new(5); /// - /// let borrowed_five = c.borrow_mut(); + /// *c.borrow_mut() = 7; + /// + /// assert_eq!(*c.borrow(), 7); /// ``` /// /// An example of panic: diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 4d772de783594..4f6c1305f7683 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -108,7 +108,6 @@ pub mod middle { pub mod free_region; pub mod intrinsicck; pub mod infer; - pub mod implicator; pub mod lang_items; pub mod liveness; pub mod mem_categorization; diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index ef011067cd077..07171e6607760 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -28,7 +28,7 @@ use util::num::ToPrimitive; use util::nodemap::NodeMap; use graphviz::IntoCow; -use syntax::{ast, abi}; +use syntax::ast; use rustc_front::hir::Expr; use rustc_front::hir; use rustc_front::intravisit::FnKind; @@ -1090,19 +1090,16 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, hir::ExprCall(ref callee, ref args) => { let sub_ty_hint = ty_hint.erase_hint(); let callee_val = try!(eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)); - let (decl, block, constness) = try!(get_fn_def(tcx, e, callee_val)); - match (ty_hint, constness) { - (ExprTypeChecked, _) => { - // no need to check for constness... either check_const - // already forbids this or we const eval over whatever - // we want - }, - (_, hir::Constness::Const) => { - // we don't know much about the function, so we force it to be a const fn - // so compilation will fail later in case the const fn's body is not const - }, - _ => signal!(e, NonConstPath), - } + let did = match callee_val { + Function(did) => did, + callee => signal!(e, CallOn(callee)), + }; + let (decl, result) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) { + (fn_like.decl(), &fn_like.body().expr) + } else { + signal!(e, NonConstPath) + }; + let result = result.as_ref().expect("const fn has no result expression"); assert_eq!(decl.inputs.len(), args.len()); let mut call_args = NodeMap(); @@ -1117,7 +1114,6 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, let old = call_args.insert(arg.pat.id, arg_val); assert!(old.is_none()); } - let result = block.expr.as_ref().unwrap(); debug!("const call({:?})", call_args); try!(eval_const_expr_partial(tcx, &**result, ty_hint, Some(&call_args))) }, @@ -1389,46 +1385,3 @@ pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>, }; compare_const_vals(&a, &b) } - - -// returns Err if callee is not `Function` -// `e` is only used for error reporting/spans -fn get_fn_def<'a>(tcx: &'a ty::ctxt, - e: &hir::Expr, - callee: ConstVal) - -> Result<(&'a hir::FnDecl, &'a hir::Block, hir::Constness), ConstEvalErr> { - let did = match callee { - Function(did) => did, - callee => signal!(e, CallOn(callee)), - }; - debug!("fn call: {:?}", tcx.map.get_if_local(did)); - match tcx.map.get_if_local(did) { - None => signal!(e, UnimplementedConstVal("calling non-local const fn")), // non-local - Some(ast_map::NodeItem(it)) => match it.node { - hir::ItemFn( - ref decl, - hir::Unsafety::Normal, - constness, - abi::Abi::Rust, - _, // ducktype generics? types are funky in const_eval - ref block, - ) => Ok((&**decl, &**block, constness)), - _ => signal!(e, NonConstPath), - }, - Some(ast_map::NodeImplItem(it)) => match it.node { - hir::ImplItemKind::Method( - hir::MethodSig { - ref decl, - unsafety: hir::Unsafety::Normal, - constness, - abi: abi::Abi::Rust, - .. // ducktype generics? types are funky in const_eval - }, - ref block, - ) => Ok((decl, block, constness)), - _ => signal!(e, NonConstPath), - }, - Some(ast_map::NodeTraitItem(..)) => signal!(e, NonConstPath), - Some(_) => signal!(e, UnimplementedConstVal("calling struct, tuple or variant")), - } -} diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 27745a85935ab..973fd65beb3d8 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -267,24 +267,28 @@ impl InlinedItem { // FIXME: find a better place for this? pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option) { - let say = |s: &str| { - match (sp, sess) { - (_, None) => panic!("{}", s), - (Some(sp), Some(sess)) => sess.span_err(sp, s), - (None, Some(sess)) => sess.err(s), + let mut err_count = 0; + { + let mut say = |s: &str| { + match (sp, sess) { + (_, None) => panic!("{}", s), + (Some(sp), Some(sess)) => sess.span_err(sp, s), + (None, Some(sess)) => sess.err(s), + } + err_count += 1; + }; + if s.is_empty() { + say("crate name must not be empty"); + } + for c in s.chars() { + if c.is_alphanumeric() { continue } + if c == '_' { continue } + say(&format!("invalid character `{}` in crate name: `{}`", c, s)); } - }; - if s.is_empty() { - say("crate name must not be empty"); - } - for c in s.chars() { - if c.is_alphanumeric() { continue } - if c == '_' { continue } - say(&format!("invalid character `{}` in crate name: `{}`", c, s)); } - match sess { - Some(sess) => sess.abort_if_errors(), - None => {} + + if err_count > 0 { + sess.unwrap().abort_if_errors(); } } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index e9029958880bd..933857269cbcd 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -527,8 +527,7 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> { debug!("{}", { let mut v = Vec::new(); self.pretty_print_to(box &mut v, blk).unwrap(); - println!("{}", String::from_utf8(v).unwrap()); - "" + String::from_utf8(v).unwrap() }); } diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs deleted file mode 100644 index d25084bbdffb5..0000000000000 --- a/src/librustc/middle/implicator.rs +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// #![warn(deprecated_mode)] - -use middle::def_id::DefId; -use middle::infer::{InferCtxt, GenericKind}; -use middle::subst::Substs; -use middle::traits; -use middle::ty::{self, ToPredicate, Ty}; -use middle::ty::fold::{TypeFoldable, TypeFolder}; - -use syntax::ast; -use syntax::codemap::Span; - -use util::common::ErrorReported; -use util::nodemap::FnvHashSet; - -// Helper functions related to manipulating region types. - -#[derive(Debug)] -pub enum Implication<'tcx> { - RegionSubRegion(Option>, ty::Region, ty::Region), - RegionSubGeneric(Option>, ty::Region, GenericKind<'tcx>), - Predicate(DefId, ty::Predicate<'tcx>), -} - -struct Implicator<'a, 'tcx: 'a> { - infcx: &'a InferCtxt<'a,'tcx>, - body_id: ast::NodeId, - stack: Vec<(ty::Region, Option>)>, - span: Span, - out: Vec>, - visited: FnvHashSet>, -} - -/// This routine computes the well-formedness constraints that must hold for the type `ty` to -/// appear in a context with lifetime `outer_region` -pub fn implications<'a,'tcx>( - infcx: &'a InferCtxt<'a,'tcx>, - body_id: ast::NodeId, - ty: Ty<'tcx>, - outer_region: ty::Region, - span: Span) - -> Vec> -{ - debug!("implications(body_id={}, ty={:?}, outer_region={:?})", - body_id, - ty, - outer_region); - - let mut stack = Vec::new(); - stack.push((outer_region, None)); - let mut wf = Implicator { infcx: infcx, - body_id: body_id, - span: span, - stack: stack, - out: Vec::new(), - visited: FnvHashSet() }; - wf.accumulate_from_ty(ty); - debug!("implications: out={:?}", wf.out); - wf.out -} - -impl<'a, 'tcx> Implicator<'a, 'tcx> { - fn tcx(&self) -> &'a ty::ctxt<'tcx> { - self.infcx.tcx - } - - fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) { - debug!("accumulate_from_ty(ty={:?})", - ty); - - // When expanding out associated types, we can visit a cyclic - // set of types. Issue #23003. - if !self.visited.insert(ty) { - return; - } - - match ty.sty { - ty::TyBool | - ty::TyChar | - ty::TyInt(..) | - ty::TyUint(..) | - ty::TyFloat(..) | - ty::TyBareFn(..) | - ty::TyError | - ty::TyStr => { - // No borrowed content reachable here. - } - - ty::TyClosure(_, ref substs) => { - // FIXME(#27086). We do not accumulate from substs, since they - // don't represent reachable data. This means that, in - // practice, some of the lifetime parameters might not - // be in scope when the body runs, so long as there is - // no reachable data with that lifetime. For better or - // worse, this is consistent with fn types, however, - // which can also encapsulate data in this fashion - // (though it's somewhat harder, and typically - // requires virtual dispatch). - // - // Note that changing this (in a naive way, at least) - // causes regressions for what appears to be perfectly - // reasonable code like this: - // - // ``` - // fn foo<'a>(p: &Data<'a>) { - // bar(|q: &mut Parser| q.read_addr()) - // } - // fn bar(p: Box) { - // } - // ``` - // - // Note that `p` (and `'a`) are not used in the - // closure at all, but to meet the requirement that - // the closure type `C: 'static` (so it can be coerced - // to the object type), we get the requirement that - // `'a: 'static` since `'a` appears in the closure - // type `C`. - // - // A smarter fix might "prune" unused `func_substs` -- - // this would avoid breaking simple examples like - // this, but would still break others (which might - // indeed be invalid, depending on your POV). Pruning - // would be a subtle process, since we have to see - // what func/type parameters are used and unused, - // taking into consideration UFCS and so forth. - - for &upvar_ty in &substs.upvar_tys { - self.accumulate_from_ty(upvar_ty); - } - } - - ty::TyTrait(ref t) => { - let required_region_bounds = - object_region_bounds(self.tcx(), &t.principal, t.bounds.builtin_bounds); - self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds) - } - - ty::TyEnum(def, substs) | - ty::TyStruct(def, substs) => { - let item_scheme = def.type_scheme(self.tcx()); - self.accumulate_from_adt(ty, def.did, &item_scheme.generics, substs) - } - - ty::TyArray(t, _) | - ty::TySlice(t) | - ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) | - ty::TyBox(t) => { - self.accumulate_from_ty(t) - } - - ty::TyRef(r_b, mt) => { - self.accumulate_from_rptr(ty, *r_b, mt.ty); - } - - ty::TyParam(p) => { - self.push_param_constraint_from_top(p); - } - - ty::TyProjection(ref data) => { - // `>::Name` - - self.push_projection_constraint_from_top(data); - } - - ty::TyTuple(ref tuptys) => { - for &tupty in tuptys { - self.accumulate_from_ty(tupty); - } - } - - ty::TyInfer(_) => { - // This should not happen, BUT: - // - // Currently we uncover region relationships on - // entering the fn check. We should do this after - // the fn check, then we can call this case a bug(). - } - } - } - - fn accumulate_from_rptr(&mut self, - ty: Ty<'tcx>, - r_b: ty::Region, - ty_b: Ty<'tcx>) { - // We are walking down a type like this, and current - // position is indicated by caret: - // - // &'a &'b ty_b - // ^ - // - // At this point, top of stack will be `'a`. We must - // require that `'a <= 'b`. - - self.push_region_constraint_from_top(r_b); - - // Now we push `'b` onto the stack, because it must - // constrain any borrowed content we find within `T`. - - self.stack.push((r_b, Some(ty))); - self.accumulate_from_ty(ty_b); - self.stack.pop().unwrap(); - } - - /// Pushes a constraint that `r_b` must outlive the top region on the stack. - fn push_region_constraint_from_top(&mut self, - r_b: ty::Region) { - - // Indicates that we have found borrowed content with a lifetime - // of at least `r_b`. This adds a constraint that `r_b` must - // outlive the region `r_a` on top of the stack. - // - // As an example, imagine walking a type like: - // - // &'a &'b T - // ^ - // - // when we hit the inner pointer (indicated by caret), `'a` will - // be on top of stack and `'b` will be the lifetime of the content - // we just found. So we add constraint that `'a <= 'b`. - - let &(r_a, opt_ty) = self.stack.last().unwrap(); - self.push_sub_region_constraint(opt_ty, r_a, r_b); - } - - /// Pushes a constraint that `r_a <= r_b`, due to `opt_ty` - fn push_sub_region_constraint(&mut self, - opt_ty: Option>, - r_a: ty::Region, - r_b: ty::Region) { - self.out.push(Implication::RegionSubRegion(opt_ty, r_a, r_b)); - } - - /// Pushes a constraint that `param_ty` must outlive the top region on the stack. - fn push_param_constraint_from_top(&mut self, - param_ty: ty::ParamTy) { - let &(region, opt_ty) = self.stack.last().unwrap(); - self.push_param_constraint(region, opt_ty, param_ty); - } - - /// Pushes a constraint that `projection_ty` must outlive the top region on the stack. - fn push_projection_constraint_from_top(&mut self, - projection_ty: &ty::ProjectionTy<'tcx>) { - let &(region, opt_ty) = self.stack.last().unwrap(); - self.out.push(Implication::RegionSubGeneric( - opt_ty, region, GenericKind::Projection(projection_ty.clone()))); - } - - /// Pushes a constraint that `region <= param_ty`, due to `opt_ty` - fn push_param_constraint(&mut self, - region: ty::Region, - opt_ty: Option>, - param_ty: ty::ParamTy) { - self.out.push(Implication::RegionSubGeneric( - opt_ty, region, GenericKind::Param(param_ty))); - } - - fn accumulate_from_adt(&mut self, - ty: Ty<'tcx>, - def_id: DefId, - _generics: &ty::Generics<'tcx>, - substs: &Substs<'tcx>) - { - let predicates = - self.tcx().lookup_predicates(def_id).instantiate(self.tcx(), substs); - let predicates = match self.fully_normalize(&predicates) { - Ok(predicates) => predicates, - Err(ErrorReported) => { return; } - }; - - for predicate in predicates.predicates.as_slice() { - match *predicate { - ty::Predicate::Trait(..) => { } - ty::Predicate::Equate(..) => { } - ty::Predicate::Projection(..) => { } - ty::Predicate::RegionOutlives(ref data) => { - match self.tcx().no_late_bound_regions(data) { - None => { } - Some(ty::OutlivesPredicate(r_a, r_b)) => { - self.push_sub_region_constraint(Some(ty), r_b, r_a); - } - } - } - ty::Predicate::TypeOutlives(ref data) => { - match self.tcx().no_late_bound_regions(data) { - None => { } - Some(ty::OutlivesPredicate(ty_a, r_b)) => { - self.stack.push((r_b, Some(ty))); - self.accumulate_from_ty(ty_a); - self.stack.pop().unwrap(); - } - } - } - ty::Predicate::ObjectSafe(_) | - ty::Predicate::WellFormed(_) => { - } - } - } - - let obligations = predicates.predicates - .into_iter() - .map(|pred| Implication::Predicate(def_id, pred)); - self.out.extend(obligations); - - let variances = self.tcx().item_variances(def_id); - self.accumulate_from_substs(substs, Some(&variances)); - } - - fn accumulate_from_substs(&mut self, - substs: &Substs<'tcx>, - variances: Option<&ty::ItemVariances>) - { - let mut tmp_variances = None; - let variances = variances.unwrap_or_else(|| { - tmp_variances = Some(ty::ItemVariances { - types: substs.types.map(|_| ty::Variance::Invariant), - regions: substs.regions().map(|_| ty::Variance::Invariant), - }); - tmp_variances.as_ref().unwrap() - }); - - for (®ion, &variance) in substs.regions().iter().zip(&variances.regions) { - match variance { - ty::Contravariant | ty::Invariant => { - // If any data with this lifetime is reachable - // within, it must be at least contravariant. - self.push_region_constraint_from_top(region) - } - ty::Covariant | ty::Bivariant => { } - } - } - - for (&ty, &variance) in substs.types.iter().zip(&variances.types) { - match variance { - ty::Covariant | ty::Invariant => { - // If any data of this type is reachable within, - // it must be at least covariant. - self.accumulate_from_ty(ty); - } - ty::Contravariant | ty::Bivariant => { } - } - } - } - - fn accumulate_from_object_ty(&mut self, - ty: Ty<'tcx>, - region_bound: ty::Region, - required_region_bounds: Vec) - { - // Imagine a type like this: - // - // trait Foo { } - // trait Bar<'c> : 'c { } - // - // &'b (Foo+'c+Bar<'d>) - // ^ - // - // In this case, the following relationships must hold: - // - // 'b <= 'c - // 'd <= 'c - // - // The first conditions is due to the normal region pointer - // rules, which say that a reference cannot outlive its - // referent. - // - // The final condition may be a bit surprising. In particular, - // you may expect that it would have been `'c <= 'd`, since - // usually lifetimes of outer things are conservative - // approximations for inner things. However, it works somewhat - // differently with trait objects: here the idea is that if the - // user specifies a region bound (`'c`, in this case) it is the - // "master bound" that *implies* that bounds from other traits are - // all met. (Remember that *all bounds* in a type like - // `Foo+Bar+Zed` must be met, not just one, hence if we write - // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and - // 'y.) - // - // Note: in fact we only permit builtin traits, not `Bar<'d>`, I - // am looking forward to the future here. - - // The content of this object type must outlive - // `bounds.region_bound`: - let r_c = region_bound; - self.push_region_constraint_from_top(r_c); - - // And then, in turn, to be well-formed, the - // `region_bound` that user specified must imply the - // region bounds required from all of the trait types: - for &r_d in &required_region_bounds { - // Each of these is an instance of the `'c <= 'b` - // constraint above - self.out.push(Implication::RegionSubRegion(Some(ty), r_d, r_c)); - } - } - - fn fully_normalize(&self, value: &T) -> Result - where T : TypeFoldable<'tcx> - { - let value = - traits::fully_normalize(self.infcx, - traits::ObligationCause::misc(self.span, self.body_id), - value); - match value { - Ok(value) => Ok(value), - Err(errors) => { - // I don't like reporting these errors here, but I - // don't know where else to report them just now. And - // I don't really expect errors to arise here - // frequently. I guess the best option would be to - // propagate them out. - traits::report_fulfillment_errors(self.infcx, &errors); - Err(ErrorReported) - } - } - } -} - -/// Given an object type like `SomeTrait+Send`, computes the lifetime -/// bounds that must hold on the elided self type. These are derived -/// from the declarations of `SomeTrait`, `Send`, and friends -- if -/// they declare `trait SomeTrait : 'static`, for example, then -/// `'static` would appear in the list. The hard work is done by -/// `ty::required_region_bounds`, see that for more information. -pub fn object_region_bounds<'tcx>( - tcx: &ty::ctxt<'tcx>, - principal: &ty::PolyTraitRef<'tcx>, - others: ty::BuiltinBounds) - -> Vec -{ - // Since we don't actually *know* the self type for an object, - // this "open(err)" serves as a kind of dummy standin -- basically - // a skolemized type. - let open_ty = tcx.mk_infer(ty::FreshTy(0)); - - // Note that we preserve the overall binding levels here. - assert!(!open_ty.has_escaping_regions()); - let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty)); - let trait_refs = vec!(ty::Binder(ty::TraitRef::new(principal.0.def_id, substs))); - - let mut predicates = others.to_predicates(tcx, open_ty); - predicates.extend(trait_refs.iter().map(|t| t.to_predicate())); - - tcx.required_region_bounds(open_ty, predicates) -} diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index ec55daca9ecdf..6e57d5dd1ba8d 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -239,7 +239,6 @@ pub fn collect_language_items(session: &Session, collector.collect(krate); let LanguageItemCollector { mut items, .. } = collector; weak_lang_items::check_crate(krate, session, &mut items); - session.abort_if_errors(); items } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 2f3af1c0d09b5..975ec0e709b7d 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -176,14 +176,15 @@ impl Session { pub fn abort_if_errors(&self) { self.diagnostic().abort_if_errors(); } - pub fn abort_if_new_errors(&self, mut f: F) - where F: FnMut() + pub fn abort_if_new_errors(&self, f: F) -> T + where F: FnOnce() -> T { let count = self.err_count(); - f(); + let result = f(); if self.err_count() > count { self.abort_if_errors(); } + result } pub fn span_warn(&self, sp: Span, msg: &str) { self.diagnostic().span_warn(sp, msg) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index fd5f711c9d639..36074a7ae0225 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -69,8 +69,8 @@ pub fn compile_input(sess: Session, let state = $make_state; (control.$point.callback)(state); - $tsess.abort_if_errors(); if control.$point.stop == Compilation::Stop { + $tsess.abort_if_errors(); return; } })} @@ -470,7 +470,11 @@ pub fn phase_2_configure_and_expand(sess: &Session, let mut feature_gated_cfgs = vec![]; krate = time(time_passes, "configuration 1", || { - syntax::config::strip_unconfigured_items(sess.diagnostic(), krate, &mut feature_gated_cfgs) + sess.abort_if_new_errors(|| { + syntax::config::strip_unconfigured_items(sess.diagnostic(), + krate, + &mut feature_gated_cfgs) + }) }); *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs); @@ -481,13 +485,15 @@ pub fn phase_2_configure_and_expand(sess: &Session, }); time(time_passes, "gated macro checking", || { - let features = syntax::feature_gate::check_crate_macros(sess.codemap(), - &sess.parse_sess.span_diagnostic, - &krate); - - // these need to be set "early" so that expansion sees `quote` if enabled. - *sess.features.borrow_mut() = features; - sess.abort_if_errors(); + sess.abort_if_new_errors(|| { + let features = + syntax::feature_gate::check_crate_macros(sess.codemap(), + &sess.parse_sess.span_diagnostic, + &krate); + + // these need to be set "early" so that expansion sees `quote` if enabled. + *sess.features.borrow_mut() = features; + }); }); @@ -525,7 +531,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups, llvm_passes, attributes, .. } = registry; - { + sess.abort_if_new_errors(|| { let mut ls = sess.lint_store.borrow_mut(); for pass in early_lint_passes { ls.register_early_pass(Some(sess), true, pass); @@ -540,17 +546,14 @@ pub fn phase_2_configure_and_expand(sess: &Session, *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; *sess.plugin_attributes.borrow_mut() = attributes.clone(); - } + }); // Lint plugins are registered; now we can process command line flags. if sess.opts.describe_lints { super::describe_lints(&*sess.lint_store.borrow(), true); return None; } - sess.lint_store.borrow_mut().process_command_line(sess); - - // Abort if there are errors from lint processing or a plugin registrar. - sess.abort_if_errors(); + sess.abort_if_new_errors(|| sess.lint_store.borrow_mut().process_command_line(sess)); krate = time(time_passes, "expansion", || { // Windows dlls do not have rpaths, so they don't know how to find their @@ -594,29 +597,36 @@ pub fn phase_2_configure_and_expand(sess: &Session, // much as possible (e.g. help the programmer avoid platform // specific differences) time(time_passes, "complete gated feature checking 1", || { - let features = syntax::feature_gate::check_crate(sess.codemap(), - &sess.parse_sess.span_diagnostic, - &krate, - &attributes, - sess.opts.unstable_features); - *sess.features.borrow_mut() = features; - sess.abort_if_errors(); + sess.abort_if_new_errors(|| { + let features = syntax::feature_gate::check_crate(sess.codemap(), + &sess.parse_sess.span_diagnostic, + &krate, + &attributes, + sess.opts.unstable_features); + *sess.features.borrow_mut() = features; + }); }); // JBC: make CFG processing part of expansion to avoid this problem: // strip again, in case expansion added anything with a #[cfg]. - krate = time(time_passes, "configuration 2", || { - syntax::config::strip_unconfigured_items(sess.diagnostic(), krate, &mut feature_gated_cfgs) - }); + krate = sess.abort_if_new_errors(|| { + let krate = time(time_passes, "configuration 2", || { + syntax::config::strip_unconfigured_items(sess.diagnostic(), + krate, + &mut feature_gated_cfgs) + }); - time(time_passes, "gated configuration checking", || { - let features = sess.features.borrow(); - feature_gated_cfgs.sort(); - feature_gated_cfgs.dedup(); - for cfg in &feature_gated_cfgs { - cfg.check_and_emit(sess.diagnostic(), &features, sess.codemap()); - } + time(time_passes, "gated configuration checking", || { + let features = sess.features.borrow(); + feature_gated_cfgs.sort(); + feature_gated_cfgs.dedup(); + for cfg in &feature_gated_cfgs { + cfg.check_and_emit(sess.diagnostic(), &features, sess.codemap()); + } + }); + + krate }); krate = time(time_passes, "maybe building test harness", || { @@ -639,13 +649,14 @@ pub fn phase_2_configure_and_expand(sess: &Session, // later, to make sure we've got everything (e.g. configuration // can insert new attributes via `cfg_attr`) time(time_passes, "complete gated feature checking 2", || { - let features = syntax::feature_gate::check_crate(sess.codemap(), - &sess.parse_sess.span_diagnostic, - &krate, - &attributes, - sess.opts.unstable_features); - *sess.features.borrow_mut() = features; - sess.abort_if_errors(); + sess.abort_if_new_errors(|| { + let features = syntax::feature_gate::check_crate(sess.codemap(), + &sess.parse_sess.span_diagnostic, + &krate, + &attributes, + sess.opts.unstable_features); + *sess.features.borrow_mut() = features; + }); }); time(time_passes, @@ -711,9 +722,11 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "external crate/lib resolution", || LocalCrateReader::new(sess, cstore, &hir_map).read_crates(krate)); - let lang_items = time(time_passes, - "language item collection", - || middle::lang_items::collect_language_items(&sess, &hir_map)); + let lang_items = time(time_passes, "language item collection", || { + sess.abort_if_new_errors(|| { + middle::lang_items::collect_language_items(&sess, &hir_map) + }) + }); let resolve::CrateMap { def_map, diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index fc7fa299fb8fa..0f85c4528d2e9 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -461,6 +461,15 @@ pub enum ArchiveKind { K_COFF, } +/// Represents the different LLVM passes Rust supports +#[derive(Copy, Clone, PartialEq, Debug)] +#[repr(C)] +pub enum SupportedPassKind { + Function, + Module, + Unsupported, +} + // Opaque pointer types #[allow(missing_copy_implementations)] pub enum Module_opaque {} @@ -2008,7 +2017,10 @@ extern { pub fn LLVMIsAAllocaInst(value_ref: ValueRef) -> ValueRef; pub fn LLVMIsAConstantInt(value_ref: ValueRef) -> ValueRef; - pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: *const c_char) -> bool; + pub fn LLVMRustPassKind(Pass: PassRef) -> SupportedPassKind; + pub fn LLVMRustFindAndCreatePass(Pass: *const c_char) -> PassRef; + pub fn LLVMRustAddPass(PM: PassManagerRef, Pass: PassRef); + pub fn LLVMRustCreateTargetMachine(Triple: *const c_char, CPU: *const c_char, Features: *const c_char, diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 9122148a8cc05..9c75007a8db76 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -258,15 +258,14 @@ impl<'a> CrateReader<'a> { metadata: &MetadataBlob) { let crate_rustc_version = decoder::crate_rustc_version(metadata.as_slice()); if crate_rustc_version != Some(rustc_version()) { - span_err!(self.sess, span, E0514, - "the crate `{}` has been compiled with {}, which is \ - incompatible with this version of rustc", - name, - crate_rustc_version - .as_ref().map(|s|&**s) - .unwrap_or("an old version of rustc") + span_fatal!(self.sess, span, E0514, + "the crate `{}` has been compiled with {}, which is \ + incompatible with this version of rustc", + name, + crate_rustc_version + .as_ref().map(|s|&**s) + .unwrap_or("an old version of rustc") ); - self.sess.abort_if_errors(); } } @@ -511,7 +510,6 @@ impl<'a> CrateReader<'a> { } }; let span = mk_sp(lo, p.last_span.hi); - p.abort_if_errors(); // Mark the attrs as used for attr in &attrs { @@ -554,8 +552,7 @@ impl<'a> CrateReader<'a> { name, config::host_triple(), self.sess.opts.target_triple); - span_err!(self.sess, span, E0456, "{}", &message[..]); - self.sess.abort_if_errors(); + span_fatal!(self.sess, span, E0456, "{}", &message[..]); } let registrar = diff --git a/src/librustc_passes/const_fn.rs b/src/librustc_passes/const_fn.rs index cda5267f7271b..f422a47572b8d 100644 --- a/src/librustc_passes/const_fn.rs +++ b/src/librustc_passes/const_fn.rs @@ -18,8 +18,9 @@ use syntax::visit::{self, Visitor, FnKind}; use syntax::codemap::Span; pub fn check_crate(sess: &Session, krate: &ast::Crate) { - visit::walk_crate(&mut CheckConstFn{ sess: sess }, krate); - sess.abort_if_errors(); + sess.abort_if_new_errors(|| { + visit::walk_crate(&mut CheckConstFn{ sess: sess }, krate); + }); } struct CheckConstFn<'a> { diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 2c08cbd32338d..27354c28d85e6 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -150,26 +150,36 @@ If you really want global mutable state, try using `static mut` or a global "##, E0018: r##" -The value of static and const variables must be known at compile time. You -can't cast a pointer as an integer because we can't know what value the -address will take. -However, pointers to other constants' addresses are allowed in constants, -example: +The value of static and constant integers must be known at compile time. You +can't cast a pointer to an integer because the address of a pointer can +vary. +For example, if you write: ``` -const X: u32 = 50; -const Y: *const u32 = &X; +static MY_STATIC: u32 = 42; +static MY_STATIC_ADDR: usize = &MY_STATIC as *const _ as usize; +static WHAT: usize = (MY_STATIC_ADDR^17) + MY_STATIC_ADDR; ``` -Therefore, casting one of these non-constant pointers to an integer results -in a non-constant integer which lead to this error. Example: +Then `MY_STATIC_ADDR` would contain the address of `MY_STATIC`. However, +the address can change when the program is linked, as well as change +between different executions due to ASLR, and many linkers would +not be able to calculate the value of `WHAT`. + +On the other hand, static and constant pointers can point either to +a known numeric address or to the address of a symbol. ``` -const X: u32 = 1; -const Y: usize = &X as *const u32 as usize; -println!("{}", Y); +static MY_STATIC_ADDR: &'static u32 = &MY_STATIC; +// ... and also +static MY_STATIC_ADDR2: *const u32 = &MY_STATIC; + +const CONST_ADDR: *const u8 = 0x5f3759df as *const u8; ``` + +This does not pose a problem by itself because they can't be +accessed directly. "##, E0019: r##" @@ -347,55 +357,59 @@ From [RFC 246]: [RFC 246]: https://github.com/rust-lang/rfcs/pull/246 "##, + E0395: r##" -The value assigned to a constant expression must be known at compile time, -which is not the case when comparing raw pointers. Erroneous code example: +The value assigned to a constant scalar must be known at compile time, +which is not the case when comparing raw pointers. + +Erroneous code example: ``` -static foo: i32 = 42; -static bar: i32 = 43; +static FOO: i32 = 42; +static BAR: i32 = 42; -static baz: bool = { (&foo as *const i32) == (&bar as *const i32) }; +static BAZ: bool = { (&FOO as *const i32) == (&BAR as *const i32) }; // error: raw pointers cannot be compared in statics! ``` -Please check that the result of the comparison can be determined at compile time -or isn't assigned to a constant expression. Example: +The address assigned by the linker to `FOO` and `BAR` may or may not +be identical, so the value of `BAZ` can't be determined. + +If you want to do the comparison, please do it at run-time. + +For example: ``` -static foo: i32 = 42; -static bar: i32 = 43; +static FOO: i32 = 42; +static BAR: i32 = 42; -let baz: bool = { (&foo as *const i32) == (&bar as *const i32) }; +let baz: bool = { (&FOO as *const i32) == (&BAR as *const i32) }; // baz isn't a constant expression so it's ok ``` "##, E0396: r##" -The value assigned to a constant expression must be known at compile time, -which is not the case when dereferencing raw pointers. Erroneous code -example: +The value behind a raw pointer can't be determined at compile-time +(or even link-time), which means it can't be used in a constant +expression. +For example: ``` -const foo: i32 = 42; -const baz: *const i32 = (&foo as *const i32); +const REG_ADDR: *const u8 = 0x5f3759df as *const u8; -const deref: i32 = *baz; +const VALUE: u8 = unsafe { *REG_ADDR }; // error: raw pointers cannot be dereferenced in constants ``` -To fix this error, please do not assign this value to a constant expression. -Example: +A possible fix is to dereference your pointer at some point in run-time. -``` -const foo: i32 = 42; -const baz: *const i32 = (&foo as *const i32); +For example: -unsafe { let deref: i32 = *baz; } -// baz isn't a constant expression so it's ok ``` +const REG_ADDR: *const u8 = 0x5f3759df as *const u8; -You'll also note that this assignment must be done in an unsafe block! +let reg_value = unsafe { *REG_ADDR }; +``` "##, E0397: r##" diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 444c43163e3c3..c698f72955320 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3037,6 +3037,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { check_ribs: bool, record_used: bool) -> Option { + if identifier.name == special_idents::invalid.name { + return Some(LocalDef::from_def(Def::Err)); + } + // First, check to see whether the name is a primitive type. if namespace == TypeNS { if let Some(&prim_ty) = self.primitive_type_table @@ -4019,10 +4023,8 @@ pub fn create_resolver<'a, 'tcx>(session: &'a Session, resolver.callback = callback; build_reduced_graph::build_reduced_graph(&mut resolver, krate); - session.abort_if_errors(); resolve_imports::resolve_imports(&mut resolver); - session.abort_if_errors(); resolver } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 85419a072503a..06d32b8f6015d 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -145,7 +145,9 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, unsafe { let pm = llvm::LLVMCreatePassManager(); llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod); - llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _); + let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); + assert!(!pass.is_null()); + llvm::LLVMRustAddPass(pm, pass); with_llvm_pmb(llmod, config, &mut |b| { llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm, @@ -153,7 +155,9 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, /* RunInliner = */ True); }); - llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _); + let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); + assert!(!pass.is_null()); + llvm::LLVMRustAddPass(pm, pass); time(sess.time_passes(), "LTO passes", || llvm::LLVMRunPassManager(pm, llmod)); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 544df1798eaf9..bc007da7174a7 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -446,9 +446,22 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, // If we're verifying or linting, add them to the function pass // manager. - let addpass = |pass: &str| { - let pass = CString::new(pass).unwrap(); - llvm::LLVMRustAddPass(fpm, pass.as_ptr()) + let addpass = |pass_name: &str| { + let pass_name = CString::new(pass_name).unwrap(); + let pass = llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr()); + if pass.is_null() { + return false; + } + let pass_manager = match llvm::LLVMRustPassKind(pass) { + llvm::SupportedPassKind::Function => fpm, + llvm::SupportedPassKind::Module => mpm, + llvm::SupportedPassKind::Unsupported => { + cgcx.handler.err("Encountered LLVM pass kind we can't handle"); + return true + }, + }; + llvm::LLVMRustAddPass(pass_manager, pass); + true }; if !config.no_verify { assert!(addpass("verify")); } diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index a6f8e3f10f117..2951cf2ee1ba4 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -135,6 +135,9 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { // always using the first ones. So, only error out if we don't have enough spans. // What could go wrong...? if spans.len() < path.segments.len() { + if generated_code(path.span) { + return vec!(); + } error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:", path_to_string(path), spans.len(), @@ -308,28 +311,26 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { id: ast::NodeId, name: ast::Name, span: Span) { - if generated_code(span) { - return; - } - debug!("process_method: {}:{}", id, name); - let method_data = self.save_ctxt.get_method_data(id, name, span); + if let Some(method_data) = self.save_ctxt.get_method_data(id, name, span) { - if body.is_some() { - self.fmt.method_str(span, - Some(method_data.span), - method_data.id, - &method_data.qualname, - method_data.declaration, - method_data.scope); - self.process_formals(&sig.decl.inputs, &method_data.qualname); - } else { - self.fmt.method_decl_str(span, - Some(method_data.span), - method_data.id, - &method_data.qualname, - method_data.scope); + if body.is_some() { + self.fmt.method_str(span, + Some(method_data.span), + method_data.id, + &method_data.qualname, + method_data.declaration, + method_data.scope); + self.process_formals(&sig.decl.inputs, &method_data.qualname); + } else { + self.fmt.method_decl_str(span, + Some(method_data.span), + method_data.id, + &method_data.qualname, + method_data.scope); + } + self.process_generic_params(&sig.generics, span, &method_data.qualname, id); } // walk arg and return types @@ -345,8 +346,6 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { if let Some(body) = body { self.nest(id, |v| v.visit_block(body)); } - - self.process_generic_params(&sig.generics, span, &method_data.qualname, id); } fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) { @@ -402,17 +401,17 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { decl: &ast::FnDecl, ty_params: &ast::Generics, body: &ast::Block) { - let fn_data = self.save_ctxt.get_item_data(item); - down_cast_data!(fn_data, FunctionData, self, item.span); - self.fmt.fn_str(item.span, - Some(fn_data.span), - fn_data.id, - &fn_data.qualname, - fn_data.scope); - - - self.process_formals(&decl.inputs, &fn_data.qualname); - self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id); + if let Some(fn_data) = self.save_ctxt.get_item_data(item) { + down_cast_data!(fn_data, FunctionData, self, item.span); + self.fmt.fn_str(item.span, + Some(fn_data.span), + fn_data.id, + &fn_data.qualname, + fn_data.scope); + + self.process_formals(&decl.inputs, &fn_data.qualname); + self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id); + } for arg in &decl.inputs { self.visit_ty(&arg.ty); @@ -426,17 +425,17 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } fn process_static_or_const_item(&mut self, item: &ast::Item, typ: &ast::Ty, expr: &ast::Expr) { - let var_data = self.save_ctxt.get_item_data(item); - down_cast_data!(var_data, VariableData, self, item.span); - self.fmt.static_str(item.span, - Some(var_data.span), - var_data.id, - &var_data.name, - &var_data.qualname, - &var_data.value, - &var_data.type_value, - var_data.scope); - + if let Some(var_data) = self.save_ctxt.get_item_data(item) { + down_cast_data!(var_data, VariableData, self, item.span); + self.fmt.static_str(item.span, + Some(var_data.span), + var_data.id, + &var_data.name, + &var_data.qualname, + &var_data.value, + &var_data.type_value, + var_data.scope); + } self.visit_ty(&typ); self.visit_expr(expr); } @@ -495,6 +494,10 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { enum_definition: &ast::EnumDef, ty_params: &ast::Generics) { let enum_data = self.save_ctxt.get_item_data(item); + let enum_data = match enum_data { + None => return, + Some(data) => data, + }; down_cast_data!(enum_data, EnumData, self, item.span); self.fmt.enum_str(item.span, Some(enum_data.span), @@ -547,36 +550,36 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { trait_ref: &Option, typ: &ast::Ty, impl_items: &[P]) { - let impl_data = self.save_ctxt.get_item_data(item); - down_cast_data!(impl_data, ImplData, self, item.span); - match impl_data.self_ref { - Some(ref self_ref) => { + let mut has_self_ref = false; + if let Some(impl_data) = self.save_ctxt.get_item_data(item) { + down_cast_data!(impl_data, ImplData, self, item.span); + if let Some(ref self_ref) = impl_data.self_ref { + has_self_ref = true; self.fmt.ref_str(recorder::TypeRef, item.span, Some(self_ref.span), self_ref.ref_id, self_ref.scope); } - None => { - self.visit_ty(&typ); + if let Some(ref trait_ref_data) = impl_data.trait_ref { + self.fmt.ref_str(recorder::TypeRef, + item.span, + Some(trait_ref_data.span), + trait_ref_data.ref_id, + trait_ref_data.scope); + visit::walk_path(self, &trait_ref.as_ref().unwrap().path); } + + self.fmt.impl_str(item.span, + Some(impl_data.span), + impl_data.id, + impl_data.self_ref.map(|data| data.ref_id), + impl_data.trait_ref.map(|data| data.ref_id), + impl_data.scope); } - if let Some(ref trait_ref_data) = impl_data.trait_ref { - self.fmt.ref_str(recorder::TypeRef, - item.span, - Some(trait_ref_data.span), - trait_ref_data.ref_id, - trait_ref_data.scope); - visit::walk_path(self, &trait_ref.as_ref().unwrap().path); + if !has_self_ref { + self.visit_ty(&typ); } - - self.fmt.impl_str(item.span, - Some(impl_data.span), - impl_data.id, - impl_data.self_ref.map(|data| data.ref_id), - impl_data.trait_ref.map(|data| data.ref_id), - impl_data.scope); - self.process_generic_params(type_parameters, item.span, "", item.id); for impl_item in impl_items { self.visit_impl_item(impl_item); @@ -633,22 +636,23 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { // `item` is the module in question, represented as an item. fn process_mod(&mut self, item: &ast::Item) { - let mod_data = self.save_ctxt.get_item_data(item); - down_cast_data!(mod_data, ModData, self, item.span); - self.fmt.mod_str(item.span, - Some(mod_data.span), - mod_data.id, - &mod_data.qualname, - mod_data.scope, - &mod_data.filename); + if let Some(mod_data) = self.save_ctxt.get_item_data(item) { + down_cast_data!(mod_data, ModData, self, item.span); + self.fmt.mod_str(item.span, + Some(mod_data.span), + mod_data.id, + &mod_data.qualname, + mod_data.scope, + &mod_data.filename); + } } fn process_path(&mut self, id: NodeId, path: &ast::Path, ref_kind: Option) { - if generated_code(path.span) { + let path_data = self.save_ctxt.get_path_data(id, path); + if generated_code(path.span) && path_data.is_none() { return; } - let path_data = self.save_ctxt.get_path_data(id, path); let path_data = match path_data { Some(pd) => pd, None => { @@ -719,10 +723,6 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fields: &Vec, variant: ty::VariantDef, base: &Option>) { - if generated_code(path.span) { - return - } - self.write_sub_paths_truncated(path, false); if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) { @@ -735,16 +735,15 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { let scope = self.save_ctxt.enclosing_scope(ex.id); for field in fields { - if generated_code(field.ident.span) { - continue; - } + if let Some(field_data) = self.save_ctxt + .get_field_ref_data(field, variant, scope) { - let field_data = self.save_ctxt.get_field_ref_data(field, variant, scope); - self.fmt.ref_str(recorder::VarRef, - field.ident.span, - Some(field_data.span), - field_data.ref_id, - field_data.scope); + self.fmt.ref_str(recorder::VarRef, + field.ident.span, + Some(field_data.span), + field_data.ref_id, + field_data.scope); + } self.visit_expr(&field.expr) } @@ -768,10 +767,6 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } fn process_pat(&mut self, p: &ast::Pat) { - if generated_code(p.span) { - return; - } - match p.node { ast::PatStruct(ref path, ref fields, _) => { visit::walk_path(self, path); @@ -780,10 +775,6 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { let variant = adt.variant_of_def(def); for &Spanned { node: ref field, span } in fields { - if generated_code(span) { - continue; - } - let sub_span = self.span.span_for_first_ident(span); if let Some(f) = variant.find_field_named(field.ident.name) { self.fmt.ref_str(recorder::VarRef, span, sub_span, f.did, self.cur_scope); @@ -827,10 +818,6 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { fn visit_item(&mut self, item: &ast::Item) { - if generated_code(item.span) { - return - } - match item.node { ast::ItemUse(ref use_item) => { match use_item.node { @@ -1025,10 +1012,6 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { } fn visit_ty(&mut self, t: &ast::Ty) { - if generated_code(t.span) { - return - } - match t.node { ast::TyPath(_, ref path) => { match self.lookup_type_ref(t.id) { @@ -1048,10 +1031,6 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { } fn visit_expr(&mut self, ex: &ast::Expr) { - if generated_code(ex.span) { - return - } - match ex.node { ast::ExprCall(ref _f, ref _args) => { // Don't need to do anything for function calls, @@ -1070,10 +1049,6 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { } ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args), ast::ExprField(ref sub_ex, _) => { - if generated_code(sub_ex.span) { - return - } - self.visit_expr(&sub_ex); if let Some(field_data) = self.save_ctxt.get_expr_data(ex) { @@ -1086,10 +1061,6 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { } } ast::ExprTupField(ref sub_ex, idx) => { - if generated_code(sub_ex.span) { - return - } - self.visit_expr(&**sub_ex); let hir_node = lower_expr(self.save_ctxt.lcx, sub_ex); @@ -1110,10 +1081,6 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { } } ast::ExprClosure(_, ref decl, ref body) => { - if generated_code(body.span) { - return - } - let mut id = String::from("$"); id.push_str(&ex.id.to_string()); self.process_formals(&decl.inputs, &id); @@ -1210,18 +1177,10 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { } fn visit_stmt(&mut self, s: &ast::Stmt) { - if generated_code(s.span) { - return - } - visit::walk_stmt(self, s) } fn visit_local(&mut self, l: &ast::Local) { - if generated_code(l.span) { - return - } - let value = self.span.snippet(l.span); self.process_var_decl(&l.pat, value); diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 00554419e649c..37b23d6ee9ce9 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -30,7 +30,7 @@ use syntax::print::pprust::ty_to_string; use self::span_utils::SpanUtils; - +#[macro_use] pub mod span_utils; pub mod recorder; @@ -209,21 +209,21 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result } - pub fn get_item_data(&self, item: &ast::Item) -> Data { + pub fn get_item_data(&self, item: &ast::Item) -> Option { match item.node { ast::ItemFn(..) => { let name = self.tcx.map.path_to_string(item.id); let qualname = format!("::{}", name); let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); - - Data::FunctionData(FunctionData { + filter!(self.span_utils, sub_span, item.span, None); + Some(Data::FunctionData(FunctionData { id: item.id, name: name, qualname: qualname, declaration: None, span: sub_span.unwrap(), scope: self.enclosing_scope(item.id), - }) + })) } ast::ItemStatic(ref typ, mt, ref expr) => { let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); @@ -235,8 +235,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { }; let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword); - - Data::VariableData(VariableData { + filter!(self.span_utils, sub_span, item.span, None); + Some(Data::VariableData(VariableData { id: item.id, name: item.ident.to_string(), qualname: qualname, @@ -244,13 +244,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(item.id), value: value, type_value: ty_to_string(&typ), - }) + })) } ast::ItemConst(ref typ, ref expr) => { let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Const); - - Data::VariableData(VariableData { + filter!(self.span_utils, sub_span, item.span, None); + Some(Data::VariableData(VariableData { id: item.id, name: item.ident.to_string(), qualname: qualname, @@ -258,7 +258,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(item.id), value: self.span_utils.snippet(expr.span), type_value: ty_to_string(&typ), - }) + })) } ast::ItemMod(ref m) => { let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); @@ -267,28 +267,28 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let filename = cm.span_to_filename(m.inner); let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Mod); - - Data::ModData(ModData { + filter!(self.span_utils, sub_span, item.span, None); + Some(Data::ModData(ModData { id: item.id, name: item.ident.to_string(), qualname: qualname, span: sub_span.unwrap(), scope: self.enclosing_scope(item.id), filename: filename, - }) + })) } ast::ItemEnum(..) => { let enum_name = format!("::{}", self.tcx.map.path_to_string(item.id)); let val = self.span_utils.snippet(item.span); let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Enum); - - Data::EnumData(EnumData { + filter!(self.span_utils, sub_span, item.span, None); + Some(Data::EnumData(EnumData { id: item.id, value: val, span: sub_span.unwrap(), qualname: enum_name, scope: self.enclosing_scope(item.id), - }) + })) } ast::ItemImpl(_, _, _, ref trait_ref, ref typ, _) => { let mut type_data = None; @@ -299,10 +299,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { match typ.node { // Common case impl for a struct or something basic. ast::TyPath(None, ref path) => { - sub_span = self.span_utils.sub_span_for_type_name(path.span).unwrap(); + sub_span = self.span_utils.sub_span_for_type_name(path.span); + filter!(self.span_utils, sub_span, path.span, None); type_data = self.lookup_ref_id(typ.id).map(|id| { TypeRefData { - span: sub_span, + span: sub_span.unwrap(), scope: parent, ref_id: id, } @@ -311,20 +312,21 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { _ => { // Less useful case, impl for a compound type. let span = typ.span; - sub_span = self.span_utils.sub_span_for_type_name(span).unwrap_or(span); + sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span)); } } let trait_data = trait_ref.as_ref() .and_then(|tr| self.get_trait_ref_data(tr, parent)); - Data::ImplData(ImplData { + filter!(self.span_utils, sub_span, typ.span, None); + Some(Data::ImplData(ImplData { id: item.id, - span: sub_span, + span: sub_span.unwrap(), scope: parent, trait_ref: trait_data, self_ref: type_data, - }) + })) } _ => { // FIXME @@ -333,12 +335,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } - pub fn get_field_data(&self, field: &ast::StructField, scope: NodeId) -> Option { + pub fn get_field_data(&self, field: &ast::StructField, + scope: NodeId) -> Option { match field.node.kind { ast::NamedField(ident, _) => { let qualname = format!("::{}::{}", self.tcx.map.path_to_string(scope), ident); let typ = self.tcx.node_types().get(&field.node.id).unwrap().to_string(); let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon); + filter!(self.span_utils, sub_span, field.span, None); Some(VariableData { id: field.node.id, name: ident.to_string(), @@ -355,7 +359,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // FIXME would be nice to take a MethodItem here, but the ast provides both // trait and impl flavours, so the caller must do the disassembly. - pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> FunctionData { + pub fn get_method_data(&self, id: ast::NodeId, + name: ast::Name, span: Span) -> Option { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. let qualname = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { @@ -430,29 +435,30 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { }); let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn); - - FunctionData { + filter!(self.span_utils, sub_span, span, None); + Some(FunctionData { id: id, name: name.to_string(), qualname: qualname, declaration: decl_id, span: sub_span.unwrap(), scope: self.enclosing_scope(id), - } + }) } pub fn get_trait_ref_data(&self, trait_ref: &ast::TraitRef, parent: NodeId) -> Option { - self.lookup_ref_id(trait_ref.ref_id).map(|def_id| { + self.lookup_ref_id(trait_ref.ref_id).and_then(|def_id| { let span = trait_ref.path.span; - let sub_span = self.span_utils.sub_span_for_type_name(span).unwrap_or(span); - TypeRefData { - span: sub_span, + let sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span)); + filter!(self.span_utils, sub_span, span, None); + Some(TypeRefData { + span: sub_span.unwrap(), scope: parent, ref_id: def_id, - } + }) }) } @@ -465,6 +471,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ty::TyStruct(def, _) => { let f = def.struct_variant().field_named(ident.node.name); let sub_span = self.span_utils.span_for_last_ident(expr.span); + filter!(self.span_utils, sub_span, expr.span, None); return Some(Data::VariableRefData(VariableRefData { name: ident.node.to_string(), span: sub_span.unwrap(), @@ -484,6 +491,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { match *ty { ty::TyStruct(def, _) => { let sub_span = self.span_utils.span_for_last_ident(path.span); + filter!(self.span_utils, sub_span, path.span, None); Some(Data::TypeRefData(TypeRefData { span: sub_span.unwrap(), scope: self.enclosing_scope(expr.id), @@ -506,6 +514,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ty::TraitContainer(_) => (None, Some(method_id)), }; let sub_span = self.span_utils.sub_span_for_meth_name(expr.span); + filter!(self.span_utils, sub_span, expr.span, None); let parent = self.enclosing_scope(expr.id); Some(Data::MethodCallData(MethodCallData { span: sub_span.unwrap(), @@ -532,6 +541,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } let def = def_map.get(&id).unwrap().full_def(); let sub_span = self.span_utils.span_for_last_ident(path.span); + filter!(self.span_utils, sub_span, path.span, None); match def { Def::Upvar(..) | Def::Local(..) | @@ -559,6 +569,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } Def::Method(decl_id) => { let sub_span = self.span_utils.sub_span_for_meth_name(path.span); + filter!(self.span_utils, sub_span, path.span, None); let def_id = if decl_id.is_local() { let ti = self.tcx.impl_or_trait_item(decl_id); match ti.container() { @@ -628,16 +639,17 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { field_ref: &ast::Field, variant: ty::VariantDef, parent: NodeId) - -> VariableRefData { + -> Option { let f = variant.field_named(field_ref.ident.node.name); // We don't really need a sub-span here, but no harm done let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span); - VariableRefData { + filter!(self.span_utils, sub_span, field_ref.ident.span, None); + Some(VariableRefData { name: field_ref.ident.node.to_string(), span: sub_span.unwrap(), scope: parent, ref_id: f.did, - } + }) } pub fn get_data_for_id(&self, _id: &NodeId) -> Data { @@ -677,17 +689,15 @@ impl PathCollector { impl<'v> Visitor<'v> for PathCollector { fn visit_pat(&mut self, p: &ast::Pat) { - if generated_code(p.span) { - return; - } - match p.node { ast::PatStruct(ref path, _, _) => { - self.collected_paths.push((p.id, path.clone(), ast::MutMutable, recorder::TypeRef)); + self.collected_paths.push((p.id, path.clone(), + ast::MutMutable, recorder::TypeRef)); } ast::PatEnum(ref path, _) | ast::PatQPath(_, ref path) => { - self.collected_paths.push((p.id, path.clone(), ast::MutMutable, recorder::VarRef)); + self.collected_paths.push((p.id, path.clone(), + ast::MutMutable, recorder::VarRef)); } ast::PatIdent(bm, ref path1, _) => { debug!("PathCollector, visit ident in pat {}: {:?} {:?}", @@ -719,10 +729,6 @@ pub fn process_crate<'l, 'tcx>(tcx: &'l ty::ctxt<'tcx>, odir: Option<&Path>) { let _ignore = tcx.dep_graph.in_ignore(); - if generated_code(krate.span) { - return; - } - assert!(analysis.glob_map.is_some()); info!("Dumping crate {}", cratename); @@ -780,8 +786,8 @@ fn escape(s: String) -> String { s.replace("\"", "\"\"") } -// If the expression is a macro expansion or other generated code, run screaming -// and don't index. +// Helper function to determine if a span came from a +// macro expansion or syntax extension. pub fn generated_code(span: Span) -> bool { span.expn_id != NO_EXPANSION || span == DUMMY_SP } diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs index 17fdbe2e8398e..eaba366c1d42a 100644 --- a/src/librustc_trans/save/recorder.rs +++ b/src/librustc_trans/save/recorder.rs @@ -318,6 +318,7 @@ impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> { span: Span, sub_span: Option, values: Vec) { + filter!(self.span, sub_span, span); match sub_span { Some(sub_span) => self.record_with_span(kind, span, sub_span, values), None => { diff --git a/src/librustc_trans/save/span_utils.rs b/src/librustc_trans/save/span_utils.rs index 773d5caea5f1a..344431032d694 100644 --- a/src/librustc_trans/save/span_utils.rs +++ b/src/librustc_trans/save/span_utils.rs @@ -66,13 +66,6 @@ impl<'a> SpanUtils<'a> { // sub_span starts at span.lo, so we need to adjust the positions etc. // If sub_span is None, we don't need to adjust. pub fn make_sub_span(&self, span: Span, sub_span: Option) -> Option { - let loc = self.sess.codemap().lookup_char_pos(span.lo); - assert!(!generated_code(span), - "generated code; we should not be processing this `{}` in {}, line {}", - self.snippet(span), - loc.file.name, - loc.line); - match sub_span { None => None, Some(sub) => { @@ -81,7 +74,7 @@ impl<'a> SpanUtils<'a> { Some(Span { lo: base + self.sess.codemap().lookup_byte_offset(sub.lo).pos, hi: base + self.sess.codemap().lookup_byte_offset(sub.hi).pos, - expn_id: NO_EXPANSION, + expn_id: span.expn_id, }) } } @@ -259,6 +252,9 @@ impl<'a> SpanUtils<'a> { let ts = toks.real_token(); if ts.tok == token::Eof { if bracket_count != 0 { + if generated_code(span) { + return vec!(); + } let loc = self.sess.codemap().lookup_char_pos(span.lo); self.sess.span_bug(span, &format!("Mis-counted brackets when breaking path? \ @@ -358,19 +354,12 @@ impl<'a> SpanUtils<'a> { // Returns a list of the spans of idents in a path. // E.g., For foo::bar::baz, we return [foo, bar, baz] (well, their spans) pub fn spans_for_path_segments(&self, path: &ast::Path) -> Vec { - if generated_code(path.span) { - return vec!(); - } - self.spans_with_brackets(path.span, 0, -1) } // Return an owned vector of the subspans of the param identifier // tokens found in span. pub fn spans_for_ty_params(&self, span: Span, number: isize) -> Vec { - if generated_code(span) { - return vec!(); - } // Type params are nested within one level of brackets: // i.e. we want Vec from Foo> self.spans_with_brackets(span, 1, number) @@ -388,4 +377,40 @@ impl<'a> SpanUtils<'a> { self.sess.bug("span errors reached 1000, giving up"); } } + + /// Return true if the span is generated code, and + /// it is not a subspan of the root callsite. + /// + /// Used to filter out spans of minimal value, + /// such as references to macro internal variables. + pub fn filter_generated(&self, sub_span: Option, parent: Span) -> bool { + if !generated_code(parent) { + if sub_span.is_none() { + // Edge case - this occurs on generated code with incorrect expansion info. + return true; + } + return false; + } + // If sub_span is none, filter out generated code. + if sub_span.is_none() { + return true; + } + // A generated span is deemed invalid if it is not a sub-span of the root + // callsite. This filters out macro internal variables and most malformed spans. + let span = self.sess.codemap().source_callsite(parent); + !(parent.lo >= span.lo && parent.hi <= span.hi) + } +} + +macro_rules! filter { + ($util: expr, $span: ident, $parent: expr, None) => { + if $util.filter_generated($span, $parent) { + return None; + } + }; + ($util: expr, $span: ident, $parent: expr) => { + if $util.filter_generated($span, $parent) { + return; + } + }; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f49b25df66e87..a8697f45d9156 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -121,7 +121,7 @@ use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::codemap::{self, Span, Spanned}; use syntax::errors::DiagnosticBuilder; -use syntax::parse::token::{self, InternedString}; +use syntax::parse::token::{self, InternedString, special_idents}; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; @@ -2839,8 +2839,10 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, method_ty } Err(error) => { - method::report_error(fcx, method_name.span, expr_t, - method_name.node, Some(rcvr), error); + if method_name.node != special_idents::invalid.name { + method::report_error(fcx, method_name.span, expr_t, + method_name.node, Some(rcvr), error); + } fcx.write_error(expr.id); fcx.tcx().types.err } @@ -2938,6 +2940,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, None => {} } + if field.node == special_idents::invalid.name { + fcx.write_error(expr.id); + return; + } + if method::exists(fcx, field.span, field.node, expr_t, expr.id) { fcx.type_error_struct(field.span, |actual| { @@ -3788,8 +3795,9 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, Some((Some(ty), slice::ref_slice(item_segment), def)) } Err(error) => { - method::report_error(fcx, span, ty, - item_name, None, error); + if item_name != special_idents::invalid.name { + method::report_error(fcx, span, ty, item_name, None, error); + } fcx.write_error(node_id); None } @@ -4221,7 +4229,9 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } // Check for unrepresentable discriminant values match hint { - attr::ReprAny | attr::ReprExtern => (), + attr::ReprAny | attr::ReprExtern => { + disr_vals.push(current_disr_val); + } attr::ReprInt(sp, ity) => { if !disr_in_range(ccx, ity, current_disr_val) { let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0082, @@ -4231,14 +4241,9 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, err.emit(); } } - attr::ReprSimd => { - ccx.tcx.sess.bug("range_to_inttype: found ReprSimd on an enum"); - } - attr::ReprPacked => { - ccx.tcx.sess.bug("range_to_inttype: found ReprPacked on an enum"); - } + // Error reported elsewhere. + attr::ReprSimd | attr::ReprPacked => {} } - disr_vals.push(current_disr_val); } } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 47cd31d9898d1..56b02412c31b2 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -86,7 +86,6 @@ use astconv::AstConv; use check::dropck; use check::FnCtxt; use middle::free_region::FreeRegionMap; -use middle::implicator::{self, Implication}; use middle::mem_categorization as mc; use middle::mem_categorization::Categorization; use middle::region::{self, CodeExtent}; @@ -365,12 +364,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { r_o, r_o.cause); let sup_type = self.resolve_type(r_o.sup_type); let origin = self.code_to_origin(r_o.cause.span, sup_type, &r_o.cause.code); - - if r_o.sub_region != ty::ReEmpty { - type_must_outlive(self, origin, sup_type, r_o.sub_region); - } else { - self.visit_old_school_wf(node_id, sup_type, origin); - } + type_must_outlive(self, origin, sup_type, r_o.sub_region); } // Processing the region obligations should not cause the list to grow further: @@ -378,47 +372,6 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { self.fcx.inh.infcx.fulfillment_cx.borrow().region_obligations(node_id).len()); } - fn visit_old_school_wf(&mut self, - body_id: ast::NodeId, - ty: Ty<'tcx>, - origin: infer::SubregionOrigin<'tcx>) { - // As a weird kind of hack, we use a region of empty as a signal - // to mean "old-school WF rules". The only reason the old-school - // WF rules are not encoded using WF is that this leads to errors, - // and we want to phase those in gradually. - - // FIXME(#27579) remove this weird special case once we phase in new WF rules completely - let implications = implicator::implications(self.infcx(), - body_id, - ty, - ty::ReEmpty, - origin.span()); - let origin_for_ty = |ty: Option>| match ty { - None => origin.clone(), - Some(ty) => infer::ReferenceOutlivesReferent(ty, origin.span()), - }; - for implication in implications { - match implication { - Implication::RegionSubRegion(ty, r1, r2) => { - self.fcx.mk_subr(origin_for_ty(ty), r1, r2); - } - Implication::RegionSubGeneric(ty, r1, GenericKind::Param(param_ty)) => { - param_ty_must_outlive(self, origin_for_ty(ty), r1, param_ty); - } - Implication::RegionSubGeneric(ty, r1, GenericKind::Projection(proj_ty)) => { - projection_must_outlive(self, origin_for_ty(ty), r1, proj_ty); - } - Implication::Predicate(def_id, predicate) => { - let cause = traits::ObligationCause::new(origin.span(), - body_id, - traits::ItemObligation(def_id)); - let obligation = traits::Obligation::new(cause, predicate); - self.fcx.register_predicate(obligation); - } - } - } - } - fn code_to_origin(&self, span: Span, sup_type: Ty<'tcx>, diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 187a1797dac04..e40a3d06f7753 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -436,19 +436,19 @@ impl OpenOptions { /// Note that setting `.write(true).append(true)` has the same effect as /// setting only `.append(true)`. /// - /// For most filesystems the operating system guarantees all writes are + /// For most filesystems, the operating system guarantees that all writes are /// atomic: no writes get mangled because another process writes at the same /// time. /// /// One maybe obvious note when using append-mode: make sure that all data - /// that belongs together, is written the the file in one operation. This + /// that belongs together is written to the file in one operation. This /// can be done by concatenating strings before passing them to `write()`, - /// or using a buffered writer (with a more than adequately sized buffer) + /// or using a buffered writer (with a buffer of adequate size), /// and calling `flush()` when the message is complete. /// /// If a file is opened with both read and append access, beware that after - /// opening and after every write the position for reading may be set at the - /// end of the file. So before writing save the current position (using + /// opening, and after every write, the position for reading may be set at the + /// end of the file. So, before writing, save the current position (using /// `seek(SeekFrom::Current(0))`, and restore it before the next read. /// /// # Examples diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index bb9d37f93ab8b..4a91cece143a9 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -439,11 +439,9 @@ fn make_argv(prog: &CString, args: &[CString]) { let mut ptrs: Vec<*const libc::c_char> = Vec::with_capacity(args.len()+1); - // Convert the CStrings into an array of pointers. Note: the - // lifetime of the various CStrings involved is guaranteed to be - // larger than the lifetime of our invocation of cb, but this is - // technically unsafe as the callback could leak these pointers - // out of our scope. + // Convert the CStrings into an array of pointers. Also return the + // vector that owns the raw pointers, to ensure they live long + // enough. ptrs.push(prog.as_ptr()); ptrs.extend(args.iter().map(|tmp| tmp.as_ptr())); @@ -457,10 +455,9 @@ fn make_envp(env: Option<&HashMap>) -> (*const c_void, Vec>, Vec<*const libc::c_char>) { // On posixy systems we can pass a char** for envp, which is a - // null-terminated array of "k=v\0" strings. Since we must create - // these strings locally, yet expose a raw pointer to them, we - // create a temporary vector to own the CStrings that outlives the - // call to cb. + // null-terminated array of "k=v\0" strings. As with make_argv, we + // return two vectors that own the data to ensure that they live + // long enough. if let Some(env) = env { let mut tmps = Vec::with_capacity(env.len()); diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 8d6c0df981f23..432c1688536bb 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -858,10 +858,15 @@ impl CodeMap { let span_str = self.span_to_string(sp); let mut span_snip = self.span_to_snippet(sp) .unwrap_or("Snippet unavailable".to_owned()); - if span_snip.len() > 50 { - span_snip.truncate(50); + + // Truncate by code points - in worst case this will be more than 50 characters, + // but ensures at least 50 characters and respects byte boundaries. + let char_vec: Vec<(usize, char)> = span_snip.char_indices().collect(); + if char_vec.len() > 50 { + span_snip.truncate(char_vec[49].0); span_snip.push_str("..."); } + output.push_str(&format!("{}{}\n{}`{}`\n", indent, span_str, indent, span_snip)); if sp.expn_id == NO_EXPANSION || sp.expn_id == COMMAND_LINE_EXPN { @@ -909,6 +914,22 @@ impl CodeMap { output } + /// Return the source span - this is either the supplied span, or the span for + /// the macro callsite that expanded to it. + pub fn source_callsite(&self, sp: Span) -> Span { + let mut span = sp; + while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN { + if let Some(callsite) = self.with_expn_info(span.expn_id, + |ei| ei.map(|ei| ei.call_site.clone())) { + span = callsite; + } + else { + break; + } + } + span + } + pub fn span_to_filename(&self, sp: Span) -> FileName { self.lookup_char_pos(sp.lo).file.name.to_string() } diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index 6983c74696ac8..a7a4ddc3b2a63 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -555,6 +555,9 @@ impl Handler { pub enum Level { Bug, Fatal, + // An error which while not immediately fatal, should stop the compiler + // progressing beyond the current phase. + PhaseFatal, Error, Warning, Note, @@ -573,7 +576,7 @@ impl fmt::Display for Level { impl Level { fn color(self) -> term::color::Color { match self { - Bug | Fatal | Error => term::color::BRIGHT_RED, + Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED, Warning => term::color::BRIGHT_YELLOW, Note => term::color::BRIGHT_GREEN, Help => term::color::BRIGHT_CYAN, @@ -584,7 +587,7 @@ impl Level { fn to_str(self) -> &'static str { match self { Bug => "error: internal compiler error", - Fatal | Error => "error", + Fatal | PhaseFatal | Error => "error", Warning => "warning", Note => "note", Help => "help", diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 5f27bdfc98a41..72537f6c7b26a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1304,9 +1304,14 @@ pub fn expand_crate(mut cx: ExtCtxt, expander.cx.syntax_env.insert(name, extension); } + let err_count = cx.parse_sess.span_diagnostic.err_count(); let mut ret = expander.fold_crate(c); ret.exported_macros = expander.cx.exported_macros.clone(); - cx.parse_sess.span_diagnostic.abort_if_errors(); + + if cx.parse_sess.span_diagnostic.err_count() > err_count { + cx.parse_sess.span_diagnostic.abort_if_errors(); + } + ret }; return (ret, cx.syntax_env.names); diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 9f069cb17ed90..bfd76db0359bd 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -1005,7 +1005,7 @@ fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result { }, "path" | "ty" => { match *tok { - OpenDelim(token::DelimToken::Brace) | + OpenDelim(token::DelimToken::Brace) | OpenDelim(token::DelimToken::Bracket) | Comma | FatArrow | Colon | Eq | Gt | Semi | BinOp(token::Or) => Ok(true), Ident(i, _) if (i.name.as_str() == "as" || i.name.as_str() == "where") => Ok(true), diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 090b070433f46..32372ccc13b47 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -98,7 +98,7 @@ pub fn parse_crate_from_source_str(name: String, cfg, name, source); - maybe_aborted(panictry!(p.parse_crate_mod()),p) + panictry!(p.parse_crate_mod()) } pub fn parse_crate_attrs_from_source_str(name: String, @@ -110,7 +110,7 @@ pub fn parse_crate_attrs_from_source_str(name: String, cfg, name, source); - maybe_aborted(panictry!(p.parse_inner_attributes()), p) + panictry!(p.parse_inner_attributes()) } pub fn parse_expr_from_source_str(name: String, @@ -119,7 +119,7 @@ pub fn parse_expr_from_source_str(name: String, sess: &ParseSess) -> P { let mut p = new_parser_from_source_str(sess, cfg, name, source); - maybe_aborted(panictry!(p.parse_expr()), p) + panictry!(p.parse_expr()) } pub fn parse_item_from_source_str(name: String, @@ -128,7 +128,7 @@ pub fn parse_item_from_source_str(name: String, sess: &ParseSess) -> Option> { let mut p = new_parser_from_source_str(sess, cfg, name, source); - maybe_aborted(panictry!(p.parse_item()), p) + panictry!(p.parse_item()) } pub fn parse_meta_from_source_str(name: String, @@ -137,7 +137,7 @@ pub fn parse_meta_from_source_str(name: String, sess: &ParseSess) -> P { let mut p = new_parser_from_source_str(sess, cfg, name, source); - maybe_aborted(panictry!(p.parse_meta_item()), p) + panictry!(p.parse_meta_item()) } pub fn parse_stmt_from_source_str(name: String, @@ -151,7 +151,7 @@ pub fn parse_stmt_from_source_str(name: String, name, source ); - maybe_aborted(panictry!(p.parse_stmt()), p) + panictry!(p.parse_stmt()) } // Warning: This parses with quote_depth > 0, which is not the default. @@ -168,7 +168,7 @@ pub fn parse_tts_from_source_str(name: String, ); p.quote_depth += 1; // right now this is re-creating the token trees from ... token trees. - maybe_aborted(panictry!(p.parse_all_token_trees()),p) + panictry!(p.parse_all_token_trees()) } // Create a new parser from a source string @@ -265,16 +265,10 @@ pub fn tts_to_parser<'a>(sess: &'a ParseSess, p } -/// Abort if necessary -pub fn maybe_aborted(result: T, p: Parser) -> T { - p.abort_if_errors(); - result -} fn abort_if_errors<'a, T>(result: PResult<'a, T>, p: &Parser) -> T { match result { Ok(c) => { - p.abort_if_errors(); c } Err(mut e) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index bfa42e761294b..acce6ed87d00b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2355,6 +2355,59 @@ impl<'a> Parser<'a> { ) } + // Assuming we have just parsed `.foo` (i.e., a dot and an ident), continue + // parsing into an expression. + fn parse_dot_suffix(&mut self, + ident: Ident, + ident_span: Span, + self_value: P) + -> PResult<'a, P> { + let (_, tys, bindings) = if self.eat(&token::ModSep) { + try!(self.expect_lt()); + try!(self.parse_generic_values_after_lt()) + } else { + (Vec::new(), Vec::new(), Vec::new()) + }; + + if !bindings.is_empty() { + let last_span = self.last_span; + self.span_err(last_span, "type bindings are only permitted on trait paths"); + } + + let lo = self_value.span.lo; + + Ok(match self.token { + // expr.f() method call. + token::OpenDelim(token::Paren) => { + let mut es = try!(self.parse_unspanned_seq( + &token::OpenDelim(token::Paren), + &token::CloseDelim(token::Paren), + seq_sep_trailing_allowed(token::Comma), + |p| Ok(try!(p.parse_expr())) + )); + let hi = self.last_span.hi; + + es.insert(0, self_value); + let id = spanned(ident_span.lo, ident_span.hi, ident); + let nd = self.mk_method_call(id, tys, es); + self.mk_expr(lo, hi, nd, None) + } + // Field access. + _ => { + if !tys.is_empty() { + let last_span = self.last_span; + self.span_err(last_span, + "field expressions may not \ + have type parameters"); + } + + let id = spanned(ident_span.lo, ident_span.hi, ident); + let field = self.mk_field(self_value, id); + self.mk_expr(lo, ident_span.hi, field, None) + } + }) + } + fn parse_dot_or_call_expr_with_(&mut self, e0: P) -> PResult<'a, P> { let mut e = e0; let lo = e.span.lo; @@ -2364,50 +2417,11 @@ impl<'a> Parser<'a> { if self.eat(&token::Dot) { match self.token { token::Ident(i, _) => { - let dot = self.last_span.hi; + let dot_pos = self.last_span.hi; hi = self.span.hi; self.bump(); - let (_, tys, bindings) = if self.eat(&token::ModSep) { - try!(self.expect_lt()); - try!(self.parse_generic_values_after_lt()) - } else { - (Vec::new(), Vec::new(), Vec::new()) - }; - - if !bindings.is_empty() { - let last_span = self.last_span; - self.span_err(last_span, "type bindings are only permitted on trait paths"); - } - // expr.f() method call - match self.token { - token::OpenDelim(token::Paren) => { - let mut es = try!(self.parse_unspanned_seq( - &token::OpenDelim(token::Paren), - &token::CloseDelim(token::Paren), - seq_sep_trailing_allowed(token::Comma), - |p| Ok(try!(p.parse_expr())) - )); - hi = self.last_span.hi; - - es.insert(0, e); - let id = spanned(dot, hi, i); - let nd = self.mk_method_call(id, tys, es); - e = self.mk_expr(lo, hi, nd, None); - } - _ => { - if !tys.is_empty() { - let last_span = self.last_span; - self.span_err(last_span, - "field expressions may not \ - have type parameters"); - } - - let id = spanned(dot, hi, i); - let field = self.mk_field(e, id); - e = self.mk_expr(lo, hi, field, None); - } - } + e = try!(self.parse_dot_suffix(i, mk_sp(dot_pos, hi), e)); } token::Literal(token::Integer(n), suf) => { let sp = self.span; @@ -2452,7 +2466,16 @@ impl<'a> Parser<'a> { self.abort_if_errors(); } - _ => return self.unexpected() + _ => { + // FIXME Could factor this out into non_fatal_unexpected or something. + let actual = self.this_token_to_string(); + self.span_err(self.span, &format!("unexpected token: `{}`", actual)); + + let dot_pos = self.last_span.hi; + e = try!(self.parse_dot_suffix(special_idents::invalid, + mk_sp(dot_pos, dot_pos), + e)); + } } continue; } diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index ed3f764c1d2aa..008067f39a352 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -13,7 +13,7 @@ use deriving::generic::ty::*; use syntax::ast; use syntax::ast::{MetaItem, Expr}; -use syntax::codemap::{Span, respan}; +use syntax::codemap::{Span, respan, DUMMY_SP}; use syntax::ext::base::{ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; use syntax::parse::token; @@ -87,7 +87,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, fmt, token::str_to_ident("debug_tuple"), vec![name]); - stmts.push(cx.stmt_let(span, true, builder, expr)); + stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr)); for field in fields { // Use double indirection to make sure this works for unsized types @@ -109,7 +109,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, fmt, token::str_to_ident("debug_struct"), vec![name]); - stmts.push(cx.stmt_let(span, true, builder, expr)); + stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr)); for field in fields { let name = cx.expr_lit(field.span, ast::Lit_::LitStr( diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 1fb2b55215ded..77bf90abbcc14 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -14,7 +14,7 @@ use self::Position::*; use fmt_macros as parse; use syntax::ast; -use syntax::codemap::{Span, respan}; +use syntax::codemap::{Span, respan, DUMMY_SP}; use syntax::ext::base::*; use syntax::ext::base; use syntax::ext::build::AstBuilder; @@ -501,7 +501,7 @@ impl<'a, 'b> Context<'a, 'b> { }; let name = self.ecx.ident_of(&format!("__arg{}", i)); - pats.push(self.ecx.pat_ident(e.span, name)); + pats.push(self.ecx.pat_ident(DUMMY_SP, name)); locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, self.ecx.expr_ident(e.span, name))); heads.push(self.ecx.expr_addr_of(e.span, e)); @@ -518,7 +518,7 @@ impl<'a, 'b> Context<'a, 'b> { let lname = self.ecx.ident_of(&format!("__arg{}", *name)); - pats.push(self.ecx.pat_ident(e.span, lname)); + pats.push(self.ecx.pat_ident(DUMMY_SP, lname)); names[*self.name_positions.get(name).unwrap()] = Some(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, self.ecx.expr_ident(e.span, lname))); diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 30096677aa4ad..d6985719acbfa 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -58,19 +58,43 @@ LLVMInitializePasses() { initializeTarget(Registry); } -extern "C" bool -LLVMRustAddPass(LLVMPassManagerRef PM, const char *PassName) { - PassManagerBase *pm = unwrap(PM); +enum class SupportedPassKind { + Function, + Module, + Unsupported +}; + +extern "C" Pass* +LLVMRustFindAndCreatePass(const char *PassName) { StringRef SR(PassName); PassRegistry *PR = PassRegistry::getPassRegistry(); const PassInfo *PI = PR->getPassInfo(SR); if (PI) { - pm->add(PI->createPass()); - return true; + return PI->createPass(); } - return false; + return NULL; +} + +extern "C" SupportedPassKind +LLVMRustPassKind(Pass *pass) { + assert(pass); + PassKind passKind = pass->getPassKind(); + if (passKind == PT_Module) { + return SupportedPassKind::Module; + } else if (passKind == PT_Function) { + return SupportedPassKind::Function; + } else { + return SupportedPassKind::Unsupported; + } +} + +extern "C" void +LLVMRustAddPass(LLVMPassManagerRef PM, Pass *pass) { + assert(pass); + PassManagerBase *pm = unwrap(PM); + pm->add(pass); } extern "C" LLVMTargetMachineRef diff --git a/src/test/compile-fail/cfg-non-opt-expr.rs b/src/test/compile-fail/cfg-non-opt-expr.rs index d9d379ddc7dd5..b3ef3d72ca3bf 100644 --- a/src/test/compile-fail/cfg-non-opt-expr.rs +++ b/src/test/compile-fail/cfg-non-opt-expr.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(stmt_expr_attributes)] + fn main() { let _ = #[cfg(unset)] (); //~^ ERROR removing an expression is not supported in this position diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs index d49da47a87c83..1143d3bd5cd96 100644 --- a/src/test/compile-fail/const-call.rs +++ b/src/test/compile-fail/const-call.rs @@ -10,15 +10,10 @@ #![feature(const_fn)] -const unsafe fn g(x: usize) -> usize { - x -} - fn f(x: usize) -> usize { x } fn main() { let _ = [0; f(2)]; //~ ERROR: non-constant path in constant expression [E0307] - let _ = [0; g(2)]; //~ ERROR: non-constant path in constant expression [E0307] } diff --git a/src/test/compile-fail/double-type-import.rs b/src/test/compile-fail/double-type-import.rs index 923f95e69d122..d6d7dbb4aecd8 100644 --- a/src/test/compile-fail/double-type-import.rs +++ b/src/test/compile-fail/double-type-import.rs @@ -20,5 +20,5 @@ mod foo { } fn main() { - let _ = foo::X; + let _ = foo::X; //~ ERROR unresolved name `foo::X` } diff --git a/src/test/compile-fail/import-from-missing.rs b/src/test/compile-fail/import-from-missing.rs index f393442de1011..489bcfbdefdd6 100644 --- a/src/test/compile-fail/import-from-missing.rs +++ b/src/test/compile-fail/import-from-missing.rs @@ -16,3 +16,4 @@ mod spam { } fn main() { ham(); eggs(); } +//~^ ERROR unresolved name `eggs` diff --git a/src/test/compile-fail/import.rs b/src/test/compile-fail/import.rs index 844d527a54607..86c4ce8b0380b 100644 --- a/src/test/compile-fail/import.rs +++ b/src/test/compile-fail/import.rs @@ -16,4 +16,4 @@ use zed::baz; mod zed { pub fn bar() { println!("bar"); } } -fn main(args: Vec) { bar(); } +fn main() { bar(); } diff --git a/src/test/compile-fail/import2.rs b/src/test/compile-fail/import2.rs index 6533bd5ddc610..1d2aecd4e3b7f 100644 --- a/src/test/compile-fail/import2.rs +++ b/src/test/compile-fail/import2.rs @@ -16,4 +16,5 @@ mod baz {} mod zed { pub fn bar() { println!("bar3"); } } -fn main(args: Vec) { bar(); } +fn main() { bar(); } +//~^ ERROR unresolved name `bar` diff --git a/src/test/compile-fail/macro-follow.rs b/src/test/compile-fail/macro-follow.rs new file mode 100644 index 0000000000000..35944bada4d64 --- /dev/null +++ b/src/test/compile-fail/macro-follow.rs @@ -0,0 +1,122 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// Check the macro follow sets (see corresponding rpass test). + +// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)} +macro_rules! follow_pat { + ($p:pat ()) => {}; //~WARN `$p:pat` is followed by `(` + ($p:pat []) => {}; //~WARN `$p:pat` is followed by `[` + ($p:pat {}) => {}; //~WARN `$p:pat` is followed by `{` + ($p:pat :) => {}; //~ERROR `$p:pat` is followed by `:` + ($p:pat >) => {}; //~ERROR `$p:pat` is followed by `>` + ($p:pat +) => {}; //~ERROR `$p:pat` is followed by `+` + ($p:pat ident) => {}; //~ERROR `$p:pat` is followed by `ident` + ($p:pat $p:pat) => {}; //~ERROR `$p:pat` is followed by `$p:pat` + ($p:pat $e:expr) => {}; //~ERROR `$p:pat` is followed by `$e:expr` + ($p:pat $t:ty) => {}; //~ERROR `$p:pat` is followed by `$t:ty` + ($p:pat $s:stmt) => {}; //~ERROR `$p:pat` is followed by `$s:stmt` + ($p:pat $p:path) => {}; //~ERROR `$p:pat` is followed by `$p:path` + ($p:pat $b:block) => {}; //~ERROR `$p:pat` is followed by `$b:block` + ($p:pat $i:ident) => {}; //~ERROR `$p:pat` is followed by `$i:ident` + ($p:pat $t:tt) => {}; //~ERROR `$p:pat` is followed by `$t:tt` + ($p:pat $i:item) => {}; //~ERROR `$p:pat` is followed by `$i:item` + ($p:pat $m:meta) => {}; //~ERROR `$p:pat` is followed by `$m:meta` +} +// FOLLOW(expr) = {FatArrow, Comma, Semicolon} +macro_rules! follow_expr { + ($e:expr ()) => {}; //~WARN `$e:expr` is followed by `(` + ($e:expr []) => {}; //~WARN `$e:expr` is followed by `[` + ($e:expr {}) => {}; //~WARN `$e:expr` is followed by `{` + ($e:expr =) => {}; //~ERROR `$e:expr` is followed by `=` + ($e:expr |) => {}; //~ERROR `$e:expr` is followed by `|` + ($e:expr :) => {}; //~ERROR `$e:expr` is followed by `:` + ($e:expr >) => {}; //~ERROR `$e:expr` is followed by `>` + ($e:expr +) => {}; //~ERROR `$e:expr` is followed by `+` + ($e:expr ident) => {}; //~ERROR `$e:expr` is followed by `ident` + ($e:expr if) => {}; //~ERROR `$e:expr` is followed by `if` + ($e:expr in) => {}; //~ERROR `$e:expr` is followed by `in` + ($e:expr $p:pat) => {}; //~ERROR `$e:expr` is followed by `$p:pat` + ($e:expr $e:expr) => {}; //~ERROR `$e:expr` is followed by `$e:expr` + ($e:expr $t:ty) => {}; //~ERROR `$e:expr` is followed by `$t:ty` + ($e:expr $s:stmt) => {}; //~ERROR `$e:expr` is followed by `$s:stmt` + ($e:expr $p:path) => {}; //~ERROR `$e:expr` is followed by `$p:path` + ($e:expr $b:block) => {}; //~ERROR `$e:expr` is followed by `$b:block` + ($e:expr $i:ident) => {}; //~ERROR `$e:expr` is followed by `$i:ident` + ($e:expr $t:tt) => {}; //~ERROR `$e:expr` is followed by `$t:tt` + ($e:expr $i:item) => {}; //~ERROR `$e:expr` is followed by `$i:item` + ($e:expr $m:meta) => {}; //~ERROR `$e:expr` is followed by `$m:meta` +} +// FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or, +// Ident(as), Ident(where), OpenDelim(Bracket)} +macro_rules! follow_ty { + ($t:ty ()) => {}; //~WARN `$t:ty` is followed by `(` + ($t:ty []) => {}; // ok (RFC 1462) + ($t:ty +) => {}; //~ERROR `$t:ty` is followed by `+` + ($t:ty ident) => {}; //~ERROR `$t:ty` is followed by `ident` + ($t:ty if) => {}; //~ERROR `$t:ty` is followed by `if` + ($t:ty $p:pat) => {}; //~ERROR `$t:ty` is followed by `$p:pat` + ($t:ty $e:expr) => {}; //~ERROR `$t:ty` is followed by `$e:expr` + ($t:ty $t:ty) => {}; //~ERROR `$t:ty` is followed by `$t:ty` + ($t:ty $s:stmt) => {}; //~ERROR `$t:ty` is followed by `$s:stmt` + ($t:ty $p:path) => {}; //~ERROR `$t:ty` is followed by `$p:path` + ($t:ty $b:block) => {}; //~ERROR `$t:ty` is followed by `$b:block` + ($t:ty $i:ident) => {}; //~ERROR `$t:ty` is followed by `$i:ident` + ($t:ty $t:tt) => {}; //~ERROR `$t:ty` is followed by `$t:tt` + ($t:ty $i:item) => {}; //~ERROR `$t:ty` is followed by `$i:item` + ($t:ty $m:meta) => {}; //~ERROR `$t:ty` is followed by `$m:meta` +} +// FOLLOW(stmt) = FOLLOW(expr) +macro_rules! follow_stmt { + ($s:stmt ()) => {}; //~WARN `$s:stmt` is followed by `(` + ($s:stmt []) => {}; //~WARN `$s:stmt` is followed by `[` + ($s:stmt {}) => {}; //~WARN `$s:stmt` is followed by `{` + ($s:stmt =) => {}; //~ERROR `$s:stmt` is followed by `=` + ($s:stmt |) => {}; //~ERROR `$s:stmt` is followed by `|` + ($s:stmt :) => {}; //~ERROR `$s:stmt` is followed by `:` + ($s:stmt >) => {}; //~ERROR `$s:stmt` is followed by `>` + ($s:stmt +) => {}; //~ERROR `$s:stmt` is followed by `+` + ($s:stmt ident) => {}; //~ERROR `$s:stmt` is followed by `ident` + ($s:stmt if) => {}; //~ERROR `$s:stmt` is followed by `if` + ($s:stmt in) => {}; //~ERROR `$s:stmt` is followed by `in` + ($s:stmt $p:pat) => {}; //~ERROR `$s:stmt` is followed by `$p:pat` + ($s:stmt $e:expr) => {}; //~ERROR `$s:stmt` is followed by `$e:expr` + ($s:stmt $t:ty) => {}; //~ERROR `$s:stmt` is followed by `$t:ty` + ($s:stmt $s:stmt) => {}; //~ERROR `$s:stmt` is followed by `$s:stmt` + ($s:stmt $p:path) => {}; //~ERROR `$s:stmt` is followed by `$p:path` + ($s:stmt $b:block) => {}; //~ERROR `$s:stmt` is followed by `$b:block` + ($s:stmt $i:ident) => {}; //~ERROR `$s:stmt` is followed by `$i:ident` + ($s:stmt $t:tt) => {}; //~ERROR `$s:stmt` is followed by `$t:tt` + ($s:stmt $i:item) => {}; //~ERROR `$s:stmt` is followed by `$i:item` + ($s:stmt $m:meta) => {}; //~ERROR `$s:stmt` is followed by `$m:meta` +} +// FOLLOW(path) = FOLLOW(ty) +macro_rules! follow_path { + ($p:path ()) => {}; //~WARN `$p:path` is followed by `(` + ($p:path []) => {}; // ok (RFC 1462) + ($p:path +) => {}; //~ERROR `$p:path` is followed by `+` + ($p:path ident) => {}; //~ERROR `$p:path` is followed by `ident` + ($p:path if) => {}; //~ERROR `$p:path` is followed by `if` + ($p:path $p:pat) => {}; //~ERROR `$p:path` is followed by `$p:pat` + ($p:path $e:expr) => {}; //~ERROR `$p:path` is followed by `$e:expr` + ($p:path $t:ty) => {}; //~ERROR `$p:path` is followed by `$t:ty` + ($p:path $s:stmt) => {}; //~ERROR `$p:path` is followed by `$s:stmt` + ($p:path $p:path) => {}; //~ERROR `$p:path` is followed by `$p:path` + ($p:path $b:block) => {}; //~ERROR `$p:path` is followed by `$b:block` + ($p:path $i:ident) => {}; //~ERROR `$p:path` is followed by `$i:ident` + ($p:path $t:tt) => {}; //~ERROR `$p:path` is followed by `$t:tt` + ($p:path $i:item) => {}; //~ERROR `$p:path` is followed by `$i:item` + ($p:path $m:meta) => {}; //~ERROR `$p:path` is followed by `$m:meta` +} +// FOLLOW(block) = any token +// FOLLOW(ident) = any token + +fn main() {} + diff --git a/src/test/compile-fail/macro-reexport-malformed-1.rs b/src/test/compile-fail/macro-reexport-malformed-1.rs index 6c85cf5c7f5db..ea2dfca0714fc 100644 --- a/src/test/compile-fail/macro-reexport-malformed-1.rs +++ b/src/test/compile-fail/macro-reexport-malformed-1.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![no_std] #![feature(macro_reexport)] #[macro_reexport] //~ ERROR bad macro reexport extern crate std; - -fn main() { } diff --git a/src/test/compile-fail/macro-reexport-malformed-2.rs b/src/test/compile-fail/macro-reexport-malformed-2.rs index 1dd0168181f83..844955fb7e664 100644 --- a/src/test/compile-fail/macro-reexport-malformed-2.rs +++ b/src/test/compile-fail/macro-reexport-malformed-2.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![no_std] #![feature(macro_reexport)] #[macro_reexport="foo"] //~ ERROR bad macro reexport extern crate std; - -fn main() { } diff --git a/src/test/compile-fail/macro-reexport-malformed-3.rs b/src/test/compile-fail/macro-reexport-malformed-3.rs index 7ae045f6e4f51..381c22854e654 100644 --- a/src/test/compile-fail/macro-reexport-malformed-3.rs +++ b/src/test/compile-fail/macro-reexport-malformed-3.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![no_std] #![feature(macro_reexport)] #[macro_reexport(foo="bar")] //~ ERROR bad macro reexport extern crate std; - -fn main() { } diff --git a/src/test/compile-fail/macro-reexport-undef.rs b/src/test/compile-fail/macro-reexport-undef.rs index 8fa6b32905ceb..5bb0b8759f486 100644 --- a/src/test/compile-fail/macro-reexport-undef.rs +++ b/src/test/compile-fail/macro-reexport-undef.rs @@ -10,6 +10,8 @@ // aux-build:two_macros.rs +#![feature(macro_reexport)] + #[macro_use(macro_two)] #[macro_reexport(no_way)] //~ ERROR reexported macro not found extern crate two_macros; diff --git a/src/test/compile-fail/macro-use-bad-args-1.rs b/src/test/compile-fail/macro-use-bad-args-1.rs index a73c4adb71f9f..39c09c6977963 100644 --- a/src/test/compile-fail/macro-use-bad-args-1.rs +++ b/src/test/compile-fail/macro-use-bad-args-1.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![no_std] + #[macro_use(foo(bar))] //~ ERROR bad macro import extern crate std; - -fn main() { -} diff --git a/src/test/compile-fail/macro-use-bad-args-2.rs b/src/test/compile-fail/macro-use-bad-args-2.rs index 31efe857605b4..11a0108b99b89 100644 --- a/src/test/compile-fail/macro-use-bad-args-2.rs +++ b/src/test/compile-fail/macro-use-bad-args-2.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![no_std] + #[macro_use(foo="bar")] //~ ERROR bad macro import extern crate std; - -fn main() { -} diff --git a/src/test/compile-fail/const-fn-stability-calls-2.rs b/src/test/compile-fail/parse-error-correct.rs similarity index 53% rename from src/test/compile-fail/const-fn-stability-calls-2.rs rename to src/test/compile-fail/parse-error-correct.rs index 592a312d80048..7715ed41841cf 100644 --- a/src/test/compile-fail/const-fn-stability-calls-2.rs +++ b/src/test/compile-fail/parse-error-correct.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,15 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test use of const fn from another crate without a feature gate. - -// aux-build:const_fn_lib.rs - -extern crate const_fn_lib; - -use const_fn_lib::foo; +// Test that the parser is error correcting missing idents. Despite a parsing +// error (or two), we still run type checking (and don't get extra errors there). fn main() { - let x: [usize; foo()] = []; - //~^ ERROR unimplemented constant expression: calling non-local const fn [E0250] + let y = 42; + let x = y.; //~ ERROR unexpected token + let x = y.(); //~ ERROR unexpected token + let x = y.foo; //~ ERROR no field } diff --git a/src/test/compile-fail/privacy3.rs b/src/test/compile-fail/privacy3.rs index da6266bc7ee6b..6a203993ccf2d 100644 --- a/src/test/compile-fail/privacy3.rs +++ b/src/test/compile-fail/privacy3.rs @@ -28,6 +28,7 @@ fn test1() { use bar::gpriv; //~^ ERROR unresolved import `bar::gpriv`. There is no `gpriv` in `bar` gpriv(); + //~^ ERROR unresolved name `gpriv` } #[start] fn main(_: isize, _: *const *const u8) -> isize { 3 } diff --git a/src/test/compile-fail/self_type_keyword.rs b/src/test/compile-fail/self_type_keyword.rs index 6f5aeead57ecb..e28197e81faf9 100644 --- a/src/test/compile-fail/self_type_keyword.rs +++ b/src/test/compile-fail/self_type_keyword.rs @@ -29,6 +29,7 @@ pub fn main() { //~^ ERROR expected identifier, found keyword `Self` Self!() => (), //~^ ERROR expected identifier, found keyword `Self` + //~^^ ERROR macro undefined: 'Self!' Foo { x: Self } => (), //~^ ERROR expected identifier, found keyword `Self` Foo { Self } => (), diff --git a/src/test/compile-fail/use-mod.rs b/src/test/compile-fail/use-mod.rs index 15640e386dfa0..9cc3c92e2e376 100644 --- a/src/test/compile-fail/use-mod.rs +++ b/src/test/compile-fail/use-mod.rs @@ -14,6 +14,7 @@ use foo::bar::{ Bar, self //~^ NOTE another `self` import appears here +//~^^ ERROR a module named `bar` has already been imported in this module }; use {self}; diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index 3e4ba5af80c4d..7a1c200ba20e8 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -287,6 +287,26 @@ pub struct blah { used_link_args: RefCell<[&'static str; 0]>, } +#[macro_use] +mod macro_use_test { + macro_rules! test_rec { + (q, $src: expr) => {{ + print!("{}", $src); + test_rec!($src); + }}; + ($src: expr) => { + print!("{}", $src); + }; + } + + macro_rules! internal_vars { + ($src: ident) => {{ + let mut x = $src; + x += 100; + }}; + } +} + fn main() { // foo let s = box some_fields {field1: 43}; hello((43, "a".to_string()), *s); @@ -356,6 +376,11 @@ fn main() { // foo while let Some(z) = None { foo_foo(z); } + + let mut x = 4; + test_rec!(q, "Hello"); + assert_eq!(x, 4); + internal_vars!(x); } fn foo_foo(_: i32) {} @@ -398,3 +423,16 @@ impl Error + 'static + Send { ::is::(self) } } +extern crate serialize; +#[derive(Clone, Copy, Hash, Encodable, Decodable, PartialEq, Eq, PartialOrd, Ord, Debug, Default)] +struct AllDerives(i32); + +fn test_format_args() { + let x = 1; + let y = 2; + let name = "Joe Blogg"; + println!("Hello {}", name); + print!("Hello {0}", name); + print!("{0} + {} = {}", x, y); + print!("x is {}, y is {1}, name is {n}", x, y, n = name); +} \ No newline at end of file diff --git a/src/test/run-pass/const-fn-cross-crate.rs b/src/test/run-pass/const-fn-cross-crate.rs index 5d0c17af71719..7b4b751fd7f25 100644 --- a/src/test/run-pass/const-fn-cross-crate.rs +++ b/src/test/run-pass/const-fn-cross-crate.rs @@ -22,4 +22,5 @@ const FOO: usize = foo(); fn main() { assert_eq!(FOO, 22); + let _: [i32; foo()] = [42; 22]; } diff --git a/src/test/run-pass/const-fn.rs b/src/test/run-pass/const-fn.rs index 38c73febc3108..5961ed8d3390d 100644 --- a/src/test/run-pass/const-fn.rs +++ b/src/test/run-pass/const-fn.rs @@ -20,14 +20,20 @@ const fn sub(x: u32, y: u32) -> u32 { x - y } +const unsafe fn div(x: u32, y: u32) -> u32 { + x / y +} + const SUM: u32 = add(44, 22); const DIFF: u32 = sub(44, 22); +const DIV: u32 = unsafe{div(44, 22)}; fn main() { assert_eq!(SUM, 66); assert!(SUM != 88); assert_eq!(DIFF, 22); + assert_eq!(DIV, 2); let _: [&'static str; sub(100, 99) as usize] = ["hi"]; } diff --git a/src/test/run-pass/macro-follow.rs b/src/test/run-pass/macro-follow.rs new file mode 100644 index 0000000000000..ce6498f67f9ee --- /dev/null +++ b/src/test/run-pass/macro-follow.rs @@ -0,0 +1,190 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check the macro follow sets (see corresponding cfail test). + +// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)} +macro_rules! follow_pat { + ($p:pat =>) => {}; + ($p:pat ,) => {}; + ($p:pat =) => {}; + ($p:pat |) => {}; + ($p:pat if) => {}; + ($p:pat in) => {}; +} +// FOLLOW(expr) = {FatArrow, Comma, Semicolon} +macro_rules! follow_expr { + ($e:expr =>) => {}; + ($e:expr ,) => {}; + ($e:expr ;) => {}; +} +// FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or, +// Ident(as), Ident(where), OpenDelim(Bracket)} +macro_rules! follow_ty { + ($t:ty {}) => {}; + ($t:ty ,) => {}; + ($t:ty =>) => {}; + ($t:ty :) => {}; + ($t:ty =) => {}; + ($t:ty >) => {}; + ($t:ty ;) => {}; + ($t:ty |) => {}; + ($t:ty as) => {}; + ($t:ty where) => {}; + ($t:ty []) => {}; +} +// FOLLOW(stmt) = FOLLOW(expr) +macro_rules! follow_stmt { + ($s:stmt =>) => {}; + ($s:stmt ,) => {}; + ($s:stmt ;) => {}; +} +// FOLLOW(path) = FOLLOW(ty) +macro_rules! follow_path { + ($p:path {}) => {}; + ($p:path ,) => {}; + ($p:path =>) => {}; + ($p:path :) => {}; + ($p:path =) => {}; + ($p:path >) => {}; + ($p:path ;) => {}; + ($p:path |) => {}; + ($p:path as) => {}; + ($p:path where) => {}; + ($p:path []) => {}; +} +// FOLLOW(block) = any token +macro_rules! follow_block { + ($b:block ()) => {}; + ($b:block []) => {}; + ($b:block {}) => {}; + ($b:block ,) => {}; + ($b:block =>) => {}; + ($b:block :) => {}; + ($b:block =) => {}; + ($b:block >) => {}; + ($b:block ;) => {}; + ($b:block |) => {}; + ($b:block +) => {}; + ($b:block ident) => {}; + ($b:block $p:pat) => {}; + ($b:block $e:expr) => {}; + ($b:block $t:ty) => {}; + ($b:block $s:stmt) => {}; + ($b:block $p:path) => {}; + ($b:block $b:block) => {}; + ($b:block $i:ident) => {}; + ($b:block $t:tt) => {}; + ($b:block $i:item) => {}; + ($b:block $m:meta) => {}; +} +// FOLLOW(ident) = any token +macro_rules! follow_ident { + ($i:ident ()) => {}; + ($i:ident []) => {}; + ($i:ident {}) => {}; + ($i:ident ,) => {}; + ($i:ident =>) => {}; + ($i:ident :) => {}; + ($i:ident =) => {}; + ($i:ident >) => {}; + ($i:ident ;) => {}; + ($i:ident |) => {}; + ($i:ident +) => {}; + ($i:ident ident) => {}; + ($i:ident $p:pat) => {}; + ($i:ident $e:expr) => {}; + ($i:ident $t:ty) => {}; + ($i:ident $s:stmt) => {}; + ($i:ident $p:path) => {}; + ($i:ident $b:block) => {}; + ($i:ident $i:ident) => {}; + ($i:ident $t:tt) => {}; + ($i:ident $i:item) => {}; + ($i:ident $m:meta) => {}; +} +// FOLLOW(tt) = any token +macro_rules! follow_tt { + ($t:tt ()) => {}; + ($t:tt []) => {}; + ($t:tt {}) => {}; + ($t:tt ,) => {}; + ($t:tt =>) => {}; + ($t:tt :) => {}; + ($t:tt =) => {}; + ($t:tt >) => {}; + ($t:tt ;) => {}; + ($t:tt |) => {}; + ($t:tt +) => {}; + ($t:tt ident) => {}; + ($t:tt $p:pat) => {}; + ($t:tt $e:expr) => {}; + ($t:tt $t:ty) => {}; + ($t:tt $s:stmt) => {}; + ($t:tt $p:path) => {}; + ($t:tt $b:block) => {}; + ($t:tt $i:ident) => {}; + ($t:tt $t:tt) => {}; + ($t:tt $i:item) => {}; + ($t:tt $m:meta) => {}; +} +// FOLLOW(item) = any token +macro_rules! follow_item { + ($i:item ()) => {}; + ($i:item []) => {}; + ($i:item {}) => {}; + ($i:item ,) => {}; + ($i:item =>) => {}; + ($i:item :) => {}; + ($i:item =) => {}; + ($i:item >) => {}; + ($i:item ;) => {}; + ($i:item |) => {}; + ($i:item +) => {}; + ($i:item ident) => {}; + ($i:item $p:pat) => {}; + ($i:item $e:expr) => {}; + ($i:item $t:ty) => {}; + ($i:item $s:stmt) => {}; + ($i:item $p:path) => {}; + ($i:item $b:block) => {}; + ($i:item $i:ident) => {}; + ($i:item $t:tt) => {}; + ($i:item $i:item) => {}; + ($i:item $m:meta) => {}; +} +// FOLLOW(meta) = any token +macro_rules! follow_meta { + ($m:meta ()) => {}; + ($m:meta []) => {}; + ($m:meta {}) => {}; + ($m:meta ,) => {}; + ($m:meta =>) => {}; + ($m:meta :) => {}; + ($m:meta =) => {}; + ($m:meta >) => {}; + ($m:meta ;) => {}; + ($m:meta |) => {}; + ($m:meta +) => {}; + ($m:meta ident) => {}; + ($m:meta $p:pat) => {}; + ($m:meta $e:expr) => {}; + ($m:meta $t:ty) => {}; + ($m:meta $s:stmt) => {}; + ($m:meta $p:path) => {}; + ($m:meta $b:block) => {}; + ($m:meta $i:ident) => {}; + ($m:meta $t:tt) => {}; + ($m:meta $i:item) => {}; + ($m:meta $m:meta) => {}; +} + +fn main() {} +