Auto merge of #48615 - Manishearth:rollup, r=Manishearth

Rollup of 10 pull requests

- Successful merges: #48355, #48359, #48380, #48419, #48420, #48461, #48522, #48570, #48572, #48603
- Failed merges:
This commit is contained in:
bors 2018-02-28 23:10:14 +00:00
commit 0e3c9bba8e
41 changed files with 678 additions and 149 deletions

View File

@ -125,6 +125,16 @@ Print version info and exit.
\fB\-v\fR, \fB\-\-verbose\fR
Use verbose output.
.TP
\fB\-\-remap\-path\-prefix\fR \fIfrom\fR=\fIto\fR
Remap source path prefixes in all output, including compiler diagnostics, debug information,
macro expansions, etc. The \fIfrom\fR=\fIto\fR parameter is scanned from right to left, so \fIfrom\fR
may contain '=', but \fIto\fR may not.
This is useful for normalizing build products, for example by removing the current directory out of
pathnames emitted into the object files. The replacement is purely textual, with no consideration of
the current system's pathname syntax. For example \fI\-\-remap\-path\-prefix foo=bar\fR will
match \fBfoo/lib.rs\fR but not \fB./foo/lib.rs\fR.
.TP
\fB\-\-extern\fR \fINAME\fR=\fIPATH\fR
Specify where an external rust library is located. These should match
\fIextern\fR declarations in the crate's source code.

View File

@ -1,37 +0,0 @@
# `remap-path-prefix`
The tracking issue for this feature is: [#41555](https://github.com/rust-lang/rust/issues/41555)
------------------------
The `-Z remap-path-prefix-from`, `-Z remap-path-prefix-to` commandline option
pair allows to replace prefixes of any file paths the compiler emits in various
places. This is useful for bringing debuginfo paths into a well-known form and
for achieving reproducible builds independent of the directory the compiler was
executed in. All paths emitted by the compiler are affected, including those in
error messages.
In order to map all paths starting with `/home/foo/my-project/src` to
`/sources/my-project`, one would invoke the compiler as follows:
```text
rustc -Zremap-path-prefix-from="/home/foo/my-project/src" -Zremap-path-prefix-to="/sources/my-project"
```
Debuginfo for code from the file `/home/foo/my-project/src/foo/mod.rs`,
for example, would then point debuggers to `/sources/my-project/foo/mod.rs`
instead of the original file.
The options can be specified multiple times when multiple prefixes should be
mapped:
```text
rustc -Zremap-path-prefix-from="/home/foo/my-project/src" \
-Zremap-path-prefix-to="/sources/my-project" \
-Zremap-path-prefix-from="/home/foo/my-project/build-dir" \
-Zremap-path-prefix-to="/stable-build-dir"
```
When the options are given multiple times, the nth `-from` will be matched up
with the nth `-to` and they can appear anywhere on the commandline. Mappings
specified later on the line will take precedence over earlier ones.

View File

@ -1062,8 +1062,8 @@ pub trait Iterator {
/// assert_eq!(merged, "alphabetagamma");
/// ```
///
/// You can also rewrite this in terms of [`flat_map()`] which is preferable
/// in this case since that conveys intent clearer:
/// You can also rewrite this in terms of [`flat_map()`], which is preferable
/// in this case since it conveys intent more clearly:
///
/// ```
/// let words = ["alpha", "beta", "gamma"];

View File

@ -64,7 +64,8 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32))
#[allow(improper_ctypes)]
extern {
#[lang = "panic_fmt"]
#[unwind]
#[cfg_attr(stage0, unwind)]
#[cfg_attr(not(stage0), unwind(allowed))]
fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !;
}
let (file, line, col) = *file_line_col;

View File

@ -286,7 +286,8 @@ unsafe fn find_eh_action(context: *mut uw::_Unwind_Context)
// See docs in the `unwind` module.
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
#[lang = "eh_unwind_resume"]
#[unwind]
#[cfg_attr(stage0, unwind)]
#[cfg_attr(not(stage0), unwind(allowed))]
unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! {
uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception);
}

View File

@ -112,7 +112,8 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8),
// Entry point for raising an exception, just delegates to the platform-specific
// implementation.
#[no_mangle]
#[unwind]
#[cfg_attr(stage0, unwind)]
#[cfg_attr(not(stage0), unwind(allowed))]
pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 {
imp::panic(mem::transmute(raw::TraitObject {
data: data as *mut (),

View File

@ -108,7 +108,8 @@ unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut c::EXCEPTION_RECO
}
#[lang = "eh_unwind_resume"]
#[unwind]
#[cfg_attr(stage0, unwind)]
#[cfg_attr(not(stage0), unwind(allowed))]
unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
let params = [panic_ctx as c::ULONG_PTR];
c::RaiseException(RUST_PANIC,

View File

@ -79,18 +79,21 @@ pub enum EXCEPTION_DISPOSITION {
pub use self::EXCEPTION_DISPOSITION::*;
extern "system" {
#[unwind]
#[cfg_attr(stage0, unwind)]
#[cfg_attr(not(stage0), unwind(allowed))]
pub fn RaiseException(dwExceptionCode: DWORD,
dwExceptionFlags: DWORD,
nNumberOfArguments: DWORD,
lpArguments: *const ULONG_PTR);
#[unwind]
#[cfg_attr(stage0, unwind)]
#[cfg_attr(not(stage0), unwind(allowed))]
pub fn RtlUnwindEx(TargetFrame: LPVOID,
TargetIp: LPVOID,
ExceptionRecord: *const EXCEPTION_RECORD,
ReturnValue: LPVOID,
OriginalContext: *const CONTEXT,
HistoryTable: *const UNWIND_HISTORY_TABLE);
#[unwind]
#[cfg_attr(stage0, unwind)]
#[cfg_attr(not(stage0), unwind(allowed))]
pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8);
}

View File

@ -316,7 +316,7 @@ impl SourceFile {
/// If the code span associated with this `SourceFile` was generated by an external macro, this
/// may not be an actual path on the filesystem. Use [`is_real`] to check.
///
/// Also note that even if `is_real` returns `true`, if `-Z remap-path-prefix-*` was passed on
/// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on
/// the command line, the path as given may not actually be valid.
///
/// [`is_real`]: #method.is_real

View File

@ -46,7 +46,7 @@ use hir::HirVec;
use hir::map::{Definitions, DefKey, DefPathData};
use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX, DefIndexAddressSpace};
use hir::def::{Def, PathResolution};
use lint::builtin::PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES;
use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES};
use middle::cstore::CrateStore;
use rustc_data_structures::indexed_vec::IndexVec;
use session::Session;
@ -912,7 +912,11 @@ impl<'a> LoweringContext<'a> {
TyKind::Path(ref qself, ref path) => {
let id = self.lower_node_id(t.id);
let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx);
return self.ty_path(id, t.span, qpath);
let ty = self.ty_path(id, t.span, qpath);
if let hir::TyTraitObject(..) = ty.node {
self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
}
return ty;
}
TyKind::ImplicitSelf => {
hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
@ -931,7 +935,7 @@ impl<'a> LoweringContext<'a> {
let expr = self.lower_body(None, |this| this.lower_expr(expr));
hir::TyTypeof(expr)
}
TyKind::TraitObject(ref bounds, ..) => {
TyKind::TraitObject(ref bounds, kind) => {
let mut lifetime_bound = None;
let bounds = bounds.iter().filter_map(|bound| {
match *bound {
@ -950,6 +954,9 @@ impl<'a> LoweringContext<'a> {
let lifetime_bound = lifetime_bound.unwrap_or_else(|| {
self.elided_lifetime(t.span)
});
if kind != TraitObjectSyntax::Dyn {
self.maybe_lint_bare_trait(t.span, t.id, false);
}
hir::TyTraitObject(bounds, lifetime_bound)
}
TyKind::ImplTrait(ref bounds) => {
@ -3685,7 +3692,6 @@ impl<'a> LoweringContext<'a> {
// The original ID is taken by the `PolyTraitRef`,
// so the `Ty` itself needs a different one.
id = self.next_id();
hir::TyTraitObject(hir_vec![principal], self.elided_lifetime(span))
} else {
hir::TyPath(hir::QPath::Resolved(None, path))
@ -3703,6 +3709,16 @@ impl<'a> LoweringContext<'a> {
name: hir::LifetimeName::Implicit,
}
}
fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) {
if self.sess.features.borrow().dyn_trait {
self.sess.buffer_lint_with_diagnostic(
builtin::BARE_TRAIT_OBJECT, id, span,
"trait objects without an explicit `dyn` are deprecated",
builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global)
)
}
}
}
fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {

View File

@ -41,6 +41,8 @@
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]
#![cfg_attr(not(stage0), allow(bare_trait_object))]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(conservative_impl_trait)]

View File

@ -14,7 +14,11 @@
//! compiler code, rather than using their own custom pass. Those
//! lints are all available in `rustc_lint::builtin`.
use errors::DiagnosticBuilder;
use lint::{LintPass, LateLintPass, LintArray};
use session::Session;
use session::config::Epoch;
use syntax::codemap::Span;
declare_lint! {
pub CONST_ERR,
@ -252,6 +256,13 @@ declare_lint! {
"hidden lifetime parameters are deprecated, try `Foo<'_>`"
}
declare_lint! {
pub BARE_TRAIT_OBJECT,
Warn,
"suggest using `dyn Trait` for trait objects",
Epoch::Epoch2018
}
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
@ -298,10 +309,34 @@ impl LintPass for HardwiredLints {
COERCE_NEVER,
SINGLE_USE_LIFETIME,
TYVAR_BEHIND_RAW_POINTER,
ELIDED_LIFETIME_IN_PATH
ELIDED_LIFETIME_IN_PATH,
BARE_TRAIT_OBJECT
)
}
}
// this could be a closure, but then implementing derive traits
// becomes hacky (and it gets allocated)
#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
pub enum BuiltinLintDiagnostics {
Normal,
BareTraitObject(Span, /* is_global */ bool)
}
impl BuiltinLintDiagnostics {
pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder) {
match self {
BuiltinLintDiagnostics::Normal => (),
BuiltinLintDiagnostics::BareTraitObject(span, is_global) => {
let sugg = match sess.codemap().span_to_snippet(span) {
Ok(ref s) if is_global => format!("dyn ({})", s),
Ok(s) => format!("dyn {}", s),
Err(_) => format!("dyn <type>")
};
db.span_suggestion(span, "use `dyn`", sugg);
}
}
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HardwiredLints {}

View File

@ -29,6 +29,7 @@ use self::TargetLint::*;
use std::slice;
use lint::{EarlyLintPassObject, LateLintPassObject};
use lint::{Level, Lint, LintId, LintPass, LintBuffer};
use lint::builtin::BuiltinLintDiagnostics;
use lint::levels::{LintLevelSets, LintLevelsBuilder};
use middle::privacy::AccessLevels;
use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
@ -92,6 +93,7 @@ pub struct BufferedEarlyLint {
pub ast_id: ast::NodeId,
pub span: MultiSpan,
pub msg: String,
pub diagnostic: BuiltinLintDiagnostics,
}
/// Extra information for a future incompatibility lint. See the call
@ -99,7 +101,11 @@ pub struct BufferedEarlyLint {
/// guidelines.
pub struct FutureIncompatibleInfo {
pub id: LintId,
pub reference: &'static str // e.g., a URL for an issue/PR/RFC or error code
/// e.g., a URL for an issue/PR/RFC or error code
pub reference: &'static str,
/// If this is an epoch fixing lint, the epoch in which
/// this lint becomes obsolete
pub epoch: Option<config::Epoch>,
}
/// The target of the `by_name` map, which accounts for renaming/deprecation.
@ -194,11 +200,24 @@ impl LintStore {
pub fn register_future_incompatible(&mut self,
sess: Option<&Session>,
lints: Vec<FutureIncompatibleInfo>) {
let ids = lints.iter().map(|f| f.id).collect();
self.register_group(sess, false, "future_incompatible", ids);
for info in lints {
self.future_incompatible.insert(info.id, info);
for epoch in config::ALL_EPOCHS {
let lints = lints.iter().filter(|f| f.epoch == Some(*epoch)).map(|f| f.id)
.collect::<Vec<_>>();
if !lints.is_empty() {
self.register_group(sess, false, epoch.lint_name(), lints)
}
}
let mut future_incompatible = vec![];
for lint in lints {
future_incompatible.push(lint.id);
self.future_incompatible.insert(lint.id, lint);
}
self.register_group(sess, false, "future_incompatible", future_incompatible);
}
pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> {
@ -429,6 +448,16 @@ pub trait LintContext<'tcx>: Sized {
self.lookup(lint, span, msg).emit();
}
fn lookup_and_emit_with_diagnostics<S: Into<MultiSpan>>(&self,
lint: &'static Lint,
span: Option<S>,
msg: &str,
diagnostic: BuiltinLintDiagnostics) {
let mut db = self.lookup(lint, span, msg);
diagnostic.run(self.sess(), &mut db);
db.emit();
}
fn lookup<S: Into<MultiSpan>>(&self,
lint: &'static Lint,
span: Option<S>,
@ -499,9 +528,10 @@ impl<'a> EarlyContext<'a> {
fn check_id(&mut self, id: ast::NodeId) {
for early_lint in self.buffered.take(id) {
self.lookup_and_emit(early_lint.lint_id.lint,
Some(early_lint.span.clone()),
&early_lint.msg);
self.lookup_and_emit_with_diagnostics(early_lint.lint_id.lint,
Some(early_lint.span.clone()),
&early_lint.msg,
early_lint.diagnostic);
}
}
}
@ -1054,7 +1084,7 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
if !sess.opts.actually_rustdoc {
for (_id, lints) in cx.buffered.map {
for early_lint in lints {
span_bug!(early_lint.span, "failed to process buffered lint here");
sess.delay_span_bug(early_lint.span, "failed to process buffered lint here");
}
}
}

View File

@ -89,14 +89,15 @@ impl LintLevelSets {
fn get_lint_level(&self,
lint: &'static Lint,
idx: u32,
aux: Option<&FxHashMap<LintId, (Level, LintSource)>>)
aux: Option<&FxHashMap<LintId, (Level, LintSource)>>,
sess: &Session)
-> (Level, LintSource)
{
let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
// If `level` is none then we actually assume the default level for this
// lint.
let mut level = level.unwrap_or(lint.default_level);
let mut level = level.unwrap_or(lint.default_level(sess));
// If we're about to issue a warning, check at the last minute for any
// directives against the warnings "lint". If, for example, there's an
@ -235,7 +236,8 @@ impl<'a> LintLevelsBuilder<'a> {
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
let (level, src) = self.sets.get_lint_level(lint,
self.cur,
Some(&specs));
Some(&specs),
&sess);
lint::struct_lint_level(self.sess,
lint,
level,
@ -248,7 +250,8 @@ impl<'a> LintLevelsBuilder<'a> {
let lint = builtin::UNKNOWN_LINTS;
let (level, src) = self.sets.get_lint_level(lint,
self.cur,
Some(&specs));
Some(&specs),
self.sess);
let msg = format!("unknown lint: `{}`", name);
let mut db = lint::struct_lint_level(self.sess,
lint,
@ -342,7 +345,7 @@ impl<'a> LintLevelsBuilder<'a> {
msg: &str)
-> DiagnosticBuilder<'a>
{
let (level, src) = self.sets.get_lint_level(lint, self.cur, None);
let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess);
lint::struct_lint_level(self.sess, lint, level, src, span, msg)
}
@ -377,11 +380,11 @@ impl LintLevelMap {
/// If the `id` was not previously registered, returns `None`. If `None` is
/// returned then the parent of `id` should be acquired and this function
/// should be called again.
pub fn level_and_source(&self, lint: &'static Lint, id: HirId)
pub fn level_and_source(&self, lint: &'static Lint, id: HirId, session: &Session)
-> Option<(Level, LintSource)>
{
self.id_to_set.get(&id).map(|idx| {
self.sets.get_lint_level(lint, *idx, None)
self.sets.get_lint_level(lint, *idx, None, session)
})
}

View File

@ -37,7 +37,8 @@ use errors::{DiagnosticBuilder, DiagnosticId};
use hir::def_id::{CrateNum, LOCAL_CRATE};
use hir::intravisit::{self, FnKind};
use hir;
use session::{Session, DiagnosticMessageId};
use lint::builtin::BuiltinLintDiagnostics;
use session::{config, Session, DiagnosticMessageId};
use std::hash;
use syntax::ast;
use syntax::codemap::MultiSpan;
@ -74,6 +75,9 @@ pub struct Lint {
///
/// e.g. "imports that are never used"
pub desc: &'static str,
/// Deny lint after this epoch
pub epoch_deny: Option<config::Epoch>,
}
impl Lint {
@ -81,18 +85,36 @@ impl Lint {
pub fn name_lower(&self) -> String {
self.name.to_ascii_lowercase()
}
pub fn default_level(&self, session: &Session) -> Level {
if let Some(epoch_deny) = self.epoch_deny {
if session.epoch() >= epoch_deny {
return Level::Deny
}
}
self.default_level
}
}
/// Declare a static item of type `&'static Lint`.
#[macro_export]
macro_rules! declare_lint {
($vis: vis $NAME: ident, $Level: ident, $desc: expr, $epoch: expr) => (
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
name: stringify!($NAME),
default_level: $crate::lint::$Level,
desc: $desc,
epoch_deny: Some($epoch)
};
);
($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
name: stringify!($NAME),
default_level: $crate::lint::$Level,
desc: $desc
desc: $desc,
epoch_deny: None,
};
)
);
}
/// Declare a static `LintArray` and return it as an expression.
@ -304,7 +326,7 @@ impl LintId {
/// Setting for how to handle a lint.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum Level {
Allow, Warn, Deny, Forbid
Allow, Warn, Deny, Forbid,
}
impl_stable_hash_for!(enum self::Level {
@ -378,12 +400,14 @@ impl LintBuffer {
lint: &'static Lint,
id: ast::NodeId,
sp: MultiSpan,
msg: &str) {
msg: &str,
diagnostic: BuiltinLintDiagnostics) {
let early_lint = BufferedEarlyLint {
lint_id: LintId::of(lint),
ast_id: id,
span: sp,
msg: msg.to_string(),
diagnostic
};
let arr = self.map.entry(id).or_insert(Vec::new());
if !arr.contains(&early_lint) {

View File

@ -41,7 +41,7 @@ use std::collections::btree_map::Iter as BTreeMapIter;
use std::collections::btree_map::Keys as BTreeMapKeysIter;
use std::collections::btree_map::Values as BTreeMapValuesIter;
use std::fmt;
use std::{fmt, str};
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
use std::collections::HashSet;
@ -113,7 +113,7 @@ pub enum OutputType {
}
/// The epoch of the compiler (RFC 2052)
#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq)]
#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq, Debug)]
#[non_exhaustive]
pub enum Epoch {
// epochs must be kept in order, newest to oldest
@ -137,6 +137,37 @@ pub enum Epoch {
// as well as changing the default Cargo template.
}
pub const ALL_EPOCHS: &[Epoch] = &[Epoch::Epoch2015, Epoch::Epoch2018];
impl ToString for Epoch {
fn to_string(&self) -> String {
match *self {
Epoch::Epoch2015 => "2015".into(),
Epoch::Epoch2018 => "2018".into(),
}
}
}
impl Epoch {
pub fn lint_name(&self) -> &'static str {
match *self {
Epoch::Epoch2015 => "epoch_2015",
Epoch::Epoch2018 => "epoch_2018",
}
}
}
impl str::FromStr for Epoch {
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
match s {
"2015" => Ok(Epoch::Epoch2015),
"2018" => Ok(Epoch::Epoch2018),
_ => Err(())
}
}
}
impl_stable_hash_for!(enum self::OutputType {
Bitcode,
Assembly,
@ -435,6 +466,9 @@ top_level_options!(
// if we otherwise use the defaults of rustc.
cli_forced_codegen_units: Option<usize> [UNTRACKED],
cli_forced_thinlto_off: bool [UNTRACKED],
// Remap source path prefixes in all output (messages, object files, debug, etc)
remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
}
);
@ -617,6 +651,7 @@ pub fn basic_options() -> Options {
actually_rustdoc: false,
cli_forced_codegen_units: None,
cli_forced_thinlto_off: false,
remap_path_prefix: Vec::new(),
}
}
@ -635,11 +670,7 @@ impl Options {
}
pub fn file_path_mapping(&self) -> FilePathMapping {
FilePathMapping::new(
self.debugging_opts.remap_path_prefix_from.iter().zip(
self.debugging_opts.remap_path_prefix_to.iter()
).map(|(src, dst)| (src.clone(), dst.clone())).collect()
)
FilePathMapping::new(self.remap_path_prefix.clone())
}
/// True if there will be an output file generated
@ -1021,11 +1052,17 @@ macro_rules! options {
fn parse_epoch(slot: &mut Epoch, v: Option<&str>) -> bool {
match v {
Some("2015") => *slot = Epoch::Epoch2015,
Some("2018") => *slot = Epoch::Epoch2018,
_ => return false,
Some(s) => {
let epoch = s.parse();
if let Ok(parsed) = epoch {
*slot = parsed;
true
} else {
false
}
}
_ => false,
}
true
}
}
) }
@ -1269,10 +1306,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"set the optimization fuel quota for a crate"),
print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
"make Rustc print the total optimization fuel used by a crate"),
remap_path_prefix_from: Vec<PathBuf> = (vec![], parse_pathbuf_push, [UNTRACKED],
"add a source pattern to the file path remapping config"),
remap_path_prefix_to: Vec<PathBuf> = (vec![], parse_pathbuf_push, [UNTRACKED],
"add a mapping target to the file path remapping config"),
force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
"force all crates to be `rustc_private` unstable"),
pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
@ -1597,6 +1630,7 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
`expanded` (crates expanded), or
`expanded,identified` (fully parenthesized, AST nodes with IDs).",
"TYPE"),
opt::multi_s("", "remap-path-prefix", "remap source names in output", "FROM=TO"),
]);
opts
}
@ -1720,23 +1754,6 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
output_types.insert(OutputType::Exe, None);
}
let remap_path_prefix_sources = debugging_opts.remap_path_prefix_from.len();
let remap_path_prefix_targets = debugging_opts.remap_path_prefix_to.len();
if remap_path_prefix_targets < remap_path_prefix_sources {
for source in &debugging_opts.remap_path_prefix_from[remap_path_prefix_targets..] {
early_error(error_format,
&format!("option `-Zremap-path-prefix-from='{}'` does not have \
a corresponding `-Zremap-path-prefix-to`", source.display()))
}
} else if remap_path_prefix_targets > remap_path_prefix_sources {
for target in &debugging_opts.remap_path_prefix_to[remap_path_prefix_sources..] {
early_error(error_format,
&format!("option `-Zremap-path-prefix-to='{}'` does not have \
a corresponding `-Zremap-path-prefix-from`", target.display()))
}
}
let mut cg = build_codegen_options(matches, error_format);
let mut codegen_units = cg.codegen_units;
let mut disable_thinlto = false;
@ -1970,6 +1987,20 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
let crate_name = matches.opt_str("crate-name");
let remap_path_prefix = matches.opt_strs("remap-path-prefix")
.into_iter()
.map(|remap| {
let mut parts = remap.rsplitn(2, '='); // reverse iterator
let to = parts.next();
let from = parts.next();
match (from, to) {
(Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
_ => early_error(error_format,
"--remap-path-prefix must contain '=' between FROM and TO"),
}
})
.collect();
(Options {
crate_types,
optimize: opt_level,
@ -1997,6 +2028,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
actually_rustdoc: false,
cli_forced_codegen_units: codegen_units,
cli_forced_thinlto_off: disable_thinlto,
remap_path_prefix,
},
cfg)
}

View File

@ -16,6 +16,7 @@ use ich::Fingerprint;
use ich;
use lint;
use lint::builtin::BuiltinLintDiagnostics;
use middle::allocator::AllocatorKind;
use middle::dependency_format;
use session::search_paths::PathKind;
@ -341,7 +342,18 @@ impl Session {
sp: S,
msg: &str) {
match *self.buffered_lints.borrow_mut() {
Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(), msg),
Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(),
msg, BuiltinLintDiagnostics::Normal),
None => bug!("can't buffer lints after HIR lowering"),
}
}
pub fn buffer_lint_with_diagnostic<S: Into<MultiSpan>>(&self,
lint: &'static lint::Lint, id: ast::NodeId, sp: S,
msg: &str, diagnostic: BuiltinLintDiagnostics) {
match *self.buffered_lints.borrow_mut() {
Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(),
msg, diagnostic),
None => bug!("can't buffer lints after HIR lowering"),
}
}
@ -869,6 +881,10 @@ impl Session {
pub fn rust_2018(&self) -> bool {
self.opts.debugging_opts.epoch >= Epoch::Epoch2018
}
pub fn epoch(&self) -> Epoch {
self.opts.debugging_opts.epoch
}
}
pub fn build_session(sopts: config::Options,

View File

@ -2234,7 +2234,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
let sets = self.lint_levels(LOCAL_CRATE);
loop {
let hir_id = self.hir.definitions().node_to_hir_id(id);
if let Some(pair) = sets.level_and_source(lint, hir_id) {
if let Some(pair) = sets.level_and_source(lint, hir_id, self.sess) {
return pair
}
let next = self.hir.get_parent_node(id);

View File

@ -737,7 +737,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session,
// Lint plugins are registered; now we can process command line flags.
if sess.opts.describe_lints {
super::describe_lints(&sess.lint_store.borrow(), true);
super::describe_lints(&sess, &sess.lint_store.borrow(), true);
return Err(CompileIncomplete::Stopped);
}

View File

@ -787,15 +787,15 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
-> Option<(Input, Option<PathBuf>)> {
match matches.free.len() {
0 => {
if sopts.describe_lints {
let mut ls = lint::LintStore::new();
rustc_lint::register_builtins(&mut ls, None);
describe_lints(&ls, false);
return None;
}
let mut sess = build_session(sopts.clone(),
None,
descriptions.clone());
if sopts.describe_lints {
let mut ls = lint::LintStore::new();
rustc_lint::register_builtins(&mut ls, Some(&sess));
describe_lints(&sess, &ls, false);
return None;
}
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let mut cfg = config::build_configuration(&sess, cfg.clone());
let trans = get_trans(&sess);
@ -1134,7 +1134,7 @@ fn usage(verbose: bool, include_unstable_options: bool) {
verbose_help);
}
fn describe_lints(lint_store: &lint::LintStore, loaded_plugins: bool) {
fn describe_lints(sess: &Session, lint_store: &lint::LintStore, loaded_plugins: bool) {
println!("
Available lint options:
-W <foo> Warn about <foo>
@ -1146,10 +1146,10 @@ Available lint options:
");
fn sort_lints(lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> {
fn sort_lints(sess: &Session, lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> {
let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect();
lints.sort_by(|x: &&Lint, y: &&Lint| {
match x.default_level.cmp(&y.default_level) {
match x.default_level(sess).cmp(&y.default_level(sess)) {
// The sort doesn't case-fold but it's doubtful we care.
Equal => x.name.cmp(y.name),
r => r,
@ -1172,8 +1172,8 @@ Available lint options:
.iter()
.cloned()
.partition(|&(_, p)| p);
let plugin = sort_lints(plugin);
let builtin = sort_lints(builtin);
let plugin = sort_lints(sess, plugin);
let builtin = sort_lints(sess, builtin);
let (plugin_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups()
.iter()

View File

@ -191,75 +191,98 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
FutureIncompatibleInfo {
id: LintId::of(PRIVATE_IN_PUBLIC),
reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(PUB_USE_OF_PRIVATE_EXTERN_CRATE),
reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(PATTERNS_IN_FNS_WITHOUT_BODY),
reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(SAFE_EXTERN_STATICS),
reference: "issue #36247 <https://github.com/rust-lang/rust/issues/36247>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(INVALID_TYPE_PARAM_DEFAULT),
reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(LEGACY_DIRECTORY_OWNERSHIP),
reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(LEGACY_IMPORTS),
reference: "issue #38260 <https://github.com/rust-lang/rust/issues/38260>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY),
reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(RESOLVE_TRAIT_ON_DEFAULTED_UNIT),
reference: "issue #39216 <https://github.com/rust-lang/rust/issues/39216>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(MISSING_FRAGMENT_SPECIFIER),
reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN),
reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(ANONYMOUS_PARAMETERS),
reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES),
reference: "issue #42238 <https://github.com/rust-lang/rust/issues/42238>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS),
reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(SAFE_PACKED_BORROWS),
reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(INCOHERENT_FUNDAMENTAL_IMPLS),
reference: "issue #46205 <https://github.com/rust-lang/rust/issues/46205>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(COERCE_NEVER),
reference: "issue #46325 <https://github.com/rust-lang/rust/issues/46325>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(TYVAR_BEHIND_RAW_POINTER),
reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>",
epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(lint::builtin::BARE_TRAIT_OBJECT),
reference: "issue #48457 <https://github.com/rust-lang/rust/issues/48457>",
epoch: Some(session::config::Epoch::Epoch2018),
}
]);
// Register renamed and removed lints

View File

@ -323,7 +323,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// paths because any relative paths are potentially relative to
// a wrong directory.
// However, if a path has been modified via
// `-Zremap-path-prefix` we assume the user has already set
// `--remap-path-prefix` we assume the user has already set
// things up the way they want and don't touch the path values
// anymore.
match filemap.name {

View File

@ -28,6 +28,7 @@ use std::mem;
use std::u32;
use syntax::abi::Abi;
use syntax::ast;
use syntax::attr::{self, UnwindAttr};
use syntax::symbol::keywords;
use syntax_pos::Span;
use transform::MirSource;
@ -355,10 +356,9 @@ macro_rules! unpack {
}
fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
fn_id: ast::NodeId,
fn_def_id: DefId,
abi: Abi)
-> bool {
// Not callable from C, so we can safely unwind through these
if abi == Abi::Rust || abi == Abi::RustCall { return false; }
@ -370,9 +370,17 @@ fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
// This is a special case: some functions have a C abi but are meant to
// unwind anyway. Don't stop them.
if tcx.has_attr(tcx.hir.local_def_id(fn_id), "unwind") { return false; }
let attrs = &tcx.get_attrs(fn_def_id);
match attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs) {
None => {
// FIXME(rust-lang/rust#48251) -- Had to disable
// abort-on-panic for backwards compatibility reasons.
false
}
return true;
Some(UnwindAttr::Allowed) => false,
Some(UnwindAttr::Aborts) => true,
}
}
///////////////////////////////////////////////////////////////////////////
@ -399,13 +407,14 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
safety,
return_ty);
let fn_def_id = tcx.hir.local_def_id(fn_id);
let call_site_scope = region::Scope::CallSite(body.value.hir_id.local_id);
let arg_scope = region::Scope::Arguments(body.value.hir_id.local_id);
let mut block = START_BLOCK;
let source_info = builder.source_info(span);
let call_site_s = (call_site_scope, source_info);
unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, block, |builder| {
if should_abort_on_panic(tcx, fn_id, abi) {
if should_abort_on_panic(tcx, fn_def_id, abi) {
builder.schedule_abort();
}

View File

@ -15,6 +15,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
*/
#![deny(warnings)]
#![cfg_attr(not(stage0), allow(bare_trait_object))]
#![feature(box_patterns)]
#![feature(box_syntax)]

View File

@ -257,6 +257,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
// Optimizations begin.
uniform_array_move_out::RestoreSubsliceArrayMoveOut,
inline::Inline,
// Lowering generator control-flow and variables

View File

@ -34,15 +34,15 @@
// and mir statement _11 = move _2[-1 of 1]; replaced by:
// _11 = move _2[2 of 3];
//
// FIXME: convert to Subslice back for performance reason
// FIXME: integrate this transformation to the mir build
use rustc::ty;
use rustc::ty::TyCtxt;
use rustc::mir::*;
use rustc::mir::visit::Visitor;
use rustc::mir::visit::{Visitor, PlaceContext};
use transform::{MirPass, MirSource};
use util::patch::MirPatch;
use rustc_data_structures::indexed_vec::{IndexVec};
pub struct UniformArrayMoveOut;
@ -67,12 +67,12 @@ struct UniformArrayMoveOutVisitor<'a, 'tcx: 'a> {
}
impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
fn visit_statement(&mut self,
block: BasicBlock,
statement: &Statement<'tcx>,
location: Location) {
if let StatementKind::Assign(ref dst_place,
Rvalue::Use(Operand::Move(ref src_place))) = statement.kind {
fn visit_assign(&mut self,
block: BasicBlock,
dst_place: &Place<'tcx>,
rvalue: &Rvalue<'tcx>,
location: Location) {
if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
if let Place::Projection(ref proj) = *src_place {
if let ProjectionElem::ConstantIndex{offset: _,
min_length: _,
@ -92,7 +92,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
}
}
}
return self.super_statement(block, statement, location);
self.super_assign(block, dst_place, rvalue, location)
}
}
@ -104,7 +104,7 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
item_ty: &'tcx ty::TyS<'tcx>,
size: u32) {
match proj.elem {
// uniform _10 = move _2[:-1];
// uniforms statements like_10 = move _2[:-1];
ProjectionElem::Subslice{from, to} => {
self.patch.make_nop(location);
let temps : Vec<_> = (from..(size-to)).map(|i| {
@ -133,7 +133,7 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
self.patch.add_statement(location, StatementKind::StorageDead(temp));
}
}
// _11 = move _2[-1 of 1];
// uniforms statements like _11 = move _2[-1 of 1];
ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
self.patch.make_nop(location);
self.patch.add_assign(location,
@ -151,3 +151,179 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> {
}
}
}
// Restore Subslice move out after analysis
// Example:
//
// next statements:
// StorageLive(_12);
// _12 = move _2[0 of 3];
// StorageLive(_13);
// _13 = move _2[1 of 3];
// _10 = [move _12, move _13]
// StorageDead(_12);
// StorageDead(_13);
//
// replaced by _10 = move _2[:-1];
pub struct RestoreSubsliceArrayMoveOut;
impl MirPass for RestoreSubsliceArrayMoveOut {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
_src: MirSource,
mir: &mut Mir<'tcx>) {
let mut patch = MirPatch::new(mir);
{
let mut visitor = RestoreDataCollector {
locals_use: IndexVec::from_elem(LocalUse::new(), &mir.local_decls),
candidates: vec![],
};
visitor.visit_mir(mir);
for candidate in &visitor.candidates {
let statement = &mir[candidate.block].statements[candidate.statement_index];
if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind {
if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
let items : Vec<_> = items.iter().map(|item| {
if let Operand::Move(Place::Local(local)) = item {
let local_use = &visitor.locals_use[*local];
let opt_index_and_place = Self::try_get_item_source(local_use, mir);
// each local should be used twice:
// in assign and in aggregate statments
if local_use.use_count == 2 && opt_index_and_place.is_some() {
let (index, src_place) = opt_index_and_place.unwrap();
return Some((local_use, index, src_place));
}
}
None
}).collect();
let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
let opt_size = opt_src_place.and_then(|src_place| {
let src_ty = src_place.ty(mir, tcx).to_ty(tcx);
if let ty::TyArray(_, ref size_o) = src_ty.sty {
size_o.val.to_const_int().and_then(|v| v.to_u64())
} else {
None
}
});
Self::check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place);
}
}
}
}
patch.apply(mir);
}
}
impl RestoreSubsliceArrayMoveOut {
// Checks that source has size, all locals are inited from same source place and
// indices is an integer interval. If all checks pass do the replacent.
// items are Vec<Option<LocalUse, index in source array, source place for init local>>
fn check_and_patch<'tcx>(candidate: Location,
items: &Vec<Option<(&LocalUse, u32, &Place<'tcx>)>>,
opt_size: Option<u64>,
patch: &mut MirPatch<'tcx>,
dst_place: &Place<'tcx>) {
let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
if opt_size.is_some() && items.iter().all(
|l| l.is_some() && l.unwrap().2 == opt_src_place.unwrap()) {
let indicies: Vec<_> = items.iter().map(|x| x.unwrap().1).collect();
for i in 1..indicies.len() {
if indicies[i - 1] + 1 != indicies[i] {
return;
}
}
let min = *indicies.first().unwrap();
let max = *indicies.last().unwrap();
for item in items {
let locals_use = item.unwrap().0;
patch.make_nop(locals_use.alive.unwrap());
patch.make_nop(locals_use.dead.unwrap());
patch.make_nop(locals_use.first_use.unwrap());
}
patch.make_nop(candidate);
let size = opt_size.unwrap() as u32;
patch.add_assign(candidate,
dst_place.clone(),
Rvalue::Use(
Operand::Move(
Place::Projection(box PlaceProjection{
base: opt_src_place.unwrap().clone(),
elem: ProjectionElem::Subslice{
from: min, to: size - max - 1}}))));
}
}
fn try_get_item_source<'a, 'tcx>(local_use: &LocalUse,
mir: &'a Mir<'tcx>) -> Option<(u32, &'a Place<'tcx>)> {
if let Some(location) = local_use.first_use {
let block = &mir[location.block];
if block.statements.len() > location.statement_index {
let statement = &block.statements[location.statement_index];
if let StatementKind::Assign(
Place::Local(_),
Rvalue::Use(Operand::Move(Place::Projection(box PlaceProjection{
ref base, elem: ProjectionElem::ConstantIndex{
offset, min_length: _, from_end: false}})))) = statement.kind {
return Some((offset, base))
}
}
}
None
}
}
#[derive(Copy, Clone, Debug)]
struct LocalUse {
alive: Option<Location>,
dead: Option<Location>,
use_count: u32,
first_use: Option<Location>,
}
impl LocalUse {
pub fn new() -> Self {
LocalUse{alive: None, dead: None, use_count: 0, first_use: None}
}
}
struct RestoreDataCollector {
locals_use: IndexVec<Local, LocalUse>,
candidates: Vec<Location>,
}
impl<'tcx> Visitor<'tcx> for RestoreDataCollector {
fn visit_assign(&mut self,
block: BasicBlock,
place: &Place<'tcx>,
rvalue: &Rvalue<'tcx>,
location: Location) {
if let Rvalue::Aggregate(box AggregateKind::Array(_), _) = *rvalue {
self.candidates.push(location);
}
self.super_assign(block, place, rvalue, location)
}
fn visit_local(&mut self,
local: &Local,
context: PlaceContext<'tcx>,
location: Location) {
let local_use = &mut self.locals_use[*local];
match context {
PlaceContext::StorageLive => local_use.alive = Some(location),
PlaceContext::StorageDead => local_use.dead = Some(location),
_ => {
local_use.use_count += 1;
if local_use.first_use.is_none() {
local_use.first_use = Some(location);
}
}
}
}
}

View File

@ -55,7 +55,8 @@ extern {
data: *mut u8,
data_ptr: *mut usize,
vtable_ptr: *mut usize) -> u32;
#[unwind]
#[cfg_attr(stage0, unwind)]
#[cfg_attr(not(stage0), unwind(allowed))]
fn __rust_start_panic(data: usize, vtable: usize) -> u32;
}
@ -315,7 +316,8 @@ pub fn panicking() -> bool {
/// Entry point of panic from the libcore crate.
#[cfg(not(test))]
#[lang = "panic_fmt"]
#[unwind]
#[cfg_attr(stage0, unwind)]
#[cfg_attr(not(stage0), unwind(allowed))]
pub extern fn rust_begin_panic(msg: fmt::Arguments,
file: &'static str,
line: u32,

View File

@ -1035,6 +1035,50 @@ impl<'a> cmp::Ord for Components<'a> {
}
}
/// An iterator over [`Path`] and its ancestors.
///
/// This `struct` is created by the [`ancestors`] method on [`Path`].
/// See its documentation for more.
///
/// # Examples
///
/// ```
/// #![feature(path_ancestors)]
///
/// use std::path::Path;
///
/// let path = Path::new("/foo/bar");
///
/// for ancestor in path.ancestors() {
/// println!("{}", ancestor.display());
/// }
/// ```
///
/// [`ancestors`]: struct.Path.html#method.ancestors
/// [`Path`]: struct.Path.html
#[derive(Copy, Clone, Debug)]
#[unstable(feature = "path_ancestors", issue = "48581")]
pub struct Ancestors<'a> {
next: Option<&'a Path>,
}
#[unstable(feature = "path_ancestors", issue = "48581")]
impl<'a> Iterator for Ancestors<'a> {
type Item = &'a Path;
fn next(&mut self) -> Option<Self::Item> {
let next = self.next;
self.next = match next {
Some(path) => path.parent(),
None => None,
};
next
}
}
#[unstable(feature = "fused", issue = "35602")]
impl<'a> FusedIterator for Ancestors<'a> {}
////////////////////////////////////////////////////////////////////////////////
// Basic types and traits
////////////////////////////////////////////////////////////////////////////////
@ -1820,6 +1864,37 @@ impl Path {
})
}
/// Produces an iterator over `Path` and its ancestors.
///
/// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero
/// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`,
/// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns
/// [`None`], the iterator will do likewise. The iterator will always yield at least one value,
/// namely `&self`.
///
/// # Examples
///
/// ```
/// #![feature(path_ancestors)]
///
/// use std::path::Path;
///
/// let mut ancestors = Path::new("/foo/bar").ancestors();
/// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar")));
/// assert_eq!(ancestors.next(), Some(Path::new("/foo")));
/// assert_eq!(ancestors.next(), Some(Path::new("/")));
/// assert_eq!(ancestors.next(), None);
/// ```
///
/// [`None`]: ../../std/option/enum.Option.html#variant.None
/// [`parent`]: struct.Path.html#method.parent
#[unstable(feature = "path_ancestors", issue = "48581")]
pub fn ancestors(&self) -> Ancestors {
Ancestors {
next: Some(&self),
}
}
/// Returns the final component of the `Path`, if there is one.
///
/// If the path is a normal file, this is the file name. If it's the path of a directory, this

View File

@ -565,6 +565,51 @@ pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> In
})
}
#[derive(Copy, Clone, PartialEq)]
pub enum UnwindAttr {
Allowed,
Aborts,
}
/// Determine what `#[unwind]` attribute is present in `attrs`, if any.
pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option<UnwindAttr> {
let syntax_error = |attr: &Attribute| {
mark_used(attr);
diagnostic.map(|d| {
span_err!(d, attr.span, E0633, "malformed `#[unwind]` attribute");
});
None
};
attrs.iter().fold(None, |ia, attr| {
if attr.path != "unwind" {
return ia;
}
let meta = match attr.meta() {
Some(meta) => meta.node,
None => return ia,
};
match meta {
MetaItemKind::Word => {
syntax_error(attr)
}
MetaItemKind::List(ref items) => {
mark_used(attr);
if items.len() != 1 {
syntax_error(attr)
} else if list_contains_name(&items[..], "allowed") {
Some(UnwindAttr::Allowed)
} else if list_contains_name(&items[..], "aborts") {
Some(UnwindAttr::Aborts)
} else {
syntax_error(attr)
}
}
_ => ia,
}
})
}
/// True if `#[inline]` or `#[inline(always)]` is present in `attrs`.
pub fn requests_inline(attrs: &[Attribute]) -> bool {
match find_inline_attr(None, attrs) {

View File

@ -129,7 +129,7 @@ pub struct CodeMap {
pub(super) files: RefCell<Vec<Rc<FileMap>>>,
file_loader: Box<FileLoader>,
// This is used to apply the file path remapping as specified via
// -Zremap-path-prefix to all FileMaps allocated within this CodeMap.
// --remap-path-prefix to all FileMaps allocated within this CodeMap.
path_mapping: FilePathMapping,
stable_id_to_filemap: RefCell<FxHashMap<StableFilemapId, Rc<FileMap>>>,
/// In case we are in a doctest, replace all file names with the PathBuf,

View File

@ -342,6 +342,33 @@ fn main() {
```
"##,
E0633: r##"
The `unwind` attribute was malformed.
Erroneous code example:
```ignore (compile_fail not working here; see Issue #43707)
#[unwind()] // error: expected one argument
pub extern fn something() {}
fn main() {}
```
The `#[unwind]` attribute should be used as follows:
- `#[unwind(aborts)]` -- specifies that if a non-Rust ABI function
should abort the process if it attempts to unwind. This is the safer
and preferred option.
- `#[unwind(allowed)]` -- specifies that a non-Rust ABI function
should be allowed to unwind. This can easily result in Undefined
Behavior (UB), so be careful.
NB. The default behavior here is "allowed", but this is unspecified
and likely to change in the future.
"##,
}
register_diagnostics! {

View File

@ -233,7 +233,7 @@ declare_features! (
// allow `extern "platform-intrinsic" { ... }`
(active, platform_intrinsics, "1.4.0", Some(27731)),
// allow `#[unwind]`
// allow `#[unwind(..)]`
// rust runtime internal
(active, unwind_attributes, "1.4.0", None),

View File

@ -670,7 +670,7 @@ pub struct FileMap {
/// originate from files has names between angle brackets by convention,
/// e.g. `<anon>`
pub name: FileName,
/// True if the `name` field above has been modified by -Zremap-path-prefix
/// True if the `name` field above has been modified by --remap-path-prefix
pub name_was_remapped: bool,
/// The unmapped path of the file that the source came from.
/// Set to `None` if the FileMap was imported from an external crate.

View File

@ -83,7 +83,8 @@ pub enum _Unwind_Context {}
pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code,
exception: *mut _Unwind_Exception);
extern "C" {
#[unwind]
#[cfg_attr(stage0, unwind)]
#[cfg_attr(not(stage0), unwind(allowed))]
pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
@ -220,7 +221,8 @@ if #[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))] {
if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
// Not 32-bit iOS
extern "C" {
#[unwind]
#[cfg_attr(stage0, unwind)]
#[cfg_attr(not(stage0), unwind(allowed))]
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
trace_argument: *mut c_void)
@ -229,7 +231,8 @@ if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
} else {
// 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace()
extern "C" {
#[unwind]
#[cfg_attr(stage0, unwind)]
#[cfg_attr(not(stage0), unwind(allowed))]
pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
}

View File

@ -19,7 +19,7 @@ extern {
fn extern_fn();
// CHECK-NOT: Function Attrs: nounwind
// CHECK: declare void @unwinding_extern_fn
#[unwind]
#[unwind(allowed)]
fn unwinding_extern_fn();
}

View File

@ -10,7 +10,7 @@
// ignore-tidy-linelength
// compile-flags: -g -Zremap-path-prefix-from={{cwd}} -Zremap-path-prefix-to=/the/aux-cwd -Zremap-path-prefix-from={{src-base}}/remap_path_prefix/auxiliary -Zremap-path-prefix-to=/the/aux-src
// compile-flags: -g --remap-path-prefix={{cwd}}=/the/aux-cwd --remap-path-prefix={{src-base}}/remap_path_prefix/auxiliary=/the/aux-src
#[inline]
pub fn some_aux_function() -> i32 {

View File

@ -11,7 +11,7 @@
// ignore-windows
// ignore-tidy-linelength
// compile-flags: -g -C no-prepopulate-passes -Zremap-path-prefix-from={{cwd}} -Zremap-path-prefix-to=/the/cwd -Zremap-path-prefix-from={{src-base}} -Zremap-path-prefix-to=/the/src
// compile-flags: -g -C no-prepopulate-passes --remap-path-prefix={{cwd}}=/the/cwd --remap-path-prefix={{src-base}}=/the/src
// aux-build:remap_path_prefix_aux.rs
extern crate remap_path_prefix_aux;

View File

@ -9,6 +9,7 @@
// except according to those terms.
#![feature(dyn_trait)]
#![allow(bare_trait_object)]
struct Foo;

View File

@ -12,7 +12,7 @@
//[rpass1] compile-flags: -g
//[rpass2] compile-flags: -g
//[rpass3] compile-flags: -g -Zremap-path-prefix-from={{src-base}} -Zremap-path-prefix-to=/the/src
//[rpass3] compile-flags: -g --remap-path-prefix={{src-base}}=/the/src
#![feature(rustc_attrs)]
#![crate_type="rlib"]

View File

@ -57,3 +57,28 @@ fn main() {
// nop;
// _0 = ();
// END rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir
// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir
// StorageLive(_6);
// StorageLive(_7);
// _7 = move _1[0 of 2];
// StorageLive(_8);
// _8 = move _1[1 of 2];
// _6 = [move _7, move _8];
// StorageDead(_7);
// StorageDead(_8);
// _0 = ();
// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir
// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir
// StorageLive(_6);
// nop;
// nop;
// nop;
// nop;
// _6 = move _1[0:];
// nop;
// nop;
// nop;
// _0 = ();
// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir

View File

@ -14,11 +14,14 @@
// ignore-cloudabi no env and process
// ignore-emscripten no processes
#![feature(unwind_attributes)]
use std::{env, panic};
use std::io::prelude::*;
use std::io;
use std::process::{Command, Stdio};
#[unwind(aborts)]
extern "C" fn panic_in_ffi() {
panic!("Test");
}