def main():
"""Entry point for the bootstrap process"""
start_time = time()
+
+ # x.py help <cmd> ...
+ if len(sys.argv) > 1 and sys.argv[1] == 'help':
+ sys.argv = sys.argv[:1] + [sys.argv[2], '-h'] + sys.argv[3:]
+
help_triggered = (
'-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1)
try:
fn copy_apple_sanitizer_dylibs(builder: &Builder, native_dir: &Path, platform: &str, into: &Path) {
for &sanitizer in &["asan", "tsan"] {
- let filename = format!("libclang_rt.{}_{}_dynamic.dylib", sanitizer, platform);
+ let filename = format!("lib__rustc__clang_rt.{}_{}_dynamic.dylib", sanitizer, platform);
let mut src_path = native_dir.join(sanitizer);
src_path.push("build");
src_path.push("lib");
pub out_dir: PathBuf,
}
+impl NativeLibBoilerplate {
+ /// On OSX we don't want to ship the exact filename that compiler-rt builds.
+ /// This conflicts with the system and ours is likely a wildly different
+ /// version, so they can't be substituted.
+ ///
+ /// As a result, we rename it here but we need to also use
+ /// `install_name_tool` on OSX to rename the commands listed inside of it to
+ /// ensure it's linked against correctly.
+ pub fn fixup_sanitizer_lib_name(&self, sanitizer_name: &str) {
+ if env::var("TARGET").unwrap() != "x86_64-apple-darwin" {
+ return
+ }
+
+ let dir = self.out_dir.join("build/lib/darwin");
+ let name = format!("clang_rt.{}_osx_dynamic", sanitizer_name);
+ let src = dir.join(&format!("lib{}.dylib", name));
+ let new_name = format!("lib__rustc__{}.dylib", name);
+ let dst = dir.join(&new_name);
+
+ println!("{} => {}", src.display(), dst.display());
+ fs::rename(&src, &dst).unwrap();
+ let status = Command::new("install_name_tool")
+ .arg("-id")
+ .arg(format!("@rpath/{}", new_name))
+ .arg(&dst)
+ .status()
+ .expect("failed to execute `install_name_tool`");
+ assert!(status.success());
+ }
+}
+
impl Drop for NativeLibBoilerplate {
fn drop(&mut self) {
if !thread::panicking() {
pub fn sanitizer_lib_boilerplate(sanitizer_name: &str)
-> Result<(NativeLibBoilerplate, String), ()>
{
- let (link_name, search_path, dynamic) = match &*env::var("TARGET").unwrap() {
+ let (link_name, search_path, apple) = match &*env::var("TARGET").unwrap() {
"x86_64-unknown-linux-gnu" => (
format!("clang_rt.{}-x86_64", sanitizer_name),
"build/lib/linux",
),
_ => return Err(()),
};
- let to_link = if dynamic {
- format!("dylib={}", link_name)
+ let to_link = if apple {
+ format!("dylib=__rustc__{}", link_name)
} else {
format!("static={}", link_name)
};
//!
//! # Examples
//!
-//! Creating a box:
+//! Move a value from the stack to the heap by creating a [`Box`]:
//!
//! ```
-//! let x = Box::new(5);
+//! let val: u8 = 5;
+//! let boxed: Box<u8> = Box::new(val);
+//! ```
+//!
+//! Move a value from a [`Box`] back to the stack by [dereferencing]:
+//!
+//! ```
+//! let boxed: Box<u8> = Box::new(5);
+//! let val: u8 = *boxed;
//! ```
//!
//! Creating a recursive data structure:
//! elements are in the list, and so we don't know how much memory to allocate
//! for a `Cons`. By introducing a `Box`, which has a defined size, we know how
//! big `Cons` needs to be.
+//!
+//! [dereferencing]: ../../std/ops/trait.Deref.html
+//! [`Box`]: struct.Box.html
#![stable(feature = "rust1", since = "1.0.0")]
use cmp;
use fmt;
use intrinsics::assume;
+use isize;
use iter::*;
use ops::{FnMut, Try, self};
use option::Option;
/// them from other data. You can obtain a pointer that is usable as `data`
/// for zero-length slices using [`NonNull::dangling()`].
///
+/// The total size of the slice must be no larger than `isize::MAX` **bytes**
+/// in memory. See the safety documentation of [`pointer::offset`].
+///
/// # Caveat
///
/// The lifetime for the returned slice is inferred from its usage. To
/// ```
///
/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling
+/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
debug_assert!(data as usize % mem::align_of::<T>() == 0, "attempt to create unaligned slice");
+ debug_assert!(mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
+ "attempt to create slice covering half the address space");
Repr { raw: FatPtr { data, len } }.rust
}
/// This function is unsafe for the same reasons as [`from_raw_parts`], as well
/// as not being able to provide a non-aliasing guarantee of the returned
/// mutable slice. `data` must be non-null and aligned even for zero-length
-/// slices as with [`from_raw_parts`]. See the documentation of
-/// [`from_raw_parts`] for more details.
+/// slices as with [`from_raw_parts`]. The total size of the slice must be no
+/// larger than `isize::MAX` **bytes** in memory.
+///
+/// See the documentation of [`from_raw_parts`] for more details.
///
/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
debug_assert!(data as usize % mem::align_of::<T>() == 0, "attempt to create unaligned slice");
- Repr { raw: FatPtr { data, len} }.rust_mut
+ debug_assert!(mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
+ "attempt to create slice covering half the address space");
+ Repr { raw: FatPtr { data, len } }.rust_mut
}
/// Converts a reference to T into a slice of length 1 (without copying).
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::thin_vec::ThinVec;
use session::Session;
+use session::config::nightly_options;
use util::common::FN_OUTPUT_NAME;
use util::nodemap::{DefIdMap, NodeMap};
Existential(Option<DefId>),
/// `impl Trait` is not accepted in this position.
- Disallowed,
+ Disallowed(ImplTraitPosition),
+}
+
+/// Position in which `impl Trait` is disallowed. Used for error reporting.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+enum ImplTraitPosition {
+ Binding,
+ Other,
}
impl<'a> ImplTraitContext<'a> {
+ #[inline]
+ fn disallowed() -> Self {
+ ImplTraitContext::Disallowed(ImplTraitPosition::Other)
+ }
+
fn reborrow(&'b mut self) -> ImplTraitContext<'b> {
use self::ImplTraitContext::*;
match self {
Universal(params) => Universal(params),
Existential(did) => Existential(*did),
- Disallowed => Disallowed,
+ Disallowed(pos) => Disallowed(*pos),
}
}
}
generic_params: this.lower_generic_params(
&f.generic_params,
&NodeMap(),
- ImplTraitContext::Disallowed,
+ ImplTraitContext::disallowed(),
),
unsafety: this.lower_unsafety(f.unsafety),
abi: f.abi,
}),
))
}
- ImplTraitContext::Disallowed => {
+ ImplTraitContext::Disallowed(pos) => {
let allowed_in = if self.sess.features_untracked()
.impl_trait_in_bindings {
"bindings or function and inherent method return types"
} else {
"function and inherent method return types"
};
- span_err!(
+ let mut err = struct_span_err!(
self.sess,
t.span,
E0562,
"`impl Trait` not allowed outside of {}",
allowed_in,
);
+ if pos == ImplTraitPosition::Binding &&
+ nightly_options::is_nightly_build() {
+ help!(err,
+ "add #![feature(impl_trait_in_bindings)] to the crate attributes \
+ to enable");
+ }
+ err.emit();
hir::TyKind::Err
}
}
param_mode,
0,
ParenthesizedGenericArgs::Err,
- ImplTraitContext::Disallowed,
+ ImplTraitContext::disallowed(),
)
})
.chain(ident.map(|ident| hir::PathSegment::from_ident(ident)))
self.with_anonymous_lifetime_mode(
AnonymousLifetimeMode::PassThrough,
|this| {
- const DISALLOWED: ImplTraitContext<'_> = ImplTraitContext::Disallowed;
let &ParenthesisedArgs { ref inputs, ref output, span } = data;
- let inputs = inputs.iter().map(|ty| this.lower_ty_direct(ty, DISALLOWED)).collect();
+ let inputs = inputs
+ .iter()
+ .map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed()))
+ .collect();
let mk_tup = |this: &mut Self, tys, span| {
let LoweredNodeId { node_id, hir_id } = this.next_id();
hir::Ty { node: hir::TyKind::Tup(tys), id: node_id, hir_id, span }
ident: Ident::from_str(FN_OUTPUT_NAME),
ty: output
.as_ref()
- .map(|ty| this.lower_ty(&ty, DISALLOWED))
+ .map(|ty| this.lower_ty(&ty, ImplTraitContext::disallowed()))
.unwrap_or_else(|| P(mk_tup(this, hir::HirVec::new(), span))),
span: output.as_ref().map_or(span, |ty| ty.span),
}
if self.sess.features_untracked().impl_trait_in_bindings {
ImplTraitContext::Existential(Some(parent_def_id))
} else {
- ImplTraitContext::Disallowed
+ ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
}
)),
pat: self.lower_pat(&l.pat),
if let Some((_, ref mut ibty)) = in_band_ty_params {
self.lower_ty_direct(&arg.ty, ImplTraitContext::Universal(ibty))
} else {
- self.lower_ty_direct(&arg.ty, ImplTraitContext::Disallowed)
+ self.lower_ty_direct(&arg.ty, ImplTraitContext::disallowed())
}
})
.collect::<HirVec<_>>();
match decl.output {
FunctionRetTy::Ty(ref ty) => match in_band_ty_params {
Some((def_id, _)) if impl_trait_return_allow => {
- hir::Return(self.lower_ty(ty, ImplTraitContext::Existential(Some(def_id))))
+ hir::Return(self.lower_ty(ty,
+ ImplTraitContext::Existential(Some(def_id))))
+ }
+ _ => {
+ hir::Return(self.lower_ty(ty, ImplTraitContext::disallowed()))
}
- _ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
},
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
}
span: ident.span,
kind: hir::GenericParamKind::Type {
default: default.as_ref().map(|x| {
- self.lower_ty(x, ImplTraitContext::Disallowed)
+ self.lower_ty(x, ImplTraitContext::disallowed())
}),
synthetic: param.attrs.iter()
.filter(|attr| attr.check_name("rustc_synthetic"))
bound_generic_params: this.lower_generic_params(
bound_generic_params,
&NodeMap(),
- ImplTraitContext::Disallowed,
+ ImplTraitContext::disallowed(),
),
- bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::Disallowed),
+ bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()),
bounds: bounds
.iter()
.filter_map(|bound| match *bound {
GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
_ => Some(this.lower_param_bound(
bound,
- ImplTraitContext::Disallowed,
+ ImplTraitContext::disallowed(),
)),
})
.collect(),
}) => hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
span,
lifetime: self.lower_lifetime(lifetime),
- bounds: self.lower_param_bounds(bounds, ImplTraitContext::Disallowed),
+ bounds: self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
}),
WherePredicate::EqPredicate(WhereEqPredicate {
id,
span,
}) => hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
id: self.lower_node_id(id).node_id,
- lhs_ty: self.lower_ty(lhs_ty, ImplTraitContext::Disallowed),
- rhs_ty: self.lower_ty(rhs_ty, ImplTraitContext::Disallowed),
+ lhs_ty: self.lower_ty(lhs_ty, ImplTraitContext::disallowed()),
+ rhs_ty: self.lower_ty(rhs_ty, ImplTraitContext::disallowed()),
span,
}),
}
None => Ident::new(Symbol::intern(&index.to_string()), f.span),
},
vis: self.lower_visibility(&f.vis, None),
- ty: self.lower_ty(&f.ty, ImplTraitContext::Disallowed),
+ ty: self.lower_ty(&f.ty, ImplTraitContext::disallowed()),
attrs: self.lower_attrs(&f.attrs),
}
}
if self.sess.features_untracked().impl_trait_in_bindings {
ImplTraitContext::Existential(None)
} else {
- ImplTraitContext::Disallowed
+ ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
}
),
self.lower_mutability(m),
if self.sess.features_untracked().impl_trait_in_bindings {
ImplTraitContext::Existential(None)
} else {
- ImplTraitContext::Disallowed
+ ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
}
),
value
ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)),
ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)),
ItemKind::Ty(ref t, ref generics) => hir::ItemKind::Ty(
- self.lower_ty(t, ImplTraitContext::Disallowed),
- self.lower_generics(generics, ImplTraitContext::Disallowed),
+ self.lower_ty(t, ImplTraitContext::disallowed()),
+ self.lower_generics(generics, ImplTraitContext::disallowed()),
),
ItemKind::Existential(ref b, ref generics) => hir::ItemKind::Existential(hir::ExistTy {
- generics: self.lower_generics(generics, ImplTraitContext::Disallowed),
- bounds: self.lower_param_bounds(b, ImplTraitContext::Disallowed),
+ generics: self.lower_generics(generics, ImplTraitContext::disallowed()),
+ bounds: self.lower_param_bounds(b, ImplTraitContext::disallowed()),
impl_trait_fn: None,
}),
ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
.map(|x| self.lower_variant(x))
.collect(),
},
- self.lower_generics(generics, ImplTraitContext::Disallowed),
+ self.lower_generics(generics, ImplTraitContext::disallowed()),
),
ItemKind::Struct(ref struct_def, ref generics) => {
let struct_def = self.lower_variant_data(struct_def);
hir::ItemKind::Struct(
struct_def,
- self.lower_generics(generics, ImplTraitContext::Disallowed),
+ self.lower_generics(generics, ImplTraitContext::disallowed()),
)
}
ItemKind::Union(ref vdata, ref generics) => {
let vdata = self.lower_variant_data(vdata);
hir::ItemKind::Union(
vdata,
- self.lower_generics(generics, ImplTraitContext::Disallowed),
+ self.lower_generics(generics, ImplTraitContext::disallowed()),
)
}
ItemKind::Impl(
AnonymousLifetimeMode::CreateParameter,
|this, _| {
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
- this.lower_trait_ref(trait_ref, ImplTraitContext::Disallowed)
+ this.lower_trait_ref(trait_ref, ImplTraitContext::disallowed())
});
if let Some(ref trait_ref) = trait_ref {
}
}
- let lowered_ty = this.lower_ty(ty, ImplTraitContext::Disallowed);
+ let lowered_ty = this.lower_ty(ty, ImplTraitContext::disallowed());
(trait_ref, lowered_ty)
},
)
}
ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref items) => {
- let bounds = self.lower_param_bounds(bounds, ImplTraitContext::Disallowed);
+ let bounds = self.lower_param_bounds(bounds, ImplTraitContext::disallowed());
let items = items
.iter()
.map(|item| self.lower_trait_item_ref(item))
hir::ItemKind::Trait(
self.lower_is_auto(is_auto),
self.lower_unsafety(unsafety),
- self.lower_generics(generics, ImplTraitContext::Disallowed),
+ self.lower_generics(generics, ImplTraitContext::disallowed()),
bounds,
items,
)
}
ItemKind::TraitAlias(ref generics, ref bounds) => hir::ItemKind::TraitAlias(
- self.lower_generics(generics, ImplTraitContext::Disallowed),
- self.lower_param_bounds(bounds, ImplTraitContext::Disallowed),
+ self.lower_generics(generics, ImplTraitContext::disallowed()),
+ self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
),
ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"),
}
let (generics, node) = match i.node {
TraitItemKind::Const(ref ty, ref default) => (
- self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
+ self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
hir::TraitItemKind::Const(
- self.lower_ty(ty, ImplTraitContext::Disallowed),
+ self.lower_ty(ty, ImplTraitContext::disallowed()),
default
.as_ref()
.map(|x| self.lower_body(None, |this| this.lower_expr(x))),
(generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id)))
}
TraitItemKind::Type(ref bounds, ref default) => (
- self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
+ self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
hir::TraitItemKind::Type(
- self.lower_param_bounds(bounds, ImplTraitContext::Disallowed),
+ self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
default
.as_ref()
- .map(|x| self.lower_ty(x, ImplTraitContext::Disallowed)),
+ .map(|x| self.lower_ty(x, ImplTraitContext::disallowed())),
),
),
TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
ImplItemKind::Const(ref ty, ref expr) => {
let body_id = self.lower_body(None, |this| this.lower_expr(expr));
(
- self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
+ self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
hir::ImplItemKind::Const(
- self.lower_ty(ty, ImplTraitContext::Disallowed),
+ self.lower_ty(ty, ImplTraitContext::disallowed()),
body_id,
),
)
(generics, hir::ImplItemKind::Method(sig, body_id))
}
ImplItemKind::Type(ref ty) => (
- self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
- hir::ImplItemKind::Type(self.lower_ty(ty, ImplTraitContext::Disallowed)),
+ self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
+ hir::ImplItemKind::Type(self.lower_ty(ty, ImplTraitContext::disallowed())),
),
ImplItemKind::Existential(ref bounds) => (
- self.lower_generics(&i.generics, ImplTraitContext::Disallowed),
+ self.lower_generics(&i.generics, ImplTraitContext::disallowed()),
hir::ImplItemKind::Existential(
- self.lower_param_bounds(bounds, ImplTraitContext::Disallowed),
+ self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
),
),
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
}
ForeignItemKind::Static(ref t, m) => {
- hir::ForeignItemKind::Static(self.lower_ty(t, ImplTraitContext::Disallowed), m)
+ hir::ForeignItemKind::Static(
+ self.lower_ty(t, ImplTraitContext::disallowed()), m)
}
ForeignItemKind::Ty => hir::ForeignItemKind::Type,
ForeignItemKind::Macro(_) => panic!("shouldn't exist here"),
&None,
path,
ParamMode::Optional,
- ImplTraitContext::Disallowed,
+ ImplTraitContext::disallowed(),
);
self.check_self_struct_ctor_feature(&qpath);
hir::PatKind::TupleStruct(
qself,
path,
ParamMode::Optional,
- ImplTraitContext::Disallowed,
+ ImplTraitContext::disallowed(),
);
self.check_self_struct_ctor_feature(&qpath);
hir::PatKind::Path(qpath)
&None,
path,
ParamMode::Optional,
- ImplTraitContext::Disallowed,
+ ImplTraitContext::disallowed(),
);
let fs = fields
ParamMode::Optional,
0,
ParenthesizedGenericArgs::Err,
- ImplTraitContext::Disallowed,
+ ImplTraitContext::disallowed(),
);
let args = args.iter().map(|x| self.lower_expr(x)).collect();
hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
ExprKind::Lit(ref l) => hir::ExprKind::Lit(P((**l).clone())),
ExprKind::Cast(ref expr, ref ty) => {
let expr = P(self.lower_expr(expr));
- hir::ExprKind::Cast(expr, self.lower_ty(ty, ImplTraitContext::Disallowed))
+ hir::ExprKind::Cast(expr, self.lower_ty(ty, ImplTraitContext::disallowed()))
}
ExprKind::Type(ref expr, ref ty) => {
let expr = P(self.lower_expr(expr));
- hir::ExprKind::Type(expr, self.lower_ty(ty, ImplTraitContext::Disallowed))
+ hir::ExprKind::Type(expr, self.lower_ty(ty, ImplTraitContext::disallowed()))
}
ExprKind::AddrOf(m, ref ohs) => {
let m = self.lower_mutability(m);
qself,
path,
ParamMode::Optional,
- ImplTraitContext::Disallowed,
+ ImplTraitContext::disallowed(),
);
self.check_self_struct_ctor_feature(&qpath);
hir::ExprKind::Path(qpath)
&None,
path,
ParamMode::Optional,
- ImplTraitContext::Disallowed,
+ ImplTraitContext::disallowed(),
),
fields.iter().map(|x| self.lower_field(x)).collect(),
maybe_expr.as_ref().map(|x| P(self.lower_expr(x))),
);
// Select everything, returning errors.
- let true_errors = match fulfill_cx.select_where_possible(self) {
- Ok(()) => vec![],
- Err(errors) => errors,
- };
+ let true_errors = fulfill_cx.select_where_possible(self).err().unwrap_or_else(Vec::new);
debug!("true_errors = {:#?}", true_errors);
if !true_errors.is_empty() {
}
// Anything left unselected *now* must be an ambiguity.
- let ambig_errors = match fulfill_cx.select_all_or_error(self) {
- Ok(()) => vec![],
- Err(errors) => errors,
- };
+ let ambig_errors = fulfill_cx.select_all_or_error(self).err().unwrap_or_else(Vec::new);
debug!("ambig_errors = {:#?}", ambig_errors);
let region_obligations = self.take_registered_region_obligations();
}
// ...also include the other query region constraints from the query.
- output_query_region_constraints.reserve(query_result.value.region_constraints.len());
- for r_c in query_result.value.region_constraints.iter() {
- let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); // reconstructed below
- let k1 = substitute_value(self.tcx, &result_subst, &k1);
- let r2 = substitute_value(self.tcx, &result_subst, &r2);
- if k1 != r2.into() {
- output_query_region_constraints
- .push(ty::Binder::bind(ty::OutlivesPredicate(k1, r2)));
- }
- }
+ output_query_region_constraints.extend(
+ query_result.value.region_constraints.iter().filter_map(|r_c| {
+ let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); // reconstructed below
+ let k1 = substitute_value(self.tcx, &result_subst, &k1);
+ let r2 = substitute_value(self.tcx, &result_subst, &r2);
+ if k1 != r2.into() {
+ Some(ty::Binder::bind(ty::OutlivesPredicate(k1, r2)))
+ } else {
+ None
+ }
+ })
+ );
let user_result: R =
query_result.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value);
.variables
.iter()
.enumerate()
- .map(|(index, info)| match opt_values[CanonicalVar::new(index)] {
- Some(k) => k,
- None => self.fresh_inference_var_for_canonical_var(cause.span, *info),
- })
+ .map(|(index, info)| opt_values[CanonicalVar::new(index)].unwrap_or_else(||
+ self.fresh_inference_var_for_canonical_var(cause.span, *info)
+ ))
.collect(),
};
let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below
let k1 = substitute_value(self.tcx, result_subst, k1);
let r2 = substitute_value(self.tcx, result_subst, r2);
- match k1.unpack() {
- UnpackedKind::Lifetime(r1) => Obligation::new(
- cause.clone(),
- param_env,
- ty::Predicate::RegionOutlives(ty::Binder::dummy(
- ty::OutlivesPredicate(r1, r2),
+
+ Obligation::new(
+ cause.clone(),
+ param_env,
+ match k1.unpack() {
+ UnpackedKind::Lifetime(r1) => ty::Predicate::RegionOutlives(
+ ty::Binder::dummy(
+ ty::OutlivesPredicate(r1, r2)
)),
- ),
-
- UnpackedKind::Type(t1) => Obligation::new(
- cause.clone(),
- param_env,
- ty::Predicate::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate(
- t1, r2,
- ))),
- ),
- }
- }),
+ UnpackedKind::Type(t1) => ty::Predicate::TypeOutlives(
+ ty::Binder::dummy(ty::OutlivesPredicate(
+ t1, r2
+ )))
+ }
+ )
+ })
) as Box<dyn Iterator<Item = _>>
}
assert!(verifys.is_empty());
assert!(givens.is_empty());
- let mut outlives: Vec<_> = constraints
- .into_iter()
- .map(|(k, _)| match *k {
- // Swap regions because we are going from sub (<=) to outlives
- // (>=).
- Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
- tcx.mk_region(ty::ReVar(v2)).into(),
- tcx.mk_region(ty::ReVar(v1)),
- ),
- Constraint::VarSubReg(v1, r2) => {
- ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1)))
- }
- Constraint::RegSubVar(r1, v2) => {
- ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
- }
- Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
- })
- .map(ty::Binder::dummy) // no bound regions in the code above
- .collect();
-
- outlives.extend(
- outlives_obligations
- .map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r))
- .map(ty::Binder::dummy), // no bound regions in the code above
- );
+ let outlives: Vec<_> = constraints
+ .into_iter()
+ .map(|(k, _)| match *k {
+ // Swap regions because we are going from sub (<=) to outlives
+ // (>=).
+ Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
+ tcx.mk_region(ty::ReVar(v2)).into(),
+ tcx.mk_region(ty::ReVar(v1)),
+ ),
+ Constraint::VarSubReg(v1, r2) => {
+ ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1)))
+ }
+ Constraint::RegSubVar(r1, v2) => {
+ ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
+ }
+ Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
+ })
+ .map(ty::Binder::dummy) // no bound regions in the code above
+ .chain(
+ outlives_obligations
+ .map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r))
+ .map(ty::Binder::dummy), // no bound regions in the code above
+ )
+ .collect();
outlives
}
match (&a.sty, &b.sty) {
(&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
infcx.type_variables.borrow_mut().equate(a_id, b_id);
- Ok(a)
}
(&ty::Infer(TyVar(a_id)), _) => {
self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?;
- Ok(a)
}
(_, &ty::Infer(TyVar(b_id))) => {
self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?;
- Ok(a)
}
_ => {
self.fields.infcx.super_combine_tys(self, a, b)?;
- Ok(a)
}
}
+
+ Ok(a)
}
fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>)
errors.clone()
} else {
errors
- .iter()
- .filter(|&e| !is_bound_failure(e))
- .cloned()
- .collect()
+ .iter()
+ .filter(|&e| !is_bound_failure(e))
+ .cloned()
+ .collect()
};
// sort the errors by span, for better error message stability.
TypeError::Sorts(ref exp_found) => {
// if they are both "path types", there's a chance of ambiguity
// due to different versions of the same crate
- match (&exp_found.expected.sty, &exp_found.found.sty) {
- (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _)) => {
- report_path_match(err, exp_adt.did, found_adt.did);
- }
- _ => (),
+ if let (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _))
+ = (&exp_found.expected.sty, &exp_found.found.sty)
+ {
+ report_path_match(err, exp_adt.did, found_adt.did);
}
}
TypeError::Traits(ref exp_found) => {
let mut labels = vec![(
span,
if &name == "_" {
- "cannot infer type".to_string()
+ "cannot infer type".to_owned()
} else {
format!("cannot infer type for `{}`", name)
},
// ```
labels.clear();
labels.push(
- (pattern.span, "consider giving this closure parameter a type".to_string()));
+ (pattern.span, "consider giving this closure parameter a type".to_owned()));
} else if let Some(pattern) = local_visitor.found_local_pattern {
if let Some(simple_ident) = pattern.simple_ident() {
match pattern.span.compiler_desugaring_kind() {
format!("consider giving `{}` a type", simple_ident))),
Some(CompilerDesugaringKind::ForLoop) => labels.push((
pattern.span,
- "the element type for this iterator is not specified".to_string(),
+ "the element type for this iterator is not specified".to_owned(),
)),
_ => {}
}
} else {
- labels.push((pattern.span, "consider giving the pattern a type".to_string()));
+ labels.push((pattern.span, "consider giving the pattern a type".to_owned()));
}
}
(None, None) => {
let (main_label_1, span_label_1) = if ty_sup.id == ty_sub.id {
(
- "this type is declared with multiple lifetimes...".to_string(),
- "...but data with one lifetime flows into the other here".to_string()
+ "this type is declared with multiple lifetimes...".to_owned(),
+ "...but data with one lifetime flows into the other here".to_owned()
)
} else {
(
- "these two types are declared with different lifetimes...".to_string(),
+ "these two types are declared with different lifetimes...".to_owned(),
format!(
"...but data{} flows{} here",
span_label_var1,
ty_sub.span,
ret_span,
"this parameter and the return type are declared \
- with different lifetimes...".to_string()
+ with different lifetimes...".to_owned()
,
format!("...but data{} is returned here", span_label_var1),
),
ty_sup.span,
ret_span,
"this parameter and the return type are declared \
- with different lifetimes...".to_string()
+ with different lifetimes...".to_owned()
,
format!("...but data{} is returned here", span_label_var1),
),
&RegionKind::ReFree(ref free_region)) = (&sub_origin, sup_region) {
let hir = &self.tcx.hir;
if let Some(node_id) = hir.as_local_node_id(free_region.scope) {
- match hir.get(node_id) {
- Node::Expr(Expr {
- node: Closure(_, _, _, closure_span, None),
- ..
- }) => {
- let sup_sp = sup_origin.span();
- let origin_sp = origin.span();
- let mut err = self.tcx.sess.struct_span_err(
- sup_sp,
- "borrowed data cannot be stored outside of its closure");
- err.span_label(sup_sp, "cannot be stored outside of its closure");
- if origin_sp == sup_sp || origin_sp.contains(sup_sp) {
+ if let Node::Expr(Expr {
+ node: Closure(_, _, _, closure_span, None),
+ ..
+ }) = hir.get(node_id) {
+ let sup_sp = sup_origin.span();
+ let origin_sp = origin.span();
+ let mut err = self.tcx.sess.struct_span_err(
+ sup_sp,
+ "borrowed data cannot be stored outside of its closure");
+ err.span_label(sup_sp, "cannot be stored outside of its closure");
+ if origin_sp == sup_sp || origin_sp.contains(sup_sp) {
// // sup_sp == origin.span():
//
// let mut x = None;
// ------------ ... because it cannot outlive this closure
// f = Some(x);
// ^ cannot be stored outside of its closure
- err.span_label(*external_span,
- "borrowed data cannot be stored into here...");
- err.span_label(*closure_span,
- "...because it cannot outlive this closure");
- } else {
+ err.span_label(*external_span,
+ "borrowed data cannot be stored into here...");
+ err.span_label(*closure_span,
+ "...because it cannot outlive this closure");
+ } else {
// FIXME: the wording for this case could be much improved
//
// let mut lines_to_use: Vec<&CrateId> = Vec::new();
// ...so that variable is valid at time of its declaration
// lines_to_use.push(installed_id);
// ^^^^^^^^^^^^ cannot be stored outside of its closure
- err.span_label(origin_sp,
- "cannot infer an appropriate lifetime...");
- err.span_label(*external_span,
- "...so that variable is valid at time of its \
- declaration");
- err.span_label(*closure_span,
- "borrowed data cannot outlive this closure");
- }
- err.emit();
- return Some(ErrorReported);
+ err.span_label(origin_sp,
+ "cannot infer an appropriate lifetime...");
+ err.span_label(*external_span,
+ "...so that variable is valid at time of its \
+ declaration");
+ err.span_label(*closure_span,
+ "borrowed data cannot outlive this closure");
}
- _ => {}
+ err.emit();
+ return Some(ErrorReported);
}
}
}
/// Print the error message for lifetime errors when the return type is a static impl Trait.
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
if let Some(ref error) = self.error {
- match error.clone() {
- RegionResolutionError::SubSupConflict(
+ if let RegionResolutionError::SubSupConflict(
var_origin,
sub_origin,
sub_r,
sup_origin,
sup_r,
- ) => {
- let anon_reg_sup = self.tcx.is_suitable_region(sup_r)?;
- if sub_r == &RegionKind::ReStatic &&
- self.tcx.return_type_impl_trait(anon_reg_sup.def_id).is_some()
- {
- let sp = var_origin.span();
- let return_sp = sub_origin.span();
- let mut err = self.tcx.sess.struct_span_err(
- sp,
- "cannot infer an appropriate lifetime",
+ ) = error.clone()
+ {
+ let anon_reg_sup = self.tcx.is_suitable_region(sup_r)?;
+ if sub_r == &RegionKind::ReStatic &&
+ self.tcx.return_type_impl_trait(anon_reg_sup.def_id).is_some()
+ {
+ let sp = var_origin.span();
+ let return_sp = sub_origin.span();
+ let mut err = self.tcx.sess.struct_span_err(
+ sp,
+ "cannot infer an appropriate lifetime",
+ );
+ err.span_label(
+ return_sp,
+ "this return type evaluates to the `'static` lifetime...",
+ );
+ err.span_label(
+ sup_origin.span(),
+ "...but this borrow...",
+ );
+
+ let (lifetime, lt_sp_opt) = self.tcx.msg_span_from_free_region(sup_r);
+ if let Some(lifetime_sp) = lt_sp_opt {
+ err.span_note(
+ lifetime_sp,
+ &format!("...can't outlive {}", lifetime),
);
- err.span_label(
+ }
+
+ let lifetime_name = match sup_r {
+ RegionKind::ReFree(FreeRegion {
+ bound_region: BoundRegion::BrNamed(_, ref name), ..
+ }) => name.to_string(),
+ _ => "'_".to_owned(),
+ };
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(return_sp) {
+ err.span_suggestion_with_applicability(
return_sp,
- "this return type evaluates to the `'static` lifetime...",
+ &format!(
+ "you can add a constraint to the return type to make it last \
+ less than `'static` and match {}",
+ lifetime,
+ ),
+ format!("{} + {}", snippet, lifetime_name),
+ Applicability::Unspecified,
);
- err.span_label(
- sup_origin.span(),
- "...but this borrow...",
- );
-
- let (lifetime, lt_sp_opt) = self.tcx.msg_span_from_free_region(sup_r);
- if let Some(lifetime_sp) = lt_sp_opt {
- err.span_note(
- lifetime_sp,
- &format!("...can't outlive {}", lifetime),
- );
- }
-
- let lifetime_name = match sup_r {
- RegionKind::ReFree(FreeRegion {
- bound_region: BoundRegion::BrNamed(_, ref name), ..
- }) => name.to_string(),
- _ => "'_".to_owned(),
- };
- if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(return_sp) {
- err.span_suggestion_with_applicability(
- return_sp,
- &format!(
- "you can add a constraint to the return type to make it last \
- less than `'static` and match {}",
- lifetime,
- ),
- format!("{} + {}", snippet, lifetime_name),
- Applicability::Unspecified,
- );
- }
- err.emit();
- return Some(ErrorReported);
}
+ err.emit();
+ return Some(ErrorReported);
}
- _ => {}
}
}
None
decl: &hir::FnDecl,
) -> Option<Span> {
let ret_ty = self.tcx.type_of(scope_def_id);
- match ret_ty.sty {
- ty::FnDef(_, _) => {
- let sig = ret_ty.fn_sig(self.tcx);
- let late_bound_regions = self.tcx
- .collect_referenced_late_bound_regions(&sig.output());
- if late_bound_regions.iter().any(|r| *r == br) {
- return Some(decl.output.span());
- }
+ if let ty::FnDef(_, _) = ret_ty.sty {
+ let sig = ret_ty.fn_sig(self.tcx);
+ let late_bound_regions = self.tcx
+ .collect_referenced_late_bound_regions(&sig.output());
+ if late_bound_regions.iter().any(|r| *r == br) {
+ return Some(decl.output.span());
}
- _ => {}
}
None
}
pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: DefId) -> bool {
is_first
&& self.tcx
- .opt_associated_item(scope_def_id)
- .map(|i| i.method_has_self_argument) == Some(true)
+ .opt_associated_item(scope_def_id)
+ .map(|i| i.method_has_self_argument) == Some(true)
}
}
}
};
- match dump_region_data_to(region_rels, ®ion_data.constraints, &output_path) {
- Ok(()) => {}
- Err(e) => {
- let msg = format!("io error dumping region constraints: {}", e);
- tcx.sess.err(&msg)
- }
+ if let Err(e) = dump_region_data_to(region_rels, ®ion_data.constraints, &output_path) {
+ let msg = format!("io error dumping region constraints: {}", e);
+ tcx.sess.err(&msg)
}
}
None => bug!("no node_id found for node: {:?}", n),
};
let name = || format!("node_{}", node_id);
- match dot::Id::new(name()) {
- Ok(id) => id,
- Err(_) => {
- bug!("failed to create graphviz node identified by {}", name());
- }
- }
+
+ dot::Id::new(name()).unwrap_or_else(|_|
+ bug!("failed to create graphviz node identified by {}", name()))
}
fn node_label(&self, n: &Node) -> dot::LabelText<'_> {
match *n {
match *e {
Edge::Constraint(ref c) =>
dot::LabelText::label(format!("{:?}", self.map.get(c).unwrap())),
- Edge::EnclScope(..) => dot::LabelText::label("(enclosed)".to_string()),
+ Edge::EnclScope(..) => dot::LabelText::label("(enclosed)".to_owned()),
}
}
}
fn construct_var_data(&self, tcx: TyCtxt<'_, '_, 'tcx>) -> LexicalRegionResolutions<'tcx> {
LexicalRegionResolutions {
error_region: tcx.types.re_static,
- values: (0..self.num_vars())
- .map(|_| VarValue::Value(tcx.types.re_empty))
- .collect(),
+ values: IndexVec::from_elem_n(VarValue::Value(tcx.types.re_empty), self.num_vars())
}
}
);
debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
+ self.obligations.reserve(bounds.predicates.len());
for predicate in bounds.predicates {
// Change the predicate to refer to the type variable,
// which will be the concrete type instead of the opaque type.
assert!(self.undo_log[snapshot.length] == OpenSnapshot);
if snapshot.length == 0 {
- self.undo_log.truncate(0);
+ self.undo_log.clear();
} else {
(*self.undo_log)[snapshot.length] = CommitedSnapshot;
}
debug!("RegionConstraintCollector: add_verify({:?})", verify);
// skip no-op cases known to be satisfied
- match verify.bound {
- VerifyBound::AllBounds(ref bs) if bs.len() == 0 => {
+ if let VerifyBound::AllBounds(ref bs) = verify.bound {
+ if bs.len() == 0 {
return;
}
- _ => {}
}
let index = self.data.verifys.len();
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if !t.needs_infer() && !ty::keep_local(&t) {
t // micro-optimize -- if there is nothing in this type that this fold affects...
- // ^ we need to have the `keep_local` check to un-default
- // defaulted tuples.
+ // ^ we need to have the `keep_local` check to un-default
+ // defaulted tuples.
} else {
let t = self.infcx.shallow_resolve(t);
match t.sty {
pub fn rollback_to(&mut self, s: Snapshot<'tcx>) {
debug!("rollback_to{:?}", {
for action in self.values.actions_since_snapshot(&s.snapshot) {
- match *action {
- sv::UndoLog::NewElem(index) => {
- debug!("inference variable _#{}t popped", index)
- }
- _ => { }
+ if let sv::UndoLog::NewElem(index) = *action {
+ debug!("inference variable _#{}t popped", index)
}
}
});
(UnpackedKind::Type(a_ty), UnpackedKind::Type(b_ty)) => {
Ok(relation.relate(&a_ty, &b_ty)?.into())
}
- (UnpackedKind::Lifetime(_), _) | (UnpackedKind::Type(_), _) => bug!()
+ (UnpackedKind::Lifetime(unpacked), x) => {
+ bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
+ }
+ (UnpackedKind::Type(unpacked), x) => {
+ bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
+ }
}
}
}
.out_dir(&native.out_dir)
.build_target(&target)
.build();
+ native.fixup_sanitizer_lib_name("asan");
}
println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
}
}
}
- /// Attempt to enqueue `element` in the work queue. Returns false if it was already present.
+ /// Attempt to pop an element from the work queue.
#[inline]
pub fn pop(&mut self) -> Option<T> {
if let Some(element) = self.deque.pop_front() {
// parser issue where a struct literal is being used on an expression
// where a brace being opened means a block is being started. Look
// ahead for the next text to see if `span` is followed by a `{`.
- let cm = this.session.source_map();
+ let sm = this.session.source_map();
let mut sp = span;
loop {
- sp = cm.next_point(sp);
- match cm.span_to_snippet(sp) {
+ sp = sm.next_point(sp);
+ match sm.span_to_snippet(sp) {
Ok(ref snippet) => {
if snippet.chars().any(|c| { !c.is_whitespace() }) {
break;
_ => break,
}
}
- let followed_by_brace = match cm.span_to_snippet(sp) {
+ let followed_by_brace = match sm.span_to_snippet(sp) {
Ok(ref snippet) if snippet == "{" => true,
_ => false,
};
- if let (PathSource::Expr(None), true) = (source, followed_by_brace) {
- err.span_label(
- span,
- format!("did you mean `({} {{ /* fields */ }})`?", path_str),
- );
- } else {
- err.span_label(
- span,
- format!("did you mean `{} {{ /* fields */ }}`?", path_str),
- );
+ match source {
+ PathSource::Expr(Some(parent)) => {
+ match parent.node {
+ ExprKind::MethodCall(ref path_assignment, _) => {
+ err.span_suggestion_with_applicability(
+ sm.start_point(parent.span)
+ .to(path_assignment.ident.span),
+ "use `::` to access an associated function",
+ format!("{}::{}",
+ path_str,
+ path_assignment.ident),
+ Applicability::MaybeIncorrect
+ );
+ return (err, candidates);
+ },
+ _ => {
+ err.span_label(
+ span,
+ format!("did you mean `{} {{ /* fields */ }}`?",
+ path_str),
+ );
+ return (err, candidates);
+ },
+ }
+ },
+ PathSource::Expr(None) if followed_by_brace == true => {
+ err.span_label(
+ span,
+ format!("did you mean `({} {{ /* fields */ }})`?",
+ path_str),
+ );
+ return (err, candidates);
+ },
+ _ => {
+ err.span_label(
+ span,
+ format!("did you mean `{} {{ /* fields */ }}`?",
+ path_str),
+ );
+ return (err, candidates);
+ },
}
}
return (err, candidates);
.out_dir(&native.out_dir)
.build_target(&target)
.build();
+ native.fixup_sanitizer_lib_name("tsan");
}
println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
}
if extern_crate.warn_if_unused {
if let Some(&span) = unused_extern_crates.get(&extern_crate.def_id) {
let msg = "unused extern crate";
+
+ // Removal suggestion span needs to include attributes (Issue #54400)
+ let span_with_attrs = tcx.get_attrs(extern_crate.def_id).iter()
+ .map(|attr| attr.span)
+ .fold(span, |acc, attr_span| acc.to(attr_span));
+
tcx.struct_span_lint_node(lint, id, span, msg)
.span_suggestion_short_with_applicability(
- span,
+ span_with_attrs,
"remove it",
String::new(),
Applicability::MachineApplicable)
|
LL | const FOO: impl Copy = 42;
| ^^^^^^^^^
+ |
+ = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> $DIR/feature-gate-impl_trait_in_bindings.rs:13:13
|
LL | static BAR: impl Copy = 42;
| ^^^^^^^^^
+ |
+ = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable
error: aborting due to 3 previous errors
|
LL | let _in_local_variable: impl Fn() = || {};
| ^^^^^^^^^
+ |
+ = help: add #![feature(impl_trait_in_bindings)] to the crate attributes to enable
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> $DIR/where-allowed.rs:232:46
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let _ = String.new();
+}
--- /dev/null
+error[E0423]: expected value, found struct `String`
+ --> $DIR/issue-22692.rs:12:13
+ |
+LL | let _ = String.new();
+ | ^^^^^^----
+ | |
+ | help: use `::` to access an associated function: `String::new`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0423`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:edition-lint-paths.rs
+// run-rustfix
+// compile-flags:--extern edition_lint_paths --cfg blandiloquence
+// edition:2018
+
+#![deny(rust_2018_idioms)]
+#![allow(dead_code)]
+
+// The suggestion span should include the attribute.
+
+
+//~^ ERROR unused extern crate
+
+fn main() {}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:edition-lint-paths.rs
+// run-rustfix
+// compile-flags:--extern edition_lint_paths --cfg blandiloquence
+// edition:2018
+
+#![deny(rust_2018_idioms)]
+#![allow(dead_code)]
+
+// The suggestion span should include the attribute.
+
+#[cfg(blandiloquence)] //~ HELP remove it
+extern crate edition_lint_paths;
+//~^ ERROR unused extern crate
+
+fn main() {}
--- /dev/null
+error: unused extern crate
+ --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:22:1
+ |
+LL | / #[cfg(blandiloquence)] //~ HELP remove it
+LL | | extern crate edition_lint_paths;
+ | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+ | |________________________________|
+ | help: remove it
+ |
+note: lint level defined here
+ --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:16:9
+ |
+LL | #![deny(rust_2018_idioms)]
+ | ^^^^^^^^^^^^^^^^
+ = note: #[deny(unused_extern_crates)] implied by #[deny(rust_2018_idioms)]
+
+error: aborting due to previous error
+
-Subproject commit 130d803b3243a92f5c2d9230935cba7fa88e263e
+Subproject commit e8f6973e2d40ab39e30cdbe0cf8e77a72c867d4f