From d7bb98f7a1367918a8c74a620dd2c69831ddae7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 4 Mar 2019 19:24:52 -0800 Subject: [PATCH] Elide object safety errors on non-existent trait function Fix #58734. --- src/librustc/session/mod.rs | 4 +++ src/librustc/traits/error_reporting.rs | 36 ++++++++++++++------- src/librustc_typeck/astconv.rs | 5 ++- src/librustc_typeck/check/method/suggest.rs | 17 ++++++---- src/test/ui/issues/issue-58734.rs | 22 +++++++++++++ src/test/ui/issues/issue-58734.stderr | 11 +++++++ 6 files changed, 74 insertions(+), 21 deletions(-) create mode 100644 src/test/ui/issues/issue-58734.rs create mode 100644 src/test/ui/issues/issue-58734.stderr diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 75a0a8195bc2e..7fc5ce6784424 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -164,6 +164,9 @@ pub struct Session { /// Cap lint level specified by a driver specifically. pub driver_lint_caps: FxHashMap, + + /// `Span`s of trait methods that weren't found to avoid emitting object safety errors + pub trait_methods_not_found: OneThread>>, } pub struct PerfStats { @@ -1230,6 +1233,7 @@ fn build_session_( has_global_allocator: Once::new(), has_panic_handler: Once::new(), driver_lint_caps, + trait_methods_not_found: OneThread::new(RefCell::new(Default::default())), }; validate_commandline_args_with_session_available(&sess); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 6c8fe0875b60c..f5f2ec38bdf27 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -754,9 +754,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Predicate::ObjectSafe(trait_def_id) => { let violations = self.tcx.global_tcx() .object_safety_violations(trait_def_id); - self.tcx.report_object_safety_error(span, - trait_def_id, - violations) + if let Some(err) = self.tcx.report_object_safety_error( + span, + trait_def_id, + violations, + ) { + err + } else { + return; + } } ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { @@ -884,7 +890,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { TraitNotObjectSafe(did) => { let violations = self.tcx.global_tcx().object_safety_violations(did); - self.tcx.report_object_safety_error(span, did, violations) + if let Some(err) = self.tcx.report_object_safety_error(span, did, violations) { + err + } else { + return; + } } // already reported in the query @@ -1293,12 +1303,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { err } - pub fn report_object_safety_error(self, - span: Span, - trait_def_id: DefId, - violations: Vec) - -> DiagnosticBuilder<'tcx> - { + pub fn report_object_safety_error( + self, + span: Span, + trait_def_id: DefId, + violations: Vec, + ) -> Option> { + if self.sess.trait_methods_not_found.borrow().contains(&span) { + // Avoid emitting error caused by non-existing method (#58734) + return None; + } let trait_str = self.def_path_str(trait_def_id); let span = self.sess.source_map().def_span(span); let mut err = struct_span_err!( @@ -1313,7 +1327,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { err.note(&violation.error_msg()); } } - err + Some(err) } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9ca75566b4280..22fa3dcfb523c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1012,9 +1012,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let object_safety_violations = tcx.global_tcx().astconv_object_safety_violations(principal.def_id()); if !object_safety_violations.is_empty() { - tcx.report_object_safety_error( - span, principal.def_id(), object_safety_violations) - .emit(); + tcx.report_object_safety_error(span, principal.def_id(), object_safety_violations) + .map(|mut err| err.emit()); return tcx.types.err; } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index b4a1a2d76c262..5088c5069ba40 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -60,13 +60,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - pub fn report_method_error<'b>(&self, - span: Span, - rcvr_ty: Ty<'tcx>, - item_name: ast::Ident, - source: SelfSource<'b>, - error: MethodError<'tcx>, - args: Option<&'gcx [hir::Expr]>) { + pub fn report_method_error<'b>( + &self, + span: Span, + rcvr_ty: Ty<'tcx>, + item_name: ast::Ident, + source: SelfSource<'b>, + error: MethodError<'tcx>, + args: Option<&'gcx [hir::Expr]>, + ) { // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { return; @@ -373,6 +375,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } else { err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str)); + self.tcx.sess.trait_methods_not_found.borrow_mut().insert(span); } if self.is_fn_ty(&rcvr_ty, span) { diff --git a/src/test/ui/issues/issue-58734.rs b/src/test/ui/issues/issue-58734.rs new file mode 100644 index 0000000000000..bbdfebe1577c7 --- /dev/null +++ b/src/test/ui/issues/issue-58734.rs @@ -0,0 +1,22 @@ +trait Trait { + fn exists(self) -> (); + + fn not_object_safe() -> Self; +} + +impl Trait for () { + fn exists(self) -> () { + } + + fn not_object_safe() -> Self { + () + } +} + +fn main() { + // object-safe or not, this call is OK + Trait::exists(()); + // no object safety error + Trait::nonexistent(()); + //~^ ERROR no function or associated item named `nonexistent` found for type `dyn Trait` +} diff --git a/src/test/ui/issues/issue-58734.stderr b/src/test/ui/issues/issue-58734.stderr new file mode 100644 index 0000000000000..d2f356df7ced3 --- /dev/null +++ b/src/test/ui/issues/issue-58734.stderr @@ -0,0 +1,11 @@ +error[E0599]: no function or associated item named `nonexistent` found for type `dyn Trait` in the current scope + --> $DIR/issue-58734.rs:20:12 + | +LL | Trait::nonexistent(()); + | -------^^^^^^^^^^^ + | | + | function or associated item not found in `dyn Trait` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`.