Auto merge of #37118 - alexcrichton:rollup, r=alexcrichton

Rollup of 17 pull requests

- Successful merges: #36762, #36831, #36973, #36991, #36995, #37023, #37049, #37050, #37056, #37064, #37066, #37067, #37084, #37089, #37091, #37092, #37110
- Failed merges:
This commit is contained in:
bors
2016-10-12 14:42:12 -07:00
committed by GitHub
105 changed files with 1334 additions and 958 deletions
Vendored
+2 -2
View File
@@ -1635,8 +1635,8 @@ do
("ccache gcc")
LLVM_CXX_32="ccache"
LLVM_CC_32="ccache"
LLVM_CXX_32_ARG1="clang++"
LLVM_CC_32_ARG1="clang"
LLVM_CXX_32_ARG1="g++"
LLVM_CC_32_ARG1="gcc"
LLVM_CXX_64="ccache"
LLVM_CC_64="ccache"
+1 -2
View File
@@ -2472,8 +2472,7 @@ The currently implemented features of the reference compiler are:
* - `default_type_parameter_fallback` - Allows type parameter defaults to
influence type inference.
* - `stmt_expr_attributes` - Allows attributes on expressions and
non-item statements.
* - `stmt_expr_attributes` - Allows attributes on expressions.
* - `type_ascription` - Allows type ascription expressions `expr: Type`.
+3 -4
View File
@@ -73,7 +73,6 @@
use fmt;
use intrinsics;
use marker::Reflect;
///////////////////////////////////////////////////////////////////////////////
// Any trait
@@ -86,7 +85,7 @@
///
/// [mod]: index.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Any: Reflect + 'static {
pub trait Any: 'static {
/// Gets the `TypeId` of `self`.
///
/// # Examples
@@ -112,7 +111,7 @@ pub trait Any: Reflect + 'static {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Reflect + 'static + ?Sized > Any for T {
impl<T: 'static + ?Sized > Any for T {
fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}
@@ -366,7 +365,7 @@ impl TypeId {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn of<T: ?Sized + Reflect + 'static>() -> TypeId {
pub fn of<T: ?Sized + 'static>() -> TypeId {
TypeId {
t: unsafe { intrinsics::type_id::<T>() },
}
+1 -1
View File
@@ -89,7 +89,7 @@
#![feature(specialization)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#![feature(never_type)]
#![feature(prelude_import)]
+3
View File
@@ -255,6 +255,9 @@ macro_rules! debug_assert_ne {
/// Helper macro for reducing boilerplate code for matching `Result` together
/// with converting downstream errors.
///
/// Prefer using `?` syntax to `try!`. `?` is built in to the language and is
/// more succinct than `try!`. It is the standard method for error propagation.
///
/// `try!` matches the given `Result`. In case of the `Ok` variant, the
/// expression has the value of the wrapped value.
///
+3
View File
@@ -587,6 +587,7 @@ unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
#[unstable(feature = "reflect_marker",
reason = "requires RFC and more experience",
issue = "27749")]
#[rustc_deprecated(since = "1.14.0", reason = "Specialization makes parametricity impossible")]
#[rustc_on_unimplemented = "`{Self}` does not implement `Any`; \
ensure all type parameters are bounded by `Any`"]
pub trait Reflect {}
@@ -594,4 +595,6 @@ pub trait Reflect {}
#[unstable(feature = "reflect_marker",
reason = "requires RFC and more experience",
issue = "27749")]
#[rustc_deprecated(since = "1.14.0", reason = "Specialization makes parametricity impossible")]
#[allow(deprecated)]
impl Reflect for .. { }
+1 -1
View File
@@ -295,7 +295,7 @@
#![cfg_attr(not(stage0), deny(warnings))]
#![feature(str_escape)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
use self::LabelText::*;
-24
View File
@@ -1327,30 +1327,6 @@ fn main() {}
// |
// type `i32` assigned to variable `x`
```
Another situation in which this occurs is when you attempt to use the `try!`
macro inside a function that does not return a `Result<T, E>`:
```compile_fail,E0308
use std::fs::File;
fn main() {
let mut f = try!(File::create("foo.txt"));
}
```
This code gives an error like this:
```text
<std macros>:5:8: 6:42 error: mismatched types:
expected `()`,
found `core::result::Result<_, _>`
(expected (),
found enum `core::result::Result`) [E0308]
```
`try!` returns a `Result<T, E>`, and so the function must. But `main()` has
`()` as its return type, hence the error.
"##,
E0309: r##"
+1 -7
View File
@@ -94,13 +94,7 @@ pub fn lower_crate(sess: &Session,
let _ignore = sess.dep_graph.in_ignore();
LoweringContext {
crate_root: if std_inject::no_core(krate) {
None
} else if std_inject::no_std(krate) {
Some("core")
} else {
Some("std")
},
crate_root: std_inject::injected_crate_name(krate),
sess: sess,
parent_def: None,
resolver: resolver,
+1 -1
View File
@@ -40,7 +40,7 @@
#![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(staged_api)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#![cfg_attr(test, feature(test))]
extern crate arena;
+8
View File
@@ -118,6 +118,8 @@ pub struct PerfStats {
pub incr_comp_hashes_time: Cell<Duration>,
// The number of incr. comp. hash computations performed
pub incr_comp_hashes_count: Cell<u64>,
// The number of bytes hashed when computing ICH values
pub incr_comp_bytes_hashed: Cell<u64>,
// The accumulated time spent on computing symbol hashes
pub symbol_hash_time: Cell<Duration>,
}
@@ -439,6 +441,11 @@ pub fn print_perf_stats(&self) {
duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get()));
println!("Total number of incr. comp. hashes computed: {}",
self.perf_stats.incr_comp_hashes_count.get());
println!("Total number of bytes hashed for incr. comp.: {}",
self.perf_stats.incr_comp_bytes_hashed.get());
println!("Average bytes hashed per incr. comp. HIR node: {}",
self.perf_stats.incr_comp_bytes_hashed.get() /
self.perf_stats.incr_comp_hashes_count.get());
println!("Total time spent computing symbol hashes: {}",
duration_to_secs_str(self.perf_stats.symbol_hash_time.get()));
}
@@ -571,6 +578,7 @@ pub fn build_session_(sopts: config::Options,
svh_time: Cell::new(Duration::from_secs(0)),
incr_comp_hashes_time: Cell::new(Duration::from_secs(0)),
incr_comp_hashes_count: Cell::new(0),
incr_comp_bytes_hashed: Cell::new(0),
symbol_hash_time: Cell::new(Duration::from_secs(0)),
}
};
+1 -1
View File
@@ -37,7 +37,7 @@
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(step_by)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#![cfg_attr(test, feature(test, rand))]
extern crate syntax;
@@ -12,6 +12,8 @@
use syntax::ast::NodeId;
use rustc::mir::repr::{BasicBlock, Mir};
use rustc_data_structures::bitslice::bits_to_string;
use rustc_data_structures::indexed_set::{IdxSet};
use rustc_data_structures::indexed_vec::Idx;
use dot;
@@ -27,8 +29,6 @@
use super::super::MoveDataParamEnv;
use super::super::MirBorrowckCtxtPreDataflow;
use bitslice::bits_to_string;
use indexed_set::{IdxSet};
use super::{BitDenotation, DataflowState};
impl<O: BitDenotation> DataflowState<O> {
@@ -10,6 +10,9 @@
use rustc::ty::TyCtxt;
use rustc::mir::repr::{self, Mir, Location};
use rustc_data_structures::bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep.
use rustc_data_structures::bitslice::{BitwiseOperator};
use rustc_data_structures::indexed_set::{IdxSet};
use rustc_data_structures::indexed_vec::Idx;
use super::super::gather_moves::{MoveOutIndex, MovePathIndex};
@@ -21,10 +24,6 @@
use super::{BitDenotation, BlockSets, DataflowOperator};
use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep.
use bitslice::{BitwiseOperator};
use indexed_set::{IdxSet};
// Dataflow analyses are built upon some interpretation of the
// bitvectors attached to each basic block, represented via a
// zero-sized structure.
@@ -8,7 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf};
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::bitslice::{bitwise, BitwiseOperator};
use rustc::ty::TyCtxt;
use rustc::mir::repr::{self, Mir};
@@ -22,9 +24,6 @@
use super::MirBorrowckCtxtPreDataflow;
use super::MoveDataParamEnv;
use bitslice::{bitwise, BitwiseOperator};
use indexed_set::{IdxSet, IdxSetBuf};
pub use self::sanity_check::sanity_check_via_rustc_peek;
pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
pub use self::impls::{DefinitelyInitializedLvals, MovingOutStatements};
@@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use indexed_set::IdxSetBuf;
use super::gather_moves::{MoveData, MovePathIndex, LookupResult};
use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use super::dataflow::{DataflowResults};
@@ -23,6 +22,7 @@
use rustc::middle::const_val::ConstVal;
use rustc::middle::lang_items;
use rustc::util::nodemap::FnvHashMap;
use rustc_data_structures::indexed_set::IdxSetBuf;
use rustc_data_structures::indexed_vec::Idx;
use syntax_pos::Span;
+1 -3
View File
@@ -26,7 +26,7 @@
#![feature(staged_api)]
#![feature(associated_consts)]
#![feature(nonzero)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate syntax_pos;
@@ -50,8 +50,6 @@
pub mod diagnostics;
mod borrowck;
mod bitslice;
mod indexed_set;
pub mod graphviz;
+4
View File
@@ -732,6 +732,10 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
hir::BiBitOr => a | b,
hir::BiEq => a == b,
hir::BiNe => a != b,
hir::BiLt => a < b,
hir::BiLe => a <= b,
hir::BiGe => a >= b,
hir::BiGt => a > b,
_ => signal!(e, InvalidOpForBools(op.node)),
})
}
+1 -1
View File
@@ -27,7 +27,7 @@
#![feature(staged_api)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_patterns)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#![feature(box_patterns)]
#![feature(box_syntax)]
+1 -1
View File
@@ -25,7 +25,7 @@
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
@@ -8,8 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// FIXME: move this to `rustc_data_structures` and potentially merge
// with `bitvec` there.
// FIXME: merge with `bitvec`
use std::mem;
@@ -8,16 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// FIXME: move this to `rustc_data_structures`
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut, Range};
use bitslice::{BitSlice, Word};
use bitslice::{bitwise, Union, Subtract};
use rustc_data_structures::indexed_vec::Idx;
use indexed_vec::Idx;
/// Represents a set (or packed family of sets), of some element type
/// E, where each E is identified by some unique index type `T`.
+2
View File
@@ -41,9 +41,11 @@
#[cfg(unix)]
extern crate libc;
pub mod bitslice;
pub mod bitvec;
pub mod graph;
pub mod ivar;
pub mod indexed_set;
pub mod indexed_vec;
pub mod obligation_forest;
pub mod snapshot_map;
+9 -3
View File
@@ -649,7 +649,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
let resolver_arenas = Resolver::arenas();
let mut resolver =
Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas);
syntax_ext::register_builtins(&mut resolver, sess.features.borrow().quote);
syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote);
krate = time(time_passes, "expansion", || {
// Windows dlls do not have rpaths, so they don't know how to find their
@@ -686,11 +686,17 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string())
};
let mut ecx = ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, &mut resolver);
let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate);
let err_count = ecx.parse_sess.span_diagnostic.err_count();
let krate = ecx.monotonic_expander().expand_crate(krate);
if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count {
ecx.parse_sess.span_diagnostic.abort_if_errors();
}
if cfg!(windows) {
env::set_var("PATH", &old_path);
}
ret
krate
});
krate.exported_macros = mem::replace(&mut resolver.exported_macros, Vec::new());
+2 -2
View File
@@ -31,7 +31,7 @@
#![feature(rustc_private)]
#![feature(set_stdio)]
#![feature(staged_api)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
extern crate arena;
extern crate flate;
@@ -1110,7 +1110,7 @@ fn flush(&mut self) -> io::Result<()> {
errors::Level::Note);
}
println!("{}", str::from_utf8(&data.lock().unwrap()).unwrap());
writeln!(io::stderr(), "{}", str::from_utf8(&data.lock().unwrap()).unwrap()).unwrap();
}
exit_on_err();
+1 -1
View File
@@ -21,7 +21,7 @@
#![allow(unused_attributes)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#![feature(range_contains)]
#![feature(libc)]
#![feature(unicode)]
@@ -0,0 +1,46 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
#[derive(Debug)]
pub struct IchHasher {
// FIXME: this should use SHA1, not DefaultHasher. DefaultHasher is not
// built to avoid collisions.
state: DefaultHasher,
bytes_hashed: u64,
}
impl IchHasher {
pub fn new() -> IchHasher {
IchHasher {
state: DefaultHasher::new(),
bytes_hashed: 0
}
}
pub fn bytes_hashed(&self) -> u64 {
self.bytes_hashed
}
}
impl Hasher for IchHasher {
#[inline]
fn finish(&self) -> u64 {
self.state.finish()
}
#[inline]
fn write(&mut self, bytes: &[u8]) {
self.state.write(bytes);
self.bytes_hashed += bytes.len() as u64;
}
}
+15 -5
View File
@@ -30,7 +30,6 @@
use syntax::ast;
use std::cell::RefCell;
use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
@@ -43,10 +42,12 @@
use self::def_path_hash::DefPathHashes;
use self::svh_visitor::StrictVersionHashVisitor;
use self::caching_codemap_view::CachingCodemapView;
use self::hasher::IchHasher;
mod def_path_hash;
mod svh_visitor;
mod caching_codemap_view;
mod hasher;
pub struct IncrementalHashesMap {
hashes: FnvHashMap<DepNode<DefId>, u64>,
@@ -74,6 +75,10 @@ pub fn insert(&mut self, k: DepNode<DefId>, v: u64) -> Option<u64> {
pub fn iter<'a>(&'a self) -> ::std::collections::hash_map::Iter<'a, DepNode<DefId>, u64> {
self.hashes.iter()
}
pub fn len(&self) -> usize {
self.hashes.len()
}
}
impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap {
@@ -102,6 +107,9 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
|v| visit::walk_crate(v, krate));
krate.visit_all_items(&mut visitor);
});
tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
visitor.hashes
}
@@ -127,9 +135,7 @@ fn calculate_def_id<W>(&mut self, def_id: DefId, mut walk_op: W)
{
assert!(def_id.is_local());
debug!("HashItemsVisitor::calculate(def_id={:?})", def_id);
// FIXME: this should use SHA1, not DefaultHasher. DefaultHasher is not
// built to avoid collisions.
let mut state = DefaultHasher::new();
let mut state = IchHasher::new();
walk_op(&mut StrictVersionHashVisitor::new(&mut state,
self.tcx,
&mut self.def_path_hashes,
@@ -138,12 +144,16 @@ fn calculate_def_id<W>(&mut self, def_id: DefId, mut walk_op: W)
let item_hash = state.finish();
self.hashes.insert(DepNode::Hir(def_id), item_hash);
debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash);
let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
state.bytes_hashed();
self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
}
fn compute_crate_hash(&mut self) {
let krate = self.tcx.map.krate();
let mut crate_state = DefaultHasher::new();
let mut crate_state = IchHasher::new();
let crate_disambiguator = self.tcx.sess.local_crate_disambiguator();
"crate_disambiguator".hash(&mut crate_state);
@@ -31,10 +31,10 @@
use rustc::ty::TyCtxt;
use rustc_data_structures::fnv;
use std::hash::Hash;
use std::collections::hash_map::DefaultHasher;
use super::def_path_hash::DefPathHashes;
use super::caching_codemap_view::CachingCodemapView;
use super::hasher::IchHasher;
const IGNORED_ATTRIBUTES: &'static [&'static str] = &[
"cfg",
@@ -48,7 +48,7 @@
pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> {
pub tcx: TyCtxt<'hash, 'tcx, 'tcx>,
pub st: &'a mut DefaultHasher,
pub st: &'a mut IchHasher,
// collect a deterministic hash of def-ids that we have seen
def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
hash_spans: bool,
@@ -56,7 +56,7 @@ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> {
}
impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
pub fn new(st: &'a mut DefaultHasher,
pub fn new(st: &'a mut IchHasher,
tcx: TyCtxt<'hash, 'tcx, 'tcx>,
def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
codemap: &'a mut CachingCodemapView<'tcx>,
+1 -1
View File
@@ -20,7 +20,7 @@
#![cfg_attr(not(stage0), deny(warnings))]
#![feature(dotdot_in_tuple_patterns)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(rand)]
+95 -67
View File
@@ -24,19 +24,21 @@
pub enum MethodLateContext {
TraitDefaultImpl,
TraitImpl,
PlainImpl
PlainImpl,
}
pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext {
let def_id = cx.tcx.map.local_def_id(id);
match cx.tcx.impl_or_trait_items.borrow().get(&def_id) {
None => span_bug!(span, "missing method descriptor?!"),
Some(item) => match item.container() {
ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
ty::ImplContainer(cid) => {
match cx.tcx.impl_trait_ref(cid) {
Some(_) => MethodLateContext::TraitImpl,
None => MethodLateContext::PlainImpl
Some(item) => {
match item.container() {
ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
ty::ImplContainer(cid) => {
match cx.tcx.impl_trait_ref(cid) {
Some(_) => MethodLateContext::TraitImpl,
None => MethodLateContext::PlainImpl,
}
}
}
}
@@ -63,19 +65,20 @@ fn is_camel_case(name: ast::Name) -> bool {
// start with a non-lowercase letter rather than non-uppercase
// ones (some scripts don't have a concept of upper/lowercase)
!name.is_empty() &&
!name.chars().next().unwrap().is_lowercase() &&
!name.contains('_')
!name.is_empty() && !name.chars().next().unwrap().is_lowercase() && !name.contains('_')
}
fn to_camel_case(s: &str) -> String {
s.split('_').flat_map(|word| word.chars().enumerate().map(|(i, c)|
if i == 0 {
c.to_uppercase().collect::<String>()
} else {
c.to_lowercase().collect()
}
)).collect::<Vec<_>>().concat()
s.split('_')
.flat_map(|word| {
word.chars().enumerate().map(|(i, c)| if i == 0 {
c.to_uppercase().collect::<String>()
} else {
c.to_lowercase().collect()
})
})
.collect::<Vec<_>>()
.concat()
}
let s = name.as_str();
@@ -83,9 +86,14 @@ fn to_camel_case(s: &str) -> String {
if !is_camel_case(name) {
let c = to_camel_case(&s);
let m = if c.is_empty() {
format!("{} `{}` should have a camel case name such as `CamelCase`", sort, s)
format!("{} `{}` should have a camel case name such as `CamelCase`",
sort,
s)
} else {
format!("{} `{}` should have a camel case name such as `{}`", sort, s, c)
format!("{} `{}` should have a camel case name such as `{}`",
sort,
s,
c)
};
cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]);
}
@@ -100,10 +108,14 @@ fn get_lints(&self) -> LintArray {
impl LateLintPass for NonCamelCaseTypes {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
let extern_repr_count = it.attrs.iter().filter(|attr| {
attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter()
.any(|r| r == &attr::ReprExtern)
}).count();
let extern_repr_count = it.attrs
.iter()
.filter(|attr| {
attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr)
.iter()
.any(|r| r == &attr::ReprExtern)
})
.count();
let has_extern_repr = extern_repr_count > 0;
if has_extern_repr {
@@ -111,12 +123,10 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
}
match it.node {
hir::ItemTy(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => {
self.check_case(cx, "type", it.name, it.span)
}
hir::ItemTrait(..) => {
self.check_case(cx, "trait", it.name, it.span)
}
hir::ItemTy(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) => self.check_case(cx, "type", it.name, it.span),
hir::ItemTrait(..) => self.check_case(cx, "trait", it.name, it.span),
hir::ItemEnum(ref enum_definition, _) => {
if has_extern_repr {
return;
@@ -126,7 +136,7 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
self.check_case(cx, "variant", variant.node.name, variant.span);
}
}
_ => ()
_ => (),
}
}
@@ -165,9 +175,7 @@ fn to_snake_case(mut str: &str) -> String {
continue;
}
for ch in s.chars() {
if !buf.is_empty() && buf != "'"
&& ch.is_uppercase()
&& !last_upper {
if !buf.is_empty() && buf != "'" && ch.is_uppercase() && !last_upper {
words.push(buf);
buf = String::new();
}
@@ -205,10 +213,11 @@ fn is_snake_case(ident: &str) -> bool {
let sc = NonSnakeCase::to_snake_case(name);
let msg = if sc != name {
format!("{} `{}` should have a snake case name such as `{}`",
sort, name, sc)
sort,
name,
sc)
} else {
format!("{} `{}` should have a snake case name",
sort, name)
format!("{} `{}` should have a snake case name", sort, name)
};
match span {
Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg),
@@ -226,8 +235,10 @@ fn get_lints(&self) -> LintArray {
impl LateLintPass for NonSnakeCase {
fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) {
let attr_crate_name = cr.attrs.iter().find(|at| at.check_name("crate_name"))
.and_then(|at| at.value_str().map(|s| (at, s)));
let attr_crate_name = cr.attrs
.iter()
.find(|at| at.check_name("crate_name"))
.and_then(|at| at.value_str().map(|s| (at, s)));
if let Some(ref name) = cx.tcx.sess.opts.crate_name {
self.check_snake_case(cx, "crate", name, None);
} else if let Some((attr, ref name)) = attr_crate_name {
@@ -235,22 +246,28 @@ fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) {
}
}
fn check_fn(&mut self, cx: &LateContext,
fk: FnKind, _: &hir::FnDecl,
_: &hir::Block, span: Span, id: ast::NodeId) {
fn check_fn(&mut self,
cx: &LateContext,
fk: FnKind,
_: &hir::FnDecl,
_: &hir::Block,
span: Span,
id: ast::NodeId) {
match fk {
FnKind::Method(name, ..) => match method_context(cx, id, span) {
MethodLateContext::PlainImpl => {
self.check_snake_case(cx, "method", &name.as_str(), Some(span))
},
MethodLateContext::TraitDefaultImpl => {
self.check_snake_case(cx, "trait method", &name.as_str(), Some(span))
},
_ => (),
},
FnKind::Method(name, ..) => {
match method_context(cx, id, span) {
MethodLateContext::PlainImpl => {
self.check_snake_case(cx, "method", &name.as_str(), Some(span))
}
MethodLateContext::TraitDefaultImpl => {
self.check_snake_case(cx, "trait method", &name.as_str(), Some(span))
}
_ => (),
}
}
FnKind::ItemFn(name, ..) => {
self.check_snake_case(cx, "function", &name.as_str(), Some(span))
},
}
FnKind::Closure(_) => (),
}
}
@@ -263,13 +280,17 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
if let hir::MethodTraitItem(_, None) = trait_item.node {
self.check_snake_case(cx, "trait method", &trait_item.name.as_str(),
self.check_snake_case(cx,
"trait method",
&trait_item.name.as_str(),
Some(trait_item.span));
}
}
fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) {
self.check_snake_case(cx, "lifetime", &t.lifetime.name.as_str(),
self.check_snake_case(cx,
"lifetime",
&t.lifetime.name.as_str(),
Some(t.lifetime.span));
}
@@ -282,8 +303,12 @@ fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
}
}
fn check_struct_def(&mut self, cx: &LateContext, s: &hir::VariantData,
_: ast::Name, _: &hir::Generics, _: ast::NodeId) {
fn check_struct_def(&mut self,
cx: &LateContext,
s: &hir::VariantData,
_: ast::Name,
_: &hir::Generics,
_: ast::NodeId) {
for sf in s.fields() {
self.check_snake_case(cx, "structure field", &sf.name.as_str(), Some(sf.span));
}
@@ -306,13 +331,16 @@ fn check_upper_case(cx: &LateContext, sort: &str, name: ast::Name, span: Span) {
if s.chars().any(|c| c.is_lowercase()) {
let uc = NonSnakeCase::to_snake_case(&s).to_uppercase();
if uc != &s[..] {
cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
&format!("{} `{}` should have an upper case name such as `{}`",
sort, s, uc));
cx.span_lint(NON_UPPER_CASE_GLOBALS,
span,
&format!("{} `{}` should have an upper case name such as `{}`",
sort,
s,
uc));
} else {
cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
&format!("{} `{}` should have an upper case name",
sort, s));
cx.span_lint(NON_UPPER_CASE_GLOBALS,
span,
&format!("{} `{}` should have an upper case name", sort, s));
}
}
}
@@ -341,8 +369,7 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) {
match ti.node {
hir::ConstTraitItem(..) => {
NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
ti.name, ti.span);
NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ti.name, ti.span);
}
_ => {}
}
@@ -351,8 +378,7 @@ fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) {
fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) {
match ii.node {
hir::ImplItemKind::Const(..) => {
NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
ii.name, ii.span);
NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ii.name, ii.span);
}
_ => {}
}
@@ -363,8 +389,10 @@ fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
if let PatKind::Path(None, ref path) = p.node {
if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() {
if let Def::Const(..) = cx.tcx.expect_def(p.id) {
NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
path.segments[0].name, path.span);
NonUpperCaseGlobals::check_upper_case(cx,
"constant in pattern",
path.segments[0].name,
path.span);
}
}
}
+176 -126
View File
@@ -37,15 +37,15 @@
use rustc::ty::adjustment;
use rustc::traits::{self, Reveal};
use rustc::hir::map as hir_map;
use util::nodemap::{NodeSet};
use util::nodemap::NodeSet;
use lint::{Level, LateContext, LintContext, LintArray, Lint};
use lint::{LintPass, LateLintPass};
use std::collections::HashSet;
use syntax::{ast};
use syntax::ast;
use syntax::attr;
use syntax_pos::{Span};
use syntax_pos::Span;
use rustc::hir::{self, PatKind};
use rustc::hir::intravisit::FnKind;
@@ -75,7 +75,8 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
if let hir::ExprWhile(ref cond, ..) = e.node {
if let hir::ExprLit(ref lit) = cond.node {
if let ast::LitKind::Bool(true) = lit.node {
cx.span_lint(WHILE_TRUE, e.span,
cx.span_lint(WHILE_TRUE,
e.span,
"denote infinite loops with loop { ... }");
}
}
@@ -93,8 +94,7 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
pub struct BoxPointers;
impl BoxPointers {
fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>,
span: Span, ty: Ty<'tcx>) {
fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>, span: Span, ty: Ty<'tcx>) {
for leaf_ty in ty.walk() {
if let ty::TyBox(_) = leaf_ty.sty {
let m = format!("type uses owned (Box type) pointers: {}", ty);
@@ -117,10 +117,8 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
hir::ItemTy(..) |
hir::ItemEnum(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) =>
self.check_heap_type(cx, it.span,
cx.tcx.node_id_to_type(it.id)),
_ => ()
hir::ItemUnion(..) => self.check_heap_type(cx, it.span, cx.tcx.node_id_to_type(it.id)),
_ => (),
}
// If it's a struct, we also have to check the fields' types
@@ -128,11 +126,12 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
hir::ItemStruct(ref struct_def, _) |
hir::ItemUnion(ref struct_def, _) => {
for struct_field in struct_def.fields() {
self.check_heap_type(cx, struct_field.span,
self.check_heap_type(cx,
struct_field.span,
cx.tcx.node_id_to_type(struct_field.id));
}
}
_ => ()
_ => (),
}
}
@@ -166,9 +165,11 @@ fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) {
}
if let PatKind::Binding(_, ident, None) = fieldpat.node.pat.node {
if ident.node == fieldpat.node.name {
cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span,
cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS,
fieldpat.span,
&format!("the `{}:` in this pattern is redundant and can \
be removed", ident.node))
be removed",
ident.node))
}
}
}
@@ -203,27 +204,35 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
match it.node {
hir::ItemTrait(hir::Unsafety::Unsafe, ..) =>
cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait"),
hir::ItemTrait(hir::Unsafety::Unsafe, ..) => {
cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait")
}
hir::ItemImpl(hir::Unsafety::Unsafe, ..) =>
cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait"),
hir::ItemImpl(hir::Unsafety::Unsafe, ..) => {
cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait")
}
_ => return,
}
}
fn check_fn(&mut self, cx: &LateContext, fk: FnKind, _: &hir::FnDecl,
_: &hir::Block, span: Span, _: ast::NodeId) {
fn check_fn(&mut self,
cx: &LateContext,
fk: FnKind,
_: &hir::FnDecl,
_: &hir::Block,
span: Span,
_: ast::NodeId) {
match fk {
FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) =>
cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"),
FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => {
cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function")
}
FnKind::Method(_, sig, ..) => {
if sig.unsafety == hir::Unsafety::Unsafe {
cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method")
}
},
}
_ => (),
}
@@ -232,7 +241,8 @@ fn check_fn(&mut self, cx: &LateContext, fk: FnKind, _: &hir::FnDecl,
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
if sig.unsafety == hir::Unsafety::Unsafe {
cx.span_lint(UNSAFE_CODE, trait_item.span,
cx.span_lint(UNSAFE_CODE,
trait_item.span,
"declaration of an `unsafe` method")
}
}
@@ -263,9 +273,9 @@ pub struct MissingDoc {
impl MissingDoc {
pub fn new() -> MissingDoc {
MissingDoc {
struct_def_stack: vec!(),
struct_def_stack: vec![],
in_variant: false,
doc_hidden_stack: vec!(false),
doc_hidden_stack: vec![false],
private_traits: HashSet::new(),
}
}
@@ -275,11 +285,11 @@ fn doc_hidden(&self) -> bool {
}
fn check_missing_docs_attrs(&self,
cx: &LateContext,
id: Option<ast::NodeId>,
attrs: &[ast::Attribute],
sp: Span,
desc: &'static str) {
cx: &LateContext,
id: Option<ast::NodeId>,
attrs: &[ast::Attribute],
sp: Span,
desc: &'static str) {
// If we're building a test harness, then warning about
// documentation is probably not really relevant right now.
if cx.sess().opts.test {
@@ -302,7 +312,8 @@ fn check_missing_docs_attrs(&self,
let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc");
if !has_doc {
cx.span_lint(MISSING_DOCS, sp,
cx.span_lint(MISSING_DOCS,
sp,
&format!("missing documentation for {}", desc));
}
}
@@ -316,8 +327,10 @@ fn get_lints(&self) -> LintArray {
impl LateLintPass for MissingDoc {
fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) {
let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
attr.check_name("doc") && match attr.meta_item_list() {
let doc_hidden = self.doc_hidden() ||
attrs.iter().any(|attr| {
attr.check_name("doc") &&
match attr.meta_item_list() {
None => false,
Some(l) => attr::list_contains_name(&l[..], "hidden"),
}
@@ -329,13 +342,21 @@ fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) {
self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
}
fn check_struct_def(&mut self, _: &LateContext, _: &hir::VariantData,
_: ast::Name, _: &hir::Generics, item_id: ast::NodeId) {
fn check_struct_def(&mut self,
_: &LateContext,
_: &hir::VariantData,
_: ast::Name,
_: &hir::Generics,
item_id: ast::NodeId) {
self.struct_def_stack.push(item_id);
}
fn check_struct_def_post(&mut self, _: &LateContext, _: &hir::VariantData,
_: ast::Name, _: &hir::Generics, item_id: ast::NodeId) {
fn check_struct_def_post(&mut self,
_: &LateContext,
_: &hir::VariantData,
_: ast::Name,
_: &hir::Generics,
item_id: ast::NodeId) {
let popped = self.struct_def_stack.pop().expect("empty struct_def_stack");
assert!(popped == item_id);
}
@@ -358,10 +379,10 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
for itm in items {
self.private_traits.insert(itm.id);
}
return
return;
}
"a trait"
},
}
hir::ItemTy(..) => "a type alias",
hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_items) => {
// If the trait is private, add the impl items to private_traits so they don't get
@@ -369,26 +390,30 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id();
if let Some(node_id) = cx.tcx.map.as_local_node_id(real_trait) {
match cx.tcx.map.find(node_id) {
Some(hir_map::NodeItem(item)) => if item.vis == hir::Visibility::Inherited {
for itm in impl_items {
self.private_traits.insert(itm.id);
Some(hir_map::NodeItem(item)) => {
if item.vis == hir::Visibility::Inherited {
for itm in impl_items {
self.private_traits.insert(itm.id);
}
}
},
_ => { }
}
_ => {}
}
}
return
},
return;
}
hir::ItemConst(..) => "a constant",
hir::ItemStatic(..) => "a static",
_ => return
_ => return,
};
self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc);
}
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
if self.private_traits.contains(&trait_item.id) { return }
if self.private_traits.contains(&trait_item.id) {
return;
}
let desc = match trait_item.node {
hir::ConstTraitItem(..) => "an associated constant",
@@ -396,9 +421,11 @@ fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
hir::TypeTraitItem(..) => "an associated type",
};
self.check_missing_docs_attrs(cx, Some(trait_item.id),
self.check_missing_docs_attrs(cx,
Some(trait_item.id),
&trait_item.attrs,
trait_item.span, desc);
trait_item.span,
desc);
}
fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
@@ -412,26 +439,34 @@ fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
hir::ImplItemKind::Method(..) => "a method",
hir::ImplItemKind::Type(_) => "an associated type",
};
self.check_missing_docs_attrs(cx, Some(impl_item.id),
self.check_missing_docs_attrs(cx,
Some(impl_item.id),
&impl_item.attrs,
impl_item.span, desc);
impl_item.span,
desc);
}
fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) {
if !sf.is_positional() {
if sf.vis == hir::Public || self.in_variant {
let cur_struct_def = *self.struct_def_stack.last()
let cur_struct_def = *self.struct_def_stack
.last()
.expect("empty struct_def_stack");
self.check_missing_docs_attrs(cx, Some(cur_struct_def),
&sf.attrs, sf.span,
self.check_missing_docs_attrs(cx,
Some(cur_struct_def),
&sf.attrs,
sf.span,
"a struct field")
}
}
}
fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) {
self.check_missing_docs_attrs(cx, Some(v.node.data.id()),
&v.node.attrs, v.span, "a variant");
self.check_missing_docs_attrs(cx,
Some(v.node.data.id()),
&v.node.attrs,
v.span,
"a variant");
assert!(!self.in_variant);
self.in_variant = true;
}
@@ -486,7 +521,9 @@ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
}
_ => return,
};
if def.has_dtor() { return; }
if def.has_dtor() {
return;
}
let parameter_environment = cx.tcx.empty_parameter_environment();
// FIXME (@jroesch) should probably inver this so that the parameter env still impls this
// method
@@ -514,9 +551,7 @@ pub struct MissingDebugImplementations {
impl MissingDebugImplementations {
pub fn new() -> MissingDebugImplementations {
MissingDebugImplementations {
impling_types: None,
}
MissingDebugImplementations { impling_types: None }
}
}
@@ -533,7 +568,9 @@ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
}
match item.node {
hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemEnum(..) => {},
hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemEnum(..) => {}
_ => return,
}
@@ -585,12 +622,13 @@ pub struct Deprecated {
impl Deprecated {
pub fn new() -> Deprecated {
Deprecated {
current_item: ast::CRATE_NODE_ID,
}
Deprecated { current_item: ast::CRATE_NODE_ID }
}
fn lint(&self, cx: &LateContext, _id: DefId, span: Span,
fn lint(&self,
cx: &LateContext,
_id: DefId,
span: Span,
stability: &Option<&attr::Stability>,
deprecation: &Option<stability::DeprecationEntry>) {
// Deprecated attributes apply in-crate and cross-crate.
@@ -641,9 +679,10 @@ fn get_lints(&self) -> LintArray {
impl LateLintPass for Deprecated {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
self.push_item(item.id);
stability::check_item(cx.tcx, item, false,
&mut |id, sp, stab, depr|
self.lint(cx, id, sp, &stab, &depr));
stability::check_item(cx.tcx,
item,
false,
&mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
}
fn check_item_post(&mut self, cx: &LateContext, item: &hir::Item) {
@@ -651,27 +690,30 @@ fn check_item_post(&mut self, cx: &LateContext, item: &hir::Item) {
}
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
stability::check_expr(cx.tcx, e,
&mut |id, sp, stab, depr|
self.lint(cx, id, sp, &stab, &depr));
stability::check_expr(cx.tcx,
e,
&mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
}
fn check_path(&mut self, cx: &LateContext, path: &hir::Path, id: ast::NodeId) {
stability::check_path(cx.tcx, path, id,
&mut |id, sp, stab, depr|
self.lint(cx, id, sp, &stab, &depr));
stability::check_path(cx.tcx,
path,
id,
&mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
}
fn check_path_list_item(&mut self, cx: &LateContext, item: &hir::PathListItem) {
stability::check_path_list_item(cx.tcx, item,
&mut |id, sp, stab, depr|
self.lint(cx, id, sp, &stab, &depr));
stability::check_path_list_item(cx.tcx,
item,
&mut |id, sp, stab, depr| {
self.lint(cx, id, sp, &stab, &depr)
});
}
fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) {
stability::check_pat(cx.tcx, pat,
&mut |id, sp, stab, depr|
self.lint(cx, id, sp, &stab, &depr));
stability::check_pat(cx.tcx,
pat,
&mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
}
fn check_impl_item(&mut self, _: &LateContext, item: &hir::ImplItem) {
@@ -716,15 +758,20 @@ fn get_lints(&self) -> LintArray {
}
impl LateLintPass for UnconditionalRecursion {
fn check_fn(&mut self, cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl,
blk: &hir::Block, sp: Span, id: ast::NodeId) {
fn check_fn(&mut self,
cx: &LateContext,
fn_kind: FnKind,
_: &hir::FnDecl,
blk: &hir::Block,
sp: Span,
id: ast::NodeId) {
let method = match fn_kind {
FnKind::ItemFn(..) => None,
FnKind::Method(..) => {
cx.tcx.impl_or_trait_item(cx.tcx.map.local_def_id(id)).as_opt_method()
}
// closures can't recur, so they don't matter.
FnKind::Closure(_) => return
FnKind::Closure(_) => return,
};
// Walk through this function (say `f`) looking to see if
@@ -779,10 +826,8 @@ fn check_fn(&mut self, cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl,
// is this a recursive call?
let self_recursive = if node_id != ast::DUMMY_NODE_ID {
match method {
Some(ref method) => {
expr_refers_to_this_method(cx.tcx, method, node_id)
}
None => expr_refers_to_this_fn(cx.tcx, id, node_id)
Some(ref method) => expr_refers_to_this_method(cx.tcx, method, node_id),
None => expr_refers_to_this_fn(cx.tcx, id, node_id),
}
} else {
false
@@ -808,7 +853,8 @@ fn check_fn(&mut self, cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl,
// no break */ }`) shouldn't be linted unless it actually
// recurs.
if !reached_exit_without_self_call && !self_call_spans.is_empty() {
let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, sp,
let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION,
sp,
"function cannot return without recurring");
// FIXME #19668: these could be span_lint_note's instead of this manual guard.
@@ -829,23 +875,21 @@ fn check_fn(&mut self, cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl,
// Functions for identifying if the given Expr NodeId `id`
// represents a call to the function `fn_id`/method `method`.
fn expr_refers_to_this_fn(tcx: TyCtxt,
fn_id: ast::NodeId,
id: ast::NodeId) -> bool {
fn expr_refers_to_this_fn(tcx: TyCtxt, fn_id: ast::NodeId, id: ast::NodeId) -> bool {
match tcx.map.get(id) {
hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
tcx.expect_def_or_none(callee.id).map_or(false, |def| {
def.def_id() == tcx.map.local_def_id(fn_id)
})
tcx.expect_def_or_none(callee.id)
.map_or(false, |def| def.def_id() == tcx.map.local_def_id(fn_id))
}
_ => false
_ => false,
}
}
// Check if the expression `id` performs a call to `method`.
fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
method: &ty::Method,
id: ast::NodeId) -> bool {
id: ast::NodeId)
-> bool {
// Check for method calls and overloaded operators.
let opt_m = tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)).cloned();
if let Some(m) = opt_m {
@@ -859,9 +903,11 @@ fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if let Some(adjustment::AdjustDerefRef(adj)) = opt_adj {
for i in 0..adj.autoderefs {
let method_call = ty::MethodCall::autoderef(id, i as u32);
if let Some(m) = tcx.tables.borrow().method_map
.get(&method_call)
.cloned() {
if let Some(m) = tcx.tables
.borrow()
.method_map
.get(&method_call)
.cloned() {
if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) {
return true;
}
@@ -877,13 +923,16 @@ fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
match tcx.expect_def_or_none(callee.id) {
Some(Def::Method(def_id)) => {
let item_substs = tcx.node_id_item_substs(callee.id);
method_call_refers_to_method(
tcx, method, def_id, &item_substs.substs, id)
method_call_refers_to_method(tcx,
method,
def_id,
&item_substs.substs,
id)
}
_ => false
_ => false,
}
}
_ => false
_ => false,
}
}
@@ -893,15 +942,14 @@ fn method_call_refers_to_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
method: &ty::Method,
callee_id: DefId,
callee_substs: &Substs<'tcx>,
expr_id: ast::NodeId) -> bool {
expr_id: ast::NodeId)
-> bool {
let callee_item = tcx.impl_or_trait_item(callee_id);
match callee_item.container() {
// This is an inherent method, so the `def_id` refers
// directly to the method definition.
ty::ImplContainer(_) => {
callee_id == method.def_id
}
ty::ImplContainer(_) => callee_id == method.def_id,
// A trait method, from any number of possible sources.
// Attempt to select a concrete impl before checking.
@@ -939,13 +987,12 @@ fn method_call_refers_to_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let container = ty::ImplContainer(vtable_impl.impl_def_id);
// It matches if it comes from the same impl,
// and has the same method name.
container == method.container
&& callee_item.name() == method.name
container == method.container && callee_item.name() == method.name
}
// There's no way to know if this call is
// recursive, so we assume it's not.
_ => false
_ => false,
}
})
}
@@ -992,7 +1039,8 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
};
if prfn.is_some() {
cx.span_lint(PLUGIN_AS_LIBRARY, it.span,
cx.span_lint(PLUGIN_AS_LIBRARY,
it.span,
"compiler plugin used as an ordinary library");
}
}
@@ -1050,15 +1098,15 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
"generic functions must be mangled");
}
}
},
}
hir::ItemStatic(..) => {
if attr::contains_name(&it.attrs, "no_mangle") &&
!cx.access_levels.is_reachable(it.id) {
!cx.access_levels.is_reachable(it.id) {
let msg = format!("static {} is marked #[no_mangle], but not exported",
it.name);
cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg);
}
},
}
hir::ItemConst(..) => {
if attr::contains_name(&it.attrs, "no_mangle") {
// Const items do not refer to a particular location in memory, and therefore
@@ -1068,7 +1116,7 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg);
}
}
_ => {},
_ => {}
}
}
}
@@ -1096,19 +1144,21 @@ fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) {
consider instead using an UnsafeCell";
match get_transmute_from_to(cx, expr) {
Some((&ty::TyRef(_, from_mt), &ty::TyRef(_, to_mt))) => {
if to_mt.mutbl == hir::Mutability::MutMutable
&& from_mt.mutbl == hir::Mutability::MutImmutable {
if to_mt.mutbl == hir::Mutability::MutMutable &&
from_mt.mutbl == hir::Mutability::MutImmutable {
cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg);
}
}
_ => ()
_ => (),
}
fn get_transmute_from_to<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr)
-> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> {
fn get_transmute_from_to<'a, 'tcx>
(cx: &LateContext<'a, 'tcx>,
expr: &hir::Expr)
-> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> {
match expr.node {
hir::ExprPath(..) => (),
_ => return None
_ => return None,
}
if let Def::Fn(did) = cx.tcx.expect_def(expr.id) {
if !def_id_is_transmute(cx, did) {
@@ -1120,8 +1170,8 @@ fn get_transmute_from_to<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr)
let from = bare_fn.sig.0.inputs[0];
let to = bare_fn.sig.0.output;
return Some((&from.sty, &to.sty));
},
_ => ()
}
_ => (),
}
}
None
@@ -1130,7 +1180,7 @@ fn get_transmute_from_to<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr)
fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool {
match cx.tcx.lookup_item_type(def_id).ty.sty {
ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (),
_ => return false
_ => return false,
}
cx.tcx.item_name(def_id).as_str() == "transmute"
}
+27 -13
View File
@@ -48,10 +48,10 @@
extern crate rustc_const_eval;
extern crate syntax_pos;
pub use rustc::lint as lint;
pub use rustc::middle as middle;
pub use rustc::session as session;
pub use rustc::util as util;
pub use rustc::lint;
pub use rustc::middle;
pub use rustc::session;
pub use rustc::util;
use session::Session;
use lint::LintId;
@@ -139,13 +139,24 @@ macro_rules! add_lint_group {
MissingDebugImplementations,
);
add_lint_group!(sess, "bad_style",
NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS);
add_lint_group!(sess,
"bad_style",
NON_CAMEL_CASE_TYPES,
NON_SNAKE_CASE,
NON_UPPER_CASE_GLOBALS);
add_lint_group!(sess, "unused",
UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE,
UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE,
UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES);
add_lint_group!(sess,
"unused",
UNUSED_IMPORTS,
UNUSED_VARIABLES,
UNUSED_ASSIGNMENTS,
DEAD_CODE,
UNUSED_MUT,
UNREACHABLE_CODE,
UNUSED_MUST_USE,
UNUSED_UNSAFE,
PATH_STATEMENTS,
UNUSED_ATTRIBUTES);
// Guidelines for creating a future incompatibility lint:
//
@@ -155,7 +166,8 @@ macro_rules! add_lint_group {
// and include the full URL.
// - Later, change lint to error
// - Eventually, remove lint
store.register_future_incompatible(sess, vec![
store.register_future_incompatible(sess,
vec![
FutureIncompatibleInfo {
id: LintId::of(PRIVATE_IN_PUBLIC),
reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
@@ -204,11 +216,13 @@ macro_rules! add_lint_group {
// Register renamed and removed lints
store.register_renamed("unknown_features", "unused_features");
store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
store.register_removed("unsigned_negation",
"replaced by negate_unsigned feature gate");
store.register_removed("negate_unsigned", "cast a signed value instead");
store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok");
// This was renamed to raw_pointer_derive, which was then removed,
// so it is also considered removed
store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok");
store.register_removed("raw_pointer_deriving",
"using derive with raw pointers is ok");
store.register_removed("drop_with_repr_extern", "drop flags have been removed");
}
+254 -236
View File
@@ -18,7 +18,7 @@
use middle::const_val::ConstVal;
use rustc_const_eval::eval_const_expr_partial;
use rustc_const_eval::EvalHint::ExprTypeChecked;
use util::nodemap::{FnvHashSet};
use util::nodemap::FnvHashSet;
use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass};
@@ -91,15 +91,15 @@ pub struct TypeLimits {
impl TypeLimits {
pub fn new() -> TypeLimits {
TypeLimits {
negated_expr_id: ast::DUMMY_NODE_ID,
}
TypeLimits { negated_expr_id: ast::DUMMY_NODE_ID }
}
}
impl LintPass for TypeLimits {
fn get_lints(&self) -> LintArray {
lint_array!(UNUSED_COMPARISONS, OVERFLOWING_LITERALS, EXCEEDING_BITSHIFTS)
lint_array!(UNUSED_COMPARISONS,
OVERFLOWING_LITERALS,
EXCEEDING_BITSHIFTS)
}
}
@@ -111,13 +111,13 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
match lit.node {
ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)) => {
forbid_unsigned_negation(cx, e.span);
},
}
ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty {
forbid_unsigned_negation(cx, e.span);
}
},
_ => ()
}
_ => (),
}
} else {
let t = cx.tcx.node_id_to_type(expr.id);
@@ -129,10 +129,11 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
if self.negated_expr_id != e.id {
self.negated_expr_id = expr.id;
}
},
}
hir::ExprBinary(binop, ref l, ref r) => {
if is_comparison(binop) && !check_limits(cx.tcx, binop, &l, &r) {
cx.span_lint(UNUSED_COMPARISONS, e.span,
cx.span_lint(UNUSED_COMPARISONS,
e.span,
"comparison is useless due to type limits");
}
@@ -140,30 +141,35 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
let opt_ty_bits = match cx.tcx.node_id_to_type(l.id).sty {
ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
_ => None
_ => None,
};
if let Some(bits) = opt_ty_bits {
let exceeding = if let hir::ExprLit(ref lit) = r.node {
if let ast::LitKind::Int(shift, _) = lit.node { shift >= bits }
else { false }
if let ast::LitKind::Int(shift, _) = lit.node {
shift >= bits
} else {
false
}
} else {
match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
Ok(ConstVal::Integral(i)) => {
i.is_negative() || i.to_u64()
.map(|i| i >= bits)
.unwrap_or(true)
},
_ => { false }
i.is_negative() ||
i.to_u64()
.map(|i| i >= bits)
.unwrap_or(true)
}
_ => false,
}
};
if exceeding {
cx.span_lint(EXCEEDING_BITSHIFTS, e.span,
cx.span_lint(EXCEEDING_BITSHIFTS,
e.span,
"bitshift exceeds the type's number of bits");
}
};
}
},
}
hir::ExprLit(ref lit) => {
match cx.tcx.node_id_to_type(e.id).sty {
ty::TyInt(t) => {
@@ -182,14 +188,15 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
// avoiding use of -min to prevent overflow/panic
if (negative && v > max as u64 + 1) ||
(!negative && v > max as u64) {
cx.span_lint(OVERFLOWING_LITERALS, e.span,
cx.span_lint(OVERFLOWING_LITERALS,
e.span,
&format!("literal out of range for {:?}", t));
return;
}
}
_ => bug!()
_ => bug!(),
};
},
}
ty::TyUint(t) => {
let uint_type = if let ast::UintTy::Us = t {
cx.sess().target.uint_type
@@ -201,13 +208,14 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
// _v is u8, within range by definition
ast::LitKind::Byte(_v) => return,
ast::LitKind::Int(v, _) => v,
_ => bug!()
_ => bug!(),
};
if lit_val < min || lit_val > max {
cx.span_lint(OVERFLOWING_LITERALS, e.span,
cx.span_lint(OVERFLOWING_LITERALS,
e.span,
&format!("literal out of range for {:?}", t));
}
},
}
ty::TyFloat(t) => {
let (min, max) = float_ty_range(t);
let lit_val: f64 = match lit.node {
@@ -215,70 +223,71 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
ast::LitKind::FloatUnsuffixed(ref v) => {
match v.parse() {
Ok(f) => f,
Err(_) => return
Err(_) => return,
}
}
_ => bug!()
_ => bug!(),
};
if lit_val < min || lit_val > max {
cx.span_lint(OVERFLOWING_LITERALS, e.span,
cx.span_lint(OVERFLOWING_LITERALS,
e.span,
&format!("literal out of range for {:?}", t));
}
},
_ => ()
}
_ => (),
};
},
_ => ()
}
_ => (),
};
fn is_valid<T:cmp::PartialOrd>(binop: hir::BinOp, v: T,
min: T, max: T) -> bool {
fn is_valid<T: cmp::PartialOrd>(binop: hir::BinOp, v: T, min: T, max: T) -> bool {
match binop.node {
hir::BiLt => v > min && v <= max,
hir::BiLe => v >= min && v < max,
hir::BiGt => v >= min && v < max,
hir::BiGe => v > min && v <= max,
hir::BiLt => v > min && v <= max,
hir::BiLe => v >= min && v < max,
hir::BiGt => v >= min && v < max,
hir::BiGe => v > min && v <= max,
hir::BiEq | hir::BiNe => v >= min && v <= max,
_ => bug!()
_ => bug!(),
}
}
fn rev_binop(binop: hir::BinOp) -> hir::BinOp {
codemap::respan(binop.span, match binop.node {
hir::BiLt => hir::BiGt,
hir::BiLe => hir::BiGe,
hir::BiGt => hir::BiLt,
hir::BiGe => hir::BiLe,
_ => return binop
})
codemap::respan(binop.span,
match binop.node {
hir::BiLt => hir::BiGt,
hir::BiLe => hir::BiGe,
hir::BiGt => hir::BiLt,
hir::BiGe => hir::BiLe,
_ => return binop,
})
}
// for isize & usize, be conservative with the warnings, so that the
// warnings are consistent between 32- and 64-bit platforms
fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) {
match int_ty {
ast::IntTy::Is => (i64::MIN, i64::MAX),
ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64),
ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64),
ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64),
ast::IntTy::I64 => (i64::MIN, i64::MAX)
ast::IntTy::Is => (i64::MIN, i64::MAX),
ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64),
ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64),
ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64),
ast::IntTy::I64 => (i64::MIN, i64::MAX),
}
}
fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) {
match uint_ty {
ast::UintTy::Us => (u64::MIN, u64::MAX),
ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64),
ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64),
ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64),
ast::UintTy::U64 => (u64::MIN, u64::MAX)
ast::UintTy::Us => (u64::MIN, u64::MAX),
ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64),
ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64),
ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64),
ast::UintTy::U64 => (u64::MIN, u64::MAX),
}
}
fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) {
match float_ty {
ast::FloatTy::F32 => (f32::MIN as f64, f32::MAX as f64),
ast::FloatTy::F64 => (f64::MIN, f64::MAX)
ast::FloatTy::F64 => (f64::MIN, f64::MAX),
}
}
@@ -305,60 +314,60 @@ fn uint_ty_bits(uint_ty: ast::UintTy, target_uint_ty: ast::UintTy) -> u64 {
fn check_limits<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
binop: hir::BinOp,
l: &hir::Expr,
r: &hir::Expr) -> bool {
r: &hir::Expr)
-> bool {
let (lit, expr, swap) = match (&l.node, &r.node) {
(&hir::ExprLit(_), _) => (l, r, true),
(_, &hir::ExprLit(_)) => (r, l, false),
_ => return true
_ => return true,
};
// Normalize the binop so that the literal is always on the RHS in
// the comparison
let norm_binop = if swap {
rev_binop(binop)
} else {
binop
};
let norm_binop = if swap { rev_binop(binop) } else { binop };
match tcx.node_id_to_type(expr.id).sty {
ty::TyInt(int_ty) => {
let (min, max) = int_ty_range(int_ty);
let lit_val: i64 = match lit.node {
hir::ExprLit(ref li) => match li.node {
ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64,
_ => return true
},
_ => bug!()
hir::ExprLit(ref li) => {
match li.node {
ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64,
_ => return true,
}
}
_ => bug!(),
};
is_valid(norm_binop, lit_val, min, max)
}
ty::TyUint(uint_ty) => {
let (min, max): (u64, u64) = uint_ty_range(uint_ty);
let lit_val: u64 = match lit.node {
hir::ExprLit(ref li) => match li.node {
ast::LitKind::Int(v, _) => v,
_ => return true
},
_ => bug!()
hir::ExprLit(ref li) => {
match li.node {
ast::LitKind::Int(v, _) => v,
_ => return true,
}
}
_ => bug!(),
};
is_valid(norm_binop, lit_val, min, max)
}
_ => true
_ => true,
}
}
fn is_comparison(binop: hir::BinOp) -> bool {
match binop.node {
hir::BiEq | hir::BiLt | hir::BiLe |
hir::BiNe | hir::BiGe | hir::BiGt => true,
_ => false
hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => true,
_ => false,
}
}
fn forbid_unsigned_negation(cx: &LateContext, span: Span) {
cx.sess()
.struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
.span_help(span, "use a cast or the `!` operator")
.emit();
.struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
.span_help(span, "use a cast or the `!` operator")
.emit();
}
}
}
@@ -370,7 +379,7 @@ fn forbid_unsigned_negation(cx: &LateContext, span: Span) {
}
struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>
cx: &'a LateContext<'a, 'tcx>,
}
enum FfiResult {
@@ -403,9 +412,13 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if def.variants[data_idx].fields.len() == 1 {
match def.variants[data_idx].fields[0].ty(tcx, substs).sty {
ty::TyFnPtr(_) => { return true; }
ty::TyRef(..) => { return true; }
_ => { }
ty::TyFnPtr(_) => {
return true;
}
ty::TyRef(..) => {
return true;
}
_ => {}
}
}
}
@@ -415,10 +428,7 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// Check if the given type is "ffi-safe" (has a stable, well-defined
/// representation which can be exported to C code).
fn check_type_for_ffi(&self,
cache: &mut FnvHashSet<Ty<'tcx>>,
ty: Ty<'tcx>)
-> FfiResult {
fn check_type_for_ffi(&self, cache: &mut FnvHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult {
use self::FfiResult::*;
let cx = self.cx.tcx;
@@ -431,112 +441,118 @@ fn check_type_for_ffi(&self,
}
match ty.sty {
ty::TyAdt(def, substs) => match def.adt_kind() {
AdtKind::Struct => {
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
return FfiUnsafe(
"found struct without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to \
the type");
}
// We can't completely trust repr(C) markings; make sure the
// fields are actually safe.
if def.struct_variant().fields.is_empty() {
return FfiUnsafe(
"found zero-size struct in foreign module, consider \
adding a member to this struct");
}
for field in &def.struct_variant().fields {
let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
let r = self.check_type_for_ffi(cache, field_ty);
match r {
FfiSafe => {}
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
FfiUnsafe(s) => { return FfiBadStruct(def.did, s); }
ty::TyAdt(def, substs) => {
match def.adt_kind() {
AdtKind::Struct => {
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
return FfiUnsafe("found struct without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to the type");
}
}
FfiSafe
}
AdtKind::Union => {
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
return FfiUnsafe(
"found union without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to \
the type");
}
for field in &def.struct_variant().fields {
let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
let r = self.check_type_for_ffi(cache, field_ty);
match r {
FfiSafe => {}
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
FfiUnsafe(s) => { return FfiBadUnion(def.did, s); }
// We can't completely trust repr(C) markings; make sure the
// fields are actually safe.
if def.struct_variant().fields.is_empty() {
return FfiUnsafe("found zero-size struct in foreign module, consider \
adding a member to this struct");
}
}
FfiSafe
}
AdtKind::Enum => {
if def.variants.is_empty() {
// Empty enums are okay... although sort of useless.
return FfiSafe
}
// Check for a repr() attribute to specify the size of the
// discriminant.
let repr_hints = cx.lookup_repr_hints(def.did);
match &repr_hints[..] {
&[] => {
// Special-case types like `Option<extern fn()>`.
if !is_repr_nullable_ptr(cx, def, substs) {
return FfiUnsafe(
"found enum without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(...)] attribute to \
the type")
}
}
&[ref hint] => {
if !hint.is_ffi_safe() {
// FIXME: This shouldn't be reachable: we should check
// this earlier.
return FfiUnsafe(
"enum has unexpected #[repr(...)] attribute")
}
// Enum with an explicitly sized discriminant; either
// a C-style enum or a discriminated union.
// The layout of enum variants is implicitly repr(C).
// FIXME: Is that correct?
}
_ => {
// FIXME: This shouldn't be reachable: we should check
// this earlier.
return FfiUnsafe(
"enum has too many #[repr(...)] attributes");
}
}
// Check the contained variants.
for variant in &def.variants {
for field in &variant.fields {
let arg = cx.normalize_associated_type(&field.ty(cx, substs));
let r = self.check_type_for_ffi(cache, arg);
for field in &def.struct_variant().fields {
let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
let r = self.check_type_for_ffi(cache, field_ty);
match r {
FfiSafe => {}
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
FfiUnsafe(s) => { return FfiBadEnum(def.did, s); }
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
return r;
}
FfiUnsafe(s) => {
return FfiBadStruct(def.did, s);
}
}
}
FfiSafe
}
AdtKind::Union => {
if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
return FfiUnsafe("found union without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to the type");
}
for field in &def.struct_variant().fields {
let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
let r = self.check_type_for_ffi(cache, field_ty);
match r {
FfiSafe => {}
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
return r;
}
FfiUnsafe(s) => {
return FfiBadUnion(def.did, s);
}
}
}
FfiSafe
}
AdtKind::Enum => {
if def.variants.is_empty() {
// Empty enums are okay... although sort of useless.
return FfiSafe;
}
// Check for a repr() attribute to specify the size of the
// discriminant.
let repr_hints = cx.lookup_repr_hints(def.did);
match &repr_hints[..] {
&[] => {
// Special-case types like `Option<extern fn()>`.
if !is_repr_nullable_ptr(cx, def, substs) {
return FfiUnsafe("found enum without foreign-function-safe \
representation annotation in foreign \
module, consider adding a #[repr(...)] \
attribute to the type");
}
}
&[ref hint] => {
if !hint.is_ffi_safe() {
// FIXME: This shouldn't be reachable: we should check
// this earlier.
return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
}
// Enum with an explicitly sized discriminant; either
// a C-style enum or a discriminated union.
// The layout of enum variants is implicitly repr(C).
// FIXME: Is that correct?
}
_ => {
// FIXME: This shouldn't be reachable: we should check
// this earlier.
return FfiUnsafe("enum has too many #[repr(...)] attributes");
}
}
// Check the contained variants.
for variant in &def.variants {
for field in &variant.fields {
let arg = cx.normalize_associated_type(&field.ty(cx, substs));
let r = self.check_type_for_ffi(cache, arg);
match r {
FfiSafe => {}
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
return r;
}
FfiUnsafe(s) => {
return FfiBadEnum(def.did, s);
}
}
}
}
FfiSafe
}
FfiSafe
}
},
}
ty::TyChar => {
FfiUnsafe("found Rust type `char` in foreign module, while \
@@ -544,8 +560,7 @@ fn check_type_for_ffi(&self,
}
// Primitive types with a stable representation.
ty::TyBool | ty::TyInt(..) | ty::TyUint(..) |
ty::TyFloat(..) | ty::TyNever => FfiSafe,
ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe,
ty::TyBox(..) => {
FfiUnsafe("found Rust type Box<_> in foreign module, \
@@ -572,24 +587,17 @@ fn check_type_for_ffi(&self,
consider using a struct instead")
}
ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => {
self.check_type_for_ffi(cache, m.ty)
}
ty::TyRawPtr(ref m) |
ty::TyRef(_, ref m) => self.check_type_for_ffi(cache, m.ty),
ty::TyArray(ty, _) => {
self.check_type_for_ffi(cache, ty)
}
ty::TyArray(ty, _) => self.check_type_for_ffi(cache, ty),
ty::TyFnPtr(bare_fn) => {
match bare_fn.abi {
Abi::Rust |
Abi::RustIntrinsic |
Abi::PlatformIntrinsic |
Abi::RustCall => {
return FfiUnsafe(
"found function pointer with Rust calling \
convention in foreign module; consider using an \
`extern` function pointer")
Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
return FfiUnsafe("found function pointer with Rust calling convention in \
foreign module; consider using an `extern` function \
pointer")
}
_ => {}
}
@@ -599,24 +607,30 @@ fn check_type_for_ffi(&self,
let r = self.check_type_for_ffi(cache, sig.output);
match r {
FfiSafe => {}
_ => { return r; }
_ => {
return r;
}
}
}
for arg in sig.inputs {
let r = self.check_type_for_ffi(cache, arg);
match r {
FfiSafe => {}
_ => { return r; }
_ => {
return r;
}
}
}
FfiSafe
}
ty::TyParam(..) | ty::TyInfer(..) | ty::TyError |
ty::TyClosure(..) | ty::TyProjection(..) | ty::TyAnon(..) |
ty::TyFnDef(..) => {
bug!("Unexpected type in foreign function")
}
ty::TyParam(..) |
ty::TyInfer(..) |
ty::TyError |
ty::TyClosure(..) |
ty::TyProjection(..) |
ty::TyAnon(..) |
ty::TyFnDef(..) => bug!("Unexpected type in foreign function"),
}
}
@@ -633,23 +647,28 @@ fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
FfiResult::FfiBadStruct(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant field.
self.cx.span_lint(IMPROPER_CTYPES, sp,
&format!("found non-foreign-function-safe member in \
struct marked #[repr(C)]: {}", s));
self.cx.span_lint(IMPROPER_CTYPES,
sp,
&format!("found non-foreign-function-safe member in struct \
marked #[repr(C)]: {}",
s));
}
FfiResult::FfiBadUnion(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant field.
self.cx.span_lint(IMPROPER_CTYPES, sp,
&format!("found non-foreign-function-safe member in \
union marked #[repr(C)]: {}", s));
self.cx.span_lint(IMPROPER_CTYPES,
sp,
&format!("found non-foreign-function-safe member in union \
marked #[repr(C)]: {}",
s));
}
FfiResult::FfiBadEnum(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant variant.
self.cx.span_lint(IMPROPER_CTYPES, sp,
&format!("found non-foreign-function-safe member in \
enum: {}", s));
self.cx.span_lint(IMPROPER_CTYPES,
sp,
&format!("found non-foreign-function-safe member in enum: {}",
s));
}
}
}
@@ -719,13 +738,13 @@ fn get_lints(&self) -> LintArray {
impl LateLintPass for VariantSizeDifferences {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
if gens.ty_params.is_empty() { // sizes only make sense for non-generic types
if gens.ty_params.is_empty() {
// sizes only make sense for non-generic types
let t = cx.tcx.node_id_to_type(it.id);
let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let ty = cx.tcx.erase_regions(&t);
ty.layout(&infcx).unwrap_or_else(|e| {
bug!("failed to get layout for `{}`: {}", t, e)
})
ty.layout(&infcx)
.unwrap_or_else(|e| bug!("failed to get layout for `{}`: {}", t, e))
});
if let Layout::General { ref variants, ref size, discr, .. } = *layout {
@@ -738,23 +757,21 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
.zip(variants)
.map(|(variant, variant_layout)| {
// Subtract the size of the enum discriminant
let bytes = variant_layout.min_size.bytes()
.saturating_sub(discr_size);
let bytes = variant_layout.min_size
.bytes()
.saturating_sub(discr_size);
debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);
bytes
})
.enumerate()
.fold((0, 0, 0),
|(l, s, li), (idx, size)|
if size > l {
(size, l, idx)
} else if size > s {
(l, size, li)
} else {
(l, s, li)
}
);
.fold((0, 0, 0), |(l, s, li), (idx, size)| if size > l {
(size, l, idx)
} else if size > s {
(l, size, li)
} else {
(l, s, li)
});
// we only warn if the largest variant is at least thrice as large as
// the second-largest.
@@ -762,7 +779,8 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
cx.span_lint(VARIANT_SIZE_DIFFERENCES,
enum_definition.variants[largest_index].span,
&format!("enum variant is more than three times larger \
({} bytes) than the next largest", largest));
({} bytes) than the next largest",
largest));
}
}
}
+56 -44
View File
@@ -49,8 +49,12 @@ fn check_unused_mut_pat(&self, cx: &LateContext, pats: &[P<hir::Pat>]) {
if let hir::BindByValue(hir::MutMutable) = mode {
if !name.as_str().starts_with("_") {
match mutables.entry(name.0 as usize) {
Vacant(entry) => { entry.insert(vec![id]); },
Occupied(mut entry) => { entry.get_mut().push(id); },
Vacant(entry) => {
entry.insert(vec![id]);
}
Occupied(mut entry) => {
entry.get_mut().push(id);
}
}
}
}
@@ -60,7 +64,8 @@ fn check_unused_mut_pat(&self, cx: &LateContext, pats: &[P<hir::Pat>]) {
let used_mutables = cx.tcx.used_mut_nodes.borrow();
for (_, v) in &mutables {
if !v.iter().any(|e| used_mutables.contains(e)) {
cx.span_lint(UNUSED_MUT, cx.tcx.map.span(v[0]),
cx.span_lint(UNUSED_MUT,
cx.tcx.map.span(v[0]),
"variable does not need to be mutable");
}
}
@@ -90,9 +95,13 @@ fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
}
}
fn check_fn(&mut self, cx: &LateContext,
_: FnKind, decl: &hir::FnDecl,
_: &hir::Block, _: Span, _: ast::NodeId) {
fn check_fn(&mut self,
cx: &LateContext,
_: FnKind,
decl: &hir::FnDecl,
_: &hir::Block,
_: Span,
_: ast::NodeId) {
for a in &decl.inputs {
self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
}
@@ -124,7 +133,7 @@ impl LateLintPass for UnusedResults {
fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
let expr = match s.node {
hir::StmtSemi(ref expr, _) => &**expr,
_ => return
_ => return,
};
if let hir::ExprRet(..) = expr.node {
@@ -184,8 +193,8 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
if let hir::ExprBlock(ref blk) = e.node {
// Don't warn about generated blocks, that'll just pollute the output.
if blk.rules == hir::UnsafeBlock(hir::UserProvided) &&
!cx.tcx.used_unsafe.borrow().contains(&blk.id) {
cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block");
!cx.tcx.used_unsafe.borrow().contains(&blk.id) {
cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block");
}
}
}
@@ -210,8 +219,7 @@ impl LateLintPass for PathStatements {
fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
if let hir::StmtSemi(ref expr, _) = s.node {
if let hir::ExprPath(..) = expr.node {
cx.span_lint(PATH_STATEMENTS, s.span,
"path statement with no effect");
cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect");
}
}
}
@@ -242,8 +250,8 @@ fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
AttributeType::Whitelisted if attr.check_name(name) => {
debug!("{:?} is Whitelisted", name);
break;
},
_ => ()
}
_ => (),
}
}
@@ -259,24 +267,22 @@ fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
debug!("Emitting warning for: {:?}", attr);
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
// Is it a builtin attribute that must be used at the crate level?
let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| {
attr.name() == name &&
ty == AttributeType::CrateLevel
}).is_some();
let known_crate = KNOWN_ATTRIBUTES.iter()
.find(|&&(name, ty, _)| attr.name() == name && ty == AttributeType::CrateLevel)
.is_some();
// Has a plugin registered this attribute as one which must be used at
// the crate level?
let plugin_crate = plugin_attributes.iter()
.find(|&&(ref x, t)| {
&*attr.name() == x &&
AttributeType::CrateLevel == t
}).is_some();
if known_crate || plugin_crate {
.find(|&&(ref x, t)| &*attr.name() == x && AttributeType::CrateLevel == t)
.is_some();
if known_crate || plugin_crate {
let msg = match attr.node.style {
ast::AttrStyle::Outer => "crate-level attribute should be an inner \
attribute: add an exclamation mark: #![foo]",
ast::AttrStyle::Inner => "crate-level attribute should be in the \
root module",
ast::AttrStyle::Outer => {
"crate-level attribute should be an inner attribute: add an exclamation \
mark: #![foo]"
}
ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
};
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
}
@@ -296,12 +302,16 @@ fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
pub struct UnusedParens;
impl UnusedParens {
fn check_unused_parens_core(&self, cx: &EarlyContext, value: &ast::Expr, msg: &str,
fn check_unused_parens_core(&self,
cx: &EarlyContext,
value: &ast::Expr,
msg: &str,
struct_lit_needs_parens: bool) {
if let ast::ExprKind::Paren(ref inner) = value.node {
let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&inner);
if !necessary {
cx.span_lint(UNUSED_PARENS, value.span,
cx.span_lint(UNUSED_PARENS,
value.span,
&format!("unnecessary parentheses around {}", msg))
}
}
@@ -319,8 +329,7 @@ fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
// X { y: 1 } + X { y: 2 }
contains_exterior_struct_lit(&lhs) ||
contains_exterior_struct_lit(&rhs)
contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
}
ast::ExprKind::Unary(_, ref x) |
ast::ExprKind::Cast(ref x, _) |
@@ -337,7 +346,7 @@ fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
contains_exterior_struct_lit(&exprs[0])
}
_ => false
_ => false,
}
}
}
@@ -363,18 +372,20 @@ fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) {
Assign(_, ref value) => (value, "assigned value", false),
AssignOp(.., ref value) => (value, "assigned value", false),
InPlace(_, ref value) => (value, "emplacement value", false),
_ => return
_ => return,
};
self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens);
}
fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) {
let (value, msg) = match s.node {
ast::StmtKind::Local(ref local) => match local.init {
Some(ref value) => (value, "assigned value"),
None => return
},
_ => return
ast::StmtKind::Local(ref local) => {
match local.init {
Some(ref value) => (value, "assigned value"),
None => return,
}
}
_ => return,
};
self.check_unused_parens_core(cx, &value, msg, false);
}
@@ -427,23 +438,24 @@ impl LateLintPass for UnusedAllocation {
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
match e.node {
hir::ExprBox(_) => {}
_ => return
_ => return,
}
if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) {
if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
ref autoref, ..
}) = *adjustment {
if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { ref autoref, .. }) =
*adjustment {
match autoref {
&Some(adjustment::AutoPtr(_, hir::MutImmutable)) => {
cx.span_lint(UNUSED_ALLOCATION, e.span,
cx.span_lint(UNUSED_ALLOCATION,
e.span,
"unnecessary allocation, use & instead");
}
&Some(adjustment::AutoPtr(_, hir::MutMutable)) => {
cx.span_lint(UNUSED_ALLOCATION, e.span,
cx.span_lint(UNUSED_ALLOCATION,
e.span,
"unnecessary allocation, use &mut instead");
}
_ => ()
_ => (),
}
}
}
+2 -1
View File
@@ -32,6 +32,7 @@
use rustc::mir::repr::Mir;
use std::borrow::Cow;
use std::cell::Ref;
use std::io;
use std::mem;
@@ -202,7 +203,7 @@ impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> {
read_f64 -> f64;
read_f32 -> f32;
read_char -> char;
read_str -> String;
read_str -> Cow<str>;
}
fn error(&mut self, err: &str) -> Self::Error {
+1 -1
View File
@@ -23,7 +23,7 @@
#![feature(dotdot_in_tuple_patterns)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_lib)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
+1 -1
View File
@@ -26,7 +26,7 @@
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#[macro_use] extern crate log;
extern crate graphviz as dot;
+44 -26
View File
@@ -13,7 +13,7 @@
//! Here we build the "reduced graph": the graph of the module tree without
//! any imports resolved.
use macros;
use macros::{InvocationData, LegacyScope};
use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
use {Module, ModuleS, ModuleKind};
use Namespace::{self, TypeNS, ValueNS};
@@ -200,16 +200,16 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
LoadedMacroKind::Def(mut def) => {
let name = def.ident.name;
if def.use_locally {
let ext = macro_rules::compile(&self.session.parse_sess, &def);
let shadowing =
self.resolve_macro_name(Mark::root(), name, false).is_some();
self.expansion_data[&Mark::root()].module.macros.borrow_mut()
.insert(name, macros::NameBinding {
ext: Rc::new(ext),
expansion: expansion,
shadowing: shadowing,
span: loaded_macro.import_site,
});
let ext =
Rc::new(macro_rules::compile(&self.session.parse_sess, &def));
if self.builtin_macros.insert(name, ext).is_some() &&
expansion != Mark::root() {
let msg = format!("`{}` is already in scope", name);
self.session.struct_span_err(loaded_macro.import_site, &msg)
.note("macro-expanded `#[macro_use]`s may not shadow \
existing macros (see RFC 1560)")
.emit();
}
self.macro_names.insert(name);
}
if def.export {
@@ -250,7 +250,6 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
attr::contains_name(&item.attrs, "no_implicit_prelude")
},
normal_ancestor_id: Some(item.id),
macros_escape: self.contains_macro_use(&item.attrs),
..ModuleS::new(Some(parent), ModuleKind::Def(def, name))
});
self.define(parent, name, TypeNS, (module, sp, vis));
@@ -520,22 +519,26 @@ fn insert_custom_derive(&mut self, name: &str, ext: Rc<MultiItemModifier>, sp: S
pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
pub resolver: &'a mut Resolver<'b>,
pub legacy_scope: LegacyScope<'b>,
pub expansion: Mark,
}
impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
fn visit_invoc(&mut self, id: ast::NodeId) {
self.resolver.expansion_data.get_mut(&Mark::from_placeholder_id(id)).unwrap().module =
self.resolver.current_module;
fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> {
let invocation = self.resolver.invocations[&Mark::from_placeholder_id(id)];
invocation.module.set(self.resolver.current_module);
invocation.legacy_scope.set(self.legacy_scope);
invocation
}
}
macro_rules! method {
($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
fn $visit(&mut self, node: &$ty) {
match node.node {
$invoc(..) => self.visit_invoc(node.id),
_ => visit::$walk(self, node),
if let $invoc(..) = node.node {
self.visit_invoc(node.id);
} else {
visit::$walk(self, node);
}
}
}
@@ -543,22 +546,35 @@ fn $visit(&mut self, node: &$ty) {
impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
method!(visit_stmt: ast::Stmt, ast::StmtKind::Mac, walk_stmt);
method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr);
method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat);
method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty);
fn visit_item(&mut self, item: &Item) {
match item.node {
let macro_use = match item.node {
ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => return, // Scope placeholder
ItemKind::Mac(..) => return self.visit_invoc(item.id),
_ => {}
}
ItemKind::Mac(..) => {
return self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
}
ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs),
_ => false,
};
let parent = self.resolver.current_module;
let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope);
self.resolver.build_reduced_graph_for_item(item, self.expansion);
visit::walk_item(self, item);
self.resolver.current_module = parent;
if !macro_use {
self.legacy_scope = legacy_scope;
}
}
fn visit_stmt(&mut self, stmt: &ast::Stmt) {
if let ast::StmtKind::Mac(..) = stmt.node {
self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(stmt.id));
} else {
visit::walk_stmt(self, stmt);
}
}
fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
@@ -567,10 +583,11 @@ fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
}
fn visit_block(&mut self, block: &Block) {
let parent = self.resolver.current_module;
let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope);
self.resolver.build_reduced_graph_for_block(block);
visit::walk_block(self, block);
self.resolver.current_module = parent;
self.legacy_scope = legacy_scope;
}
fn visit_trait_item(&mut self, item: &TraitItem) {
@@ -578,7 +595,8 @@ fn visit_trait_item(&mut self, item: &TraitItem) {
let def_id = parent.def_id().unwrap();
if let TraitItemKind::Macro(_) = item.node {
return self.visit_invoc(item.id);
self.visit_invoc(item.id);
return
}
// Add the item to the trait info.
+38 -12
View File
@@ -57,6 +57,7 @@
use syntax::ext::hygiene::Mark;
use syntax::ast::{self, FloatTy};
use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy};
use syntax::ext::base::SyntaxExtension;
use syntax::parse::token::{self, keywords};
use syntax::util::lev_distance::find_best_match_for_name;
@@ -77,6 +78,7 @@
use std::rc::Rc;
use resolve_imports::{ImportDirective, NameResolution};
use macros::{InvocationData, LegacyBinding, LegacyScope};
// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
@@ -791,9 +793,6 @@ pub struct ModuleS<'a> {
// access the children must be preceded with a
// `populate_module_if_necessary` call.
populated: Cell<bool>,
macros: RefCell<FnvHashMap<Name, macros::NameBinding>>,
macros_escape: bool,
}
pub type Module<'a> = &'a ModuleS<'a>;
@@ -811,8 +810,6 @@ fn new(parent: Option<Module<'a>>, kind: ModuleKind) -> Self {
globs: RefCell::new((Vec::new())),
traits: RefCell::new(None),
populated: Cell::new(true),
macros: RefCell::new(FnvHashMap()),
macros_escape: false,
}
}
@@ -1076,7 +1073,7 @@ pub struct Resolver<'a> {
privacy_errors: Vec<PrivacyError<'a>>,
ambiguity_errors: Vec<AmbiguityError<'a>>,
macro_shadowing_errors: FnvHashSet<Span>,
disallowed_shadowing: Vec<(Name, Span, LegacyScope<'a>)>,
arenas: &'a ResolverArenas<'a>,
dummy_binding: &'a NameBinding<'a>,
@@ -1086,9 +1083,10 @@ pub struct Resolver<'a> {
pub derive_modes: FnvHashMap<Name, Rc<MultiItemModifier>>,
crate_loader: &'a mut CrateLoader,
macro_names: FnvHashSet<Name>,
builtin_macros: FnvHashMap<Name, Rc<SyntaxExtension>>,
// Maps the `Mark` of an expansion to its containing module or block.
expansion_data: FnvHashMap<Mark, macros::ExpansionData<'a>>,
invocations: FnvHashMap<Mark, &'a InvocationData<'a>>,
}
pub struct ResolverArenas<'a> {
@@ -1097,6 +1095,8 @@ pub struct ResolverArenas<'a> {
name_bindings: arena::TypedArena<NameBinding<'a>>,
import_directives: arena::TypedArena<ImportDirective<'a>>,
name_resolutions: arena::TypedArena<RefCell<NameResolution<'a>>>,
invocation_data: arena::TypedArena<InvocationData<'a>>,
legacy_bindings: arena::TypedArena<LegacyBinding<'a>>,
}
impl<'a> ResolverArenas<'a> {
@@ -1120,6 +1120,13 @@ fn alloc_import_directive(&'a self, import_directive: ImportDirective<'a>)
fn alloc_name_resolution(&'a self) -> &'a RefCell<NameResolution<'a>> {
self.name_resolutions.alloc(Default::default())
}
fn alloc_invocation_data(&'a self, expansion_data: InvocationData<'a>)
-> &'a InvocationData<'a> {
self.invocation_data.alloc(expansion_data)
}
fn alloc_legacy_binding(&'a self, binding: LegacyBinding<'a>) -> &'a LegacyBinding<'a> {
self.legacy_bindings.alloc(binding)
}
}
impl<'a> ty::NodeIdTree for Resolver<'a> {
@@ -1205,8 +1212,9 @@ pub fn new(session: &'a Session,
let mut definitions = Definitions::new();
DefCollector::new(&mut definitions).collect_root();
let mut expansion_data = FnvHashMap();
expansion_data.insert(Mark::root(), macros::ExpansionData::root(graph_root));
let mut invocations = FnvHashMap();
invocations.insert(Mark::root(),
arenas.alloc_invocation_data(InvocationData::root(graph_root)));
Resolver {
session: session,
@@ -1252,7 +1260,7 @@ pub fn new(session: &'a Session,
privacy_errors: Vec::new(),
ambiguity_errors: Vec::new(),
macro_shadowing_errors: FnvHashSet(),
disallowed_shadowing: Vec::new(),
arenas: arenas,
dummy_binding: arenas.alloc_name_binding(NameBinding {
@@ -1266,7 +1274,8 @@ pub fn new(session: &'a Session,
derive_modes: FnvHashMap(),
crate_loader: crate_loader,
macro_names: FnvHashSet(),
expansion_data: expansion_data,
builtin_macros: FnvHashMap(),
invocations: invocations,
}
}
@@ -1277,6 +1286,8 @@ pub fn arenas() -> ResolverArenas<'a> {
name_bindings: arena::TypedArena::new(),
import_directives: arena::TypedArena::new(),
name_resolutions: arena::TypedArena::new(),
invocation_data: arena::TypedArena::new(),
legacy_bindings: arena::TypedArena::new(),
}
}
@@ -3338,7 +3349,8 @@ fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
vis.is_accessible_from(module.normal_ancestor_id.unwrap(), self)
}
fn report_errors(&self) {
fn report_errors(&mut self) {
self.report_shadowing_errors();
let mut reported_spans = FnvHashSet();
for &AmbiguityError { span, name, b1, b2 } in &self.ambiguity_errors {
@@ -3366,6 +3378,20 @@ fn report_errors(&self) {
}
}
fn report_shadowing_errors(&mut self) {
let mut reported_errors = FnvHashSet();
for (name, span, scope) in replace(&mut self.disallowed_shadowing, Vec::new()) {
if self.resolve_macro_name(scope, name, false).is_some() &&
reported_errors.insert((name, span)) {
let msg = format!("`{}` is already in scope", name);
self.session.struct_span_err(span, &msg)
.note("macro-expanded `macro_rules!`s may not shadow \
existing macros (see RFC 1560)")
.emit();
}
}
}
fn report_conflict(&self,
parent: Module,
name: Name,
+130 -83
View File
@@ -12,47 +12,76 @@
use build_reduced_graph::BuildReducedGraphVisitor;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex};
use rustc::hir::map::{self, DefCollector};
use rustc::util::nodemap::FnvHashMap;
use std::cell::Cell;
use std::rc::Rc;
use syntax::ast;
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier};
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator, MultiItemModifier};
use syntax::ext::base::{NormalTT, SyntaxExtension};
use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
use syntax::parse::token::intern;
use syntax::util::lev_distance::find_best_match_for_name;
use syntax_pos::{Span, DUMMY_SP};
// FIXME(jseyfried) Merge with `::NameBinding`.
pub struct NameBinding {
pub ext: Rc<SyntaxExtension>,
pub expansion: Mark,
pub shadowing: bool,
pub span: Span,
}
use syntax_pos::Span;
#[derive(Clone)]
pub struct ExpansionData<'a> {
backtrace: SyntaxContext,
pub module: Module<'a>,
pub struct InvocationData<'a> {
pub module: Cell<Module<'a>>,
def_index: DefIndex,
// True if this expansion is in a `const_integer` position, for example `[u32; m!()]`.
// c.f. `DefCollector::visit_ast_const_integer`.
const_integer: bool,
// The scope in which the invocation path is resolved.
pub legacy_scope: Cell<LegacyScope<'a>>,
// The smallest scope that includes this invocation's expansion,
// or `Empty` if this invocation has not been expanded yet.
pub expansion: Cell<LegacyScope<'a>>,
}
impl<'a> ExpansionData<'a> {
impl<'a> InvocationData<'a> {
pub fn root(graph_root: Module<'a>) -> Self {
ExpansionData {
backtrace: SyntaxContext::empty(),
module: graph_root,
InvocationData {
module: Cell::new(graph_root),
def_index: CRATE_DEF_INDEX,
const_integer: false,
legacy_scope: Cell::new(LegacyScope::Empty),
expansion: Cell::new(LegacyScope::Empty),
}
}
}
#[derive(Copy, Clone)]
pub enum LegacyScope<'a> {
Empty,
Invocation(&'a InvocationData<'a>), // The scope of the invocation, not including its expansion
Expansion(&'a InvocationData<'a>), // The scope of the invocation, including its expansion
Binding(&'a LegacyBinding<'a>),
}
impl<'a> LegacyScope<'a> {
fn simplify_expansion(mut invoc: &'a InvocationData<'a>) -> Self {
while let LegacyScope::Invocation(_) = invoc.expansion.get() {
match invoc.legacy_scope.get() {
LegacyScope::Expansion(new_invoc) => invoc = new_invoc,
LegacyScope::Binding(_) => break,
scope @ _ => return scope,
}
}
LegacyScope::Expansion(invoc)
}
}
pub struct LegacyBinding<'a> {
parent: LegacyScope<'a>,
name: ast::Name,
ext: Rc<SyntaxExtension>,
span: Span,
}
pub type LegacyImports = FnvHashMap<ast::Name, (Rc<SyntaxExtension>, Span)>;
impl<'a> base::Resolver for Resolver<'a> {
fn next_node_id(&mut self) -> ast::NodeId {
self.session.next_node_id()
@@ -61,19 +90,28 @@ fn next_node_id(&mut self) -> ast::NodeId {
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
let mark = Mark::fresh();
let module = self.module_map[&id];
self.expansion_data.insert(mark, ExpansionData {
backtrace: SyntaxContext::empty(),
module: module,
self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData {
module: Cell::new(module),
def_index: module.def_id().unwrap().index,
const_integer: false,
});
legacy_scope: Cell::new(LegacyScope::Empty),
expansion: Cell::new(LegacyScope::Empty),
}));
mark
}
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
self.collect_def_ids(mark, expansion);
self.current_module = self.expansion_data[&mark].module;
expansion.visit_with(&mut BuildReducedGraphVisitor { resolver: self, expansion: mark });
let invocation = self.invocations[&mark];
self.collect_def_ids(invocation, expansion);
self.current_module = invocation.module.get();
let mut visitor = BuildReducedGraphVisitor {
resolver: self,
legacy_scope: LegacyScope::Invocation(invocation),
expansion: mark,
};
expansion.visit_with(&mut visitor);
invocation.expansion.set(visitor.legacy_scope);
}
fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
@@ -81,17 +119,14 @@ fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
}
if def.use_locally {
let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope];
while module.macros_escape {
module = module.parent.unwrap();
}
let binding = NameBinding {
let invocation = self.invocations[&scope];
let binding = self.arenas.alloc_legacy_binding(LegacyBinding {
parent: invocation.legacy_scope.get(),
name: def.ident.name,
ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
expansion: backtrace.data().prev_ctxt.data().outer_mark,
shadowing: self.resolve_macro_name(scope, def.ident.name, false).is_some(),
span: def.span,
};
module.macros.borrow_mut().insert(def.ident.name, binding);
});
invocation.legacy_scope.set(LegacyScope::Binding(binding));
self.macro_names.insert(def.ident.name);
}
if def.export {
@@ -104,12 +139,7 @@ fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
if let NormalTT(..) = *ext {
self.macro_names.insert(ident.name);
}
self.graph_root.macros.borrow_mut().insert(ident.name, NameBinding {
ext: ext,
expansion: Mark::root(),
shadowing: false,
span: DUMMY_SP,
});
self.builtin_macros.insert(ident.name, ext);
}
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
@@ -119,8 +149,8 @@ fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
fn find_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
for i in 0..attrs.len() {
let name = intern(&attrs[i].name());
match self.expansion_data[&Mark::root()].module.macros.borrow().get(&name) {
Some(binding) => match *binding.ext {
match self.builtin_macros.get(&name) {
Some(ext) => match **ext {
MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
return Some(attrs.remove(i))
}
@@ -132,7 +162,8 @@ fn find_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::At
None
}
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy> {
let (name, span) = match invoc.kind {
InvocationKind::Bang { ref mac, .. } => {
let path = &mac.node.path;
@@ -140,19 +171,27 @@ fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<Syntax
!path.segments[0].parameters.is_empty() {
self.session.span_err(path.span,
"expected macro name without module separators");
return None;
return Err(Determinacy::Determined);
}
(path.segments[0].identifier.name, path.span)
}
InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
};
self.resolve_macro_name(scope, name, true).or_else(|| {
let mut err =
self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
self.suggest_macro_name(&name.as_str(), &mut err);
err.emit();
None
let invocation = self.invocations[&scope];
if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() {
invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent));
}
self.resolve_macro_name(invocation.legacy_scope.get(), name, true).ok_or_else(|| {
if force {
let mut err =
self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
self.suggest_macro_name(&name.as_str(), &mut err);
err.emit();
Determinacy::Determined
} else {
Determinacy::Undetermined
}
})
}
@@ -162,36 +201,40 @@ fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModif
}
impl<'a> Resolver<'a> {
pub fn resolve_macro_name(&mut self, scope: Mark, name: ast::Name, record_used: bool)
pub fn resolve_macro_name(&mut self,
mut scope: LegacyScope<'a>,
name: ast::Name,
record_used: bool)
-> Option<Rc<SyntaxExtension>> {
let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope];
let mut relative_depth: u32 = 0;
loop {
if let Some(binding) = module.macros.borrow().get(&name) {
let mut backtrace = backtrace.data();
while binding.expansion != backtrace.outer_mark {
if backtrace.outer_mark != Mark::root() {
backtrace = backtrace.prev_ctxt.data();
continue
scope = match scope {
LegacyScope::Empty => break,
LegacyScope::Expansion(invocation) => {
if let LegacyScope::Empty = invocation.expansion.get() {
invocation.legacy_scope.get()
} else {
relative_depth += 1;
invocation.expansion.get()
}
if record_used && binding.shadowing &&
self.macro_shadowing_errors.insert(binding.span) {
let msg = format!("`{}` is already in scope", name);
self.session.struct_span_err(binding.span, &msg)
.note("macro-expanded `macro_rules!`s and `#[macro_use]`s \
may not shadow existing macros (see RFC 1560)")
.emit();
}
break
}
return Some(binding.ext.clone());
}
match module.parent {
Some(parent) => module = parent,
None => break,
}
LegacyScope::Invocation(invocation) => {
relative_depth = relative_depth.saturating_sub(1);
invocation.legacy_scope.get()
}
LegacyScope::Binding(binding) => {
if binding.name == name {
if record_used && relative_depth > 0 {
self.disallowed_shadowing.push((name, binding.span, binding.parent));
}
return Some(binding.ext.clone());
}
binding.parent
}
};
}
None
self.builtin_macros.get(&name).cloned()
}
fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
@@ -204,15 +247,19 @@ fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
}
}
fn collect_def_ids(&mut self, mark: Mark, expansion: &Expansion) {
let expansion_data = &mut self.expansion_data;
let ExpansionData { backtrace, def_index, const_integer, module } = expansion_data[&mark];
fn collect_def_ids(&mut self, invocation: &'a InvocationData<'a>, expansion: &Expansion) {
let Resolver { ref mut invocations, arenas, graph_root, .. } = *self;
let InvocationData { def_index, const_integer, .. } = *invocation;
let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| {
expansion_data.entry(invoc.mark).or_insert(ExpansionData {
backtrace: backtrace.apply_mark(invoc.mark),
def_index: invoc.def_index,
const_integer: invoc.const_integer,
module: module,
invocations.entry(invoc.mark).or_insert_with(|| {
arenas.alloc_invocation_data(InvocationData {
def_index: invoc.def_index,
const_integer: invoc.const_integer,
module: Cell::new(graph_root),
expansion: Cell::new(LegacyScope::Empty),
legacy_scope: Cell::new(LegacyScope::Empty),
})
});
};
+3 -8
View File
@@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use self::Determinacy::*;
use self::ImportDirectiveSubclass::*;
use Module;
@@ -26,6 +25,7 @@
use rustc::hir::def::*;
use syntax::ast::{NodeId, Name};
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::util::lev_distance::find_best_match_for_name;
use syntax_pos::Span;
@@ -37,12 +37,6 @@ pub fn resolve_imports(&mut self) {
}
}
#[derive(Copy, Clone, Debug)]
pub enum Determinacy {
Determined,
Undetermined,
}
/// Contains data for specific types of import directives.
#[derive(Clone, Debug)]
pub enum ImportDirectiveSubclass<'a> {
@@ -197,7 +191,8 @@ pub fn resolve_name_in_module(&mut self,
// If the resolution doesn't depend on glob definability, check privacy and return.
if let Some(result) = self.try_result(&resolution, ns) {
return result.and_then(|binding| {
if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) {
if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) ||
binding.is_extern_crate() { // c.f. issue #37020
Success(binding)
} else {
Failed(None)
+2 -1
View File
@@ -114,7 +114,8 @@ pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
if tys.len() != 2 {
return None;
}
Some([tys[0], tys[1]])
Some([ccx.tcx().normalize_associated_type(&tys[0]),
ccx.tcx().normalize_associated_type(&tys[1])])
}
_ => None
}
+1 -1
View File
@@ -36,7 +36,7 @@
#![feature(slice_patterns)]
#![feature(staged_api)]
#![feature(unicode)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
use rustc::dep_graph::WorkProduct;
+1 -1
View File
@@ -82,7 +82,7 @@
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
+55 -40
View File
@@ -11,64 +11,79 @@
use std::fs::File;
use std::io::prelude::*;
use std::io;
use std::path::{PathBuf, Path};
use std::path::Path;
use std::str;
#[derive(Clone)]
pub struct ExternalHtml{
/// Content that will be included inline in the <head> section of a
/// rendered Markdown file or generated documentation
pub in_header: String,
/// Content that will be included inline between <body> and the content of
/// a rendered Markdown file or generated documentation
pub before_content: String,
/// Content that will be included inline between the content and </body> of
/// a rendered Markdown file or generated documentation
pub after_content: String
}
impl ExternalHtml {
pub fn load(in_header: &[String], before_content: &[String], after_content: &[String])
-> Option<ExternalHtml> {
match (load_external_files(in_header),
load_external_files(before_content),
load_external_files(after_content)) {
(Some(ih), Some(bc), Some(ac)) => Some(ExternalHtml {
in_header: ih,
before_content: bc,
after_content: ac
}),
_ => None
load_external_files(in_header)
.and_then(|ih|
load_external_files(before_content)
.map(|bc| (ih, bc))
)
.and_then(|(ih, bc)|
load_external_files(after_content)
.map(|ac| (ih, bc, ac))
)
.map(|(ih, bc, ac)|
ExternalHtml {
in_header: ih,
before_content: bc,
after_content: ac,
}
)
}
}
pub enum LoadStringError {
ReadFail,
BadUtf8,
}
pub fn load_string<P: AsRef<Path>>(file_path: P) -> Result<String, LoadStringError> {
let file_path = file_path.as_ref();
let mut contents = vec![];
let result = File::open(file_path)
.and_then(|mut f| f.read_to_end(&mut contents));
if let Err(e) = result {
let _ = writeln!(&mut io::stderr(),
"error reading `{}`: {}",
file_path.display(), e);
return Err(LoadStringError::ReadFail);
}
match str::from_utf8(&contents) {
Ok(s) => Ok(s.to_string()),
Err(_) => {
let _ = writeln!(&mut io::stderr(),
"error reading `{}`: not UTF-8",
file_path.display());
Err(LoadStringError::BadUtf8)
}
}
}
pub fn load_string(input: &Path) -> io::Result<Option<String>> {
let mut f = File::open(input)?;
let mut d = Vec::new();
f.read_to_end(&mut d)?;
Ok(str::from_utf8(&d).map(|s| s.to_string()).ok())
}
macro_rules! load_or_return {
($input: expr, $cant_read: expr, $not_utf8: expr) => {
{
let input = PathBuf::from(&$input[..]);
match ::externalfiles::load_string(&input) {
Err(e) => {
let _ = writeln!(&mut io::stderr(),
"error reading `{}`: {}", input.display(), e);
return $cant_read;
}
Ok(None) => {
let _ = writeln!(&mut io::stderr(),
"error reading `{}`: not UTF-8", input.display());
return $not_utf8;
}
Ok(Some(s)) => s
}
}
}
}
pub fn load_external_files(names: &[String]) -> Option<String> {
fn load_external_files(names: &[String]) -> Option<String> {
let mut out = String::new();
for name in names {
out.push_str(&*load_or_return!(&name, None, None));
let s = match load_string(name) {
Ok(s) => s,
Err(_) => return None,
};
out.push_str(&s);
out.push('\n');
}
Some(out)
+1 -1
View File
@@ -28,7 +28,7 @@
#![feature(staged_api)]
#![feature(test)]
#![feature(unicode)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
extern crate arena;
extern crate getopts;
+11 -3
View File
@@ -19,7 +19,7 @@
use rustc::session::search_paths::SearchPaths;
use rustc::session::config::Externs;
use externalfiles::ExternalHtml;
use externalfiles::{ExternalHtml, LoadStringError, load_string};
use html::render::reset_ids;
use html::escape::Escape;
@@ -58,7 +58,11 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
css.push_str(&s)
}
let input_str = load_or_return!(input, 1, 2);
let input_str = match load_string(input) {
Ok(s) => s,
Err(LoadStringError::ReadFail) => return 1,
Err(LoadStringError::BadUtf8) => return 2,
};
let playground = matches.opt_str("markdown-playground-url");
if playground.is_some() {
markdown::PLAYGROUND_KRATE.with(|s| { *s.borrow_mut() = Some(None); });
@@ -144,7 +148,11 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
/// Run any tests/code examples in the markdown file `input`.
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
mut test_args: Vec<String>) -> isize {
let input_str = load_or_return!(input, 1, 2);
let input_str = match load_string(input) {
Ok(s) => s,
Err(LoadStringError::ReadFail) => return 1,
Err(LoadStringError::BadUtf8) => return 2,
};
let mut opts = TestOptions::default();
opts.no_crate_inject = true;
+3 -4
View File
@@ -199,6 +199,7 @@
use self::ParserState::*;
use self::InternalStackElement::*;
use std::borrow::Cow;
use std::collections::{HashMap, BTreeMap};
use std::io::prelude::*;
use std::io;
@@ -2081,9 +2082,7 @@ impl Decoder {
pub fn new(json: Json) -> Decoder {
Decoder { stack: vec![json] }
}
}
impl Decoder {
fn pop(&mut self) -> Json {
self.stack.pop().unwrap()
}
@@ -2182,8 +2181,8 @@ fn read_char(&mut self) -> DecodeResult<char> {
Err(ExpectedError("single character string".to_owned(), format!("{}", s)))
}
fn read_str(&mut self) -> DecodeResult<string::String> {
expect!(self.pop(), String)
fn read_str(&mut self) -> DecodeResult<Cow<str>> {
expect!(self.pop(), String).map(Cow::Owned)
}
fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T> where
+1 -1
View File
@@ -35,7 +35,7 @@
#![feature(specialization)]
#![feature(staged_api)]
#![feature(unicode)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#![cfg_attr(test, feature(test))]
// test harness access
+3 -2
View File
@@ -9,6 +9,7 @@
// except according to those terms.
use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128};
use std::borrow::Cow;
use std::io::{self, Write};
use serialize;
@@ -246,11 +247,11 @@ fn read_char(&mut self) -> Result<char, Self::Error> {
Ok(::std::char::from_u32(bits).unwrap())
}
fn read_str(&mut self) -> Result<String, Self::Error> {
fn read_str(&mut self) -> Result<Cow<str>, Self::Error> {
let len = self.read_usize()?;
let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap();
self.position += len;
Ok(s.to_string())
Ok(Cow::Borrowed(s))
}
fn error(&mut self, err: &str) -> Self::Error {
+3 -2
View File
@@ -14,6 +14,7 @@
Core encoding and decoding interfaces.
*/
use std::borrow::Cow;
use std::intrinsics;
use std::path;
use std::rc::Rc;
@@ -156,7 +157,7 @@ pub trait Decoder {
fn read_f64(&mut self) -> Result<f64, Self::Error>;
fn read_f32(&mut self) -> Result<f32, Self::Error>;
fn read_char(&mut self) -> Result<char, Self::Error>;
fn read_str(&mut self) -> Result<String, Self::Error>;
fn read_str(&mut self) -> Result<Cow<str>, Self::Error>;
// Compound types:
fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
@@ -401,7 +402,7 @@ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
impl Decodable for String {
fn decode<D: Decoder>(d: &mut D) -> Result<String, D::Error> {
d.read_str()
Ok(d.read_str()?.into_owned())
}
}
+1 -2
View File
@@ -55,7 +55,6 @@
use cell;
use char;
use fmt::{self, Debug, Display};
use marker::Reflect;
use mem::transmute;
use num;
use str;
@@ -63,7 +62,7 @@
/// Base functionality for all errors in Rust.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Error: Debug + Display + Reflect {
pub trait Error: Debug + Display {
/// A short description of the error.
///
/// The description should not contain newlines or sentence-ending
+1 -2
View File
@@ -12,7 +12,6 @@
use io::prelude::*;
use marker::Reflect;
use cmp;
use error;
use fmt;
@@ -578,7 +577,7 @@ fn from(iie: IntoInnerError<W>) -> Error { iie.1 }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Reflect + Send + fmt::Debug> error::Error for IntoInnerError<W> {
impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {
fn description(&self) -> &str {
error::Error::description(self.error())
}
+37 -32
View File
@@ -12,18 +12,15 @@
//!
//! The `std::io` module contains a number of common things you'll need
//! when doing input and output. The most core part of this module is
//! the [`Read`][read] and [`Write`][write] traits, which provide the
//! the [`Read`] and [`Write`] traits, which provide the
//! most general interface for reading and writing input and output.
//!
//! [read]: trait.Read.html
//! [write]: trait.Write.html
//!
//! # Read and Write
//!
//! Because they are traits, `Read` and `Write` are implemented by a number
//! Because they are traits, [`Read`] and [`Write`] are implemented by a number
//! of other types, and you can implement them for your types too. As such,
//! you'll see a few different types of I/O throughout the documentation in
//! this module: `File`s, `TcpStream`s, and sometimes even `Vec<T>`s. For
//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
//! example, `Read` adds a `read()` method, which we can use on `File`s:
//!
//! ```
@@ -43,15 +40,15 @@
//! # }
//! ```
//!
//! `Read` and `Write` are so important, implementors of the two traits have a
//! [`Read`] and [`Write`] are so important, implementors of the two traits have a
//! nickname: readers and writers. So you'll sometimes see 'a reader' instead
//! of 'a type that implements the `Read` trait'. Much easier!
//! of 'a type that implements the [`Read`] trait'. Much easier!
//!
//! ## Seek and BufRead
//!
//! Beyond that, there are two important traits that are provided: [`Seek`][seek]
//! and [`BufRead`][bufread]. Both of these build on top of a reader to control
//! how the reading happens. `Seek` lets you control where the next byte is
//! Beyond that, there are two important traits that are provided: [`Seek`]
//! and [`BufRead`]. Both of these build on top of a reader to control
//! how the reading happens. [`Seek`] lets you control where the next byte is
//! coming from:
//!
//! ```
@@ -75,21 +72,18 @@
//! # }
//! ```
//!
//! [seek]: trait.Seek.html
//! [bufread]: trait.BufRead.html
//!
//! `BufRead` uses an internal buffer to provide a number of other ways to read, but
//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but
//! to show it off, we'll need to talk about buffers in general. Keep reading!
//!
//! ## BufReader and BufWriter
//!
//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be
//! making near-constant calls to the operating system. To help with this,
//! `std::io` comes with two structs, `BufReader` and `BufWriter`, which wrap
//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap
//! readers and writers. The wrapper uses a buffer, reducing the number of
//! calls and providing nicer methods for accessing exactly what you want.
//!
//! For example, `BufReader` works with the `BufRead` trait to add extra
//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra
//! methods to any reader:
//!
//! ```
@@ -111,8 +105,8 @@
//! # }
//! ```
//!
//! `BufWriter` doesn't add any new ways of writing; it just buffers every call
//! to [`write()`][write()]:
//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
//! to [`write()`]:
//!
//! ```
//! use std::io;
@@ -134,8 +128,6 @@
//! # }
//! ```
//!
//! [write()]: trait.Write.html#tymethod.write
//!
//! ## Standard input and output
//!
//! A very common source of input is standard input:
@@ -165,13 +157,13 @@
//! # }
//! ```
//!
//! Of course, using `io::stdout()` directly is less common than something like
//! `println!`.
//! Of course, using [`io::stdout()`] directly is less common than something like
//! [`println!`].
//!
//! ## Iterator types
//!
//! A large number of the structures provided by `std::io` are for various
//! ways of iterating over I/O. For example, `Lines` is used to split over
//! ways of iterating over I/O. For example, [`Lines`] is used to split over
//! lines:
//!
//! ```
@@ -211,10 +203,10 @@
//!
//! ## io::Result
//!
//! Last, but certainly not least, is [`io::Result`][result]. This type is used
//! Last, but certainly not least, is [`io::Result`]. This type is used
//! as the return type of many `std::io` functions that can cause an error, and
//! can be returned from your own functions as well. Many of the examples in this
//! module use the [`try!`][try] macro:
//! module use the [`try!`] macro:
//!
//! ```
//! use std::io;
@@ -230,14 +222,11 @@
//! }
//! ```
//!
//! The return type of `read_input()`, `io::Result<()>`, is a very common type
//! for functions which don't have a 'real' return value, but do want to return
//! errors if they happen. In this case, the only purpose of this function is
//! The return type of `read_input()`, [`io::Result<()>`][`io::Result`], is a very
//! common type for functions which don't have a 'real' return value, but do want to
//! return errors if they happen. In this case, the only purpose of this function is
//! to read the line and print it, so we use `()`.
//!
//! [result]: type.Result.html
//! [try]: ../macro.try.html
//!
//! ## Platform-specific behavior
//!
//! Many I/O functions throughout the standard library are documented to indicate
@@ -246,6 +235,22 @@
//! any possibly unclear semantics. Note, however, that this is informative, not a binding
//! contract. The implementation of many of these functions are subject to change over
//! time and may call fewer or more syscalls/library functions.
//!
//! [`Read`]: trait.Read.html
//! [`Write`]: trait.Write.html
//! [`Seek`]: trait.Seek.html
//! [`BufRead`]: trait.BufRead.html
//! [`File`]: ../fs/struct.File.html
//! [`TcpStream`]: ../net/struct.TcpStream.html
//! [`Vec<T>`]: ../vec/struct.Vec.html
//! [`BufReader`]: struct.BufReader.html
//! [`BufWriter`]: struct.BufWriter.html
//! [`write()`]: trait.Write.html#tymethod.write
//! [`io::stdout()`]: fn.stdout.html
//! [`println!`]: ../macro.println.html
//! [`Lines`]: struct.Lines.html
//! [`io::Result`]: type.Result.html
//! [`try!`]: ../macro.try.html
#![stable(feature = "rust1", since = "1.0.0")]
+1 -2
View File
@@ -255,10 +255,9 @@
#![feature(panic_unwind)]
#![feature(placement_in_syntax)]
#![feature(prelude_import)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#![feature(rand)]
#![feature(raw)]
#![feature(reflect_marker)]
#![feature(repr_simd)]
#![feature(rustc_attrs)]
#![feature(shared)]
+2 -3
View File
@@ -270,7 +270,6 @@
use fmt;
use mem;
use cell::UnsafeCell;
use marker::Reflect;
use time::{Duration, Instant};
#[unstable(feature = "mpsc_select", issue = "27800")]
@@ -1163,7 +1162,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Send + Reflect> error::Error for SendError<T> {
impl<T: Send> error::Error for SendError<T> {
fn description(&self) -> &str {
"sending on a closed channel"
}
@@ -1198,7 +1197,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Send + Reflect> error::Error for TrySendError<T> {
impl<T: Send> error::Error for TrySendError<T> {
fn description(&self) -> &str {
match *self {
+2 -3
View File
@@ -10,7 +10,6 @@
use error::{Error};
use fmt;
use marker::Reflect;
use sync::atomic::{AtomicBool, Ordering};
use thread;
@@ -117,7 +116,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Reflect> Error for PoisonError<T> {
impl<T> Error for PoisonError<T> {
fn description(&self) -> &str {
"poisoned lock: another task failed inside"
}
@@ -174,7 +173,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Reflect> Error for TryLockError<T> {
impl<T> Error for TryLockError<T> {
fn description(&self) -> &str {
match *self {
TryLockError::Poisoned(ref p) => p.description(),
+1 -1
View File
@@ -71,7 +71,7 @@ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
impl Decodable for Name {
fn decode<D: Decoder>(d: &mut D) -> Result<Name, D::Error> {
Ok(token::intern(&d.read_str()?[..]))
Ok(token::intern(&d.read_str()?))
}
}
+2 -3
View File
@@ -153,7 +153,7 @@ pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
}
// Visit attributes on expression and statements (but not attributes on items in blocks).
fn visit_stmt_or_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
// flag the offending attributes
for attr in attrs.iter() {
if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
@@ -227,7 +227,7 @@ pub fn configure_expr_kind(&mut self, expr_kind: ast::ExprKind) -> ast::ExprKind
}
pub fn configure_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
self.visit_stmt_or_expr_attrs(expr.attrs());
self.visit_expr_attrs(expr.attrs());
// If an expr is valid to cfg away it will have been removed by the
// outer stmt or expression folder before descending in here.
@@ -245,7 +245,6 @@ pub fn configure_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
}
pub fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option<ast::Stmt> {
self.visit_stmt_or_expr_attrs(stmt.attrs());
self.configure(stmt)
}
}
+11 -26
View File
@@ -22,7 +22,6 @@
use parse::token;
use parse::token::{InternedString, str_to_ident};
use ptr::P;
use std_inject;
use util::small_vector::SmallVector;
use std::path::PathBuf;
@@ -523,10 +522,17 @@ pub trait Resolver {
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>>;
fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy>;
fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>>;
}
#[derive(Copy, Clone, Debug)]
pub enum Determinacy {
Determined,
Undetermined,
}
pub struct DummyResolver;
impl Resolver for DummyResolver {
@@ -540,8 +546,9 @@ fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {}
fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
fn resolve_derive_mode(&mut self, _ident: ast::Ident) -> Option<Rc<MultiItemModifier>> { None }
fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
None
fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation, _force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy> {
Err(Determinacy::Determined)
}
}
@@ -737,28 +744,6 @@ pub fn std_path(&self, components: &[&str]) -> Vec<ast::Ident> {
pub fn name_of(&self, st: &str) -> ast::Name {
token::intern(st)
}
pub fn initialize(&mut self, user_exts: Vec<NamedSyntaxExtension>, krate: &ast::Crate) {
if std_inject::no_core(&krate) {
self.crate_root = None;
} else if std_inject::no_std(&krate) {
self.crate_root = Some("core");
} else {
self.crate_root = Some("std");
}
for (name, extension) in user_exts {
let ident = ast::Ident::with_empty_ctxt(name);
self.resolver.add_ext(ident, Rc::new(extension));
}
let mut module = ModuleData {
mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)],
directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)),
};
module.directory.pop();
self.current_expansion.module = Rc::new(module);
}
}
/// Extract a string literal from the macro expanded version of `expr`,
+45 -33
View File
@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ast::{Block, Crate, Ident, Mac_, PatKind};
use ast::{Block, Ident, Mac_, PatKind};
use ast::{Name, MacStmtStyle, StmtKind, ItemKind};
use ast;
use ext::hygiene::Mark;
@@ -26,6 +26,7 @@
use parse::token::{self, intern, keywords};
use print::pprust;
use ptr::P;
use std_inject;
use tokenstream::{TokenTree, TokenStream};
use util::small_vector::SmallVector;
use visit::Visitor;
@@ -186,8 +187,14 @@ pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
MacroExpander { cx: cx, monotonic: monotonic }
}
fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
let err_count = self.cx.parse_sess.span_diagnostic.err_count();
pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
self.cx.crate_root = std_inject::injected_crate_name(&krate);
let mut module = ModuleData {
mod_path: vec![token::str_to_ident(&self.cx.ecfg.crate_name)],
directory: PathBuf::from(self.cx.codemap().span_to_filename(krate.span)),
};
module.directory.pop();
self.cx.current_expansion.module = Rc::new(module);
let krate_item = Expansion::Items(SmallVector::one(P(ast::Item {
attrs: krate.attrs,
@@ -206,10 +213,6 @@ fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
_ => unreachable!(),
};
if self.cx.parse_sess.span_diagnostic.err_count() - self.cx.resolve_err_count > err_count {
self.cx.parse_sess.span_diagnostic.abort_if_errors();
}
krate
}
@@ -221,25 +224,47 @@ fn expand(&mut self, expansion: Expansion) -> Expansion {
let (expansion, mut invocations) = self.collect_invocations(expansion);
invocations.reverse();
let mut expansions = vec![vec![(0, expansion)]];
while let Some(invoc) = invocations.pop() {
let mut expansions = Vec::new();
let mut undetermined_invocations = Vec::new();
let (mut progress, mut force) = (false, !self.monotonic);
loop {
let invoc = if let Some(invoc) = invocations.pop() {
invoc
} else if undetermined_invocations.is_empty() {
break
} else {
invocations = mem::replace(&mut undetermined_invocations, Vec::new());
force = !mem::replace(&mut progress, false);
continue
};
let scope =
if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
let ext = match self.cx.resolver.resolve_invoc(scope, &invoc, force) {
Ok(ext) => Some(ext),
Err(Determinacy::Determined) => None,
Err(Determinacy::Undetermined) => {
undetermined_invocations.push(invoc);
continue
}
};
progress = true;
let ExpansionData { depth, mark, .. } = invoc.expansion_data;
self.cx.current_expansion = invoc.expansion_data.clone();
let scope = if self.monotonic { mark } else { orig_expansion_data.mark };
self.cx.current_expansion.mark = scope;
let expansion = match self.cx.resolver.resolve_invoc(scope, &invoc) {
let expansion = match ext {
Some(ext) => self.expand_invoc(invoc, ext),
None => invoc.expansion_kind.dummy(invoc.span()),
};
self.cx.current_expansion.depth = depth + 1;
let (expansion, new_invocations) = self.collect_invocations(expansion);
if expansions.len() == depth {
if expansions.len() < depth {
expansions.push(Vec::new());
}
expansions[depth].push((mark.as_u32(), expansion));
expansions[depth - 1].push((mark.as_u32(), expansion));
if !self.cx.ecfg.single_step {
invocations.extend(new_invocations.into_iter().rev());
}
@@ -250,12 +275,11 @@ fn expand(&mut self, expansion: Expansion) -> Expansion {
let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
while let Some(expansions) = expansions.pop() {
for (mark, expansion) in expansions.into_iter().rev() {
let expansion = expansion.fold_with(&mut placeholder_expander);
placeholder_expander.add(ast::NodeId::from_u32(mark), expansion);
}
}
placeholder_expander.remove(ast::NodeId::from_u32(0))
expansion.fold_with(&mut placeholder_expander)
}
fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec<Invocation>) {
@@ -538,7 +562,11 @@ fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Ex
self.invocations.push(Invocation {
kind: kind,
expansion_kind: expansion_kind,
expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() },
expansion_data: ExpansionData {
mark: mark,
depth: self.cx.current_expansion.depth + 1,
..self.cx.current_expansion.clone()
},
});
placeholder(expansion_kind, ast::NodeId::from_u32(mark.as_u32()))
}
@@ -866,22 +894,6 @@ fn enable_proc_macro = proc_macro,
}
}
pub fn expand_crate(cx: &mut ExtCtxt,
user_exts: Vec<NamedSyntaxExtension>,
c: Crate) -> Crate {
cx.initialize(user_exts, &c);
cx.monotonic_expander().expand_crate(c)
}
// Expands crate using supplied MacroExpander - allows for
// non-standard expansion behaviour (e.g. step-wise).
pub fn expand_crate_with_expander(expander: &mut MacroExpander,
user_exts: Vec<NamedSyntaxExtension>,
c: Crate) -> Crate {
expander.cx.initialize(user_exts, &c);
expander.expand_crate(c)
}
// A Marker adds the given mark to the syntax context and
// sets spans' `expn_id` to the given expn_id (unless it is `None`).
struct Marker { mark: Mark, expn_id: Option<ExpnId> }
+2 -1
View File
@@ -88,10 +88,11 @@ pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
}
pub fn add(&mut self, id: ast::NodeId, expansion: Expansion) {
let expansion = expansion.fold_with(self);
self.expansions.insert(id, expansion);
}
pub fn remove(&mut self, id: ast::NodeId) -> Expansion {
fn remove(&mut self, id: ast::NodeId) -> Expansion {
self.expansions.remove(&id).unwrap()
}
}
+2 -6
View File
@@ -253,9 +253,6 @@ pub fn new() -> Features {
// a...b and ...b
(active, inclusive_range_syntax, "1.7.0", Some(28237)),
// `expr?`
(active, question_mark, "1.9.0", Some(31436)),
// impl specialization (RFC 1210)
(active, specialization, "1.7.0", Some(31844)),
@@ -348,6 +345,8 @@ pub fn new() -> Features {
(accepted, while_let, "1.0.0", None),
// Allows `#[deprecated]` attribute
(accepted, deprecated, "1.9.0", Some(29935)),
// `expr?`
(accepted, question_mark, "1.14.0", Some(31436)),
);
// (changing above list without updating src/doc/reference.md makes @cmr sad)
@@ -1072,9 +1071,6 @@ fn visit_expr(&mut self, e: &ast::Expr) {
e.span,
"inclusive range syntax is experimental");
}
ast::ExprKind::Try(..) => {
gate_feature_post!(&self, question_mark, e.span, "the `?` operator is not stable");
}
ast::ExprKind::InPlace(..) => {
gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
}
+1 -1
View File
@@ -31,7 +31,7 @@
#![feature(staged_api)]
#![feature(str_escape)]
#![feature(unicode)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#![feature(rustc_diagnostic_macros)]
#![feature(specialization)]
+1 -1
View File
@@ -566,7 +566,7 @@ fn ne(&self, other: &InternedString) -> bool {
impl Decodable for InternedString {
fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
Ok(intern(d.read_str()?.as_ref()).as_str())
Ok(intern(&d.read_str()?).as_str())
}
}
+1 -1
View File
@@ -112,7 +112,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
out,
ann,
is_expanded);
if is_expanded && !std_inject::no_std(krate) {
if is_expanded && !std_inject::injected_crate_name(krate).is_none() {
// We need to print `#![no_std]` (and its feature gate) so that
// compiling pretty-printed source won't inject libstd again.
// However we don't want these attributes in the AST because
+12 -10
View File
@@ -34,23 +34,25 @@ fn ignored_span(sess: &ParseSess, sp: Span) -> Span {
return sp;
}
pub fn no_core(krate: &ast::Crate) -> bool {
attr::contains_name(&krate.attrs, "no_core")
}
pub fn no_std(krate: &ast::Crate) -> bool {
attr::contains_name(&krate.attrs, "no_std") || no_core(krate)
pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> {
if attr::contains_name(&krate.attrs, "no_core") {
None
} else if attr::contains_name(&krate.attrs, "no_std") {
Some("core")
} else {
Some("std")
}
}
pub fn maybe_inject_crates_ref(sess: &ParseSess,
mut krate: ast::Crate,
alt_std_name: Option<String>)
-> ast::Crate {
if no_core(&krate) {
return krate;
}
let name = match injected_crate_name(&krate) {
Some(name) => name,
None => return krate,
};
let name = if no_std(&krate) { "core" } else { "std" };
let crate_name = token::intern(&alt_std_name.unwrap_or(name.to_string()));
krate.module.items.insert(0, P(ast::Item {
+30 -5
View File
@@ -11,6 +11,7 @@
//! The compiler code necessary to implement the `#[derive]` extensions.
use syntax::ast::{self, MetaItem};
use syntax::attr::HasAttrs;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
@@ -104,13 +105,37 @@ pub fn expand_derive(cx: &mut ExtCtxt,
}
};
if mitem.value_str().is_some() {
cx.span_err(mitem.span, "unexpected value in `derive`");
let mut derive_attrs = Vec::new();
item = item.map_attrs(|attrs| {
let partition = attrs.into_iter().partition(|attr| &attr.name() == "derive");
derive_attrs = partition.0;
partition.1
});
// Expand `#[derive]`s after other attribute macro invocations.
if cx.resolver.find_attr_invoc(&mut item.attrs.clone()).is_some() {
return vec![Annotatable::Item(item.map_attrs(|mut attrs| {
attrs.push(cx.attribute(span, P(mitem.clone())));
attrs.extend(derive_attrs);
attrs
}))];
}
let mut traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
if traits.is_empty() {
cx.span_warn(mitem.span, "empty trait list in `derive`");
let get_traits = |mitem: &MetaItem, cx: &ExtCtxt| {
if mitem.value_str().is_some() {
cx.span_err(mitem.span, "unexpected value in `derive`");
}
let traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
if traits.is_empty() {
cx.span_warn(mitem.span, "empty trait list in `derive`");
}
traits
};
let mut traits = get_traits(mitem, cx);
for derive_attr in derive_attrs {
traits.extend(get_traits(&derive_attr.node.value, cx));
}
// First, weed out malformed #[derive]
+14 -7
View File
@@ -50,20 +50,23 @@
use std::rc::Rc;
use syntax::ast;
use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier};
use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier, NamedSyntaxExtension};
use syntax::ext::tt::macro_rules::MacroRulesExpander;
use syntax::parse::token::intern;
pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) {
pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
user_exts: Vec<NamedSyntaxExtension>,
enable_quotes: bool) {
let mut register = |name, ext| {
resolver.add_ext(ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext));
resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
};
register("macro_rules", IdentTT(Box::new(MacroRulesExpander), None, false));
register(intern("macro_rules"), IdentTT(Box::new(MacroRulesExpander), None, false));
macro_rules! register {
($( $name:ident: $f:expr, )*) => { $(
register(stringify!($name), NormalTT(Box::new($f as MacroExpanderFn), None, false));
register(intern(stringify!($name)),
NormalTT(Box::new($f as MacroExpanderFn), None, false));
)* }
}
@@ -108,7 +111,11 @@ macro_rules! register {
}
// format_args uses `unstable` things internally.
register("format_args", NormalTT(Box::new(format::expand_format_args), None, true));
register(intern("format_args"), NormalTT(Box::new(format::expand_format_args), None, true));
register("derive", MultiModifier(Box::new(deriving::expand_derive)));
register(intern("derive"), MultiModifier(Box::new(deriving::expand_derive)));
for (name, ext) in user_exts {
register(name, ext);
}
}
+1 -1
View File
@@ -27,7 +27,7 @@
#![allow(unused_attributes)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#![feature(specialization)]
use std::cell::{Cell, RefCell};
+1 -1
View File
@@ -59,7 +59,7 @@
#![cfg_attr(windows, feature(libc))]
// Handle rustfmt skips
#![feature(custom_attribute)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#![allow(unused_attributes)]
use std::io::prelude::*;
+1 -1
View File
@@ -38,7 +38,7 @@
#![feature(rustc_private)]
#![feature(set_stdio)]
#![feature(staged_api)]
#![feature(question_mark)]
#![cfg_attr(stage0, feature(question_mark))]
#![feature(panic_unwind)]
extern crate getopts;
+1 -3
View File
@@ -8,12 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(question_mark)]
// Make sure that the span of try shorthand does not include the trailing
// semicolon;
fn a() -> Result<i32, ()> {
Err(5)?; //~ ERROR 16:5: 16:12
Err(5)?; //~ ERROR 14:5: 14:12
Ok(1)
}
-3
View File
@@ -8,9 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(reflect_marker)]
use std::marker::Reflect;
use std::any::Any;
struct Foo;
+6 -9
View File
@@ -12,31 +12,28 @@
macro_rules! foo { () => {} }
macro_rules! macro_one { () => {} }
#[macro_use(macro_two)] extern crate two_macros;
macro_rules! m1 { () => {
macro_rules! foo { () => {} } //~ ERROR `foo` is already in scope
//~^ NOTE macro-expanded `macro_rules!`s and `#[macro_use]`s may not shadow existing macros
//~^ NOTE macro-expanded `macro_rules!`s may not shadow existing macros
#[macro_use] //~ ERROR `macro_one` is already in scope
//~^ NOTE macro-expanded `macro_rules!`s and `#[macro_use]`s may not shadow existing macros
extern crate two_macros;
#[macro_use] //~ ERROR `macro_two` is already in scope
//~^ NOTE macro-expanded `#[macro_use]`s may not shadow existing macros
extern crate two_macros as __;
}}
m1!(); //~ NOTE in this expansion
//~| NOTE in this expansion
//~| NOTE in this expansion
//~| NOTE in this expansion
fn f() { macro_one!(); }
foo!();
macro_rules! m2 { () => {
macro_rules! foo { () => {} }
#[macro_use] extern crate two_macros as __;
fn g() { macro_one!(); }
foo!();
}}
m2!();
//^ Since `foo` and `macro_one` are not used outside this expansion, they are not shadowing errors.
//^ Since `foo` is not used outside this expansion, it is not a shadowing error.
fn main() {}
+3 -3
View File
@@ -19,10 +19,10 @@ fn f() {
#[macro_use(macro_one)] // Check that this macro is usable in the above function
extern crate two_macros;
fn g() {
macro_two!();
}
macro_rules! m { () => {
fn g() {
macro_two!();
}
#[macro_use(macro_two)] // Check that this macro is usable in the above function
extern crate two_macros as _two_macros;
} }
@@ -11,7 +11,6 @@
// General test of maybe_uninits state computed by MIR dataflow.
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
use std::intrinsics::rustc_peek;
use std::mem::{drop, replace};
@@ -11,7 +11,6 @@
// General test of maybe_inits state computed by MIR dataflow.
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
use std::intrinsics::rustc_peek;
use std::mem::{drop, replace};
@@ -11,7 +11,6 @@
// General test of maybe_uninits state computed by MIR dataflow.
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
use std::intrinsics::rustc_peek;
use std::mem::{drop, replace};
@@ -11,7 +11,6 @@
// General test of maybe_uninits state computed by MIR dataflow.
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
use std::intrinsics::rustc_peek;
use std::mem::{drop, replace};
@@ -21,15 +21,15 @@ fn main() {
#[attr]
fn a() {}
#[attr] //~ ERROR 15701
#[attr]
{
}
#[attr] //~ ERROR 15701
#[attr]
5;
#[attr] //~ ERROR 15701
#[attr]
stmt_mac!();
}
@@ -43,7 +43,7 @@ fn c() {
#[cfg(not(unset))]
fn j() {
#[attr] //~ ERROR 15701
#[attr]
5;
}
@@ -55,7 +55,7 @@ fn d() {
#[cfg_attr(not(unset), cfg(not(unset)))]
fn i() {
#[attr] //~ ERROR 15701
#[attr]
8;
}
@@ -64,7 +64,7 @@ fn i() {
macro_rules! item_mac {
($e:ident) => {
fn $e() {
#[attr] //~ ERROR 15701
#[attr]
42;
#[cfg(unset)]
@@ -75,7 +75,7 @@ fn f() {
#[cfg(not(unset))]
fn k() {
#[attr] //~ ERROR 15701
#[attr]
5;
}
@@ -87,7 +87,7 @@ fn g() {
#[cfg_attr(not(unset), cfg(not(unset)))]
fn h() {
#[attr] //~ ERROR 15701
#[attr]
8;
}
@@ -236,3 +236,74 @@ struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64)
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail3")]
pub struct Visibility;
struct ReferencedType1;
struct ReferencedType2;
// Tuple Struct Change Field Type Indirectly -----------------------------------
mod tuple_struct_change_field_type_indirectly {
#[cfg(cfail1)]
use super::ReferencedType1 as FieldType;
#[cfg(not(cfail1))]
use super::ReferencedType2 as FieldType;
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
struct TupleStruct(FieldType);
}
// Record Struct Change Field Type Indirectly -----------------------------------
mod record_struct_change_field_type_indirectly {
#[cfg(cfail1)]
use super::ReferencedType1 as FieldType;
#[cfg(not(cfail1))]
use super::ReferencedType2 as FieldType;
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
struct RecordStruct {
_x: FieldType
}
}
trait ReferencedTrait1 {}
trait ReferencedTrait2 {}
// Change Trait Bound Indirectly -----------------------------------------------
mod change_trait_bound_indirectly {
#[cfg(cfail1)]
use super::ReferencedTrait1 as Trait;
#[cfg(not(cfail1))]
use super::ReferencedTrait2 as Trait;
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
struct Struct<T: Trait>(T);
}
// Change Trait Bound Indirectly In Where Clause -------------------------------
mod change_trait_bound_indirectly_in_where_clause {
#[cfg(cfail1)]
use super::ReferencedTrait1 as Trait;
#[cfg(not(cfail1))]
use super::ReferencedTrait2 as Trait;
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
struct Struct<T>(T) where T : Trait;
}
+1 -1
View File
@@ -17,8 +17,8 @@
#[macro_use] #[no_link]
extern crate macro_crate_test;
#[into_multi_foo]
#[derive(PartialEq, Clone, Debug)]
#[into_multi_foo]
fn foo() -> AnotherFakeTypeThatHadBetterGoAway {}
// Check that the `#[into_multi_foo]`-generated `foo2` is configured away
@@ -21,6 +21,6 @@
#[proc_macro_derive(AToB)]
pub fn derive(input: TokenStream) -> TokenStream {
let input = input.to_string();
assert_eq!(input, "struct A;\n");
assert_eq!(input, "#[derive(Copy, Clone)]\nstruct A;\n");
"struct B;".parse().unwrap()
}
@@ -18,6 +18,7 @@
#[macro_use]
extern crate derive_ctod;
#[derive(Copy, Clone)]
#[derive(AToB)]
struct A;
+4
View File
@@ -17,4 +17,8 @@
fn main() {
let _ = ((-1 as i8) << 8 - 1) as f32;
let _ = 0u8 as char;
let _ = true > false;
let _ = true >= false;
let _ = true < false;
let _ = true >= false;
}
-2
View File
@@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(stmt_expr_attributes)]
#[deny(const_err)]
fn main() {
@@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(stmt_expr_attributes)]
use std::mem::size_of;
enum Ei8 {
-1
View File
@@ -14,7 +14,6 @@
#![allow(unused_must_use)]
#![allow(unused_features)]
#![feature(box_syntax)]
#![feature(question_mark)]
use std::fmt::{self, Write};
use std::usize;
+1 -1
View File
@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(conservative_impl_trait, question_mark)]
#![feature(conservative_impl_trait)]
struct State;
type Error = ();
-2
View File
@@ -10,8 +10,6 @@
// pretty-expanded FIXME #23616
#![feature(question_mark)]
use std::fs::File;
use std::io::{self, BufReader, Read};
+1 -4
View File
@@ -8,17 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(reflect_marker)]
use std::any::TypeId;
use std::marker::Reflect;
use std::rc::Rc;
type Fp<T> = Rc<T>;
struct Engine;
trait Component: 'static + Reflect {}
trait Component: 'static {}
impl Component for Engine {}
trait Env {
-2
View File
@@ -10,8 +10,6 @@
// Regression test for #20797.
#![feature(question_mark)]
use std::default::Default;
use std::io;
use std::fs;
-2
View File
@@ -11,8 +11,6 @@
// Regression test for #21400 which itself was extracted from
// stackoverflow.com/questions/28031155/is-my-borrow-checker-drunk/28031580
#![feature(question_mark)]
fn main() {
let mut t = Test;
assert_eq!(t.method1("one"), Ok(1));
@@ -8,11 +8,18 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
macro_rules! id {
($e:expr) => { $e }
#![allow(private_in_public)]
mod foo {
pub mod bar {
extern crate core;
}
}
mod baz {
pub use foo::bar::core;
}
fn main() {
id!(x?); //~ error: the `?` operator is not stable (see issue #31436)
y?; //~ error: the `?` operator is not stable (see issue #31436)
baz::core::cell::Cell::new(0u32);
}
+25
View File
@@ -0,0 +1,25 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
trait ToRef<'a> {
type Ref: 'a;
}
impl<'a, U: 'a> ToRef<'a> for U {
type Ref = &'a U;
}
fn example<'a, T>(value: &'a T) -> (<T as ToRef<'a>>::Ref, u32) {
(value, 0)
}
fn main() {
example(&0);
}
+1 -1
View File
@@ -11,7 +11,7 @@
// ignore-emscripten no threads support
// ignore-pretty : (#23623) problems when ending with // comments
#![feature(rustc_attrs, stmt_expr_attributes, zero_one)]
#![feature(rustc_attrs, zero_one)]
use std::num::Zero;
use std::thread;
@@ -18,8 +18,6 @@
// This test verifies that the expansion is hygienic, i.e. it's not affected by other `val` and
// `err` bindings that may be in scope.
#![feature(question_mark)]
use std::num::ParseIntError;
fn main() {

Some files were not shown because too many files have changed in this diff Show More