about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-12-18 07:20:50 +0000
committerbors <bors@rust-lang.org>2021-12-18 07:20:50 +0000
commit208ced64db20bd947a2ba5c90f37936fd3ab352b (patch)
tree1aa23a0e304a1935b962258e3884fe6f86d00011 /compiler
parentdde825db464b08d6f572766579dfb629b837368c (diff)
parentfd445ddf96f11aadc01fd0d60bb92b419d7ffaa7 (diff)
downloadrust-208ced64db20bd947a2ba5c90f37936fd3ab352b.tar.gz
rust-208ced64db20bd947a2ba5c90f37936fd3ab352b.zip
Auto merge of #92059 - matthiaskrgr:rollup-bainfyh, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #87901 (Fix suggestion of additional `pub` when using `pub pub fn ...`)
 - #89090 (Lint bare traits in AstConv.)
 - #91818 (Show the unused type for `unused_results` lint)
 - #91910 (miri: lift restriction on extern types being the only field in a struct)
 - #91928 (Constify (most) `Option` methods)
 - #91975 (Move generator check earlier in inlining.)
 - #92016 (builtin_macros: allow external consumers for AsmArgs parsing)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs48
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs72
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs16
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs22
-rw-r--r--compiler/rustc_lint/src/context.rs10
-rw-r--r--compiler/rustc_lint/src/unused.rs4
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs21
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs14
-rw-r--r--compiler/rustc_parse/src/parser/item.rs112
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs8
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs77
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs58
13 files changed, 247 insertions, 216 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 0077dec889d..77738b2c5cc 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -46,7 +46,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{struct_span_err, Applicability};
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{DefId, DefPathHash, LocalDefId, CRATE_DEF_ID};
@@ -55,11 +55,9 @@ use rustc_hir::intravisit;
 use rustc_hir::{ConstArg, GenericArg, ParamName};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_query_system::ich::StableHashingContext;
-use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
-use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
+use rustc_session::lint::LintBuffer;
 use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
 use rustc_session::Session;
-use rustc_span::edition::Edition;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::source_map::{respan, DesugaringKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -1184,11 +1182,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     ) -> hir::Ty<'hir> {
         let id = self.lower_node_id(t.id);
         let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
-        let ty = self.ty_path(id, t.span, qpath);
-        if let hir::TyKind::TraitObject(..) = ty.kind {
-            self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
-        }
-        ty
+        self.ty_path(id, t.span, qpath)
     }
 
     fn ty(&mut self, span: Span, kind: hir::TyKind<'hir>) -> hir::Ty<'hir> {
@@ -1285,9 +1279,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
                     (bounds, lifetime_bound)
                 });
-                if kind != TraitObjectSyntax::Dyn {
-                    self.maybe_lint_bare_trait(t.span, t.id, false);
-                }
                 hir::TyKind::TraitObject(bounds, lifetime_bound, kind)
             }
             TyKind::ImplTrait(def_node_id, ref bounds) => {
@@ -2380,39 +2371,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             name: hir::LifetimeName::Implicit(missing),
         }
     }
-
-    fn maybe_lint_bare_trait(&mut self, span: Span, id: NodeId, is_global: bool) {
-        // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
-        // call site which do not have a macro backtrace. See #61963.
-        let is_macro_callsite = self
-            .sess
-            .source_map()
-            .span_to_snippet(span)
-            .map(|snippet| snippet.starts_with("#["))
-            .unwrap_or(true);
-        if !is_macro_callsite {
-            if span.edition() < Edition::Edition2021 {
-                self.resolver.lint_buffer().buffer_lint_with_diagnostic(
-                    BARE_TRAIT_OBJECTS,
-                    id,
-                    span,
-                    "trait objects without an explicit `dyn` are deprecated",
-                    BuiltinLintDiagnostics::BareTraitObject(span, is_global),
-                )
-            } else {
-                let msg = "trait objects must include the `dyn` keyword";
-                let label = "add `dyn` keyword before this trait";
-                let mut err = struct_span_err!(self.sess, span, E0782, "{}", msg,);
-                err.span_suggestion_verbose(
-                    span.shrink_to_lo(),
-                    label,
-                    String::from("dyn "),
-                    Applicability::MachineApplicable,
-                );
-                err.emit();
-            }
-        }
-    }
 }
 
 /// Helper struct for delayed construction of GenericArgs.
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index d67d872b884..768cb99510f 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -8,13 +8,14 @@ use rustc_expand::base::{self, *};
 use rustc_parse::parser::Parser;
 use rustc_parse_format as parse;
 use rustc_session::lint;
+use rustc_session::parse::ParseSess;
 use rustc_span::symbol::Ident;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{InnerSpan, Span};
 use rustc_target::asm::InlineAsmArch;
 use smallvec::smallvec;
 
-struct AsmArgs {
+pub struct AsmArgs {
     templates: Vec<P<ast::Expr>>,
     operands: Vec<(ast::InlineAsmOperand, Span)>,
     named_args: FxHashMap<Symbol, usize>,
@@ -31,15 +32,28 @@ fn parse_args<'a>(
     is_global_asm: bool,
 ) -> Result<AsmArgs, DiagnosticBuilder<'a>> {
     let mut p = ecx.new_parser_from_tts(tts);
+    let sess = &ecx.sess.parse_sess;
+    parse_asm_args(&mut p, sess, sp, is_global_asm)
+}
+
+// Primarily public for rustfmt consumption.
+// Internal consumers should continue to leverage `expand_asm`/`expand__global_asm`
+pub fn parse_asm_args<'a>(
+    p: &mut Parser<'a>,
+    sess: &'a ParseSess,
+    sp: Span,
+    is_global_asm: bool,
+) -> Result<AsmArgs, DiagnosticBuilder<'a>> {
+    let diag = &sess.span_diagnostic;
 
     if p.token == token::Eof {
-        return Err(ecx.struct_span_err(sp, "requires at least a template string argument"));
+        return Err(diag.struct_span_err(sp, "requires at least a template string argument"));
     }
 
     // Detect use of the legacy llvm_asm! syntax (which used to be called asm!)
     if !is_global_asm && p.look_ahead(1, |t| *t == token::Colon || *t == token::ModSep) {
         let mut err =
-            ecx.struct_span_err(sp, "the legacy LLVM-style asm! syntax is no longer supported");
+            diag.struct_span_err(sp, "the legacy LLVM-style asm! syntax is no longer supported");
         err.note("consider migrating to the new asm! syntax specified in RFC 2873");
         err.note("alternatively, switch to llvm_asm! to keep your code working as it is");
         return Err(err);
@@ -61,7 +75,7 @@ fn parse_args<'a>(
         if !p.eat(&token::Comma) {
             if allow_templates {
                 // After a template string, we always expect *only* a comma...
-                let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
+                let mut err = diag.struct_span_err(p.token.span, "expected token: `,`");
                 err.span_label(p.token.span, "expected `,`");
                 p.maybe_annotate_with_ascription(&mut err, false);
                 return Err(err);
@@ -76,14 +90,14 @@ fn parse_args<'a>(
 
         // Parse clobber_abi
         if p.eat_keyword(sym::clobber_abi) {
-            parse_clobber_abi(&mut p, &mut args)?;
+            parse_clobber_abi(p, &mut args)?;
             allow_templates = false;
             continue;
         }
 
         // Parse options
         if p.eat_keyword(sym::options) {
-            parse_options(&mut p, &mut args, is_global_asm)?;
+            parse_options(p, &mut args, is_global_asm)?;
             allow_templates = false;
             continue;
         }
@@ -103,25 +117,25 @@ fn parse_args<'a>(
 
         let mut explicit_reg = false;
         let op = if !is_global_asm && p.eat_keyword(kw::In) {
-            let reg = parse_reg(&mut p, &mut explicit_reg)?;
+            let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
-                let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+                let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
                 return Err(err);
             }
             let expr = p.parse_expr()?;
             ast::InlineAsmOperand::In { reg, expr }
         } else if !is_global_asm && p.eat_keyword(sym::out) {
-            let reg = parse_reg(&mut p, &mut explicit_reg)?;
+            let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: false }
         } else if !is_global_asm && p.eat_keyword(sym::lateout) {
-            let reg = parse_reg(&mut p, &mut explicit_reg)?;
+            let reg = parse_reg(p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: true }
         } else if !is_global_asm && p.eat_keyword(sym::inout) {
-            let reg = parse_reg(&mut p, &mut explicit_reg)?;
+            let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
-                let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+                let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
                 return Err(err);
             }
             let expr = p.parse_expr()?;
@@ -133,9 +147,9 @@ fn parse_args<'a>(
                 ast::InlineAsmOperand::InOut { reg, expr, late: false }
             }
         } else if !is_global_asm && p.eat_keyword(sym::inlateout) {
-            let reg = parse_reg(&mut p, &mut explicit_reg)?;
+            let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
-                let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+                let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
                 return Err(err);
             }
             let expr = p.parse_expr()?;
@@ -154,7 +168,7 @@ fn parse_args<'a>(
             match expr.kind {
                 ast::ExprKind::Path(..) => {}
                 _ => {
-                    let err = ecx
+                    let err = diag
                         .struct_span_err(expr.span, "argument to `sym` must be a path expression");
                     return Err(err);
                 }
@@ -173,7 +187,7 @@ fn parse_args<'a>(
                     } else {
                         "expected operand, clobber_abi, options, or additional template string"
                     };
-                    let mut err = ecx.struct_span_err(template.span, errstr);
+                    let mut err = diag.struct_span_err(template.span, errstr);
                     err.span_label(template.span, errstr);
                     return Err(err);
                 }
@@ -193,31 +207,31 @@ fn parse_args<'a>(
         // clobber_abi/options. We do this at the end once we have the full span
         // of the argument available.
         if !args.options_spans.is_empty() {
-            ecx.struct_span_err(span, "arguments are not allowed after options")
+            diag.struct_span_err(span, "arguments are not allowed after options")
                 .span_labels(args.options_spans.clone(), "previous options")
                 .span_label(span, "argument")
                 .emit();
         } else if let Some((_, abi_span)) = args.clobber_abis.last() {
-            ecx.struct_span_err(span, "arguments are not allowed after clobber_abi")
+            diag.struct_span_err(span, "arguments are not allowed after clobber_abi")
                 .span_label(*abi_span, "clobber_abi")
                 .span_label(span, "argument")
                 .emit();
         }
         if explicit_reg {
             if name.is_some() {
-                ecx.struct_span_err(span, "explicit register arguments cannot have names").emit();
+                diag.struct_span_err(span, "explicit register arguments cannot have names").emit();
             }
             args.reg_args.insert(slot);
         } else if let Some(name) = name {
             if let Some(&prev) = args.named_args.get(&name) {
-                ecx.struct_span_err(span, &format!("duplicate argument named `{}`", name))
+                diag.struct_span_err(span, &format!("duplicate argument named `{}`", name))
                     .span_label(args.operands[prev].1, "previously here")
                     .span_label(span, "duplicate argument")
                     .emit();
                 continue;
             }
             if !args.reg_args.is_empty() {
-                let mut err = ecx.struct_span_err(
+                let mut err = diag.struct_span_err(
                     span,
                     "named arguments cannot follow explicit register arguments",
                 );
@@ -230,7 +244,7 @@ fn parse_args<'a>(
             args.named_args.insert(name, slot);
         } else {
             if !args.named_args.is_empty() || !args.reg_args.is_empty() {
-                let mut err = ecx.struct_span_err(
+                let mut err = diag.struct_span_err(
                     span,
                     "positional arguments cannot follow named arguments \
                      or explicit register arguments",
@@ -251,21 +265,21 @@ fn parse_args<'a>(
         && args.options.contains(ast::InlineAsmOptions::READONLY)
     {
         let spans = args.options_spans.clone();
-        ecx.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
+        diag.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
             .emit();
     }
     if args.options.contains(ast::InlineAsmOptions::PURE)
         && args.options.contains(ast::InlineAsmOptions::NORETURN)
     {
         let spans = args.options_spans.clone();
-        ecx.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
+        diag.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
             .emit();
     }
     if args.options.contains(ast::InlineAsmOptions::PURE)
         && !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
     {
         let spans = args.options_spans.clone();
-        ecx.struct_span_err(
+        diag.struct_span_err(
             spans,
             "the `pure` option must be combined with either `nomem` or `readonly`",
         )
@@ -296,14 +310,14 @@ fn parse_args<'a>(
         }
     }
     if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
-        ecx.struct_span_err(
+        diag.struct_span_err(
             args.options_spans.clone(),
             "asm with the `pure` option must have at least one output",
         )
         .emit();
     }
     if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() {
-        let err = ecx
+        let err = diag
             .struct_span_err(outputs_sp, "asm outputs are not allowed with the `noreturn` option");
 
         // Bail out now since this is likely to confuse MIR
@@ -312,7 +326,7 @@ fn parse_args<'a>(
 
     if args.clobber_abis.len() > 0 {
         if is_global_asm {
-            let err = ecx.struct_span_err(
+            let err = diag.struct_span_err(
                 args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
                 "`clobber_abi` cannot be used with `global_asm!`",
             );
@@ -321,7 +335,7 @@ fn parse_args<'a>(
             return Err(err);
         }
         if !regclass_outputs.is_empty() {
-            ecx.struct_span_err(
+            diag.struct_span_err(
                 regclass_outputs.clone(),
                 "asm with `clobber_abi` must specify explicit registers for outputs",
             )
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index d768f06c4f0..d9faa6777ea 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -616,19 +616,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     match self.size_and_align_of(metadata, &field)? {
                         Some(size_and_align) => size_and_align,
                         None => {
-                            // A field with extern type.  If this field is at offset 0, we behave
-                            // like the underlying extern type.
-                            // FIXME: Once we have made decisions for how to handle size and alignment
-                            // of `extern type`, this should be adapted.  It is just a temporary hack
-                            // to get some code to work that probably ought to work.
-                            if sized_size == Size::ZERO {
-                                return Ok(None);
-                            } else {
-                                span_bug!(
-                                    self.cur_span(),
-                                    "Fields cannot be extern types, unless they are at offset 0"
-                                )
-                            }
+                            // A field with an extern type. We don't know the actual dynamic size
+                            // or the alignment.
+                            return Ok(None);
                         }
                     };
 
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 851c2a6bb2e..818b95b7fc4 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -362,21 +362,15 @@ where
             // Re-use parent metadata to determine dynamic field layout.
             // With custom DSTS, this *will* execute user-defined code, but the same
             // happens at run-time so that's okay.
-            let align = match self.size_and_align_of(&base.meta, &field_layout)? {
-                Some((_, align)) => align,
-                None if offset == Size::ZERO => {
-                    // An extern type at offset 0, we fall back to its static alignment.
-                    // FIXME: Once we have made decisions for how to handle size and alignment
-                    // of `extern type`, this should be adapted.  It is just a temporary hack
-                    // to get some code to work that probably ought to work.
-                    field_layout.align.abi
+            match self.size_and_align_of(&base.meta, &field_layout)? {
+                Some((_, align)) => (base.meta, offset.align_to(align)),
+                None => {
+                    // For unsized types with an extern type tail we perform no adjustments.
+                    // NOTE: keep this in sync with `PlaceRef::project_field` in the codegen backend.
+                    assert!(matches!(base.meta, MemPlaceMeta::None));
+                    (base.meta, offset)
                 }
-                None => span_bug!(
-                    self.cur_span(),
-                    "cannot compute offset for extern type field at non-0 offset"
-                ),
-            };
-            (base.meta, offset.align_to(align))
+            }
         } else {
             // base.meta could be present; we might be accessing a sized field of an unsized
             // struct.
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 71db58f2d8b..ba1b8caa368 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -633,16 +633,6 @@ pub trait LintContext: Sized {
                     }
                 },
                 BuiltinLintDiagnostics::Normal => (),
-                BuiltinLintDiagnostics::BareTraitObject(span, is_global) => {
-                    let (sugg, app) = match sess.source_map().span_to_snippet(span) {
-                        Ok(s) if is_global => {
-                            (format!("dyn ({})", s), Applicability::MachineApplicable)
-                        }
-                        Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable),
-                        Err(_) => ("dyn <type>".to_string(), Applicability::HasPlaceholders),
-                    };
-                    db.span_suggestion(span, "use `dyn`", sugg, app);
-                }
                 BuiltinLintDiagnostics::AbsPathWithModule(span) => {
                     let (sugg, app) = match sess.source_map().span_to_snippet(span) {
                         Ok(ref s) => {
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index da1edcf6fe3..ed24b94e2fd 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -169,7 +169,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
         }
 
         if !(type_permits_lack_of_use || fn_warned || op_warned) {
-            cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| lint.build("unused result").emit());
+            cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| {
+                lint.build(&format!("unused result of type `{}`", ty)).emit()
+            });
         }
 
         // Returns whether an error has been emitted (and thus another does not need to be later).
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 3f504d75dfc..e22c9c68de6 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -285,7 +285,6 @@ pub enum ExternDepSpec {
 #[derive(PartialEq, Debug)]
 pub enum BuiltinLintDiagnostics {
     Normal,
-    BareTraitObject(Span, /* is_global */ bool),
     AbsPathWithModule(Span),
     ProcMacroDeriveResolutionFallback(Span),
     MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 78e33544655..e2de9f12aaa 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -771,11 +771,24 @@ rustc_queries! {
         desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
         cache_on_disk_if { true }
         load_cached(tcx, id) {
-            let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
-                .on_disk_cache().as_ref()
-                .and_then(|c| c.try_load_query_result(*tcx, id));
+            #[cfg(bootstrap)]
+            {
+                match match tcx.on_disk_cache().as_ref() {
+                    Some(c) => c.try_load_query_result(*tcx, id),
+                    None => None,
+                } {
+                    Some(x) => Some(&*tcx.arena.alloc(x)),
+                    None => None,
+                }
+            }
+            #[cfg(not(bootstrap))]
+            {
+                let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
+                    .on_disk_cache().as_ref()
+                    .and_then(|c| c.try_load_query_result(*tcx, id));
 
-            typeck_results.map(|x| &*tcx.arena.alloc(x))
+                typeck_results.map(|x| &*tcx.arena.alloc(x))
+            }
         }
     }
 
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 558b1ce082e..8be95b2d95a 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -68,6 +68,12 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
     if body.source.promoted.is_some() {
         return false;
     }
+    // Avoid inlining into generators, since their `optimized_mir` is used for layout computation,
+    // which can create a cycle, even when no attempt is made to inline the function in the other
+    // direction.
+    if body.generator.is_some() {
+        return false;
+    }
 
     let mut this = Inliner {
         tcx,
@@ -202,14 +208,6 @@ impl<'tcx> Inliner<'tcx> {
 
         if let Some(callee_def_id) = callee.def_id().as_local() {
             let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id);
-            // Avoid inlining into generators,
-            // since their `optimized_mir` is used for layout computation, which can
-            // create a cycle, even when no attempt is made to inline the function
-            // in the other direction.
-            if caller_body.generator.is_some() {
-                return Err("local generator (query cycle avoidance)");
-            }
-
             // Avoid a cycle here by only using `instance_mir` only if we have
             // a lower `HirId` than the callee. This ensures that the callee will
             // not inline us. This trick only works without incremental compilation.
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 516e301ec3a..618aa3fd002 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -223,7 +223,7 @@ impl<'a> Parser<'a> {
             (Ident::empty(), ItemKind::Use(tree))
         } else if self.check_fn_front_matter(def_final) {
             // FUNCTION ITEM
-            let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo)?;
+            let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis)?;
             (ident, ItemKind::Fn(Box::new(Fn { defaultness: def(), sig, generics, body })))
         } else if self.eat_keyword(kw::Extern) {
             if self.eat_keyword(kw::Crate) {
@@ -1511,9 +1511,16 @@ impl<'a> Parser<'a> {
         let (ident, is_raw) = self.ident_or_err()?;
         if !is_raw && ident.is_reserved() {
             let err = if self.check_fn_front_matter(false) {
+                let inherited_vis = Visibility {
+                    span: rustc_span::DUMMY_SP,
+                    kind: VisibilityKind::Inherited,
+                    tokens: None,
+                };
                 // We use `parse_fn` to get a span for the function
                 let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
-                if let Err(mut db) = self.parse_fn(&mut Vec::new(), fn_parse_mode, lo) {
+                if let Err(mut db) =
+                    self.parse_fn(&mut Vec::new(), fn_parse_mode, lo, &inherited_vis)
+                {
                     db.delay_as_bug();
                 }
                 let mut err = self.struct_span_err(
@@ -1793,8 +1800,9 @@ impl<'a> Parser<'a> {
         attrs: &mut Vec<Attribute>,
         fn_parse_mode: FnParseMode,
         sig_lo: Span,
+        vis: &Visibility,
     ) -> PResult<'a, (Ident, FnSig, Generics, Option<P<Block>>)> {
-        let header = self.parse_fn_front_matter()?; // `const ... fn`
+        let header = self.parse_fn_front_matter(vis)?; // `const ... fn`
         let ident = self.parse_ident()?; // `foo`
         let mut generics = self.parse_generics()?; // `<'a, T, ...>`
         let decl =
@@ -1903,12 +1911,15 @@ impl<'a> Parser<'a> {
     /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration,
     /// up to and including the `fn` keyword. The formal grammar is:
     ///
-    /// ```
+    /// ```text
     /// Extern = "extern" StringLit? ;
     /// FnQual = "const"? "async"? "unsafe"? Extern? ;
     /// FnFrontMatter = FnQual "fn" ;
     /// ```
-    pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
+    ///
+    /// `vis` represents the visibility that was already parsed, if any. Use
+    /// `Visibility::Inherited` when no visibility is known.
+    pub(super) fn parse_fn_front_matter(&mut self, orig_vis: &Visibility) -> PResult<'a, FnHeader> {
         let sp_start = self.token.span;
         let constness = self.parse_constness();
 
@@ -1934,51 +1945,94 @@ impl<'a> Parser<'a> {
                 Ok(false) => unreachable!(),
                 Err(mut err) => {
                     // Qualifier keywords ordering check
+                    enum WrongKw {
+                        Duplicated(Span),
+                        Misplaced(Span),
+                    }
 
-                    // This will allow the machine fix to directly place the keyword in the correct place
-                    let current_qual_sp = if self.check_keyword(kw::Const) {
-                        Some(async_start_sp)
+                    // This will allow the machine fix to directly place the keyword in the correct place or to indicate
+                    // that the keyword is already present and the second instance should be removed.
+                    let wrong_kw = if self.check_keyword(kw::Const) {
+                        match constness {
+                            Const::Yes(sp) => Some(WrongKw::Duplicated(sp)),
+                            Const::No => Some(WrongKw::Misplaced(async_start_sp)),
+                        }
                     } else if self.check_keyword(kw::Async) {
-                        Some(unsafe_start_sp)
+                        match asyncness {
+                            Async::Yes { span, .. } => Some(WrongKw::Duplicated(span)),
+                            Async::No => Some(WrongKw::Misplaced(unsafe_start_sp)),
+                        }
                     } else if self.check_keyword(kw::Unsafe) {
-                        Some(ext_start_sp)
+                        match unsafety {
+                            Unsafe::Yes(sp) => Some(WrongKw::Duplicated(sp)),
+                            Unsafe::No => Some(WrongKw::Misplaced(ext_start_sp)),
+                        }
                     } else {
                         None
                     };
 
-                    if let Some(current_qual_sp) = current_qual_sp {
-                        let current_qual_sp = current_qual_sp.to(self.prev_token.span);
-                        if let Ok(current_qual) = self.span_to_snippet(current_qual_sp) {
-                            let invalid_qual_sp = self.token.uninterpolated_span();
-                            let invalid_qual = self.span_to_snippet(invalid_qual_sp).unwrap();
+                    // The keyword is already present, suggest removal of the second instance
+                    if let Some(WrongKw::Duplicated(original_sp)) = wrong_kw {
+                        let original_kw = self
+                            .span_to_snippet(original_sp)
+                            .expect("Span extracted directly from keyword should always work");
+
+                        err.span_suggestion(
+                            self.token.uninterpolated_span(),
+                            &format!("`{}` already used earlier, remove this one", original_kw),
+                            "".to_string(),
+                            Applicability::MachineApplicable,
+                        )
+                        .span_note(original_sp, &format!("`{}` first seen here", original_kw));
+                    }
+                    // The keyword has not been seen yet, suggest correct placement in the function front matter
+                    else if let Some(WrongKw::Misplaced(correct_pos_sp)) = wrong_kw {
+                        let correct_pos_sp = correct_pos_sp.to(self.prev_token.span);
+                        if let Ok(current_qual) = self.span_to_snippet(correct_pos_sp) {
+                            let misplaced_qual_sp = self.token.uninterpolated_span();
+                            let misplaced_qual = self.span_to_snippet(misplaced_qual_sp).unwrap();
 
                             err.span_suggestion(
-                                current_qual_sp.to(invalid_qual_sp),
-                                &format!("`{}` must come before `{}`", invalid_qual, current_qual),
-                                format!("{} {}", invalid_qual, current_qual),
-                                Applicability::MachineApplicable,
-                            ).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
+                                    correct_pos_sp.to(misplaced_qual_sp),
+                                    &format!("`{}` must come before `{}`", misplaced_qual, current_qual),
+                                    format!("{} {}", misplaced_qual, current_qual),
+                                    Applicability::MachineApplicable,
+                                ).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
                         }
                     }
-                    // Recover incorrect visibility order such as `async pub`.
+                    // Recover incorrect visibility order such as `async pub`
                     else if self.check_keyword(kw::Pub) {
                         let sp = sp_start.to(self.prev_token.span);
                         if let Ok(snippet) = self.span_to_snippet(sp) {
-                            let vis = match self.parse_visibility(FollowedByType::No) {
+                            let current_vis = match self.parse_visibility(FollowedByType::No) {
                                 Ok(v) => v,
                                 Err(mut d) => {
                                     d.cancel();
                                     return Err(err);
                                 }
                             };
-                            let vs = pprust::vis_to_string(&vis);
+                            let vs = pprust::vis_to_string(&current_vis);
                             let vs = vs.trim_end();
-                            err.span_suggestion(
-                                sp_start.to(self.prev_token.span),
-                                &format!("visibility `{}` must come before `{}`", vs, snippet),
-                                format!("{} {}", vs, snippet),
-                                Applicability::MachineApplicable,
-                            );
+
+                            // There was no explicit visibility
+                            if matches!(orig_vis.kind, VisibilityKind::Inherited) {
+                                err.span_suggestion(
+                                    sp_start.to(self.prev_token.span),
+                                    &format!("visibility `{}` must come before `{}`", vs, snippet),
+                                    format!("{} {}", vs, snippet),
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                            // There was an explicit visibility
+                            else {
+                                err.span_suggestion(
+                                    current_vis.span,
+                                    "there is already a visibility modifier, remove one",
+                                    "".to_string(),
+                                    Applicability::MachineApplicable,
+                                )
+                                .span_note(orig_vis.span, "explicit visibility first seen here");
+                            }
                         }
                     }
                     return Err(err);
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 9bfde0e3900..02a774ba129 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -474,7 +474,13 @@ impl<'a> Parser<'a> {
         params: Vec<GenericParam>,
         recover_return_sign: RecoverReturnSign,
     ) -> PResult<'a, TyKind> {
-        let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?;
+        let inherited_vis = rustc_ast::Visibility {
+            span: rustc_span::DUMMY_SP,
+            kind: rustc_ast::VisibilityKind::Inherited,
+            tokens: None,
+        };
+        let ast::FnHeader { ext, unsafety, constness, asyncness } =
+            self.parse_fn_front_matter(&inherited_vis)?;
         let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
         let whole_span = lo.to(self.prev_token.span);
         if let ast::Const::Yes(span) = constness {
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 23c3b5af262..8db706c3709 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -13,6 +13,7 @@ use crate::errors::{
 };
 use crate::middle::resolve_lifetime as rl;
 use crate::require_c_abi_if_c_variadic;
+use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, ErrorReported, FatalError};
 use rustc_hir as hir;
@@ -24,7 +25,8 @@ use rustc_hir::{GenericArg, GenericArgs};
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
 use rustc_middle::ty::{self, Const, DefIdTree, Ty, TyCtxt, TypeFoldable};
-use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
+use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
+use rustc_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -2266,13 +2268,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     /// Parses the programmer's textual representation of a type into our
     /// internal notion of a type.
     pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
-        self.ast_ty_to_ty_inner(ast_ty, false)
+        self.ast_ty_to_ty_inner(ast_ty, false, false)
+    }
+
+    /// Parses the programmer's textual representation of a type into our
+    /// internal notion of a type.  This is meant to be used within a path.
+    pub fn ast_ty_to_ty_in_path(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
+        self.ast_ty_to_ty_inner(ast_ty, false, true)
     }
 
     /// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait
     /// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors.
     #[tracing::instrument(level = "debug", skip(self))]
-    fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool) -> Ty<'tcx> {
+    fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> {
         let tcx = self.tcx();
 
         let result_ty = match ast_ty.kind {
@@ -2283,7 +2291,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             hir::TyKind::Rptr(ref region, ref mt) => {
                 let r = self.ast_region_to_region(region, None);
                 debug!(?r);
-                let t = self.ast_ty_to_ty_inner(mt.ty, true);
+                let t = self.ast_ty_to_ty_inner(mt.ty, true, false);
                 tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl })
             }
             hir::TyKind::Never => tcx.types.never,
@@ -2302,6 +2310,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 ))
             }
             hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
+                self.maybe_lint_bare_trait(ast_ty, in_path);
                 self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed)
             }
             hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
@@ -2329,7 +2338,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
                 debug!(?qself, ?segment);
-                let ty = self.ast_ty_to_ty(qself);
+                let ty = self.ast_ty_to_ty_inner(qself, false, true);
 
                 let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = qself.kind {
                     path.res
@@ -2586,4 +2595,62 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         }
         Some(r)
     }
+
+    fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
+        let tcx = self.tcx();
+        if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
+            self_ty.kind
+        {
+            let needs_bracket = in_path
+                && !tcx
+                    .sess
+                    .source_map()
+                    .span_to_prev_source(self_ty.span)
+                    .ok()
+                    .map_or(false, |s| s.trim_end().ends_with('<'));
+
+            let is_global = poly_trait_ref.trait_ref.path.is_global();
+            let sugg = Vec::from_iter([
+                (
+                    self_ty.span.shrink_to_lo(),
+                    format!(
+                        "{}dyn {}",
+                        if needs_bracket { "<" } else { "" },
+                        if is_global { "(" } else { "" },
+                    ),
+                ),
+                (
+                    self_ty.span.shrink_to_hi(),
+                    format!(
+                        "{}{}",
+                        if is_global { ")" } else { "" },
+                        if needs_bracket { ">" } else { "" },
+                    ),
+                ),
+            ]);
+            if self_ty.span.edition() >= Edition::Edition2021 {
+                let msg = "trait objects must include the `dyn` keyword";
+                let label = "add `dyn` keyword before this trait";
+                rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg)
+                    .multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable)
+                    .emit();
+            } else {
+                let msg = "trait objects without an explicit `dyn` are deprecated";
+                tcx.struct_span_lint_hir(
+                    BARE_TRAIT_OBJECTS,
+                    self_ty.hir_id,
+                    self_ty.span,
+                    |lint| {
+                        lint.build(msg)
+                            .multipart_suggestion_verbose(
+                                "use `dyn`",
+                                sugg,
+                                Applicability::MachineApplicable,
+                            )
+                            .emit()
+                    },
+                );
+            }
+        }
+    }
 }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 738af9bfb8c..67630fd4e58 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -6,7 +6,6 @@ use crate::check::callee::{self, DeferredCallResolution};
 use crate::check::method::{self, MethodCallee, SelfSource};
 use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
 
-use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
@@ -14,7 +13,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ExprKind, GenericArg, Node, QPath, TyKind};
+use rustc_hir::{ExprKind, GenericArg, Node, QPath};
 use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc_infer::infer::{InferOk, InferResult};
@@ -28,8 +27,6 @@ use rustc_middle::ty::{
     Ty, UserType,
 };
 use rustc_session::lint;
-use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
-use rustc_span::edition::Edition;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::{original_sp, DUMMY_SP};
 use rustc_span::symbol::{kw, sym, Ident};
@@ -855,7 +852,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // to be object-safe.
                 // We manually call `register_wf_obligation` in the success path
                 // below.
-                (<dyn AstConv<'_>>::ast_ty_to_ty(self, qself), qself, segment)
+                (<dyn AstConv<'_>>::ast_ty_to_ty_in_path(self, qself), qself, segment)
             }
             QPath::LangItem(..) => {
                 bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`")
@@ -901,7 +898,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             });
 
         if result.is_ok() {
-            self.maybe_lint_bare_trait(qpath, hir_id, span);
             self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
         }
 
@@ -914,56 +910,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         )
     }
 
-    fn maybe_lint_bare_trait(&self, qpath: &QPath<'_>, hir_id: hir::HirId, span: Span) {
-        if let QPath::TypeRelative(self_ty, _) = qpath {
-            if let TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
-                self_ty.kind
-            {
-                let msg = "trait objects without an explicit `dyn` are deprecated";
-                let (sugg, app) = match self.tcx.sess.source_map().span_to_snippet(self_ty.span) {
-                    Ok(s) if poly_trait_ref.trait_ref.path.is_global() => {
-                        (format!("dyn ({})", s), Applicability::MachineApplicable)
-                    }
-                    Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable),
-                    Err(_) => ("dyn <type>".to_string(), Applicability::HasPlaceholders),
-                };
-                // Wrap in `<..>` if it isn't already.
-                let sugg = match self.tcx.sess.source_map().span_to_snippet(span) {
-                    Ok(s) if s.starts_with('<') => sugg,
-                    _ => format!("<{}>", sugg),
-                };
-                let sugg_label = "use `dyn`";
-                if self.sess().edition() >= Edition::Edition2021 {
-                    let mut err = rustc_errors::struct_span_err!(
-                        self.sess(),
-                        self_ty.span,
-                        E0782,
-                        "{}",
-                        msg,
-                    );
-                    err.span_suggestion(
-                        self_ty.span,
-                        sugg_label,
-                        sugg,
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
-                } else {
-                    self.tcx.struct_span_lint_hir(
-                        BARE_TRAIT_OBJECTS,
-                        hir_id,
-                        self_ty.span,
-                        |lint| {
-                            let mut db = lint.build(msg);
-                            db.span_suggestion(self_ty.span, sugg_label, sugg, app);
-                            db.emit()
-                        },
-                    );
-                }
-            }
-        }
-    }
-
     /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
     pub(in super::super) fn get_node_fn_decl(
         &self,