Auto merge of #94376 - c410-f3r:more-let-chains, r=petrochenkov
Initiate the inner usage of `let_chains` The intention here is create a strong and robust foundation for a possible future stabilization so please, do not let the lack of any external tool support prevent the merge of this PR. Besides, `let_chains` is useful by itself. cc #53667
This commit is contained in:
commit
6f681a8eb3
@ -3855,7 +3855,6 @@ dependencies = [
|
|||||||
name = "rustc_lint"
|
name = "rustc_lint"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"if_chain",
|
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
"rustc_ast_pretty",
|
"rustc_ast_pretty",
|
||||||
"rustc_attr",
|
"rustc_attr",
|
||||||
|
@ -4,7 +4,6 @@ version = "0.0.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
if_chain = "1.0"
|
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
unicode-security = "0.0.5"
|
unicode-security = "0.0.5"
|
||||||
rustc_middle = { path = "../rustc_middle" }
|
rustc_middle = { path = "../rustc_middle" }
|
||||||
|
@ -25,20 +25,21 @@
|
|||||||
//!
|
//!
|
||||||
//! This API is completely unstable and subject to change.
|
//! This API is completely unstable and subject to change.
|
||||||
|
|
||||||
|
#![allow(rustc::potential_query_instability)]
|
||||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||||
#![feature(array_windows)]
|
#![feature(array_windows)]
|
||||||
#![feature(bool_to_option)]
|
#![feature(bool_to_option)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
#![feature(control_flow_enum)]
|
||||||
#![feature(crate_visibility_modifier)]
|
#![feature(crate_visibility_modifier)]
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
#![feature(iter_intersperse)]
|
#![feature(iter_intersperse)]
|
||||||
#![feature(iter_order_by)]
|
#![feature(iter_order_by)]
|
||||||
|
#![feature(let_chains)]
|
||||||
#![feature(let_else)]
|
#![feature(let_else)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![feature(control_flow_enum)]
|
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
#![allow(rustc::potential_query_instability)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rustc_middle;
|
extern crate rustc_middle;
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
use rustc_target::abi::{Integer, TagEncoding, Variants};
|
use rustc_target::abi::{Integer, TagEncoding, Variants};
|
||||||
use rustc_target::spec::abi::Abi as SpecAbi;
|
use rustc_target::spec::abi::Abi as SpecAbi;
|
||||||
|
|
||||||
use if_chain::if_chain;
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
@ -1456,21 +1455,18 @@ fn inherent_atomic_method_call<'hir>(
|
|||||||
sym::AtomicI64,
|
sym::AtomicI64,
|
||||||
sym::AtomicI128,
|
sym::AtomicI128,
|
||||||
];
|
];
|
||||||
if_chain! {
|
if let ExprKind::MethodCall(ref method_path, args, _) = &expr.kind
|
||||||
if let ExprKind::MethodCall(ref method_path, args, _) = &expr.kind;
|
&& recognized_names.contains(&method_path.ident.name)
|
||||||
if recognized_names.contains(&method_path.ident.name);
|
&& let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||||
if let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
|
&& let Some(impl_did) = cx.tcx.impl_of_method(m_def_id)
|
||||||
if let Some(impl_did) = cx.tcx.impl_of_method(m_def_id);
|
&& let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def()
|
||||||
if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def();
|
|
||||||
// skip extension traits, only lint functions from the standard library
|
// skip extension traits, only lint functions from the standard library
|
||||||
if cx.tcx.trait_id_of_impl(impl_did).is_none();
|
&& cx.tcx.trait_id_of_impl(impl_did).is_none()
|
||||||
|
&& let Some(parent) = cx.tcx.parent(adt.did)
|
||||||
if let Some(parent) = cx.tcx.parent(adt.did);
|
&& cx.tcx.is_diagnostic_item(sym::atomic_mod, parent)
|
||||||
if cx.tcx.is_diagnostic_item(sym::atomic_mod, parent);
|
&& ATOMIC_TYPES.contains(&cx.tcx.item_name(adt.did))
|
||||||
if ATOMIC_TYPES.contains(&cx.tcx.item_name(adt.did));
|
{
|
||||||
then {
|
return Some((method_path.ident.name, args));
|
||||||
return Some((method_path.ident.name, args));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -1499,111 +1495,103 @@ fn opt_ordering_defid(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option<DefId>
|
|||||||
fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::QPath;
|
use rustc_hir::QPath;
|
||||||
if_chain! {
|
if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
|
||||||
if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store]);
|
&& let Some((ordering_arg, invalid_ordering)) = match method {
|
||||||
if let Some((ordering_arg, invalid_ordering)) = match method {
|
|
||||||
sym::load => Some((&args[1], sym::Release)),
|
sym::load => Some((&args[1], sym::Release)),
|
||||||
sym::store => Some((&args[2], sym::Acquire)),
|
sym::store => Some((&args[2], sym::Acquire)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
|
||||||
|
|
||||||
if let ExprKind::Path(QPath::Resolved(_, path)) = ordering_arg.kind;
|
|
||||||
if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res;
|
|
||||||
if Self::matches_ordering(cx, ctor_id, &[invalid_ordering, sym::AcqRel]);
|
|
||||||
then {
|
|
||||||
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, |diag| {
|
|
||||||
if method == sym::load {
|
|
||||||
diag.build("atomic loads cannot have `Release` or `AcqRel` ordering")
|
|
||||||
.help("consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`")
|
|
||||||
.emit()
|
|
||||||
} else {
|
|
||||||
debug_assert_eq!(method, sym::store);
|
|
||||||
diag.build("atomic stores cannot have `Acquire` or `AcqRel` ordering")
|
|
||||||
.help("consider using ordering modes `Release`, `SeqCst` or `Relaxed`")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
&& let ExprKind::Path(QPath::Resolved(_, path)) = ordering_arg.kind
|
||||||
|
&& let Res::Def(DefKind::Ctor(..), ctor_id) = path.res
|
||||||
|
&& Self::matches_ordering(cx, ctor_id, &[invalid_ordering, sym::AcqRel])
|
||||||
|
{
|
||||||
|
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, |diag| {
|
||||||
|
if method == sym::load {
|
||||||
|
diag.build("atomic loads cannot have `Release` or `AcqRel` ordering")
|
||||||
|
.help("consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`")
|
||||||
|
.emit()
|
||||||
|
} else {
|
||||||
|
debug_assert_eq!(method, sym::store);
|
||||||
|
diag.build("atomic stores cannot have `Acquire` or `AcqRel` ordering")
|
||||||
|
.help("consider using ordering modes `Release`, `SeqCst` or `Relaxed`")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_memory_fence(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
fn check_memory_fence(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
if_chain! {
|
if let ExprKind::Call(ref func, ref args) = expr.kind
|
||||||
if let ExprKind::Call(ref func, ref args) = expr.kind;
|
&& let ExprKind::Path(ref func_qpath) = func.kind
|
||||||
if let ExprKind::Path(ref func_qpath) = func.kind;
|
&& let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id()
|
||||||
if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
|
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence))
|
||||||
if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence));
|
&& let ExprKind::Path(ref ordering_qpath) = &args[0].kind
|
||||||
if let ExprKind::Path(ref ordering_qpath) = &args[0].kind;
|
&& let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id()
|
||||||
if let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id();
|
&& Self::matches_ordering(cx, ordering_def_id, &[sym::Relaxed])
|
||||||
if Self::matches_ordering(cx, ordering_def_id, &[sym::Relaxed]);
|
{
|
||||||
then {
|
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, |diag| {
|
||||||
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, |diag| {
|
diag.build("memory fences cannot have `Relaxed` ordering")
|
||||||
diag.build("memory fences cannot have `Relaxed` ordering")
|
.help("consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`")
|
||||||
.help("consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`")
|
.emit();
|
||||||
.emit();
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
if_chain! {
|
if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::fetch_update, sym::compare_exchange, sym::compare_exchange_weak])
|
||||||
if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::fetch_update, sym::compare_exchange, sym::compare_exchange_weak]);
|
&& let Some((success_order_arg, failure_order_arg)) = match method {
|
||||||
if let Some((success_order_arg, failure_order_arg)) = match method {
|
|
||||||
sym::fetch_update => Some((&args[1], &args[2])),
|
sym::fetch_update => Some((&args[1], &args[2])),
|
||||||
sym::compare_exchange | sym::compare_exchange_weak => Some((&args[3], &args[4])),
|
sym::compare_exchange | sym::compare_exchange_weak => Some((&args[3], &args[4])),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
}
|
||||||
|
&& let Some(fail_ordering_def_id) = Self::opt_ordering_defid(cx, failure_order_arg)
|
||||||
|
{
|
||||||
|
// Helper type holding on to some checking and error reporting data. Has
|
||||||
|
// - (success ordering,
|
||||||
|
// - list of failure orderings forbidden by the success order,
|
||||||
|
// - suggestion message)
|
||||||
|
type OrdLintInfo = (Symbol, &'static [Symbol], &'static str);
|
||||||
|
const RELAXED: OrdLintInfo = (sym::Relaxed, &[sym::SeqCst, sym::Acquire], "ordering mode `Relaxed`");
|
||||||
|
const ACQUIRE: OrdLintInfo = (sym::Acquire, &[sym::SeqCst], "ordering modes `Acquire` or `Relaxed`");
|
||||||
|
const SEQ_CST: OrdLintInfo = (sym::SeqCst, &[], "ordering modes `Acquire`, `SeqCst` or `Relaxed`");
|
||||||
|
const RELEASE: OrdLintInfo = (sym::Release, RELAXED.1, RELAXED.2);
|
||||||
|
const ACQREL: OrdLintInfo = (sym::AcqRel, ACQUIRE.1, ACQUIRE.2);
|
||||||
|
const SEARCH: [OrdLintInfo; 5] = [RELAXED, ACQUIRE, SEQ_CST, RELEASE, ACQREL];
|
||||||
|
|
||||||
if let Some(fail_ordering_def_id) = Self::opt_ordering_defid(cx, failure_order_arg);
|
let success_lint_info = Self::opt_ordering_defid(cx, success_order_arg)
|
||||||
then {
|
.and_then(|success_ord_def_id| -> Option<OrdLintInfo> {
|
||||||
// Helper type holding on to some checking and error reporting data. Has
|
SEARCH
|
||||||
// - (success ordering,
|
.iter()
|
||||||
// - list of failure orderings forbidden by the success order,
|
.copied()
|
||||||
// - suggestion message)
|
.find(|(ordering, ..)| {
|
||||||
type OrdLintInfo = (Symbol, &'static [Symbol], &'static str);
|
Self::matches_ordering(cx, success_ord_def_id, &[*ordering])
|
||||||
const RELAXED: OrdLintInfo = (sym::Relaxed, &[sym::SeqCst, sym::Acquire], "ordering mode `Relaxed`");
|
})
|
||||||
const ACQUIRE: OrdLintInfo = (sym::Acquire, &[sym::SeqCst], "ordering modes `Acquire` or `Relaxed`");
|
});
|
||||||
const SEQ_CST: OrdLintInfo = (sym::SeqCst, &[], "ordering modes `Acquire`, `SeqCst` or `Relaxed`");
|
if Self::matches_ordering(cx, fail_ordering_def_id, &[sym::Release, sym::AcqRel]) {
|
||||||
const RELEASE: OrdLintInfo = (sym::Release, RELAXED.1, RELAXED.2);
|
// If we don't know the success order is, use what we'd suggest
|
||||||
const ACQREL: OrdLintInfo = (sym::AcqRel, ACQUIRE.1, ACQUIRE.2);
|
// if it were maximally permissive.
|
||||||
const SEARCH: [OrdLintInfo; 5] = [RELAXED, ACQUIRE, SEQ_CST, RELEASE, ACQREL];
|
let suggested = success_lint_info.unwrap_or(SEQ_CST).2;
|
||||||
|
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, failure_order_arg.span, |diag| {
|
||||||
let success_lint_info = Self::opt_ordering_defid(cx, success_order_arg)
|
let msg = format!(
|
||||||
.and_then(|success_ord_def_id| -> Option<OrdLintInfo> {
|
"{}'s failure ordering may not be `Release` or `AcqRel`",
|
||||||
SEARCH
|
method,
|
||||||
.iter()
|
);
|
||||||
.copied()
|
diag.build(&msg)
|
||||||
.find(|(ordering, ..)| {
|
.help(&format!("consider using {} instead", suggested))
|
||||||
Self::matches_ordering(cx, success_ord_def_id, &[*ordering])
|
.emit();
|
||||||
})
|
});
|
||||||
});
|
} else if let Some((success_ord, bad_ords_given_success, suggested)) = success_lint_info {
|
||||||
if Self::matches_ordering(cx, fail_ordering_def_id, &[sym::Release, sym::AcqRel]) {
|
if Self::matches_ordering(cx, fail_ordering_def_id, bad_ords_given_success) {
|
||||||
// If we don't know the success order is, use what we'd suggest
|
|
||||||
// if it were maximally permissive.
|
|
||||||
let suggested = success_lint_info.unwrap_or(SEQ_CST).2;
|
|
||||||
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, failure_order_arg.span, |diag| {
|
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, failure_order_arg.span, |diag| {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"{}'s failure ordering may not be `Release` or `AcqRel`",
|
"{}'s failure ordering may not be stronger than the success ordering of `{}`",
|
||||||
method,
|
method,
|
||||||
|
success_ord,
|
||||||
);
|
);
|
||||||
diag.build(&msg)
|
diag.build(&msg)
|
||||||
.help(&format!("consider using {} instead", suggested))
|
.help(&format!("consider using {} instead", suggested))
|
||||||
.emit();
|
.emit();
|
||||||
});
|
});
|
||||||
} else if let Some((success_ord, bad_ords_given_success, suggested)) = success_lint_info {
|
|
||||||
if Self::matches_ordering(cx, fail_ordering_def_id, bad_ords_given_success) {
|
|
||||||
cx.struct_span_lint(INVALID_ATOMIC_ORDERING, failure_order_arg.span, |diag| {
|
|
||||||
let msg = format!(
|
|
||||||
"{}'s failure ordering may not be stronger than the success ordering of `{}`",
|
|
||||||
method,
|
|
||||||
success_ord,
|
|
||||||
);
|
|
||||||
diag.build(&msg)
|
|
||||||
.help(&format!("consider using {} instead", suggested))
|
|
||||||
.emit();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user