mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
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:
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
@@ -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)]
|
||||
|
||||
|
||||
@@ -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.
|
||||
///
|
||||
|
||||
@@ -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 .. { }
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
|
||||
+1
-1
Submodule src/liblibc updated: 5a17b4a733...ebeab042e6
@@ -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##"
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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)),
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
|
||||
@@ -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`.
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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>,
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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");
|
||||
}
|
||||
_ => ()
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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),
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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)]
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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()?))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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> }
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = ();
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
// pretty-expanded FIXME #23616
|
||||
|
||||
#![feature(question_mark)]
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufReader, Read};
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
// Regression test for #20797.
|
||||
|
||||
#![feature(question_mark)]
|
||||
|
||||
use std::default::Default;
|
||||
use std::io;
|
||||
use std::fs;
|
||||
|
||||
@@ -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));
|
||||
|
||||
+11
-4
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user