diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_ast_lowering/src/expr.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_error_messages/locales/en-US/lint.ftl | 3 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/coherence/orphan.rs | 23 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/demand.rs | 25 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/expr.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 84 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/builtin.rs | 72 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/lib.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 26 |
10 files changed, 228 insertions, 36 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index a3f5c18f2e7..3634e6e47ce 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -656,18 +656,14 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Closure(c) }; - let track_caller = self - .attrs - .get(&outer_hir_id.local_id) - .map_or(false, |attrs| attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))); - let hir_id = self.lower_node_id(closure_node_id); - if track_caller { - let unstable_span = self.mark_span_with_reason( - DesugaringKind::Async, - span, - self.allow_gen_future.clone(), - ); + let unstable_span = + self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); + + if self.tcx.features().closure_track_caller + && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) + && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)) + { self.lower_attrs( hir_id, &[Attribute { diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 7e28f22c0ba..2eb409a5ddd 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -350,6 +350,9 @@ lint_builtin_mutable_transmutes = lint_builtin_unstable_features = unstable feature +lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op + .label = this function will not propagate the caller location + lint_builtin_unreachable_pub = unreachable `pub` {$what} .suggestion = consider restricting its visibility .help = or consider exporting it for use by other crates diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index cc5114dba5e..c6d4aeefc80 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -184,11 +184,19 @@ fn emit_orphan_check_error<'tcx>( ty::Adt(def, _) => tcx.mk_adt(*def, ty::List::empty()), _ => ty, }; - let this = "this".to_string(); - let (ty, postfix) = match &ty.kind() { - ty::Slice(_) => (this, " because slices are always foreign"), - ty::Array(..) => (this, " because arrays are always foreign"), - ty::Tuple(..) => (this, " because tuples are always foreign"), + let msg = |ty: &str, postfix: &str| { + format!("{ty} is not defined in the current crate{postfix}") + }; + let this = |name: &str| msg("this", &format!(" because {name} are always foreign")); + let msg = match &ty.kind() { + ty::Slice(_) => this("slices"), + ty::Array(..) => this("arrays"), + ty::Tuple(..) => this("tuples"), + ty::Alias(ty::Opaque, ..) => { + "type alias impl trait is treated as if it were foreign, \ + because its hidden type could be from a foreign crate" + .to_string() + } ty::RawPtr(ptr_ty) => { emit_newtype_suggestion_for_raw_ptr( full_impl_span, @@ -198,12 +206,11 @@ fn emit_orphan_check_error<'tcx>( &mut err, ); - (format!("`{}`", ty), " because raw pointers are always foreign") + msg(&format!("`{ty}`"), " because raw pointers are always foreign") } - _ => (format!("`{}`", ty), ""), + _ => msg(&format!("`{ty}`"), ""), }; - let msg = format!("{} is not defined in the current crate{}", ty, postfix); if is_target_ty { // Point at `D<A>` in `impl<A, B> for C<B> in D<A>` err.span_label(self_ty_span, &msg); diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 479aaf2e1a7..e68bd1297c8 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -23,24 +23,24 @@ use std::cmp::min; use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub fn emit_coerce_suggestions( + pub fn emit_type_mismatch_suggestions( &self, err: &mut Diagnostic, expr: &hir::Expr<'tcx>, expr_ty: Ty<'tcx>, expected: Ty<'tcx>, expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, - error: Option<TypeError<'tcx>>, + _error: Option<TypeError<'tcx>>, ) { if expr_ty == expected { return; } - self.annotate_expected_due_to_let_ty(err, expr, error); - // Use `||` to give these suggestions a precedence let _ = self.suggest_missing_parentheses(err, expr) + || self.suggest_associated_const(err, expr, expected) || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr) + || self.suggest_option_to_bool(err, expr, expr_ty, expected) || self.suggest_compatible_variants(err, expr, expected, expr_ty) || self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty) || self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) @@ -49,9 +49,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected) || self.suggest_copied_or_cloned(err, expr, expr_ty, expected) || self.suggest_into(err, expr, expr_ty, expected) - || self.suggest_option_to_bool(err, expr, expr_ty, expected) || self.suggest_floating_point_literal(err, expr, expected); + } + pub fn emit_coerce_suggestions( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'tcx>, + expr_ty: Ty<'tcx>, + expected: Ty<'tcx>, + expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, + error: Option<TypeError<'tcx>>, + ) { + if expr_ty == expected { + return; + } + + self.annotate_expected_due_to_let_ty(err, expr, error); + self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error); self.note_type_is_not_clone(err, expected, expr_ty, expr); self.note_need_for_fn_pointer(err, expected, expr_ty); self.note_internal_mutation_in_method(err, expr, expected, expr_ty); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index edbbb7272ac..ae641b26eee 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -104,16 +104,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { - // FIXME(compiler-errors): We probably should fold some of the - // `suggest_` functions from `emit_coerce_suggestions` into here, - // since some of those aren't necessarily just coerce suggestions. - let _ = self.suggest_deref_ref_or_into( + let _ = self.emit_type_mismatch_suggestions( &mut err, expr.peel_drop_temps(), - expected_ty, ty, + expected_ty, None, - ) || self.suggest_option_to_bool(&mut err, expr, ty, expected_ty); + None, + ); extend_err(&mut err); err.emit(); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index d1e0964112b..877680053f0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -214,7 +214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "cannot use call notation; the first type parameter \ for the function trait is neither a tuple nor unit" ) - .delay_as_bug(); + .emit(); (self.err_args(provided_args.len()), None) } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index c9d179de39f..efec0244633 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1,6 +1,7 @@ use super::FnCtxt; use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel}; +use crate::method::probe::{IsSuggestion, Mode, ProbeScope}; use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; use rustc_errors::{Applicability, Diagnostic, MultiSpan}; use rustc_hir as hir; @@ -15,10 +16,11 @@ use rustc_infer::traits::{self, StatementAsExpression}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{ self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty, + TypeVisitable, }; use rustc_session::errors::ExprParenthesesNeeded; -use rustc_span::symbol::sym; -use rustc_span::Span; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::{Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::DefIdOrName; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -1236,6 +1238,84 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub(crate) fn suggest_associated_const( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'_>, + expected_ty: Ty<'tcx>, + ) -> bool { + let Some((DefKind::AssocFn, old_def_id)) = self.typeck_results.borrow().type_dependent_def(expr.hir_id) else { + return false; + }; + let old_item_name = self.tcx.item_name(old_def_id); + let capitalized_name = Symbol::intern(&old_item_name.as_str().to_uppercase()); + if old_item_name == capitalized_name { + return false; + } + let (item, segment) = match expr.kind { + hir::ExprKind::Path(QPath::Resolved( + Some(ty), + hir::Path { segments: [segment], .. }, + )) + | hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => { + let self_ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty); + if let Ok(pick) = self.probe_for_name( + Mode::Path, + Ident::new(capitalized_name, segment.ident.span), + IsSuggestion(true), + self_ty, + expr.hir_id, + ProbeScope::TraitsInScope, + ) { + (pick.item, segment) + } else { + return false; + } + } + hir::ExprKind::Path(QPath::Resolved( + None, + hir::Path { segments: [.., segment], .. }, + )) => { + // we resolved through some path that doesn't end in the item name, + // better not do a bad suggestion by accident. + if old_item_name != segment.ident.name { + return false; + } + if let Some(item) = self + .tcx + .associated_items(self.tcx.parent(old_def_id)) + .filter_by_name_unhygienic(capitalized_name) + .next() + { + (*item, segment) + } else { + return false; + } + } + _ => return false, + }; + if item.def_id == old_def_id || self.tcx.def_kind(item.def_id) != DefKind::AssocConst { + // Same item + return false; + } + let item_ty = self.tcx.type_of(item.def_id); + // FIXME(compiler-errors): This check is *so* rudimentary + if item_ty.needs_subst() { + return false; + } + if self.can_coerce(item_ty, expected_ty) { + err.span_suggestion_verbose( + segment.ident.span, + format!("try referring to the associated const `{capitalized_name}` instead",), + capitalized_name, + Applicability::MachineApplicable, + ); + true + } else { + false + } + } + fn is_loop(&self, id: hir::HirId) -> bool { let node = self.tcx.hir().get(id); matches!(node, Node::Expr(Expr { kind: ExprKind::Loop(..), .. })) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index cd19e65b6fc..d6de6e70ead 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -25,6 +25,7 @@ use crate::{ types::{transparent_newtype_field, CItemKind}, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, }; +use hir::IsAsync; use rustc_ast::attr; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; @@ -40,7 +41,10 @@ use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, Gate use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; -use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, Node, PatKind, PredicateOrigin}; +use rustc_hir::intravisit::FnKind as HirFnKind; +use rustc_hir::{ + Body, FnDecl, ForeignItemKind, GenericParamKind, HirId, Node, PatKind, PredicateOrigin, +}; use rustc_index::vec::Idx; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::{LayoutError, LayoutOf}; @@ -1371,6 +1375,72 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { } declare_lint! { + /// The `ungated_async_fn_track_caller` lint warns when the + /// `#[track_caller]` attribute is used on an async function, method, or + /// closure, without enabling the corresponding unstable feature flag. + /// + /// ### Example + /// + /// ```rust + /// #[track_caller] + /// async fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The attribute must be used in conjunction with the + /// [`closure_track_caller` feature flag]. Otherwise, the `#[track_caller]` + /// annotation will function as as no-op. + /// + /// [`closure_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/closure-track-caller.html + UNGATED_ASYNC_FN_TRACK_CALLER, + Warn, + "enabling track_caller on an async fn is a no-op unless the closure_track_caller feature is enabled" +} + +declare_lint_pass!( + /// Explains corresponding feature flag must be enabled for the `#[track_caller] attribute to + /// do anything + UngatedAsyncFnTrackCaller => [UNGATED_ASYNC_FN_TRACK_CALLER] +); + +impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { + fn check_fn( + &mut self, + cx: &LateContext<'_>, + fn_kind: HirFnKind<'_>, + _: &'tcx FnDecl<'_>, + _: &'tcx Body<'_>, + span: Span, + hir_id: HirId, + ) { + if fn_kind.asyncness() == IsAsync::Async + && !cx.tcx.features().closure_track_caller + && let attrs = cx.tcx.hir().attrs(hir_id) + // Now, check if the function has the `#[track_caller]` attribute + && let Some(attr) = attrs.iter().find(|attr| attr.has_name(sym::track_caller)) + { + cx.struct_span_lint( + UNGATED_ASYNC_FN_TRACK_CALLER, + attr.span, + fluent::lint_ungated_async_fn_track_caller, + |lint| { + lint.span_label(span, fluent::label); + rustc_session::parse::add_feature_diagnostics( + lint, + &cx.tcx.sess.parse_sess, + sym::closure_track_caller, + ); + lint + }, + ); + } + } +} + +declare_lint! { /// The `unreachable_pub` lint triggers for `pub` items not reachable from /// the crate root. /// diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 11022eb80ea..1275d6f223c 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -219,6 +219,7 @@ late_lint_methods!( // May Depend on constants elsewhere UnusedBrokenConst: UnusedBrokenConst, UnstableFeatures: UnstableFeatures, + UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller, ArrayIntoIter: ArrayIntoIter::default(), DropTraitConstraints: DropTraitConstraints, TemporaryCStringAsPtr: TemporaryCStringAsPtr, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 4861ee746aa..2182b736937 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1686,6 +1686,24 @@ impl<'a> Resolver<'a> { .or_insert_with(|| self.arenas.alloc_name_resolution()) } + /// Test if AmbiguityError ambi is any identical to any one inside ambiguity_errors + fn matches_previous_ambiguity_error(&mut self, ambi: &AmbiguityError<'_>) -> bool { + for ambiguity_error in &self.ambiguity_errors { + // if the span location and ident as well as its span are the same + if ambiguity_error.kind == ambi.kind + && ambiguity_error.ident == ambi.ident + && ambiguity_error.ident.span == ambi.ident.span + && ambiguity_error.b1.span == ambi.b1.span + && ambiguity_error.b2.span == ambi.b2.span + && ambiguity_error.misc1 == ambi.misc1 + && ambiguity_error.misc2 == ambi.misc2 + { + return true; + } + } + false + } + fn record_use( &mut self, ident: Ident, @@ -1693,14 +1711,18 @@ impl<'a> Resolver<'a> { is_lexical_scope: bool, ) { if let Some((b2, kind)) = used_binding.ambiguity { - self.ambiguity_errors.push(AmbiguityError { + let ambiguity_error = AmbiguityError { kind, ident, b1: used_binding, b2, misc1: AmbiguityErrorMisc::None, misc2: AmbiguityErrorMisc::None, - }); + }; + if !self.matches_previous_ambiguity_error(&ambiguity_error) { + // avoid dumplicated span information to be emitt out + self.ambiguity_errors.push(ambiguity_error); + } } if let NameBindingKind::Import { import, binding, ref used } = used_binding.kind { // Avoid marking `extern crate` items that refer to a name from extern prelude, |
