提交 af140757 编写于 作者: B bors

Auto merge of #88240 - GuillaumeGomez:rollup-wdom91m, r=GuillaumeGomez

Rollup of 7 pull requests

Successful merges:

 - #86747 (Improve wording of the `drop_bounds` lint)
 - #87166 (Show discriminant before overflow in diagnostic for duplicate values.)
 - #88077 (Generate an iOS LLVM target with a specific version)
 - #88164 (PassWrapper: adapt for LLVM 14 changes)
 - #88211 (cleanup: `Span::new` -> `Span::with_lo`)
 - #88229 (Suggest importing the right kind of macro.)
 - #88238 (Stop tracking namespace in used_imports.)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
......@@ -18,23 +18,27 @@
///
/// ### Explanation
///
/// `Drop` bounds do not really accomplish anything. A type may have
/// compiler-generated drop glue without implementing the `Drop` trait
/// itself. The `Drop` trait also only has one method, `Drop::drop`, and
/// that function is by fiat not callable in user code. So there is really
/// no use case for using `Drop` in trait bounds.
/// A generic trait bound of the form `T: Drop` is most likely misleading
/// and not what the programmer intended (they probably should have used
/// `std::mem::needs_drop` instead).
///
/// The most likely use case of a drop bound is to distinguish between
/// types that have destructors and types that don't. Combined with
/// specialization, a naive coder would write an implementation that
/// assumed a type could be trivially dropped, then write a specialization
/// for `T: Drop` that actually calls the destructor. Except that doing so
/// is not correct; String, for example, doesn't actually implement Drop,
/// but because String contains a Vec, assuming it can be trivially dropped
/// will leak memory.
/// `Drop` bounds do not actually indicate whether a type can be trivially
/// dropped or not, because a composite type containing `Drop` types does
/// not necessarily implement `Drop` itself. Naïvely, one might be tempted
/// to write an implementation that assumes that a type can be trivially
/// dropped while also supplying a specialization for `T: Drop` that
/// actually calls the destructor. However, this breaks down e.g. when `T`
/// is `String`, which does not implement `Drop` itself but contains a
/// `Vec`, which does implement `Drop`, so assuming `T` can be trivially
/// dropped would lead to a memory leak here.
///
/// Furthermore, the `Drop` trait only contains one method, `Drop::drop`,
/// which may not be called explicitly in user code (`E0040`), so there is
/// really no use case for using `Drop` in trait bounds, save perhaps for
/// some obscure corner cases, which can use `#[allow(drop_bounds)]`.
pub DROP_BOUNDS,
Warn,
"bounds of the form `T: Drop` are useless"
"bounds of the form `T: Drop` are most likely incorrect"
}
declare_lint! {
......@@ -102,8 +106,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
None => return,
};
let msg = format!(
"bounds on `{}` are useless, consider instead \
using `{}` to detect if a type has a destructor",
"bounds on `{}` are most likely incorrect, consider instead \
using `{}` to detect whether a type can be trivially dropped",
predicate,
cx.tcx.def_path_str(needs_drop)
);
......
......@@ -922,9 +922,17 @@ LLVMRustOptimizeWithNewPassManager(
MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
MPM.addPass(ModuleAddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
#if LLVM_VERSION_GE(14, 0)
AddressSanitizerOptions opts(/*CompileKernel=*/false,
SanitizerOptions->SanitizeAddressRecover,
/*UseAfterScope=*/true,
AsanDetectStackUseAfterReturnMode::Runtime);
MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(opts)));
#else
MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
/*UseAfterScope=*/true)));
#endif
}
);
#else
......@@ -952,8 +960,15 @@ LLVMRustOptimizeWithNewPassManager(
#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
#if LLVM_VERSION_GE(14, 0)
HWAddressSanitizerOptions opts(
/*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover,
/*DisableOptimization=*/false);
MPM.addPass(HWAddressSanitizerPass(opts));
#else
MPM.addPass(HWAddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
#endif
}
);
#else
......
......@@ -189,7 +189,7 @@ pub fn span(&self, tcx: TyCtxt<'_>, scope_tree: &ScopeTree) -> Span {
// To avoid issues with macro-generated spans, the span
// of the statement must be nested in that of the block.
if span.lo() <= stmt_span.lo() && stmt_span.lo() <= span.hi() {
return Span::new(stmt_span.lo(), span.hi(), span.ctxt());
return span.with_lo(stmt_span.lo());
}
}
}
......
......@@ -63,8 +63,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
// We have information about whether `use` (import) items are actually
// used now. If an import is not used at all, we signal a lint error.
fn check_import(&mut self, id: ast::NodeId) {
let mut used = false;
self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
let used = self.r.used_imports.contains(&id);
let def_id = self.r.local_def_id(id);
if !used {
if self.r.maybe_unused_trait_imports.contains(&def_id) {
......
......@@ -950,9 +950,7 @@ fn lookup_import_candidates_from_module<FilterFn>(
self.add_typo_suggestion(err, suggestion, ident.span);
let import_suggestions =
self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, |res| {
matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _))
});
self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
show_candidates(err, None, &import_suggestions, false, true);
if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
......
......@@ -303,7 +303,7 @@ impl<'a> Resolver<'a> {
if self.last_import_segment && check_usable(self, binding).is_err() {
Err((Determined, Weak::No))
} else {
self.record_use(ident, ns, binding, restricted_shadowing);
self.record_use(ident, binding, restricted_shadowing);
if let Some(shadowed_glob) = resolution.shadowed_glob {
// Forbid expanded shadowing to avoid time travel.
......@@ -609,9 +609,9 @@ fn import_dummy_binding(&mut self, import: &'a Import<'a>) {
self.per_ns(|this, ns| {
let key = this.new_key(target, ns);
let _ = this.try_define(import.parent_scope.module, key, dummy_binding);
// Consider erroneous imports used to avoid duplicate diagnostics.
this.record_use(target, ns, dummy_binding, false);
});
// Consider erroneous imports used to avoid duplicate diagnostics.
self.record_use(target, dummy_binding, false);
}
}
}
......@@ -709,7 +709,7 @@ pub fn finalize_imports(&mut self) {
}
} else if is_indeterminate {
// Consider erroneous imports used to avoid duplicate diagnostics.
self.r.used_imports.insert((import.id, TypeNS));
self.r.used_imports.insert(import.id);
let path = import_path_to_string(
&import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
&import.kind,
......@@ -902,7 +902,7 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
import.vis.set(orig_vis);
if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res {
// Consider erroneous imports used to avoid duplicate diagnostics.
self.r.used_imports.insert((import.id, TypeNS));
self.r.used_imports.insert(import.id);
}
let module = match path_res {
PathResult::Module(module) => {
......@@ -1043,7 +1043,6 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
{
this.record_use(
ident,
ns,
target_binding,
import.module_path.is_empty(),
);
......
......@@ -1738,7 +1738,7 @@ fn try_resolve_as_non_binding(
// whether they can be shadowed by fresh bindings or not, so force an error.
// issues/33118#issuecomment-233962221 (see below) still applies here,
// but we have to ignore it for backward compatibility.
self.r.record_use(ident, ValueNS, binding, false);
self.r.record_use(ident, binding, false);
return None;
}
LexicalScopeBinding::Item(binding) => (binding.res(), Some(binding)),
......@@ -1753,7 +1753,7 @@ fn try_resolve_as_non_binding(
) if is_syntactic_ambiguity => {
// Disambiguate in favor of a unit struct/variant or constant pattern.
if let Some(binding) = binding {
self.r.record_use(ident, ValueNS, binding, false);
self.r.record_use(ident, binding, false);
}
Some(res)
}
......
......@@ -942,7 +942,7 @@ pub struct Resolver<'a> {
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
/// Visibilities in "lowered" form, for all entities that have them.
visibilities: FxHashMap<LocalDefId, ty::Visibility>,
used_imports: FxHashSet<(NodeId, Namespace)>,
used_imports: FxHashSet<NodeId>,
maybe_unused_trait_imports: FxHashSet<LocalDefId>,
maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
......@@ -1656,7 +1656,6 @@ fn resolution(
fn record_use(
&mut self,
ident: Ident,
ns: Namespace,
used_binding: &'a NameBinding<'a>,
is_lexical_scope: bool,
) {
......@@ -1684,9 +1683,9 @@ fn record_use(
}
used.set(true);
import.used.set(true);
self.used_imports.insert((import.id, ns));
self.used_imports.insert(import.id);
self.add_to_glob_map(&import, ident);
self.record_use(ident, ns, binding, false);
self.record_use(ident, binding, false);
}
}
......@@ -3241,7 +3240,7 @@ fn extern_prelude_get(
self.extern_prelude.get(&ident.normalize_to_macros_2_0()).cloned().and_then(|entry| {
if let Some(binding) = entry.extern_crate_item {
if !speculative && entry.introduced_by_item {
self.record_use(ident, TypeNS, binding, false);
self.record_use(ident, binding, false);
}
Some(binding)
} else {
......@@ -3428,7 +3427,7 @@ fn resolve_main(&mut self) {
let is_import = name_binding.is_import();
let span = name_binding.span;
if let Res::Def(DefKind::Fn, _) = res {
self.record_use(ident, ValueNS, name_binding, false);
self.record_use(ident, name_binding, false);
}
self.main_def = Some(MainDefinition { res, is_import, span });
}
......
......@@ -1090,7 +1090,7 @@ struct Flags: u8 {
) {
Ok(binding) => {
let initial_res = initial_binding.map(|initial_binding| {
self.record_use(ident, MacroNS, initial_binding, false);
self.record_use(ident, initial_binding, false);
initial_binding.res()
});
let res = binding.res();
......
......@@ -2,8 +2,15 @@
use crate::spec::{FramePointer, Target, TargetOptions};
pub fn target() -> Target {
// Clang automatically chooses a more specific target based on
// IPHONEOS_DEPLOYMENT_TARGET.
// This is required for the target to pick the right
// MACH-O commands, so we do too.
let arch = "arm64";
let llvm_target = super::apple_base::ios_llvm_target(arch);
Target {
llvm_target: "arm64-apple-ios".to_string(),
llvm_target,
pointer_width: 64,
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
arch: "aarch64".to_string(),
......
......@@ -91,6 +91,11 @@ fn ios_deployment_target() -> (u32, u32) {
deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
}
pub fn ios_llvm_target(arch: &str) -> String {
let (major, minor) = ios_deployment_target();
format!("{}-apple-ios{}.{}.0", arch, major, minor)
}
pub fn ios_sim_llvm_target(arch: &str) -> String {
let (major, minor) = ios_deployment_target();
format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
......
......@@ -1413,15 +1413,17 @@ fn check_enum<'tcx>(
Some(ref expr) => tcx.hir().span(expr.hir_id),
None => v.span,
};
let display_discr = display_discriminant_value(tcx, v, discr.val);
let display_discr_i = display_discriminant_value(tcx, variant_i, disr_vals[i].val);
struct_span_err!(
tcx.sess,
span,
E0081,
"discriminant value `{}` already exists",
disr_vals[i]
discr.val,
)
.span_label(i_span, format!("first use of `{}`", disr_vals[i]))
.span_label(span, format!("enum already has `{}`", disr_vals[i]))
.span_label(i_span, format!("first use of {}", display_discr_i))
.span_label(span, format!("enum already has {}", display_discr))
.emit();
}
disr_vals.push(discr);
......@@ -1431,6 +1433,25 @@ fn check_enum<'tcx>(
check_transparent(tcx, sp, def);
}
/// Format an enum discriminant value for use in a diagnostic message.
fn display_discriminant_value<'tcx>(
tcx: TyCtxt<'tcx>,
variant: &hir::Variant<'_>,
evaluated: u128,
) -> String {
if let Some(expr) = &variant.disr_expr {
let body = &tcx.hir().body(expr.body).value;
if let hir::ExprKind::Lit(lit) = &body.kind {
if let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node {
if evaluated != *lit_value {
return format!("`{}` (overflowed from `{}`)", evaluated, lit_value);
}
}
}
}
format!("`{}`", evaluated)
}
pub(super) fn check_type_params_are_used<'tcx>(
tcx: TyCtxt<'tcx>,
generics: &ty::Generics,
......
......@@ -708,11 +708,7 @@ fn compare_number_of_method_arguments<'tcx>(
Some(if pos == 0 {
arg.span
} else {
Span::new(
trait_m_sig.decl.inputs[0].span.lo(),
arg.span.hi(),
arg.span.ctxt(),
)
arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
})
} else {
trait_item_span
......@@ -731,11 +727,7 @@ fn compare_number_of_method_arguments<'tcx>(
if pos == 0 {
arg.span
} else {
Span::new(
impl_m_sig.decl.inputs[0].span.lo(),
arg.span.hi(),
arg.span.ctxt(),
)
arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
}
} else {
impl_m_span
......
error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
error: bounds on `T: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
--> $DIR/drop-bounds.rs:2:11
|
LL | fn foo<T: Drop>() {}
......@@ -10,37 +10,37 @@ note: the lint level is defined here
LL | #![deny(drop_bounds)]
| ^^^^^^^^^^^
error: bounds on `U: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
error: bounds on `U: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
--> $DIR/drop-bounds.rs:5:8
|
LL | U: Drop,
| ^^^^
error: bounds on `impl Drop: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
error: bounds on `impl Drop: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
--> $DIR/drop-bounds.rs:8:17
|
LL | fn baz(_x: impl Drop) {}
| ^^^^
error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
error: bounds on `T: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
--> $DIR/drop-bounds.rs:9:15
|
LL | struct Foo<T: Drop> {
| ^^^^
error: bounds on `U: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
error: bounds on `U: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
--> $DIR/drop-bounds.rs:12:24
|
LL | struct Bar<U> where U: Drop {
| ^^^^
error: bounds on `Self: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
error: bounds on `Self: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
--> $DIR/drop-bounds.rs:15:12
|
LL | trait Baz: Drop {
| ^^^^
error: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
error: bounds on `T: Drop` are most likely incorrect, consider instead using `std::mem::needs_drop` to detect whether a type can be trivially dropped
--> $DIR/drop-bounds.rs:17:9
|
LL | impl<T: Drop> Baz for T {
......
......@@ -4,8 +4,10 @@
// so force the repr.
#[cfg_attr(not(target_pointer_width = "32"), repr(i32))]
enum Eu64 {
Au64 = 0,
Bu64 = 0x8000_0000_0000_0000 //~ERROR already exists
Au64 = 0, //~NOTE first use of `0`
Bu64 = 0x8000_0000_0000_0000
//~^ ERROR discriminant value `0` already exists
//~| NOTE enum already has `0` (overflowed from `9223372036854775808`)
}
fn main() {}
......@@ -4,7 +4,7 @@ error[E0081]: discriminant value `0` already exists
LL | Au64 = 0,
| - first use of `0`
LL | Bu64 = 0x8000_0000_0000_0000
| ^^^^^^^^^^^^^^^^^^^^^ enum already has `0`
| ^^^^^^^^^^^^^^^^^^^^^ enum already has `0` (overflowed from `9223372036854775808`)
error: aborting due to previous error
......
enum Enum {
P = 3,
//~^ NOTE first use of `3`
X = 3,
//~^ ERROR discriminant value `3` already exists
//~| NOTE enum already has `3`
Y = 5
}
#[repr(u8)]
enum EnumOverflowRepr {
P = 257,
//~^ NOTE first use of `1` (overflowed from `257`)
X = 513,
//~^ ERROR discriminant value `1` already exists
//~| NOTE enum already has `1` (overflowed from `513`)
}
fn main() {
}
error[E0081]: discriminant value `3` already exists
--> $DIR/E0081.rs:3:9
--> $DIR/E0081.rs:4:9
|
LL | P = 3,
| - first use of `3`
LL |
LL | X = 3,
| ^ enum already has `3`
error: aborting due to previous error
error[E0081]: discriminant value `1` already exists
--> $DIR/E0081.rs:14:9
|
LL | P = 257,
| --- first use of `1` (overflowed from `257`)
LL |
LL | X = 513,
| ^^^ enum already has `1` (overflowed from `513`)
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0081`.
// compile-flags: -Z deduplicate-diagnostics=yes
// edition:2018
mod hey {
pub use Copy as Bla;
pub use std::println as bla;
}
#[derive(Bla)]
//~^ ERROR cannot find derive macro `Bla`
//~| NOTE consider importing this derive macro
struct A;
#[derive(println)]
//~^ ERROR cannot find derive macro `println`
struct B;
fn main() {
bla!();
//~^ ERROR cannot find macro `bla`
//~| NOTE consider importing this macro
}
error: cannot find macro `bla` in this scope
--> $DIR/issue-88228.rs:19:5
|
LL | bla!();
| ^^^
|
= note: consider importing this macro:
crate::hey::bla
error: cannot find derive macro `println` in this scope
--> $DIR/issue-88228.rs:14:10
|
LL | #[derive(println)]
| ^^^^^^^
error: cannot find derive macro `Bla` in this scope
--> $DIR/issue-88228.rs:9:10
|
LL | #[derive(Bla)]
| ^^^
|
= note: consider importing this derive macro:
crate::hey::Bla
error: aborting due to 3 previous errors
......@@ -16,6 +16,8 @@ error: cannot find attribute `empty_helper` in this scope
LL | #[derive(GenHelperUse)]
| ^^^^^^^^^^^^
|
= note: consider importing this attribute macro:
empty_helper
= note: this error originates in the derive macro `GenHelperUse` (in Nightly builds, run with -Z macro-backtrace for more info)
error: cannot find attribute `empty_helper` in this scope
......@@ -27,6 +29,8 @@ LL | #[empty_helper]
LL | gen_helper_use!();
| ------------------ in this macro invocation
|
= note: consider importing this attribute macro:
crate::empty_helper
= note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0659]: `empty_helper` is ambiguous (name vs any other name during import resolution)
......
......@@ -127,7 +127,7 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa
then {
let data = stmt.span.data();
// Make a span out of the semicolon for the help message
Some((span, Some(Span::new(data.hi-BytePos(1), data.hi, data.ctxt))))
Some((span, Some(data.with_lo(data.hi-BytePos(1)))))
} else {
Some((span, None))
}
......
......@@ -299,7 +299,7 @@ fn is_build_script(cx: &EarlyContext<'_>) -> bool {
let nl_span = match (dest, only_nl) {
// Special case of `write!(buf, "\n")`: Mark everything from the end of
// `buf` for removal so no trailing comma [`writeln!(buf, )`] remains.
(Some(dest_expr), true) => Span::new(dest_expr.span.hi(), nl_span.hi(), nl_span.ctxt()),
(Some(dest_expr), true) => nl_span.with_lo(dest_expr.span.hi()),
_ => nl_span,
};
span_lint_and_then(
......
......@@ -881,7 +881,7 @@ fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap();
let line_no = source_map_and_line.line;
let line_start = source_map_and_line.sf.lines[line_no];
Span::new(line_start, span.hi(), span.ctxt())
span.with_lo(line_start)
}
/// Gets the parent node, if any.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册