diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 291dbf603612a..c3c95226aebf6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -442,7 +442,7 @@ jobs: - name: x86_64-msvc-cargo env: SCRIPT: python x.py test src/tools/cargotest src/tools/cargo - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-lld" VCVARS_BAT: vcvars64.bat NO_DEBUG_ASSERTIONS: 1 NO_LLVM_ASSERTIONS: 1 diff --git a/.mailmap b/.mailmap index da17344c2085e..9639c1174964c 100644 --- a/.mailmap +++ b/.mailmap @@ -44,6 +44,7 @@ Brian Anderson Brian Anderson Brian Dawn Brian Leibig Brian Leibig +Camelid <37223377+camelid@users.noreply.github.com> Carl-Anton Ingmarsson Carol (Nichols || Goulding) <193874+carols10cents@users.noreply.github.com> Carol (Nichols || Goulding) @@ -152,6 +153,10 @@ Kang Seonghoon Keegan McAllister Kevin Butler Kyeongwoon Lee +Kyle J Strand +Kyle J Strand +Kyle J Strand +Kyle J Strand Laurențiu Nicola Lee Jeffery Lee Jeffery Lee Wondong diff --git a/RELEASES.md b/RELEASES.md index fc9628bb365b4..8d6535b20c2eb 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -100,7 +100,7 @@ Compatibility Notes - [Removed the `-C no_integrated_as` flag from rustc.][70345] - [The `file_name` property in JSON output of macro errors now points the actual source file rather than the previous format of ``.][70969] - **Note:** this may not point a file that actually exists on the user's system. + **Note:** this may not point to a file that actually exists on the user's system. - [The minimum required external LLVM version has been bumped to LLVM 8.][71147] - [`mem::{zeroed, uninitialised}` will now panic when used with types that do not allow zero initialization such as `NonZeroU8`.][66059] This was diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml index 46d3cf7a38ca2..f8fa7b727d179 100644 --- a/src/ci/azure-pipelines/auto.yml +++ b/src/ci/azure-pipelines/auto.yml @@ -148,7 +148,7 @@ jobs: INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc x86_64-msvc-cargo: SCRIPT: python x.py test src/tools/cargotest src/tools/cargo - INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc + INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld VCVARS_BAT: vcvars64.bat # FIXME(#59637) NO_DEBUG_ASSERTIONS: 1 diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 1c120f8163459..92fec593a5410 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -505,7 +505,7 @@ jobs: - name: x86_64-msvc-cargo env: SCRIPT: python x.py test src/tools/cargotest src/tools/cargo - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld VCVARS_BAT: vcvars64.bat # FIXME(#59637) NO_DEBUG_ASSERTIONS: 1 diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 22d43468771b4..ffae3b5c7894f 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -343,15 +343,18 @@ impl Vec { /// /// // The vector contains no items, even though it has capacity for more /// assert_eq!(vec.len(), 0); + /// assert_eq!(vec.capacity(), 10); /// /// // These are all done without reallocating... /// for i in 0..10 { /// vec.push(i); /// } + /// assert_eq!(vec.len(), 10); /// assert_eq!(vec.capacity(), 10); /// /// // ...but this may make the vector reallocate /// vec.push(11); + /// assert_eq!(vec.len(), 11); /// assert!(vec.capacity() >= 11); /// ``` #[inline] diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index dcce1d45298cc..cff84b11aa098 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -1253,20 +1253,10 @@ fn add_post_link_objects( /// Add arbitrary "pre-link" args defined by the target spec or from command line. /// FIXME: Determine where exactly these args need to be inserted. -fn add_pre_link_args( - cmd: &mut dyn Linker, - sess: &Session, - flavor: LinkerFlavor, - crate_type: CrateType, -) { +fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) { cmd.args(args); } - if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) { - if sess.crt_static(Some(crate_type)) { - cmd.args(args); - } - } cmd.args(&sess.opts.debugging_opts.pre_link_args); } @@ -1502,7 +1492,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( let crt_objects_fallback = crt_objects_fallback(sess, crate_type); // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT - add_pre_link_args(cmd, sess, flavor, crate_type); + add_pre_link_args(cmd, sess, flavor); // NO-OPT-OUT add_link_script(cmd, sess, tmpdir, crate_type); diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index 77cb31bf3d278..d9fed998c92fb 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -315,6 +315,21 @@ impl<'a> Linker for GccLinker<'a> { self.build_dylib(out_filename); } } + // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc, + // it switches linking for libc and similar system libraries to static without using + // any `#[link]` attributes in the `libc` crate, see #72782 for details. + // FIXME: Switch to using `#[link]` attributes in the `libc` crate + // similarly to other targets. + if self.sess.target.target.target_os == "vxworks" + && matches!( + output_kind, + LinkOutputKind::StaticNoPicExe + | LinkOutputKind::StaticPicExe + | LinkOutputKind::StaticDylib + ) + { + self.cmd.arg("--static-crt"); + } } fn link_dylib(&mut self, lib: Symbol) { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 68ce93d3db90f..ccea041699ee1 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -346,12 +346,15 @@ pub fn run_compiler( queries.global_ctxt()?; + // Drop AST after creating GlobalCtxt to free memory + let _timer = sess.prof.generic_activity("drop_ast"); + mem::drop(queries.expansion()?.take()); + if sess.opts.debugging_opts.no_analysis || sess.opts.debugging_opts.ast_json { return early_exit(); } if sess.opts.debugging_opts.save_analysis { - let expanded_crate = &queries.expansion()?.peek().0; let crate_name = queries.crate_name()?.peek().clone(); queries.global_ctxt()?.peek_mut().enter(|tcx| { let result = tcx.analysis(LOCAL_CRATE); @@ -359,7 +362,6 @@ pub fn run_compiler( sess.time("save_analysis", || { save::process_crate( tcx, - &expanded_crate, &crate_name, &compiler.input(), None, @@ -371,13 +373,7 @@ pub fn run_compiler( }); result - // AST will be dropped *after* the `after_analysis` callback - // (needed by the RLS) })?; - } else { - // Drop AST after creating GlobalCtxt to free memory - let _timer = sess.prof.generic_activity("drop_ast"); - mem::drop(queries.expansion()?.take()); } queries.global_ctxt()?.peek_mut().enter(|tcx| tcx.analysis(LOCAL_CRATE))?; @@ -386,10 +382,6 @@ pub fn run_compiler( return early_exit(); } - if sess.opts.debugging_opts.save_analysis { - mem::drop(queries.expansion()?.take()); - } - queries.ongoing_codegen()?; if sess.opts.debugging_opts.print_type_sizes { diff --git a/src/librustc_hir_pretty/lib.rs b/src/librustc_hir_pretty/lib.rs index 8eb19cbb65a0a..e642915b86a5e 100644 --- a/src/librustc_hir_pretty/lib.rs +++ b/src/librustc_hir_pretty/lib.rs @@ -203,6 +203,30 @@ pub fn visibility_qualified>>(vis: &hir::Visibility<'_ }) } +pub fn generic_params_to_string(generic_params: &[GenericParam<'_>]) -> String { + to_string(NO_ANN, |s| s.print_generic_params(generic_params)) +} + +pub fn bounds_to_string<'b>(bounds: impl IntoIterator>) -> String { + to_string(NO_ANN, |s| s.print_bounds("", bounds)) +} + +pub fn param_to_string(arg: &hir::Param<'_>) -> String { + to_string(NO_ANN, |s| s.print_param(arg)) +} + +pub fn ty_to_string(ty: &hir::Ty<'_>) -> String { + to_string(NO_ANN, |s| s.print_type(ty)) +} + +pub fn path_segment_to_string(segment: &hir::PathSegment<'_>) -> String { + to_string(NO_ANN, |s| s.print_path_segment(segment)) +} + +pub fn path_to_string(segment: &hir::Path<'_>) -> String { + to_string(NO_ANN, |s| s.print_path(segment, false)) +} + impl<'a> State<'a> { pub fn cbox(&mut self, u: usize) { self.s.cbox(u); diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index f127a239eea2c..5aad64f84cee3 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -186,17 +186,19 @@ pub fn run_compiler_in_existing_thread_pool( override_queries: config.override_queries, }; - let r = { - let _sess_abort_error = OnDrop(|| { - compiler.sess.finish_diagnostics(registry); - }); - - f(&compiler) - }; - - let prof = compiler.sess.prof.clone(); - prof.generic_activity("drop_compiler").run(move || drop(compiler)); - r + rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || { + let r = { + let _sess_abort_error = OnDrop(|| { + compiler.sess.finish_diagnostics(registry); + }); + + f(&compiler) + }; + + let prof = compiler.sess.prof.clone(); + prof.generic_activity("drop_compiler").run(move || drop(compiler)); + r + }) } pub fn run_compiler(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index a34cff06bc1cd..00c00a63b6b5d 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1846,7 +1846,7 @@ pub struct FieldDef { /// The definition of a user-defined type, e.g., a `struct`, `enum`, or `union`. /// -/// These are all interned (by `intern_adt_def`) into the `adt_defs` table. +/// These are all interned (by `alloc_adt_def`) into the global arena. /// /// The initialism *ADT* stands for an [*algebraic data type (ADT)*][adt]. /// This is slightly wrong because `union`s are not ADTs. diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index cee0afacb68f7..f6f5dfd651612 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -987,7 +987,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { - folder.tcx().mk_predicate(ty::PredicateKind::super_fold_with(self.kind, folder)) + let new = ty::PredicateKind::super_fold_with(self.kind, folder); + if new != *self.kind { folder.tcx().mk_predicate(new) } else { *self } } fn super_visit_with>(&self, visitor: &mut V) -> bool { diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index ea237f1a04f99..59fadfc41b06e 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -680,7 +680,9 @@ impl<'a> Resolver<'a> { Res::Def(DefKind::Ctor(..), did) => this.parent(did), _ => res.opt_def_id(), }; - candidates.push(ImportSuggestion { did, descr: res.descr(), path }); + if candidates.iter().all(|v: &ImportSuggestion| v.did != did) { + candidates.push(ImportSuggestion { did, descr: res.descr(), path }); + } } } } @@ -1475,7 +1477,7 @@ crate fn show_candidates( // This is `None` if all placement locations are inside expansions use_placement_span: Option, candidates: &[ImportSuggestion], - better: bool, + instead: bool, found_use: bool, ) { if candidates.is_empty() { @@ -1486,6 +1488,7 @@ crate fn show_candidates( // by iterating through a hash map, so make sure they are ordered: let mut path_strings: Vec<_> = candidates.iter().map(|c| path_names_to_string(&c.path)).collect(); + path_strings.sort(); path_strings.dedup(); @@ -1494,8 +1497,9 @@ crate fn show_candidates( } else { ("one of these", "items") }; - let instead = if better { " instead" } else { "" }; - let msg = format!("consider importing {} {}{}", determiner, kind, instead); + + let instead = if instead { " instead" } else { "" }; + let mut msg = format!("consider importing {} {}{}", determiner, kind, instead); if let Some(span) = use_placement_span { for candidate in &mut path_strings { @@ -1507,12 +1511,13 @@ crate fn show_candidates( err.span_suggestions(span, &msg, path_strings.into_iter(), Applicability::Unspecified); } else { - let mut msg = msg; msg.push(':'); + for candidate in path_strings { msg.push('\n'); msg.push_str(&candidate); } + err.note(&msg); } } diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 3b49b3b6ff7d2..2085c8109fd5c 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -29,8 +29,9 @@ use rustc_span::Span; use smallvec::{smallvec, SmallVec}; use log::debug; +use rustc_span::source_map::{respan, Spanned}; use std::collections::BTreeSet; -use std::mem::replace; +use std::mem::{replace, take}; mod diagnostics; crate mod lifetimes; @@ -234,6 +235,13 @@ impl<'a> PathSource<'a> { } } + fn is_call(self) -> bool { + match self { + PathSource::Expr(Some(&Expr { kind: ExprKind::Call(..), .. })) => true, + _ => false, + } + } + crate fn is_expected(self, res: Res) -> bool { match self { PathSource::Type => match res { @@ -1620,14 +1628,83 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let report_errors = |this: &mut Self, res: Option| { let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); + let def_id = this.parent_scope.module.normal_ancestor_id; - let better = res.is_some(); + let instead = res.is_some(); let suggestion = if res.is_none() { this.report_missing_type_error(path) } else { None }; - this.r.use_injections.push(UseError { err, candidates, def_id, better, suggestion }); + + this.r.use_injections.push(UseError { err, candidates, def_id, instead, suggestion }); + PartialRes::new(Res::Err) }; + // For paths originating from calls (like in `HashMap::new()`), tries + // to enrich the plain `failed to resolve: ...` message with hints + // about possible missing imports. + // + // Similar thing, for types, happens in `report_errors` above. + let report_errors_for_call = |this: &mut Self, parent_err: Spanned>| { + if !source.is_call() { + return Some(parent_err); + } + + // Before we start looking for candidates, we have to get our hands + // on the type user is trying to perform invocation on; basically: + // we're transforming `HashMap::new` into just `HashMap` + let path = if let Some((_, path)) = path.split_last() { + path + } else { + return Some(parent_err); + }; + + let (mut err, candidates) = + this.smart_resolve_report_errors(path, span, PathSource::Type, None); + + if candidates.is_empty() { + err.cancel(); + return Some(parent_err); + } + + // There are two different error messages user might receive at + // this point: + // - E0412 cannot find type `{}` in this scope + // - E0433 failed to resolve: use of undeclared type or module `{}` + // + // The first one is emitted for paths in type-position, and the + // latter one - for paths in expression-position. + // + // Thus (since we're in expression-position at this point), not to + // confuse the user, we want to keep the *message* from E0432 (so + // `parent_err`), but we want *hints* from E0412 (so `err`). + // + // And that's what happens below - we're just mixing both messages + // into a single one. + let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node); + + parent_err.cancel(); + + err.message = take(&mut parent_err.message); + err.code = take(&mut parent_err.code); + err.children = take(&mut parent_err.children); + + drop(parent_err); + + let def_id = this.parent_scope.module.normal_ancestor_id; + + this.r.use_injections.push(UseError { + err, + candidates, + def_id, + instead: false, + suggestion: None, + }); + + // We don't return `Some(parent_err)` here, because the error will + // be already printed as part of the `use` injections + None + }; + let partial_res = match self.resolve_qpath_anywhere( id, qself, @@ -1637,14 +1714,15 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { source.defer_to_typeck(), crate_lint, ) { - Some(partial_res) if partial_res.unresolved_segments() == 0 => { + Ok(Some(partial_res)) if partial_res.unresolved_segments() == 0 => { if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err { partial_res } else { report_errors(self, Some(partial_res.base_res())) } } - Some(partial_res) if source.defer_to_typeck() => { + + Ok(Some(partial_res)) if source.defer_to_typeck() => { // Not fully resolved associated item `T::A::B` or `::A::B` // or `::A::B`. If `B` should be resolved in value namespace then // it needs to be added to the trait map. @@ -1655,25 +1733,34 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } let mut std_path = vec![Segment::from_ident(Ident::with_dummy_span(sym::std))]; + std_path.extend(path); + if self.r.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) { - let cl = CrateLint::No; - let ns = Some(ns); if let PathResult::Module(_) | PathResult::NonModule(_) = - self.resolve_path(&std_path, ns, false, span, cl) + self.resolve_path(&std_path, Some(ns), false, span, CrateLint::No) { - // check if we wrote `str::from_utf8` instead of `std::str::from_utf8` + // Check if we wrote `str::from_utf8` instead of `std::str::from_utf8` let item_span = path.iter().last().map(|segment| segment.ident.span).unwrap_or(span); - debug!("accessed item from `std` submodule as a bare type {:?}", std_path); + let mut hm = self.r.session.confused_type_with_std_module.borrow_mut(); hm.insert(item_span, span); - // In some places (E0223) we only have access to the full path hm.insert(span, span); } } + partial_res } + + Err(err) => { + if let Some(err) = report_errors_for_call(self, err) { + self.r.report_error(err.span, err.node); + } + + PartialRes::new(Res::Err) + } + _ => report_errors(self, None), }; @@ -1682,6 +1769,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Avoid recording definition of `A::B` in `::B::C`. self.r.record_partial_res(id, partial_res); } + partial_res } @@ -1711,17 +1799,16 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { span: Span, defer_to_typeck: bool, crate_lint: CrateLint, - ) -> Option { + ) -> Result, Spanned>> { let mut fin_res = None; + for (i, ns) in [primary_ns, TypeNS, ValueNS].iter().cloned().enumerate() { if i == 0 || ns != primary_ns { - match self.resolve_qpath(id, qself, path, ns, span, crate_lint) { - // If defer_to_typeck, then resolution > no resolution, - // otherwise full resolution > partial resolution > no resolution. + match self.resolve_qpath(id, qself, path, ns, span, crate_lint)? { Some(partial_res) if partial_res.unresolved_segments() == 0 || defer_to_typeck => { - return Some(partial_res); + return Ok(Some(partial_res)); } partial_res => { if fin_res.is_none() { @@ -1732,19 +1819,19 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } - // `MacroNS` assert!(primary_ns != MacroNS); + if qself.is_none() { let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); let path = Path { segments: path.iter().map(path_seg).collect(), span }; if let Ok((_, res)) = self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false) { - return Some(PartialRes::new(res)); + return Ok(Some(PartialRes::new(res))); } } - fin_res + Ok(fin_res) } /// Handles paths that may refer to associated items. @@ -1756,7 +1843,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ns: Namespace, span: Span, crate_lint: CrateLint, - ) -> Option { + ) -> Result, Spanned>> { debug!( "resolve_qpath(id={:?}, qself={:?}, path={:?}, ns={:?}, span={:?})", id, qself, path, ns, span, @@ -1767,10 +1854,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // This is a case like `::B`, where there is no // trait to resolve. In that case, we leave the `B` // segment to be resolved by type-check. - return Some(PartialRes::with_unresolved_segments( + return Ok(Some(PartialRes::with_unresolved_segments( Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)), path.len(), - )); + ))); } // Make sure `A::B` in `::C` is a trait item. @@ -1800,10 +1887,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // The remaining segments (the `C` in our example) will // have to be resolved by type-check, since that requires doing // trait resolution. - return Some(PartialRes::with_unresolved_segments( + return Ok(Some(PartialRes::with_unresolved_segments( partial_res.base_res(), partial_res.unresolved_segments() + path.len() - qself.position - 1, - )); + ))); } let result = match self.resolve_path(&path, Some(ns), true, span, crate_lint) { @@ -1838,11 +1925,10 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { PartialRes::new(module.res().unwrap()) } PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => { - self.r.report_error(span, ResolutionError::FailedToResolve { label, suggestion }); - PartialRes::new(Res::Err) + return Err(respan(span, ResolutionError::FailedToResolve { label, suggestion })); } - PathResult::Module(..) | PathResult::Failed { .. } => return None, - PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"), + PathResult::Module(..) | PathResult::Failed { .. } => return Ok(None), + PathResult::Indeterminate => bug!("indeterminate path result in resolve_qpath"), }; if path.len() > 1 @@ -1862,7 +1948,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { PathResult::Module(ModuleOrUniformRoot::Module(module)) => { module.res().unwrap() } - _ => return Some(result), + _ => return Ok(Some(result)), } }; if result.base_res() == unqualified_result { @@ -1871,7 +1957,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } - Some(result) + Ok(Some(result)) } fn with_resolved_label(&mut self, label: Option