about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-08-22 20:23:37 +0000
committerbors <bors@rust-lang.org>2021-08-22 20:23:37 +0000
commitaf140757b4cb1a60d107c690720311ba8e06e7de (patch)
tree061b9cd2842ef1ef966322cff231d92fac26e3c3
parent91f9806208834de3fb5f62712356b0d84ec388fd (diff)
parent3e8e8d2dad6181f58e78c14b9dd19c267ad602c0 (diff)
downloadrust-af140757b4cb1a60d107c690720311ba8e06e7de.tar.gz
rust-af140757b4cb1a60d107c690720311ba8e06e7de.zip
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
-rw-r--r--compiler/rustc_lint/src/traits.rs36
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp15
-rw-r--r--compiler/rustc_middle/src/middle/region.rs2
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs3
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs4
-rw-r--r--compiler/rustc_resolve/src/imports.rs11
-rw-r--r--compiler/rustc_resolve/src/late.rs4
-rw-r--r--compiler/rustc_resolve/src/lib.rs11
-rw-r--r--compiler/rustc_resolve/src/macros.rs2
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios.rs9
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs5
-rw-r--r--compiler/rustc_typeck/src/check/check.rs27
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs12
-rw-r--r--src/test/ui/drop-bounds/drop-bounds.stderr14
-rw-r--r--src/test/ui/enum/enum-discrim-autosizing.rs6
-rw-r--r--src/test/ui/enum/enum-discrim-autosizing.stderr2
-rw-r--r--src/test/ui/error-codes/E0081.rs11
-rw-r--r--src/test/ui/error-codes/E0081.stderr14
-rw-r--r--src/test/ui/macros/issue-88228.rs22
-rw-r--r--src/test/ui/macros/issue-88228.stderr26
-rw-r--r--src/test/ui/proc-macro/derive-helper-shadowing.stderr4
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
24 files changed, 180 insertions, 66 deletions
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 2c039b6d05d..edb158dd378 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -18,23 +18,27 @@ declare_lint! {
     ///
     /// ### 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 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
                         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)
                     );
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index f563870e3e0..b3f86f3295a 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -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
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index f44267a404b..ffa26b9f299 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -189,7 +189,7 @@ impl Scope {
                 // 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());
                 }
             }
         }
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 9f4f2b82f60..760b7469961 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -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) {
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 0a5da653fab..3cf04268756 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -950,9 +950,7 @@ impl<'a> Resolver<'a> {
         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) {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index acfa389fed5..dfb6d89a0d1 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -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 @@ impl<'a> Resolver<'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 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 }
             } 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 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         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 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                                 {
                                     this.record_use(
                                         ident,
-                                        ns,
                                         target_binding,
                                         import.module_path.is_empty(),
                                     );
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 00d291946df..0b552aa07f5 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1738,7 +1738,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 // 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 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             ) 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)
             }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 7114fd33188..465007507da 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -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 @@ impl<'a> Resolver<'a> {
     fn record_use(
         &mut self,
         ident: Ident,
-        ns: Namespace,
         used_binding: &'a NameBinding<'a>,
         is_lexical_scope: bool,
     ) {
@@ -1684,9 +1683,9 @@ impl<'a> Resolver<'a> {
             }
             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 @@ impl<'a> Resolver<'a> {
         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 @@ impl<'a> Resolver<'a> {
         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 });
     }
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index b2a8aa0cecc..7f86f891c44 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -1090,7 +1090,7 @@ impl<'a> Resolver<'a> {
             ) {
                 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();
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
index e5805d9e691..6468419fce7 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
@@ -2,8 +2,15 @@ use super::apple_sdk_base::{opts, Arch};
 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(),
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 0c8a89210ff..cff0b3651e1 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -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)
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 8eb51b977ed..aae9518ad51 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -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,
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 316a097556a..8d5bf98be99 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -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
diff --git a/src/test/ui/drop-bounds/drop-bounds.stderr b/src/test/ui/drop-bounds/drop-bounds.stderr
index 15ba4c9a649..3ffb855a55d 100644
--- a/src/test/ui/drop-bounds/drop-bounds.stderr
+++ b/src/test/ui/drop-bounds/drop-bounds.stderr
@@ -1,4 +1,4 @@
-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 {
diff --git a/src/test/ui/enum/enum-discrim-autosizing.rs b/src/test/ui/enum/enum-discrim-autosizing.rs
index e9bb9275971..473a0ad6f7a 100644
--- a/src/test/ui/enum/enum-discrim-autosizing.rs
+++ b/src/test/ui/enum/enum-discrim-autosizing.rs
@@ -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() {}
diff --git a/src/test/ui/enum/enum-discrim-autosizing.stderr b/src/test/ui/enum/enum-discrim-autosizing.stderr
index 8848f984cfb..a0f39098a2e 100644
--- a/src/test/ui/enum/enum-discrim-autosizing.stderr
+++ b/src/test/ui/enum/enum-discrim-autosizing.stderr
@@ -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
 
diff --git a/src/test/ui/error-codes/E0081.rs b/src/test/ui/error-codes/E0081.rs
index 33c8c14306b..255e05ced19 100644
--- a/src/test/ui/error-codes/E0081.rs
+++ b/src/test/ui/error-codes/E0081.rs
@@ -1,9 +1,20 @@
 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() {
 }
diff --git a/src/test/ui/error-codes/E0081.stderr b/src/test/ui/error-codes/E0081.stderr
index 0b3d351e1ac..9b279bb0214 100644
--- a/src/test/ui/error-codes/E0081.stderr
+++ b/src/test/ui/error-codes/E0081.stderr
@@ -1,11 +1,21 @@
 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`.
diff --git a/src/test/ui/macros/issue-88228.rs b/src/test/ui/macros/issue-88228.rs
new file mode 100644
index 00000000000..615b865e9f1
--- /dev/null
+++ b/src/test/ui/macros/issue-88228.rs
@@ -0,0 +1,22 @@
+// 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
+}
diff --git a/src/test/ui/macros/issue-88228.stderr b/src/test/ui/macros/issue-88228.stderr
new file mode 100644
index 00000000000..b164e39064c
--- /dev/null
+++ b/src/test/ui/macros/issue-88228.stderr
@@ -0,0 +1,26 @@
+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
+
diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.stderr b/src/test/ui/proc-macro/derive-helper-shadowing.stderr
index 4115fec86fb..3b160935a2f 100644
--- a/src/test/ui/proc-macro/derive-helper-shadowing.stderr
+++ b/src/test/ui/proc-macro/derive-helper-shadowing.stderr
@@ -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)
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index ee675838c4c..db0f412f2a1 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -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))
                 }
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 4553ac704a2..85d1f65c51f 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -299,7 +299,7 @@ impl EarlyLintPass for Write {
                     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(
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 7d7c3b8846c..2777e5bd0c4 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -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.