mirror of https://github.com/rust-lang/rust.git
Auto merge of #129331 - matthiaskrgr:rollup-rxv463w, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #128662 (Lint on tail expr drop order change in Edition 2024) - #128932 (skip updating when external binding is existed) - #129270 (Don't consider locals to shadow inner items' generics) - #129277 (Update annotate-snippets to 0.11) - #129294 (Stabilize `iter::repeat_n`) - #129308 (fix: simple typo in compiler directory) - #129309 (ctfe: make CompileTimeInterpCx type alias public) - #129314 (fix a broken link in `mir/mod.rs`) - #129318 (Remove unneeded conversion to `DefId` for `ExtraInfo`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
4d7c095832
14
Cargo.lock
14
Cargo.lock
|
@ -94,16 +94,6 @@ dependencies = [
|
|||
"yansi-term",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "annotate-snippets"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d9b665789884a7e8fb06c84b295e923b03ca51edbb7d08f91a6a50322ecbfe6"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "annotate-snippets"
|
||||
version = "0.11.4"
|
||||
|
@ -3642,7 +3632,7 @@ dependencies = [
|
|||
name = "rustc_errors"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.10.2",
|
||||
"annotate-snippets 0.11.4",
|
||||
"derive_setters",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
|
@ -3702,7 +3692,7 @@ dependencies = [
|
|||
name = "rustc_fluent_macro"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.10.2",
|
||||
"annotate-snippets 0.11.4",
|
||||
"fluent-bundle",
|
||||
"fluent-syntax",
|
||||
"proc-macro2",
|
||||
|
|
|
@ -40,7 +40,10 @@ const TINY_LINT_TERMINATOR_LIMIT: usize = 20;
|
|||
/// power of two of interpreted terminators.
|
||||
const PROGRESS_INDICATOR_START: usize = 4_000_000;
|
||||
|
||||
/// Extra machine state for CTFE, and the Machine instance
|
||||
/// Extra machine state for CTFE, and the Machine instance.
|
||||
//
|
||||
// Should be public because out-of-tree rustc consumers need this
|
||||
// if they want to interact with constant values.
|
||||
pub struct CompileTimeMachine<'tcx> {
|
||||
/// The number of terminators that have been evaluated.
|
||||
///
|
||||
|
@ -160,7 +163,7 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxIndexMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>;
|
||||
pub type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum MemoryKind {
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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?
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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}`
|
||||
|
|
|
@ -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,
|
||||
]
|
||||
]
|
||||
);
|
||||
|
|
|
@ -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>,
|
||||
}
|
|
@ -1368,7 +1368,7 @@ rustc_index::newtype_index! {
|
|||
/// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg
|
||||
/// [data-flow analyses]:
|
||||
/// https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis
|
||||
/// [`CriticalCallEdges`]: ../../rustc_const_eval/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges
|
||||
/// [`CriticalCallEdges`]: ../../rustc_mir_transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges
|
||||
/// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/
|
||||
#[derive(HashStable)]
|
||||
#[encodable]
|
||||
|
|
|
@ -748,7 +748,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
self.cfg.terminate(block, source_info, TerminatorKind::UnwindResume);
|
||||
}
|
||||
|
||||
/// Sets up the drops for explict tail calls.
|
||||
/// Sets up the drops for explicit tail calls.
|
||||
///
|
||||
/// Unlike other kinds of early exits, tail calls do not go through the drop tree.
|
||||
/// Instead, all scheduled drops are immediately added to the CFG.
|
||||
|
|
|
@ -547,7 +547,7 @@ impl<D: Deps> EncoderState<D> {
|
|||
/// Encodes a node that was promoted from the previous graph. It reads the information directly from
|
||||
/// the previous dep graph for performance reasons.
|
||||
///
|
||||
/// This differs from `encode_node` where you have to explictly provide the relevant `NodeInfo`.
|
||||
/// This differs from `encode_node` where you have to explicitly provide the relevant `NodeInfo`.
|
||||
///
|
||||
/// It expects all edges to already have a new dep node index assigned.
|
||||
#[inline]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -131,7 +131,6 @@
|
|||
#![feature(inplace_iteration)]
|
||||
#![feature(iter_advance_by)]
|
||||
#![feature(iter_next_chunk)]
|
||||
#![feature(iter_repeat_n)]
|
||||
#![feature(layout_for_ptr)]
|
||||
#![feature(local_waker)]
|
||||
#![feature(maybe_uninit_slice)]
|
||||
|
|
|
@ -436,7 +436,7 @@ pub use self::sources::{once, Once};
|
|||
pub use self::sources::{once_with, OnceWith};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::sources::{repeat, Repeat};
|
||||
#[unstable(feature = "iter_repeat_n", issue = "104434")]
|
||||
#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub use self::sources::{repeat_n, RepeatN};
|
||||
#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
|
||||
pub use self::sources::{repeat_with, RepeatWith};
|
||||
|
|
|
@ -24,7 +24,7 @@ pub use self::once::{once, Once};
|
|||
pub use self::once_with::{once_with, OnceWith};
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::repeat::{repeat, Repeat};
|
||||
#[unstable(feature = "iter_repeat_n", issue = "104434")]
|
||||
#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub use self::repeat_n::{repeat_n, RepeatN};
|
||||
#[stable(feature = "iterator_repeat_with", since = "1.28.0")]
|
||||
pub use self::repeat_with::{repeat_with, RepeatWith};
|
||||
|
|
|
@ -18,7 +18,6 @@ use crate::num::NonZero;
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_repeat_n)]
|
||||
/// use std::iter;
|
||||
///
|
||||
/// // four of the number four:
|
||||
|
@ -36,7 +35,6 @@ use crate::num::NonZero;
|
|||
/// For non-`Copy` types,
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(iter_repeat_n)]
|
||||
/// use std::iter;
|
||||
///
|
||||
/// let v: Vec<i32> = Vec::with_capacity(123);
|
||||
|
@ -58,7 +56,7 @@ use crate::num::NonZero;
|
|||
/// assert_eq!(None, it.next());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_repeat_n", issue = "104434")]
|
||||
#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn repeat_n<T: Clone>(element: T, count: usize) -> RepeatN<T> {
|
||||
let mut element = ManuallyDrop::new(element);
|
||||
|
||||
|
@ -77,7 +75,7 @@ pub fn repeat_n<T: Clone>(element: T, count: usize) -> RepeatN<T> {
|
|||
/// This `struct` is created by the [`repeat_n()`] function.
|
||||
/// See its documentation for more.
|
||||
#[derive(Clone, Debug)]
|
||||
#[unstable(feature = "iter_repeat_n", issue = "104434")]
|
||||
#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub struct RepeatN<A> {
|
||||
count: usize,
|
||||
// Invariant: has been dropped iff count == 0.
|
||||
|
@ -101,14 +99,14 @@ impl<A> RepeatN<A> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "iter_repeat_n", issue = "104434")]
|
||||
#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<A> Drop for RepeatN<A> {
|
||||
fn drop(&mut self) {
|
||||
self.take_element();
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "iter_repeat_n", issue = "104434")]
|
||||
#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<A: Clone> Iterator for RepeatN<A> {
|
||||
type Item = A;
|
||||
|
||||
|
@ -156,14 +154,14 @@ impl<A: Clone> Iterator for RepeatN<A> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "iter_repeat_n", issue = "104434")]
|
||||
#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<A: Clone> ExactSizeIterator for RepeatN<A> {
|
||||
fn len(&self) -> usize {
|
||||
self.count
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "iter_repeat_n", issue = "104434")]
|
||||
#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<A: Clone> DoubleEndedIterator for RepeatN<A> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> {
|
||||
|
@ -181,12 +179,12 @@ impl<A: Clone> DoubleEndedIterator for RepeatN<A> {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "iter_repeat_n", issue = "104434")]
|
||||
#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<A: Clone> FusedIterator for RepeatN<A> {}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<A: Clone> TrustedLen for RepeatN<A> {}
|
||||
#[unstable(feature = "trusted_len_next_unchecked", issue = "37572")]
|
||||
#[stable(feature = "iter_repeat_n", since = "CURRENT_RUSTC_VERSION")]
|
||||
impl<A: Clone> UncheckedIterator for RepeatN<A> {
|
||||
#[inline]
|
||||
unsafe fn next_unchecked(&mut self) -> Self::Item {
|
||||
|
|
|
@ -73,7 +73,6 @@
|
|||
#![feature(iter_next_chunk)]
|
||||
#![feature(iter_order_by)]
|
||||
#![feature(iter_partition_in_place)]
|
||||
#![feature(iter_repeat_n)]
|
||||
#![feature(iterator_try_collect)]
|
||||
#![feature(iterator_try_reduce)]
|
||||
#![feature(layout_for_ptr)]
|
||||
|
|
|
@ -12,7 +12,7 @@ use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel, StableS
|
|||
use rustc_const_eval::const_eval::is_unstable_const_fn;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{BodyId, Mutability};
|
||||
use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
|
||||
|
@ -88,6 +88,11 @@ impl ItemId {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn as_local_def_id(self) -> Option<LocalDefId> {
|
||||
self.as_def_id().and_then(|id| id.as_local())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn krate(self) -> CrateNum {
|
||||
match self {
|
||||
|
|
|
@ -136,7 +136,7 @@ impl<'a, 'tcx> HirCollector<'a, 'tcx> {
|
|||
self.enable_per_target_ignores,
|
||||
Some(&crate::html::markdown::ExtraInfo::new(
|
||||
self.tcx,
|
||||
def_id.to_def_id(),
|
||||
def_id,
|
||||
span_of_fragments(&attrs.doc_strings).unwrap_or(sp),
|
||||
)),
|
||||
);
|
||||
|
|
|
@ -40,7 +40,7 @@ use pulldown_cmark::{
|
|||
};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{Diag, DiagMessage};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
pub(crate) use rustc_resolve::rustdoc::main_body_opts;
|
||||
use rustc_resolve::rustdoc::may_be_doc_link;
|
||||
|
@ -818,27 +818,25 @@ pub(crate) fn find_codes<T: doctest::DocTestVisitor>(
|
|||
}
|
||||
|
||||
pub(crate) struct ExtraInfo<'tcx> {
|
||||
def_id: DefId,
|
||||
def_id: LocalDefId,
|
||||
sp: Span,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ExtraInfo<'tcx> {
|
||||
pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: DefId, sp: Span) -> ExtraInfo<'tcx> {
|
||||
pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, sp: Span) -> ExtraInfo<'tcx> {
|
||||
ExtraInfo { def_id, sp, tcx }
|
||||
}
|
||||
|
||||
fn error_invalid_codeblock_attr(&self, msg: impl Into<DiagMessage>) {
|
||||
if let Some(def_id) = self.def_id.as_local() {
|
||||
self.tcx.node_span_lint(
|
||||
crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
|
||||
self.tcx.local_def_id_to_hir_id(def_id),
|
||||
self.sp,
|
||||
|lint| {
|
||||
lint.primary_message(msg);
|
||||
},
|
||||
);
|
||||
}
|
||||
self.tcx.node_span_lint(
|
||||
crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
|
||||
self.tcx.local_def_id_to_hir_id(self.def_id),
|
||||
self.sp,
|
||||
|lint| {
|
||||
lint.primary_message(msg);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn error_invalid_codeblock_attr_with_help(
|
||||
|
@ -846,17 +844,15 @@ impl<'tcx> ExtraInfo<'tcx> {
|
|||
msg: impl Into<DiagMessage>,
|
||||
f: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
|
||||
) {
|
||||
if let Some(def_id) = self.def_id.as_local() {
|
||||
self.tcx.node_span_lint(
|
||||
crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
|
||||
self.tcx.local_def_id_to_hir_id(def_id),
|
||||
self.sp,
|
||||
|lint| {
|
||||
lint.primary_message(msg);
|
||||
f(lint);
|
||||
},
|
||||
);
|
||||
}
|
||||
self.tcx.node_span_lint(
|
||||
crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
|
||||
self.tcx.local_def_id_to_hir_id(self.def_id),
|
||||
self.sp,
|
||||
|lint| {
|
||||
lint.primary_message(msg);
|
||||
f(lint);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,9 +16,11 @@ use crate::core::DocContext;
|
|||
use crate::html::markdown::{self, RustCodeBlock};
|
||||
|
||||
pub(crate) fn visit_item(cx: &DocContext<'_>, item: &clean::Item) {
|
||||
if let Some(dox) = &item.opt_doc_value() {
|
||||
if let Some(def_id) = item.item_id.as_local_def_id()
|
||||
&& let Some(dox) = &item.opt_doc_value()
|
||||
{
|
||||
let sp = item.attr_span(cx.tcx);
|
||||
let extra = crate::html::markdown::ExtraInfo::new(cx.tcx, item.item_id.expect_def_id(), sp);
|
||||
let extra = crate::html::markdown::ExtraInfo::new(cx.tcx, def_id, sp);
|
||||
for code_block in markdown::rust_code_blocks(dox, &extra) {
|
||||
check_rust_syntax(cx, item, dox, code_block);
|
||||
}
|
||||
|
|
|
@ -444,6 +444,7 @@ impl<'a> LintExtractor<'a> {
|
|||
let mut cmd = Command::new(self.rustc_path);
|
||||
if options.contains(&"edition2024") {
|
||||
cmd.arg("--edition=2024");
|
||||
cmd.arg("-Zunstable-options");
|
||||
} else if options.contains(&"edition2021") {
|
||||
cmd.arg("--edition=2021");
|
||||
} else if options.contains(&"edition2018") {
|
||||
|
|
|
@ -1289,8 +1289,7 @@ ui/imports/auxiliary/issue-52891.rs
|
|||
ui/imports/auxiliary/issue-55811.rs
|
||||
ui/imports/auxiliary/issue-56125.rs
|
||||
ui/imports/auxiliary/issue-59764.rs
|
||||
ui/imports/auxiliary/issue-85992-extern-1.rs
|
||||
ui/imports/auxiliary/issue-85992-extern-2.rs
|
||||
ui/imports/auxiliary/issue-85992-extern.rs
|
||||
ui/imports/issue-109148.rs
|
||||
ui/imports/issue-109343.rs
|
||||
ui/imports/issue-113953.rs
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
// This test ensures that `tail_expr_drop_order` does not activate in case Edition 2024 is not used
|
||||
// or the feature gate `shorter_tail_lifetimes` is disabled.
|
||||
|
||||
//@ revisions: neither no_feature_gate edition_less_than_2024
|
||||
//@ check-pass
|
||||
//@ [neither] edition: 2021
|
||||
//@ [no_feature_gate] compile-flags: -Z unstable-options
|
||||
//@ [no_feature_gate] edition: 2024
|
||||
//@ [edition_less_than_2024] edition: 2021
|
||||
|
||||
#![deny(tail_expr_drop_order)]
|
||||
#![cfg_attr(edition_less_than_2024, feature(shorter_tail_lifetimes))]
|
||||
|
||||
struct LoudDropper;
|
||||
impl Drop for LoudDropper {
|
||||
fn drop(&mut self) {
|
||||
// This destructor should be considered significant because it is a custom destructor
|
||||
// and we will assume that the destructor can generate side effects arbitrarily so that
|
||||
// a change in drop order is visible.
|
||||
println!("loud drop");
|
||||
}
|
||||
}
|
||||
impl LoudDropper {
|
||||
fn get(&self) -> i32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn should_not_lint() -> i32 {
|
||||
let x = LoudDropper;
|
||||
x.get() + LoudDropper.get()
|
||||
// Lint should not action
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,71 @@
|
|||
//@ compile-flags: -Z unstable-options
|
||||
//@ edition: 2024
|
||||
|
||||
// Edition 2024 lint for change in drop order at tail expression
|
||||
// This lint is to capture potential change in program semantics
|
||||
// due to implementation of RFC 3606 <https://github.com/rust-lang/rfcs/pull/3606>
|
||||
|
||||
#![deny(tail_expr_drop_order)]
|
||||
#![feature(shorter_tail_lifetimes)]
|
||||
|
||||
struct LoudDropper;
|
||||
impl Drop for LoudDropper {
|
||||
fn drop(&mut self) {
|
||||
// This destructor should be considered significant because it is a custom destructor
|
||||
// and we will assume that the destructor can generate side effects arbitrarily so that
|
||||
// a change in drop order is visible.
|
||||
println!("loud drop");
|
||||
}
|
||||
}
|
||||
impl LoudDropper {
|
||||
fn get(&self) -> i32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn should_lint() -> i32 {
|
||||
let x = LoudDropper;
|
||||
// Should lint
|
||||
x.get() + LoudDropper.get()
|
||||
//~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
}
|
||||
|
||||
fn should_lint_closure() -> impl FnOnce() -> i32 {
|
||||
let x = LoudDropper;
|
||||
move || x.get() + LoudDropper.get()
|
||||
//~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
}
|
||||
|
||||
fn should_not_lint() -> i32 {
|
||||
let x = LoudDropper;
|
||||
// Should not lint
|
||||
x.get()
|
||||
}
|
||||
|
||||
fn should_not_lint_in_nested_block() -> i32 {
|
||||
let x = LoudDropper;
|
||||
// Should not lint because Edition 2021 drops temporaries in blocks earlier already
|
||||
{ LoudDropper.get() }
|
||||
}
|
||||
|
||||
fn should_not_lint_in_match_arm() -> i32 {
|
||||
let x = LoudDropper;
|
||||
// Should not lint because Edition 2021 drops temporaries in blocks earlier already
|
||||
match &x {
|
||||
_ => LoudDropper.get(),
|
||||
}
|
||||
}
|
||||
|
||||
fn should_lint_in_nested_items() {
|
||||
fn should_lint_me() -> i32 {
|
||||
let x = LoudDropper;
|
||||
// Should lint
|
||||
x.get() + LoudDropper.get()
|
||||
//~^ ERROR: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
|
||||
//~| WARN: this changes meaning in Rust 2024
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,42 @@
|
|||
error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
|
||||
--> $DIR/lint-tail-expr-drop-order.rs:29:15
|
||||
|
|
||||
LL | let x = LoudDropper;
|
||||
| - these values have significant drop implementation and will observe changes in drop order under Edition 2024
|
||||
LL | // Should lint
|
||||
LL | x.get() + LoudDropper.get()
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
|
||||
note: the lint level is defined here
|
||||
--> $DIR/lint-tail-expr-drop-order.rs:8:9
|
||||
|
|
||||
LL | #![deny(tail_expr_drop_order)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
|
||||
--> $DIR/lint-tail-expr-drop-order.rs:36:23
|
||||
|
|
||||
LL | let x = LoudDropper;
|
||||
| - these values have significant drop implementation and will observe changes in drop order under Edition 2024
|
||||
LL | move || x.get() + LoudDropper.get()
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
|
||||
|
||||
error: these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
|
||||
--> $DIR/lint-tail-expr-drop-order.rs:65:19
|
||||
|
|
||||
LL | let x = LoudDropper;
|
||||
| - these values have significant drop implementation and will observe changes in drop order under Edition 2024
|
||||
LL | // Should lint
|
||||
LL | x.get() + LoudDropper.get()
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= warning: this changes meaning in Rust 2024
|
||||
= note: for more information, see issue #123739 <https://github.com/rust-lang/rust/issues/123739>
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#[macro_export]
|
||||
macro_rules! m {
|
||||
() => {
|
||||
use issue_85992_extern_2::Outcome;
|
||||
use empty::Outcome;
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
//@ edition: 2021
|
||||
//@ compile-flags: --extern issue_85992_extern_1 --extern issue_85992_extern_2
|
||||
//@ aux-build: issue-85992-extern-1.rs
|
||||
//@ aux-build: issue-85992-extern-2.rs
|
||||
//@ compile-flags: --extern issue_85992_extern --extern empty
|
||||
//@ aux-build: issue-85992-extern.rs
|
||||
//@ aux-build: empty.rs
|
||||
|
||||
issue_85992_extern_1::m!();
|
||||
issue_85992_extern::m!();
|
||||
|
||||
use crate::issue_85992_extern_2;
|
||||
//~^ ERROR unresolved import `crate::issue_85992_extern_2`
|
||||
use crate::empty;
|
||||
//~^ ERROR unresolved import `crate::empty`
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0432]: unresolved import `crate::issue_85992_extern_2`
|
||||
error[E0432]: unresolved import `crate::empty`
|
||||
--> $DIR/issue-85992.rs:8:5
|
||||
|
|
||||
LL | use crate::issue_85992_extern_2;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `issue_85992_extern_2` in the root
|
||||
LL | use crate::empty;
|
||||
| ^^^^^^^^^^^^ no `empty` in the root
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
//@ edition: 2021
|
||||
|
||||
// issue#128813
|
||||
|
||||
extern crate core;
|
||||
|
||||
macro_rules! m {
|
||||
() => {
|
||||
extern crate std as core;
|
||||
//~^ ERROR: the name `core` is defined multiple times
|
||||
};
|
||||
}
|
||||
|
||||
m!();
|
||||
|
||||
fn main() {
|
||||
use ::core;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
error[E0259]: the name `core` is defined multiple times
|
||||
--> $DIR/multiple-extern-by-macro-for-buitlin.rs:9:9
|
||||
|
|
||||
LL | extern crate core;
|
||||
| ------------------ previous import of the extern crate `core` here
|
||||
...
|
||||
LL | extern crate std as core;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ `core` reimported here
|
||||
...
|
||||
LL | m!();
|
||||
| ---- in this macro invocation
|
||||
|
|
||||
= note: `core` must be defined only once in the type namespace of this module
|
||||
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | extern crate std as other_core;
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0259`.
|
|
@ -0,0 +1,19 @@
|
|||
//@ edition: 2021
|
||||
//@ aux-build: empty.rs
|
||||
|
||||
// issue#128813
|
||||
|
||||
extern crate empty;
|
||||
|
||||
macro_rules! m {
|
||||
() => {
|
||||
extern crate std as empty;
|
||||
//~^ ERROR: the name `empty` is defined multiple times
|
||||
};
|
||||
}
|
||||
|
||||
m!();
|
||||
|
||||
fn main() {
|
||||
use ::empty;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
error[E0259]: the name `empty` is defined multiple times
|
||||
--> $DIR/multiple-extern-by-macro-for-custom.rs:10:9
|
||||
|
|
||||
LL | extern crate empty;
|
||||
| ------------------- previous import of the extern crate `empty` here
|
||||
...
|
||||
LL | extern crate std as empty;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `empty` reimported here
|
||||
...
|
||||
LL | m!();
|
||||
| ---- in this macro invocation
|
||||
|
|
||||
= note: `empty` must be defined only once in the type namespace of this module
|
||||
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | extern crate std as other_empty;
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0259`.
|
|
@ -0,0 +1,19 @@
|
|||
//@ edition: 2021
|
||||
|
||||
// issue#128813
|
||||
|
||||
extern crate non_existent;
|
||||
//~^ ERROR: can't find crate for `non_existent`
|
||||
|
||||
macro_rules! m {
|
||||
() => {
|
||||
extern crate std as non_existent;
|
||||
//~^ ERROR: the name `non_existent` is defined multiple times
|
||||
};
|
||||
}
|
||||
|
||||
m!();
|
||||
|
||||
fn main() {
|
||||
use ::non_existent;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
error[E0463]: can't find crate for `non_existent`
|
||||
--> $DIR/multiple-extern-by-macro-for-inexist.rs:5:1
|
||||
|
|
||||
LL | extern crate non_existent;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate
|
||||
|
||||
error[E0259]: the name `non_existent` is defined multiple times
|
||||
--> $DIR/multiple-extern-by-macro-for-inexist.rs:10:9
|
||||
|
|
||||
LL | extern crate non_existent;
|
||||
| -------------------------- previous import of the extern crate `non_existent` here
|
||||
...
|
||||
LL | extern crate std as non_existent;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `non_existent` reimported here
|
||||
...
|
||||
LL | m!();
|
||||
| ---- in this macro invocation
|
||||
|
|
||||
= note: `non_existent` must be defined only once in the type namespace of this module
|
||||
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | extern crate std as other_non_existent;
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0259, E0463.
|
||||
For more information about an error, try `rustc --explain E0259`.
|
|
@ -0,0 +1,18 @@
|
|||
//@ edition: 2021
|
||||
|
||||
// issue#128813
|
||||
|
||||
extern crate core as _;
|
||||
|
||||
macro_rules! m {
|
||||
() => {
|
||||
extern crate std as _;
|
||||
};
|
||||
}
|
||||
|
||||
m!();
|
||||
|
||||
fn main() {
|
||||
use ::_;
|
||||
//~^ ERROR: expected identifier, found reserved identifier `_`
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
error: expected identifier, found reserved identifier `_`
|
||||
--> $DIR/multiple-extern-by-macro-for-underscore.rs:16:11
|
||||
|
|
||||
LL | use ::_;
|
||||
| ^ expected identifier, found reserved identifier
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
//@ check-pass
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
pub fn main() {
|
||||
let a = 1;
|
||||
struct Foo<a> { field: a, };
|
||||
}
|
Loading…
Reference in New Issue