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:
commit
0e3c9bba8e
@ -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.
|
||||
|
@ -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.
|
@ -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"];
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 (),
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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> {
|
||||
|
@ -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)]
|
||||
|
@ -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 {}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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! {
|
||||
|
@ -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),
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(dyn_trait)]
|
||||
#![allow(bare_trait_object)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
|
@ -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"]
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user