diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_ast_passes/src/feature_gate.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_errors/Cargo.toml | 2 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs | 69 | ||||
| -rw-r--r-- | compiler/rustc_feature/src/accepted.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_feature/src/unstable.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_fluent_macro/Cargo.toml | 2 | ||||
| -rw-r--r-- | compiler/rustc_fluent_macro/src/fluent.rs | 30 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/hir.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_lint/messages.ftl | 3 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/impl_trait_overcaptures.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/lib.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/tail_expr_drop_order.rs | 306 | ||||
| -rw-r--r-- | compiler/rustc_monomorphize/src/collector.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/build_reduced_graph.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/error_reporting/infer/region.rs | 22 |
17 files changed, 378 insertions, 101 deletions
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5ab99fbac86..45e397a58c0 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -556,7 +556,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(fn_delegation, "functions delegation is not yet fully implemented"); gate_all!(postfix_match, "postfix match is experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental"); - gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental"); gate_all!(global_registration, "global registration is experimental"); gate_all!(return_type_notation, "return type notation is experimental"); diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 2fff9f2de50..59cf4e5f210 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -annotate-snippets = "0.10" +annotate-snippets = "0.11" derive_setters = "0.1.6" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index df4e9792f95..d71ae9d210d 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -5,7 +5,7 @@ //! //! [annotate_snippets]: https://docs.rs/crate/annotate-snippets/ -use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation}; +use annotate_snippets::{Renderer, Snippet}; use rustc_data_structures::sync::Lrc; use rustc_error_messages::FluentArgs; use rustc_span::source_map::SourceMap; @@ -83,15 +83,17 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String { file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or_default() } -/// Maps `diagnostic::Level` to `snippet::AnnotationType` -fn annotation_type_for_level(level: Level) -> AnnotationType { +/// Maps [`crate::Level`] to [`annotate_snippets::Level`] +fn annotation_level_for_level(level: Level) -> annotate_snippets::Level { match level { - Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => AnnotationType::Error, - Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning, - Level::Note | Level::OnceNote => AnnotationType::Note, - Level::Help | Level::OnceHelp => AnnotationType::Help, + Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => { + annotate_snippets::Level::Error + } + Level::ForceWarning(_) | Level::Warning => annotate_snippets::Level::Warning, + Level::Note | Level::OnceNote => annotate_snippets::Level::Note, + Level::Help | Level::OnceHelp => annotate_snippets::Level::Help, // FIXME(#59346): Not sure how to map this level - Level::FailureNote => AnnotationType::Error, + Level::FailureNote => annotate_snippets::Level::Error, Level::Allow => panic!("Should not call with Allow"), Level::Expect(_) => panic!("Should not call with Expect"), } @@ -180,42 +182,29 @@ impl AnnotateSnippetEmitter { }) .collect(); let code = code.map(|code| code.to_string()); - let snippet = Snippet { - title: Some(Annotation { - label: Some(&message), - id: code.as_deref(), - annotation_type: annotation_type_for_level(*level), - }), - footer: vec![], - slices: annotated_files - .iter() - .map(|(file_name, source, line_index, annotations)| { - Slice { - source, - line_start: *line_index, - origin: Some(file_name), - // FIXME(#59346): Not really sure when `fold` should be true or false - fold: false, - annotations: annotations - .iter() - .map(|annotation| SourceAnnotation { - range: ( - annotation.start_col.display, - annotation.end_col.display, - ), - label: annotation.label.as_deref().unwrap_or_default(), - annotation_type: annotation_type_for_level(*level), - }) - .collect(), - } - }) - .collect(), - }; + + let snippets = + annotated_files.iter().map(|(file_name, source, line_index, annotations)| { + Snippet::source(source) + .line_start(*line_index) + .origin(file_name) + // FIXME(#59346): Not really sure when `fold` should be true or false + .fold(false) + .annotations(annotations.iter().map(|annotation| { + annotation_level_for_level(*level) + .span(annotation.start_col.display..annotation.end_col.display) + .label(annotation.label.as_deref().unwrap_or_default()) + })) + }); + let mut message = annotation_level_for_level(*level).title(&message).snippets(snippets); + if let Some(code) = code.as_deref() { + message = message.id(code) + } // FIXME(#59346): Figure out if we can _always_ print to stderr or not. // `emitter.rs` has the `Destination` enum that lists various possible output // destinations. let renderer = Renderer::plain().anonymized_line_numbers(self.ui_testing); - eprintln!("{}", renderer.render(snippet)) + eprintln!("{}", renderer.render(message)) } // FIXME(#59346): Is it ok to return None if there's no source_map? } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 7838abca9b8..a4a2028e26e 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -309,6 +309,8 @@ declare_features! ( (accepted, param_attrs, "1.39.0", Some(60406)), /// Allows parentheses in patterns. (accepted, pattern_parentheses, "1.31.0", Some(51087)), + /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. + (accepted, precise_capturing, "CURRENT_RUSTC_VERSION", Some(123432)), /// Allows procedural macros in `proc-macro` crates. (accepted, proc_macro, "1.29.0", Some(38356)), /// Allows multi-segment paths in attributes and derives. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 14e353f13ca..a1741ac33ca 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -561,8 +561,6 @@ declare_features! ( (unstable, patchable_function_entry, "1.81.0", Some(123115)), /// Allows postfix match `expr.match { ... }` (unstable, postfix_match, "1.79.0", Some(121618)), - /// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args. - (unstable, precise_capturing, "1.79.0", Some(123432)), /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. diff --git a/compiler/rustc_fluent_macro/Cargo.toml b/compiler/rustc_fluent_macro/Cargo.toml index c5a53ae8313..eeceaa4691a 100644 --- a/compiler/rustc_fluent_macro/Cargo.toml +++ b/compiler/rustc_fluent_macro/Cargo.toml @@ -8,7 +8,7 @@ proc-macro = true [dependencies] # tidy-alphabetical-start -annotate-snippets = "0.10" +annotate-snippets = "0.11" fluent-bundle = "0.15.2" fluent-syntax = "0.11" proc-macro2 = "1" diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs index 23795a96b92..ca8bace28f3 100644 --- a/compiler/rustc_fluent_macro/src/fluent.rs +++ b/compiler/rustc_fluent_macro/src/fluent.rs @@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet}; use std::fs::read_to_string; use std::path::{Path, PathBuf}; -use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation}; +use annotate_snippets::{Renderer, Snippet}; use fluent_bundle::{FluentBundle, FluentError, FluentResource}; use fluent_syntax::ast::{ Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern, PatternElement, @@ -154,27 +154,15 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok .unwrap() .0; - let snippet = Snippet { - title: Some(Annotation { - label: Some(&err), - id: None, - annotation_type: AnnotationType::Error, - }), - footer: vec![], - slices: vec![Slice { - source: this.source(), - line_start, - origin: Some(&relative_ftl_path), - fold: true, - annotations: vec![SourceAnnotation { - label: "", - annotation_type: AnnotationType::Error, - range: (pos.start, pos.end - 1), - }], - }], - }; + let message = annotate_snippets::Level::Error.title(&err).snippet( + Snippet::source(this.source()) + .line_start(line_start) + .origin(&relative_ftl_path) + .fold(true) + .annotation(annotate_snippets::Level::Error.span(pos.start..pos.end - 1)), + ); let renderer = Renderer::plain(); - eprintln!("{}\n", renderer.render(snippet)); + eprintln!("{}\n", renderer.render(message)); } return failed(&crate_name); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6c7125b75db..57c47d29857 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2773,7 +2773,6 @@ impl PreciseCapturingArg<'_> { /// resolution to. Lifetimes don't have this problem, and for them, it's actually /// kind of detrimental to use a custom node type versus just using [`Lifetime`], /// since resolve_bound_vars operates on `Lifetime`s. -// FIXME(precise_capturing): Investigate storing this as a path instead? #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct PreciseCapturingNonLifetimeArg { pub hir_id: HirId, diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 7a394a6d6c1..28aef9055ef 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -758,6 +758,9 @@ lint_suspicious_double_ref_clone = lint_suspicious_double_ref_deref = using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type +lint_tail_expr_drop_order = these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021 + .label = these values have significant drop implementation and will observe changes in drop order under Edition 2024 + lint_trailing_semi_macro = trailing semicolon in macro used in expression position .note1 = macro invocations at the end of a block are treated as expressions .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}` diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index e914169f4c3..990fb2d16f9 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -27,8 +27,6 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail - /// # #![feature(precise_capturing)] - /// # #![allow(incomplete_features)] /// # #![deny(impl_trait_overcaptures)] /// # use std::fmt::Display; /// let mut x = vec![]; @@ -56,7 +54,6 @@ declare_lint! { pub IMPL_TRAIT_OVERCAPTURES, Allow, "`impl Trait` will capture more lifetimes than possibly intended in edition 2024", - @feature_gate = precise_capturing; //@future_incompatible = FutureIncompatibleInfo { // reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), // reference: "<FIXME>", @@ -75,8 +72,7 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail - /// # #![feature(precise_capturing, lifetime_capture_rules_2024)] - /// # #![allow(incomplete_features)] + /// # #![feature(lifetime_capture_rules_2024)] /// # #![deny(impl_trait_redundant_captures)] /// fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x } /// ``` @@ -90,7 +86,6 @@ declare_lint! { pub IMPL_TRAIT_REDUNDANT_CAPTURES, Warn, "redundant precise-capturing `use<...>` syntax on an `impl Trait`", - @feature_gate = precise_capturing; } declare_lint_pass!( diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 4f3933d461b..1828b6ea93c 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -78,6 +78,7 @@ mod ptr_nulls; mod redundant_semicolon; mod reference_casting; mod shadowed_into_iter; +mod tail_expr_drop_order; mod traits; mod types; mod unit_bindings; @@ -115,6 +116,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use shadowed_into_iter::ShadowedIntoIter; pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; +use tail_expr_drop_order::TailExprDropOrder; use traits::*; use types::*; use unit_bindings::*; @@ -238,6 +240,7 @@ late_lint_methods!( AsyncFnInTrait: AsyncFnInTrait, NonLocalDefinitions: NonLocalDefinitions::default(), ImplTraitOvercaptures: ImplTraitOvercaptures, + TailExprDropOrder: TailExprDropOrder, ] ] ); diff --git a/compiler/rustc_lint/src/tail_expr_drop_order.rs b/compiler/rustc_lint/src/tail_expr_drop_order.rs new file mode 100644 index 00000000000..f9ecc8c9806 --- /dev/null +++ b/compiler/rustc_lint/src/tail_expr_drop_order.rs @@ -0,0 +1,306 @@ +use std::mem::swap; + +use rustc_ast::UnOp; +use rustc_hir::def::Res; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::{self as hir, Block, Expr, ExprKind, LetStmt, Pat, PatKind, QPath, StmtKind}; +use rustc_macros::LintDiagnostic; +use rustc_middle::ty; +use rustc_session::lint::FutureIncompatibilityReason; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::edition::Edition; +use rustc_span::Span; + +use crate::{LateContext, LateLintPass}; + +declare_lint! { + /// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location, that of type + /// with a significant `Drop` implementation, such as locks. + /// In case there are also local variables of type with significant `Drop` implementation as well, + /// this lint warns you of a potential transposition in the drop order. + /// Your discretion on the new drop order introduced by Edition 2024 is required. + /// + /// ### Example + /// ```rust,edition2024 + /// #![feature(shorter_tail_lifetimes)] + /// #![warn(tail_expr_drop_order)] + /// struct Droppy(i32); + /// impl Droppy { + /// fn get(&self) -> i32 { + /// self.0 + /// } + /// } + /// impl Drop for Droppy { + /// fn drop(&mut self) { + /// // This is a custom destructor and it induces side-effects that is observable + /// // especially when the drop order at a tail expression changes. + /// println!("loud drop {}", self.0); + /// } + /// } + /// fn edition_2024() -> i32 { + /// let another_droppy = Droppy(0); + /// Droppy(1).get() + /// } + /// fn main() { + /// edition_2024(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In tail expression of blocks or function bodies, + /// values of type with significant `Drop` implementation has an ill-specified drop order + /// before Edition 2024 so that they are dropped only after dropping local variables. + /// Edition 2024 introduces a new rule with drop orders for them, + /// so that they are dropped first before dropping local variables. + /// + /// A significant `Drop::drop` destructor here refers to an explicit, arbitrary + /// implementation of the `Drop` trait on the type, with exceptions including `Vec`, + /// `Box`, `Rc`, `BTreeMap` and `HashMap` that are marked by the compiler otherwise + /// so long that the generic types have no significant destructor recursively. + /// In other words, a type has a significant drop destructor when it has a `Drop` implementation + /// or its destructor invokes a significant destructor on a type. + /// Since we cannot completely reason about the change by just inspecting the existence of + /// a significant destructor, this lint remains only a suggestion and is set to `allow` by default. + /// + /// This lint only points out the issue with `Droppy`, which will be dropped before `another_droppy` + /// does in Edition 2024. + /// No fix will be proposed by this lint. + /// However, the most probable fix is to hoist `Droppy` into its own local variable binding. + /// ```rust + /// struct Droppy(i32); + /// impl Droppy { + /// fn get(&self) -> i32 { + /// self.0 + /// } + /// } + /// fn edition_2024() -> i32 { + /// let value = Droppy(0); + /// let another_droppy = Droppy(1); + /// value.get() + /// } + /// ``` + pub TAIL_EXPR_DROP_ORDER, + Allow, + "Detect and warn on significant change in drop order in tail expression location", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), + reference: "issue #123739 <https://github.com/rust-lang/rust/issues/123739>", + }; +} + +declare_lint_pass!(TailExprDropOrder => [TAIL_EXPR_DROP_ORDER]); + +impl TailExprDropOrder { + fn check_fn_or_closure<'tcx>( + cx: &LateContext<'tcx>, + fn_kind: hir::intravisit::FnKind<'tcx>, + body: &'tcx hir::Body<'tcx>, + def_id: rustc_span::def_id::LocalDefId, + ) { + let mut locals = vec![]; + if matches!(fn_kind, hir::intravisit::FnKind::Closure) { + for &capture in cx.tcx.closure_captures(def_id) { + if matches!(capture.info.capture_kind, ty::UpvarCapture::ByValue) + && capture.place.ty().has_significant_drop(cx.tcx, cx.param_env) + { + locals.push(capture.var_ident.span); + } + } + } + for param in body.params { + if cx + .typeck_results() + .node_type(param.hir_id) + .has_significant_drop(cx.tcx, cx.param_env) + { + locals.push(param.span); + } + } + if let hir::ExprKind::Block(block, _) = body.value.kind { + LintVisitor { cx, locals }.check_block_inner(block); + } else { + LintTailExpr { cx, locals: &locals, is_root_tail_expr: true }.visit_expr(body.value); + } + } +} + +impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + fn_kind: hir::intravisit::FnKind<'tcx>, + _: &'tcx hir::FnDecl<'tcx>, + body: &'tcx hir::Body<'tcx>, + _: Span, + def_id: rustc_span::def_id::LocalDefId, + ) { + if cx.tcx.sess.at_least_rust_2024() && cx.tcx.features().shorter_tail_lifetimes { + Self::check_fn_or_closure(cx, fn_kind, body, def_id); + } + } +} + +struct LintVisitor<'tcx, 'a> { + cx: &'a LateContext<'tcx>, + // We only record locals that have significant drops + locals: Vec<Span>, +} + +struct LocalCollector<'tcx, 'a> { + cx: &'a LateContext<'tcx>, + locals: &'a mut Vec<Span>, +} + +impl<'tcx, 'a> Visitor<'tcx> for LocalCollector<'tcx, 'a> { + type Result = (); + fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) { + if let PatKind::Binding(_binding_mode, id, ident, pat) = pat.kind { + let ty = self.cx.typeck_results().node_type(id); + if ty.has_significant_drop(self.cx.tcx, self.cx.param_env) { + self.locals.push(ident.span); + } + if let Some(pat) = pat { + self.visit_pat(pat); + } + } else { + intravisit::walk_pat(self, pat); + } + } +} + +impl<'tcx, 'a> Visitor<'tcx> for LintVisitor<'tcx, 'a> { + fn visit_block(&mut self, block: &'tcx Block<'tcx>) { + let mut locals = <_>::default(); + swap(&mut locals, &mut self.locals); + self.check_block_inner(block); + swap(&mut locals, &mut self.locals); + } + fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) { + LocalCollector { cx: self.cx, locals: &mut self.locals }.visit_local(local); + } +} + +impl<'tcx, 'a> LintVisitor<'tcx, 'a> { + fn check_block_inner(&mut self, block: &Block<'tcx>) { + if !block.span.at_least_rust_2024() { + // We only lint for Edition 2024 onwards + return; + } + let Some(tail_expr) = block.expr else { return }; + for stmt in block.stmts { + match stmt.kind { + StmtKind::Let(let_stmt) => self.visit_local(let_stmt), + StmtKind::Item(_) => {} + StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e), + } + } + if self.locals.is_empty() { + return; + } + LintTailExpr { cx: self.cx, locals: &self.locals, is_root_tail_expr: true } + .visit_expr(tail_expr); + } +} + +struct LintTailExpr<'tcx, 'a> { + cx: &'a LateContext<'tcx>, + is_root_tail_expr: bool, + locals: &'a [Span], +} + +impl<'tcx, 'a> LintTailExpr<'tcx, 'a> { + fn expr_eventually_point_into_local(mut expr: &Expr<'tcx>) -> bool { + loop { + match expr.kind { + ExprKind::Index(access, _, _) | ExprKind::Field(access, _) => expr = access, + ExprKind::AddrOf(_, _, referee) | ExprKind::Unary(UnOp::Deref, referee) => { + expr = referee + } + ExprKind::Path(_) + if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind + && let [local, ..] = path.segments + && let Res::Local(_) = local.res => + { + return true; + } + _ => return false, + } + } + } + + fn expr_generates_nonlocal_droppy_value(&self, expr: &Expr<'tcx>) -> bool { + if Self::expr_eventually_point_into_local(expr) { + return false; + } + self.cx.typeck_results().expr_ty(expr).has_significant_drop(self.cx.tcx, self.cx.param_env) + } +} + +impl<'tcx, 'a> Visitor<'tcx> for LintTailExpr<'tcx, 'a> { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + if self.is_root_tail_expr { + self.is_root_tail_expr = false; + } else if self.expr_generates_nonlocal_droppy_value(expr) { + self.cx.tcx.emit_node_span_lint( + TAIL_EXPR_DROP_ORDER, + expr.hir_id, + expr.span, + TailExprDropOrderLint { spans: self.locals.to_vec() }, + ); + return; + } + match expr.kind { + ExprKind::Match(scrutinee, _, _) => self.visit_expr(scrutinee), + + ExprKind::ConstBlock(_) + | ExprKind::Array(_) + | ExprKind::Break(_, _) + | ExprKind::Continue(_) + | ExprKind::Ret(_) + | ExprKind::Become(_) + | ExprKind::Yield(_, _) + | ExprKind::InlineAsm(_) + | ExprKind::If(_, _, _) + | ExprKind::Loop(_, _, _, _) + | ExprKind::Closure(_) + | ExprKind::DropTemps(_) + | ExprKind::OffsetOf(_, _) + | ExprKind::Assign(_, _, _) + | ExprKind::AssignOp(_, _, _) + | ExprKind::Lit(_) + | ExprKind::Err(_) => {} + + ExprKind::MethodCall(_, _, _, _) + | ExprKind::Call(_, _) + | ExprKind::Type(_, _) + | ExprKind::Tup(_) + | ExprKind::Binary(_, _, _) + | ExprKind::Unary(_, _) + | ExprKind::Path(_) + | ExprKind::Let(_) + | ExprKind::Cast(_, _) + | ExprKind::Field(_, _) + | ExprKind::Index(_, _, _) + | ExprKind::AddrOf(_, _, _) + | ExprKind::Struct(_, _, _) + | ExprKind::Repeat(_, _) => intravisit::walk_expr(self, expr), + + ExprKind::Block(_, _) => { + // We do not lint further because the drop order stays the same inside the block + } + } + } + fn visit_block(&mut self, block: &'tcx Block<'tcx>) { + LintVisitor { cx: self.cx, locals: <_>::default() }.check_block_inner(block); + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_tail_expr_drop_order)] +struct TailExprDropOrderLint { + #[label] + pub spans: Vec<Span>, +} diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 0ae635f9b73..9f449868f03 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -888,7 +888,9 @@ fn visit_instance_use<'tcx>( if tcx.should_codegen_locally(panic_instance) { output.push(create_fn_mono_item(tcx, panic_instance, source)); } - } else if tcx.has_attr(def_id, sym::rustc_intrinsic) { + } else if tcx.has_attr(def_id, sym::rustc_intrinsic) + && !tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden) + { // Codegen the fallback body of intrinsics with fallback bodies let instance = ty::Instance::new(def_id, instance.args); if tcx.should_codegen_locally(instance) { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a8e8270673a..52f0b1c1b04 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -851,7 +851,6 @@ impl<'a> Parser<'a> { // lifetimes and ident params (including SelfUpper). These are validated later // for order, duplication, and whether they actually reference params. let use_span = self.prev_token.span; - self.psess.gated_spans.gate(sym::precise_capturing, use_span); let (args, args_span) = self.parse_precise_capturing_args()?; GenericBound::Use(args, use_span.to(args_span)) } else { diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d57dabdd78d..3a27f96dde8 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -896,7 +896,8 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.potentially_unused_imports.push(import); let imported_binding = self.r.import(binding, import); if parent == self.r.graph_root { - if let Some(entry) = self.r.extern_prelude.get(&ident.normalize_to_macros_2_0()) { + let ident = ident.normalize_to_macros_2_0(); + if let Some(entry) = self.r.extern_prelude.get(&ident) { if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() { self.r.dcx().emit_err( errors::MacroExpandedExternCrateCannotShadowExternArguments { @@ -913,14 +914,21 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let entry = self .r .extern_prelude - .entry(ident.normalize_to_macros_2_0()) + .entry(ident) .or_insert(ExternPreludeEntry { binding: None, introduced_by_item: true }); - // Binding from `extern crate` item in source code can replace - // a binding from `--extern` on command line here. - entry.binding = Some(imported_binding); if orig_name.is_some() { entry.introduced_by_item = true; } + // Binding from `extern crate` item in source code can replace + // a binding from `--extern` on command line here. + if !entry.is_import() { + entry.binding = Some(imported_binding) + } else if ident.name != kw::Underscore { + self.r.dcx().span_delayed_bug( + item.span, + format!("it had been define the external module '{ident}' multiple times"), + ); + } } self.r.define(parent, ident, TypeNS, imported_binding); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 4a70fc0f308..40fdb01a72c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2677,14 +2677,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // We also can't shadow bindings from associated parent items. for ns in [ValueNS, TypeNS] { for parent_rib in self.ribs[ns].iter().rev() { - seen_bindings - .extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span))); - // Break at mod level, to account for nested items which are // allowed to shadow generic param names. if matches!(parent_rib.kind, RibKind::Module(..)) { break; } + + seen_bindings + .extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span))); } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 3cee8ff5f4c..877a8a23d7f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -17,8 +17,8 @@ use rustc_span::{BytePos, ErrorGuaranteed, Span, Symbol}; use rustc_type_ir::Upcast as _; use super::nice_region_error::find_anon_type; -use super::{nice_region_error, ObligationCauseAsDiagArg}; -use crate::error_reporting::infer::ObligationCauseExt as _; +use super::ObligationCauseAsDiagArg; +use crate::error_reporting::infer::ObligationCauseExt; use crate::error_reporting::TypeErrCtxt; use crate::errors::{ self, note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, @@ -1212,22 +1212,8 @@ pub fn unexpected_hidden_region_diagnostic<'a, 'tcx>( hidden_region, "", ); - if let Some(reg_info) = tcx.is_suitable_region(generic_param_scope, hidden_region) { - if infcx.tcx.features().precise_capturing { - suggest_precise_capturing(tcx, opaque_ty_key.def_id, hidden_region, &mut err); - } else { - let fn_returns = tcx.return_type_impl_or_dyn_traits(reg_info.def_id); - nice_region_error::suggest_new_region_bound( - tcx, - &mut err, - fn_returns, - hidden_region.to_string(), - None, - format!("captures `{hidden_region}`"), - None, - Some(reg_info.def_id), - ) - } + if let Some(_) = tcx.is_suitable_region(generic_param_scope, hidden_region) { + suggest_precise_capturing(tcx, opaque_ty_key.def_id, hidden_region, &mut err); } } ty::RePlaceholder(_) => { |
