Auto merge of #18183 - lnicola:sync-from-rust, r=lnicola

internal: Sync from downstream
This commit is contained in:
bors 2024-09-25 06:41:56 +00:00
commit 34aff74fb0
4923 changed files with 72750 additions and 49766 deletions

View file

@ -51,9 +51,7 @@ static HOSTS: &[&str] = &[
static TARGETS: &[&str] = &[
"aarch64-apple-darwin",
"arm64e-apple-darwin",
"aarch64-apple-ios",
"arm64e-apple-ios",
"aarch64-apple-ios-macabi",
"aarch64-apple-ios-sim",
"aarch64-unknown-fuchsia",
@ -68,6 +66,9 @@ static TARGETS: &[&str] = &[
"aarch64-unknown-none-softfloat",
"aarch64-unknown-redox",
"aarch64-unknown-uefi",
"arm64e-apple-darwin",
"arm64e-apple-ios",
"arm64e-apple-tvos",
"arm-linux-androideabi",
"arm-unknown-linux-gnueabi",
"arm-unknown-linux-gnueabihf",
@ -597,14 +598,11 @@ impl Builder {
})
.collect();
dst.insert(
pkg.manifest_component_name(),
Package {
version: version_info.version.unwrap_or_default(),
git_commit_hash: version_info.git_commit,
target: targets,
},
);
dst.insert(pkg.manifest_component_name(), Package {
version: version_info.version.unwrap_or_default(),
git_commit_hash: version_info.git_commit,
target: targets,
});
}
fn url(&self, path: &Path) -> String {

View file

@ -3,8 +3,8 @@ use std::path::{Path, PathBuf};
use serde::{Serialize, Serializer};
use crate::versions::PkgType;
use crate::Builder;
use crate::versions::PkgType;
#[derive(Serialize)]
#[serde(rename_all = "kebab-case")]

View file

@ -1,9 +1,10 @@
use std::path::Path;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
pub struct GitConfig<'a> {
pub git_repository: &'a str,
pub nightly_branch: &'a str,
pub git_merge_commit_email: &'a str,
}
/// Runs a command and returns the output
@ -95,7 +96,11 @@ pub fn updated_master_branch(
Err("Cannot find any suitable upstream master branch".to_owned())
}
pub fn get_git_merge_base(
/// Finds the nearest merge commit by comparing the local `HEAD` with the upstream branch's state.
/// To work correctly, the upstream remote must be properly configured using `git remote add <name> <url>`.
/// In most cases `get_closest_merge_commit` is the function you are looking for as it doesn't require remote
/// to be configured.
fn git_upstream_merge_base(
config: &GitConfig<'_>,
git_dir: Option<&Path>,
) -> Result<String, String> {
@ -107,6 +112,38 @@ pub fn get_git_merge_base(
Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned())
}
/// Searches for the nearest merge commit in the repository that also exists upstream.
///
/// If it fails to find the upstream remote, it then looks for the most recent commit made
/// by the merge bot by matching the author's email address with the merge bot's email.
pub fn get_closest_merge_commit(
git_dir: Option<&Path>,
config: &GitConfig<'_>,
target_paths: &[PathBuf],
) -> Result<String, String> {
let mut git = Command::new("git");
if let Some(git_dir) = git_dir {
git.current_dir(git_dir);
}
let merge_base = git_upstream_merge_base(config, git_dir).unwrap_or_else(|_| "HEAD".into());
git.args([
"rev-list",
&format!("--author={}", config.git_merge_commit_email),
"-n1",
"--first-parent",
&merge_base,
]);
if !target_paths.is_empty() {
git.arg("--").args(target_paths);
}
Ok(output_result(&mut git)?.trim().to_owned())
}
/// Returns the files that have been modified in the current branch compared to the master branch.
/// The `extensions` parameter can be used to filter the files by their extension.
/// Does not include removed files.
@ -116,7 +153,7 @@ pub fn get_git_modified_files(
git_dir: Option<&Path>,
extensions: &[&str],
) -> Result<Option<Vec<String>>, String> {
let merge_base = get_git_merge_base(config, git_dir)?;
let merge_base = get_closest_merge_commit(git_dir, config, &[])?;
let mut git = Command::new("git");
if let Some(git_dir) = git_dir {
@ -159,3 +196,67 @@ pub fn get_git_untracked_files(
.collect();
Ok(Some(files))
}
/// Print a warning if the branch returned from `updated_master_branch` is old
///
/// For certain configurations of git repository, this remote will not be
/// updated when running `git pull`.
///
/// This can result in formatting thousands of files instead of a dozen,
/// so we should warn the user something is wrong.
pub fn warn_old_master_branch(config: &GitConfig<'_>, git_dir: &Path) {
if crate::ci::CiEnv::is_ci() {
// this warning is useless in CI,
// and CI probably won't have the right branches anyway.
return;
}
// this will be overwritten by the actual name, if possible
let mut updated_master = "the upstream master branch".to_string();
match warn_old_master_branch_(config, git_dir, &mut updated_master) {
Ok(branch_is_old) => {
if !branch_is_old {
return;
}
// otherwise fall through and print the rest of the warning
}
Err(err) => {
eprintln!("warning: unable to check if {updated_master} is old due to error: {err}")
}
}
eprintln!(
"warning: {updated_master} is used to determine if files have been modified\n\
warning: if it is not updated, this may cause files to be needlessly reformatted"
);
}
pub fn warn_old_master_branch_(
config: &GitConfig<'_>,
git_dir: &Path,
updated_master: &mut String,
) -> Result<bool, Box<dyn std::error::Error>> {
use std::time::Duration;
*updated_master = updated_master_branch(config, Some(git_dir))?;
let branch_path = git_dir.join(".git/refs/remotes").join(&updated_master);
const WARN_AFTER: Duration = Duration::from_secs(60 * 60 * 24 * 10);
let meta = match std::fs::metadata(&branch_path) {
Ok(meta) => meta,
Err(err) => {
let gcd = git_common_dir(&git_dir)?;
if branch_path.starts_with(&gcd) {
return Err(Box::new(err));
}
std::fs::metadata(Path::new(&gcd).join("refs/remotes").join(&updated_master))?
}
};
if meta.modified()?.elapsed()? > WARN_AFTER {
eprintln!("warning: {updated_master} has not been updated in 10 days");
Ok(true)
} else {
Ok(false)
}
}
fn git_common_dir(dir: &Path) -> Result<String, String> {
output_result(Command::new("git").arg("-C").arg(dir).arg("rev-parse").arg("--git-common-dir"))
.map(|x| x.trim().to_string())
}

View file

@ -1,7 +1,7 @@
#![deny(unused_variables)]
use anyhow::{Context, Error};
use build_helper::stage0_parser::{parse_stage0_file, Stage0Config, VersionMetadata};
use build_helper::stage0_parser::{Stage0Config, VersionMetadata, parse_stage0_file};
use curl::easy::Easy;
use indexmap::IndexMap;

@ -1 +1 @@
Subproject commit 8f40fc59fb0c8df91c97405785197f3c630304ea
Subproject commit eaee77dc1584be45949b75e4c4c9a841605e3a4b

View file

@ -17,7 +17,9 @@ macro_rules! msrv_aliases {
// names may refer to stabilized feature flags or library items
msrv_aliases! {
1,81,0 { LINT_REASONS_STABILIZATION }
1,83,0 { CONST_EXTERN_FN }
1,83,0 { CONST_FLOAT_BITS_CONV }
1,81,0 { LINT_REASONS_STABILIZATION }
1,80,0 { BOX_INTO_ITER}
1,77,0 { C_STR_LITERALS }
1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT }
@ -26,7 +28,7 @@ msrv_aliases! {
1,68,0 { PATH_MAIN_SEPARATOR_STR }
1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
1,63,0 { CLONE_INTO }
1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_FN }
1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN }
1,59,0 { THREAD_LOCAL_CONST_INIT }
1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF }
1,56,0 { CONST_FN_UNION }

View file

@ -386,7 +386,6 @@ fn check_unsafe_derive_deserialize<'tcx>(
.tcx
.inherent_impls(def.did())
.into_iter()
.flatten()
.map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local()))
.any(|imp| has_unsafe(cx, imp))
{

View file

@ -1,8 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context};
use clippy_utils::{
can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, match_def_path,
paths, peel_hir_expr_while, SpanlessEq,
can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified,
peel_hir_expr_while, SpanlessEq,
};
use core::fmt::{self, Write};
use rustc_errors::Applicability;
@ -11,7 +11,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{Block, Expr, ExprKind, HirId, Pat, Stmt, StmtKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::{Span, SyntaxContext, DUMMY_SP};
use rustc_span::{sym, Span, SyntaxContext, DUMMY_SP};
declare_clippy_lint! {
/// ### What it does
@ -269,9 +269,9 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio
key,
call_ctxt: expr.span.ctxt(),
};
if match_def_path(cx, id, &paths::BTREEMAP_CONTAINS_KEY) {
if cx.tcx.is_diagnostic_item(sym::btreemap_contains_key, id) {
Some((MapType::BTree, expr))
} else if match_def_path(cx, id, &paths::HASHMAP_CONTAINS_KEY) {
} else if cx.tcx.is_diagnostic_item(sym::hashmap_contains_key, id) {
Some((MapType::Hash, expr))
} else {
None
@ -306,7 +306,7 @@ struct InsertExpr<'tcx> {
fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind {
let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) {
if cx.tcx.is_diagnostic_item(sym::btreemap_insert, id) || cx.tcx.is_diagnostic_item(sym::hashmap_insert, id) {
Some(InsertExpr { map, key, value })
} else {
None

View file

@ -50,7 +50,7 @@ declare_clippy_lint! {
}
fn is_non_trait_box(ty: Ty<'_>) -> bool {
ty.is_box() && !ty.boxed_ty().is_trait()
ty.boxed_ty().is_some_and(|boxed| !boxed.is_trait())
}
struct EscapeDelegate<'a, 'tcx> {
@ -191,8 +191,8 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
impl<'a, 'tcx> EscapeDelegate<'a, 'tcx> {
fn is_large_box(&self, ty: Ty<'tcx>) -> bool {
// Large types need to be boxed to avoid stack overflows.
if ty.is_box() {
self.cx.layout_of(ty.boxed_ty()).map_or(0, |l| l.size.bytes()) > self.too_large_for_stack
if let Some(boxed_ty) = ty.boxed_ty() {
self.cx.layout_of(boxed_ty).map_or(0, |l| l.size.bytes()) > self.too_large_for_stack
} else {
false
}

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{higher, match_def_path, paths};
use clippy_utils::higher;
use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString {
let arg = match expr.kind {
ExprKind::MethodCall(_, _, [arg], _) => {
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
&& match_def_path(cx, fn_def_id, &paths::PUSH_STR)
&& cx.tcx.is_diagnostic_item(sym::string_push_str, fn_def_id)
{
arg
} else {

View file

@ -246,7 +246,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds
&& let [.., path] = poly_trait.trait_ref.path.segments
&& poly_trait.bound_generic_params.is_empty()
&& let Some(trait_def_id) = path.res.opt_def_id()
&& let predicates = cx.tcx.explicit_super_predicates_of(trait_def_id).predicates
&& let predicates = cx.tcx.explicit_super_predicates_of(trait_def_id).skip_binder()
// If the trait has no supertrait, there is no need to collect anything from that bound
&& !predicates.is_empty()
{

View file

@ -51,9 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
// List of spans to lint. (lint_span, first_span)
let mut lint_spans = Vec::new();
let Ok(impls) = cx.tcx.crate_inherent_impls(()) else {
return;
};
let (impls, _) = cx.tcx.crate_inherent_impls(());
for (&id, impl_ids) in &impls.inherent_impls {
if impl_ids.len() < 2

View file

@ -112,7 +112,7 @@ impl LateLintPass<'_> for InstantSubtraction {
fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
if let ExprKind::Call(fn_expr, []) = expr_block.kind
&& let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr)
&& clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW)
&& cx.tcx.is_diagnostic_item(sym::instant_now, fn_id)
{
true
} else {

View file

@ -1,10 +1,5 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::higher::ForLoop;
use clippy_utils::match_any_def_paths;
use clippy_utils::paths::{
HASHMAP_DRAIN, HASHMAP_ITER, HASHMAP_ITER_MUT, HASHMAP_KEYS, HASHMAP_VALUES, HASHMAP_VALUES_MUT, HASHSET_DRAIN,
HASHSET_ITER_TY,
};
use clippy_utils::ty::is_type_diagnostic_item;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
@ -44,28 +39,23 @@ declare_lint_pass!(IterOverHashType => [ITER_OVER_HASH_TYPE]);
impl LateLintPass<'_> for IterOverHashType {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>) {
let hash_iter_tys = [
sym::HashMap,
sym::HashSet,
sym::hashmap_keys_ty,
sym::hashmap_values_ty,
sym::hashmap_values_mut_ty,
sym::hashmap_iter_ty,
sym::hashmap_iter_mut_ty,
sym::hashmap_drain_ty,
sym::hashset_iter_ty,
sym::hashset_drain_ty,
];
if let Some(for_loop) = ForLoop::hir(expr)
&& !for_loop.body.span.from_expansion()
&& let ty = cx.typeck_results().expr_ty(for_loop.arg).peel_refs()
&& let Some(adt) = ty.ty_adt_def()
&& let did = adt.did()
&& (match_any_def_paths(
cx,
did,
&[
&HASHMAP_KEYS,
&HASHMAP_VALUES,
&HASHMAP_VALUES_MUT,
&HASHMAP_ITER,
&HASHMAP_ITER_MUT,
&HASHMAP_DRAIN,
&HASHSET_ITER_TY,
&HASHSET_DRAIN,
],
)
.is_some()
|| is_type_diagnostic_item(cx, ty, sym::HashMap)
|| is_type_diagnostic_item(cx, ty, sym::HashSet))
&& hash_iter_tys.into_iter().any(|sym| is_type_diagnostic_item(cx, ty, sym))
{
span_lint(
cx,

View file

@ -448,7 +448,6 @@ fn check_for_is_empty(
.tcx
.inherent_impls(impl_ty)
.into_iter()
.flatten()
.flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty))
.find(|item| item.kind == AssocKind::Fn);
@ -616,7 +615,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
/// Checks the inherent impl's items for an `is_empty(self)` method.
fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
let is_empty = sym!(is_empty);
cx.tcx.inherent_impls(id).into_iter().flatten().any(|imp| {
cx.tcx.inherent_impls(id).into_iter().any(|imp| {
cx.tcx
.associated_items(*imp)
.filter_by_name_unhygienic(is_empty)

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths};
use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id};
use rustc_errors::Applicability;
use rustc_hir::{Body, Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@ -96,7 +96,7 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> boo
ExprKind::Path(qpath) => cx
.qpath_res(qpath, fm_arg.hir_id)
.opt_def_id()
.is_some_and(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)),
.is_some_and(|did| cx.tcx.is_diagnostic_item(sym::result_ok_method, did)),
// Detect `|x| x.ok()`
ExprKind::Closure(Closure { body, .. }) => {
if let Body {

View file

@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::{match_def_path, paths, SpanlessEq};
use clippy_utils::SpanlessEq;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp};
use rustc_lint::LateContext;
use rustc_span::Span;
use rustc_span::{sym, Symbol, Span};
use std::borrow::Cow;
use super::MANUAL_WHILE_LET_SOME;
@ -47,20 +47,20 @@ fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>,
);
}
fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: &[&str]) -> bool {
fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: Symbol) -> bool {
if let ExprKind::MethodCall(..) = expr.kind
&& let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
{
match_def_path(cx, id, method)
cx.tcx.is_diagnostic_item(method, id)
} else {
false
}
}
fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, is_empty_recv: &Expr<'_>) -> bool {
if (match_method_call(cx, expr, &paths::OPTION_UNWRAP) || match_method_call(cx, expr, &paths::OPTION_EXPECT))
if (match_method_call(cx, expr, sym::option_unwrap) || match_method_call(cx, expr, sym::option_expect))
&& let ExprKind::MethodCall(_, unwrap_recv, ..) = expr.kind
&& match_method_call(cx, unwrap_recv, &paths::VEC_POP)
&& match_method_call(cx, unwrap_recv, sym::vec_pop)
&& let ExprKind::MethodCall(_, pop_recv, ..) = unwrap_recv.kind
{
// make sure they're the same `Vec`
@ -96,7 +96,7 @@ fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &E
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, full_cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>, loop_span: Span) {
if let ExprKind::Unary(UnOp::Not, cond) = full_cond.kind
&& let ExprKind::MethodCall(_, is_empty_recv, _, _) = cond.kind
&& match_method_call(cx, cond, &paths::VEC_IS_EMPTY)
&& match_method_call(cx, cond, sym::vec_is_empty)
&& let ExprKind::Block(body, _) = body.kind
&& let Some(stmt) = body.stmts.first()
{

View file

@ -1,7 +1,7 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::{is_trait_method, match_def_path, paths, peel_hir_expr_refs};
use clippy_utils::{is_trait_method, peel_hir_expr_refs};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind, Mutability, QPath};
@ -56,7 +56,7 @@ impl LateLintPass<'_> for ManualMainSeparatorStr {
&& let Res::Def(DefKind::Const, receiver_def_id) = path.res
&& is_trait_method(cx, target, sym::ToString)
&& self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR)
&& match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR)
&& cx.tcx.is_diagnostic_item(sym::path_main_separator, receiver_def_id)
&& let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind()
&& ty.is_str()
{

View file

@ -3,22 +3,22 @@ use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
use clippy_utils::{match_def_path, paths, SpanlessEq};
use clippy_utils::SpanlessEq;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::ExprKind::Assign;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
use rustc_span::symbol::sym;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
const ACCEPTABLE_METHODS: [&[&str]; 5] = [
&paths::BINARYHEAP_ITER,
&paths::HASHSET_ITER,
&paths::BTREESET_ITER,
&paths::SLICE_INTO,
&paths::VEC_DEQUE_ITER,
const ACCEPTABLE_METHODS: [Symbol; 5] = [
sym::binaryheap_iter,
sym::hashset_iter,
sym::btreeset_iter,
sym::slice_iter,
sym::vecdeque_iter,
];
declare_clippy_lint! {
@ -84,7 +84,7 @@ fn check_into_iter(
) {
if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
&& cx.tcx.is_diagnostic_item(sym::iter_filter, filter_def_id)
&& let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind
&& let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id)
&& Some(into_iter_def_id) == cx.tcx.lang_items().into_iter_fn()
@ -127,14 +127,14 @@ fn check_iter(
) {
if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
&& let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& (match_def_path(cx, copied_def_id, &paths::CORE_ITER_COPIED)
|| match_def_path(cx, copied_def_id, &paths::CORE_ITER_CLONED))
&& (cx.tcx.is_diagnostic_item(sym::iter_copied, copied_def_id)
|| cx.tcx.is_diagnostic_item(sym::iter_cloned, copied_def_id))
&& let hir::ExprKind::MethodCall(_, iter_expr, [_], _) = &filter_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
&& cx.tcx.is_diagnostic_item(sym::iter_filter, filter_def_id)
&& let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &iter_expr.kind
&& let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id)
&& match_acceptable_def_path(cx, iter_expr_def_id)
&& match_acceptable_sym(cx, iter_expr_def_id)
&& match_acceptable_type(cx, left_expr, msrv)
&& SpanlessEq::new(cx).eq_expr(left_expr, struct_expr)
&& let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind
@ -189,10 +189,10 @@ fn check_to_owned(
&& cx.tcx.is_diagnostic_item(sym::to_owned_method, to_owned_def_id)
&& let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
&& cx.tcx.is_diagnostic_item(sym::iter_filter, filter_def_id)
&& let hir::ExprKind::MethodCall(_, str_expr, [], _) = &chars_expr.kind
&& let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
&& match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS)
&& cx.tcx.is_diagnostic_item(sym::str_chars, chars_expr_def_id)
&& let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
&& is_type_lang_item(cx, ty, hir::LangItem::String)
&& SpanlessEq::new(cx).eq_expr(left_expr, str_expr)
@ -247,10 +247,10 @@ fn make_sugg(
}
}
fn match_acceptable_def_path(cx: &LateContext<'_>, collect_def_id: DefId) -> bool {
fn match_acceptable_sym(cx: &LateContext<'_>, collect_def_id: DefId) -> bool {
ACCEPTABLE_METHODS
.iter()
.any(|&method| match_def_path(cx, collect_def_id, method))
.any(|&method| cx.tcx.is_diagnostic_item(method, collect_def_id))
}
fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv) -> bool {

View file

@ -4,7 +4,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::usage::mutated_variables;
use clippy_utils::{eq_expr_value, higher, match_def_path, paths};
use clippy_utils::{eq_expr_value, higher};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
@ -14,7 +14,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::impl_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::Span;
use rustc_span::{sym, Span};
use std::iter;
declare_clippy_lint! {
@ -76,9 +76,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
&& self.msrv.meets(msrvs::STR_STRIP_PREFIX)
&& let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id)
{
let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) {
let strip_kind = if cx.tcx.is_diagnostic_item(sym::str_starts_with, method_def_id) {
StripKind::Prefix
} else if match_def_path(cx, method_def_id, &paths::STR_ENDS_WITH) {
} else if cx.tcx.is_diagnostic_item(sym::str_ends_with, method_def_id) {
StripKind::Suffix
} else {
return;
@ -137,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
if let ExprKind::MethodCall(_, arg, [], _) = expr.kind
&& let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
&& match_def_path(cx, method_def_id, &paths::STR_LEN)
&& cx.tcx.is_diagnostic_item(sym::str_len, method_def_id)
{
Some(arg)
} else {

View file

@ -1,9 +1,8 @@
use super::FILTER_MAP_BOOL_THEN;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::paths::BOOL_THEN;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::is_copy;
use clippy_utils::{is_from_proc_macro, is_trait_method, match_def_path, peel_blocks};
use clippy_utils::{is_from_proc_macro, is_trait_method, peel_blocks};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LintContext};
@ -35,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
&& let ExprKind::Closure(then_closure) = then_arg.kind
&& let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value)
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id)
&& match_def_path(cx, def_id, &BOOL_THEN)
&& cx.tcx.is_diagnostic_item(sym::bool_then, def_id)
&& !is_from_proc_macro(cx, expr)
// Count the number of derefs needed to get to the bool because we need those in the suggestion
&& let needed_derefs = cx.typeck_results().expr_adjustments(recv)

View file

@ -5187,8 +5187,8 @@ impl SelfKind {
fn matches_value<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
if ty == parent_ty {
true
} else if ty.is_box() {
ty.boxed_ty() == parent_ty
} else if let Some(boxed_ty) = ty.boxed_ty() {
boxed_ty == parent_ty
} else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) {
if let ty::Adt(_, args) = ty.kind() {
args.types().next().map_or(false, |t| t == parent_ty)

View file

@ -126,17 +126,18 @@ fn get_open_options(
&& let ExprKind::Path(path) = callee.kind
&& let Some(did) = cx.qpath_res(&path, callee.hir_id).opt_def_id()
{
match_any_def_paths(
cx,
did,
&[
&paths::TOKIO_IO_OPEN_OPTIONS_NEW,
&paths::OPEN_OPTIONS_NEW,
&paths::FILE_OPTIONS,
&paths::TOKIO_FILE_OPTIONS,
],
)
.is_some()
let std_file_options = [
sym::file_options,
sym::open_options_new,
];
let tokio_file_options: &[&[&str]] = &[
&paths::TOKIO_IO_OPEN_OPTIONS_NEW,
&paths::TOKIO_FILE_OPTIONS,
];
let is_std_options = std_file_options.into_iter().any(|sym| cx.tcx.is_diagnostic_item(sym, did));
is_std_options || match_any_def_paths(cx, did, tokio_file_options).is_some()
} else {
false
}

View file

@ -2,12 +2,12 @@ use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{match_def_path, path_to_local_id, paths, peel_blocks};
use clippy_utils::{path_to_local_id, peel_blocks};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::sym;
use rustc_span::{sym, Symbol};
use super::OPTION_AS_REF_DEREF;
@ -31,14 +31,14 @@ pub(super) fn check(
return;
}
let deref_aliases: [&[&str]; 7] = [
&paths::CSTRING_AS_C_STR,
&paths::OS_STRING_AS_OS_STR,
&paths::PATH_BUF_AS_PATH,
&paths::STRING_AS_STR,
&paths::STRING_AS_MUT_STR,
&paths::VEC_AS_SLICE,
&paths::VEC_AS_MUT_SLICE,
let deref_aliases: [Symbol; 7] = [
sym::cstring_as_c_str,
sym::os_string_as_os_str,
sym::pathbuf_as_path,
sym::string_as_str,
sym::string_as_mut_str,
sym::vec_as_slice,
sym::vec_as_mut_slice,
];
let is_deref = match map_arg.kind {
@ -48,7 +48,7 @@ pub(super) fn check(
.map_or(false, |fun_def_id| {
cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id)
|| cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id)
|| deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
|| deref_aliases.iter().any(|&sym| cx.tcx.is_diagnostic_item(sym, fun_def_id))
})
},
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
@ -69,7 +69,7 @@ pub(super) fn check(
let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
cx.tcx.is_diagnostic_item(sym::deref_method, method_did)
|| cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did)
|| deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
|| deref_aliases.iter().any(|&sym| cx.tcx.is_diagnostic_item(sym, method_did))
} else {
false
}

View file

@ -78,7 +78,6 @@ pub(super) fn check<'tcx>(
cx.tcx
.inherent_impls(adt_def.did())
.into_iter()
.flatten()
.flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg))
.find_map(|assoc| {
if assoc.fn_has_self_parameter

View file

@ -8,7 +8,7 @@ use rustc_span::sym;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::implements_trait;
use clippy_utils::{match_def_path, paths};
use clippy_utils::is_enum_variant_ctor;
use super::SEEK_FROM_CURRENT;
@ -36,8 +36,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
if let ExprKind::Call(f, args) = expr.kind
&& let ExprKind::Path(ref path) = f.kind
&& let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id()
&& match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT)
&& let Some(ctor_call_id) = cx.qpath_res(path, f.hir_id).opt_def_id()
&& is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Current), ctor_call_id)
{
// check if argument of `SeekFrom::Current` is `0`
if args.len() == 1

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::implements_trait;
use clippy_utils::{is_expr_used_or_unified, match_def_path, paths};
use clippy_utils::{is_expr_used_or_unified, is_enum_variant_ctor};
use rustc_ast::ast::{LitIntType, LitKind};
use rustc_data_structures::packed::Pu128;
use rustc_errors::Applicability;
@ -28,8 +28,8 @@ pub(super) fn check<'tcx>(
&& implements_trait(cx, ty, seek_trait_id, &[])
&& let ExprKind::Call(func, args1) = arg.kind
&& let ExprKind::Path(ref path) = func.kind
&& let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
&& match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START)
&& let Some(ctor_call_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
&& is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Start), ctor_call_id)
&& args1.len() == 1
&& let ExprKind::Lit(lit) = args1[0].kind
&& let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node

View file

@ -1,13 +1,13 @@
use crate::methods::{single_char_insert_string, single_char_push_string};
use clippy_utils::{match_def_path, paths};
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
if cx.tcx.is_diagnostic_item(sym::string_push_str, fn_def_id) {
single_char_push_string::check(cx, expr, receiver, args);
} else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
} else if cx.tcx.is_diagnostic_item(sym::string_insert_str, fn_def_id) {
single_char_insert_string::check(cx, expr, receiver, args);
}
}

View file

@ -25,8 +25,7 @@ fn is_subtrait_of_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
|| cx
.tcx
.explicit_super_predicates_of(tr.def_id)
.predicates
.iter()
.iter_identity_copied()
.any(|(clause, _)| {
matches!(clause.kind().skip_binder(), ty::ClauseKind::Trait(super_tr)
if cx.tcx.is_diagnostic_item(sym::Any, super_tr.def_id()))

View file

@ -6,7 +6,7 @@ use clippy_utils::source::{snippet, SpanRangeExt};
use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item};
use clippy_utils::visitors::find_all_ret_expressions;
use clippy_utils::{
fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, peel_middle_ty_refs,
fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs,
return_ty,
};
use rustc_errors::Applicability;
@ -250,7 +250,7 @@ fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>,
if let Some((call, arg)) = skip_addr_of_ancestors(cx, expr)
&& !arg.span.from_expansion()
&& let ExprKind::Call(callee, _) = call.kind
&& fn_def_id(cx, call).is_some_and(|did| match_def_path(cx, did, &paths::STRING_FROM_UTF8))
&& fn_def_id(cx, call).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::string_from_utf8, did))
&& let Some(unwrap_call) = get_parent_expr(cx, call)
&& let ExprKind::MethodCall(unwrap_method_name, ..) = unwrap_call.kind
&& matches!(unwrap_method_name.ident.name, sym::unwrap | sym::expect)

View file

@ -16,7 +16,7 @@ pub(super) fn derefs_to_slice<'tcx>(
fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
match ty.kind() {
ty::Slice(_) => true,
ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
ty::Adt(..) if let Some(boxed) = ty.boxed_ty() => may_slice(cx, boxed),
ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::Vec),
ty::Array(_, size) => size.try_eval_target_usize(cx.tcx, cx.param_env).is_some(),
ty::Ref(_, inner, _) => may_slice(cx, *inner),
@ -33,7 +33,7 @@ pub(super) fn derefs_to_slice<'tcx>(
} else {
match ty.kind() {
ty::Slice(_) => Some(expr),
ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr),
_ if ty.boxed_ty().is_some_and(|boxed| may_slice(cx, boxed)) => Some(expr),
ty::Ref(_, inner, _) => {
if may_slice(cx, *inner) {
Some(expr)

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{is_trait_method, match_def_path, paths};
use clippy_utils::is_trait_method;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
@ -12,7 +12,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
let ty = cx.typeck_results().expr_ty(recv);
if let Some(did) = ty.ty_adt_def()
&& match_def_path(cx, did.did(), &paths::WAKER)
&& cx.tcx.is_diagnostic_item(sym::Waker, did.did())
&& let ExprKind::MethodCall(_, waker_ref, &[], _) = recv.kind
&& is_trait_method(cx, recv, sym::Clone)
{

View file

@ -119,9 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
.iter()
.any(|param| matches!(param.kind, GenericParamKind::Const { .. }));
if already_const(header)
|| has_const_generic_params
|| !could_be_const_with_abi(cx, &self.msrv, header.abi)
if already_const(header) || has_const_generic_params || !could_be_const_with_abi(&self.msrv, header.abi)
{
return;
}
@ -183,13 +181,13 @@ fn already_const(header: hir::FnHeader) -> bool {
header.constness == Constness::Const
}
fn could_be_const_with_abi(cx: &LateContext<'_>, msrv: &Msrv, abi: Abi) -> bool {
fn could_be_const_with_abi(msrv: &Msrv, abi: Abi) -> bool {
match abi {
Abi::Rust => true,
// `const extern "C"` was stabilized after 1.62.0
Abi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_FN),
Abi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_C_FN),
// Rest ABIs are still unstable and need the `const_extern_fn` feature enabled.
_ => cx.tcx.features().const_extern_fn,
_ => msrv.meets(msrvs::CONST_EXTERN_FN),
}
}

View file

@ -91,7 +91,7 @@ fn path_to_sized_bound(cx: &LateContext<'_>, trait_bound: &PolyTraitRef<'_>) ->
return true;
}
for &(predicate, _) in cx.tcx.explicit_super_predicates_of(trait_def_id).predicates {
for (predicate, _) in cx.tcx.explicit_super_predicates_of(trait_def_id).iter_identity_copied() {
if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
&& trait_predicate.polarity == PredicatePolarity::Positive
&& !path.contains(&trait_predicate.def_id())

View file

@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{snippet_with_applicability, SpanRangeExt};
use clippy_utils::{match_def_path, paths};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@ -63,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
ExprKind::Call(func, [param]) => {
if let ExprKind::Path(ref path) = func.kind
&& let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
&& match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE)
&& cx.tcx.is_diagnostic_item(sym::permissions_from_mode, def_id)
&& let ExprKind::Lit(_) = param.kind
&& param.span.eq_ctxt(expr.span)
&& param

View file

@ -1,12 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{match_def_path, paths, sugg};
use clippy_utils::sugg;
use rustc_ast::util::parser::AssocOp;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::source_map::Spanned;
use rustc_span::{sym, source_map::Spanned};
use super::FLOAT_EQUALITY_WITHOUT_ABS;
@ -36,7 +36,7 @@ pub(crate) fn check<'tcx>(
// right hand side matches either f32::EPSILON or f64::EPSILON
&& let ExprKind::Path(ref epsilon_path) = rhs.kind
&& let Res::Def(DefKind::AssocConst, def_id) = cx.qpath_res(epsilon_path, rhs.hir_id)
&& (match_def_path(cx, def_id, &paths::F32_EPSILON) || match_def_path(cx, def_id, &paths::F64_EPSILON))
&& ([sym::f32_epsilon, sym::f64_epsilon].into_iter().any(|sym| cx.tcx.is_diagnostic_item(sym, def_id)))
// values of the subtractions on the left hand side are of the type float
&& let t_val_l = cx.typeck_results().expr_ty(val_l)

View file

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap};
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, is_type_lang_item, walk_ptrs_ty_depth};
use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths};
use clippy_utils::fn_has_unsatisfiable_preds;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{def_id, Body, FnDecl, LangItem};
@ -102,8 +102,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
&& is_type_lang_item(cx, arg_ty, LangItem::String));
let from_deref = !from_borrow
&& (match_def_path(cx, fn_def_id, &paths::PATH_TO_PATH_BUF)
|| match_def_path(cx, fn_def_id, &paths::OS_STR_TO_OS_STRING));
&& (cx.tcx.is_diagnostic_item(sym::path_to_pathbuf, fn_def_id)
|| cx.tcx.is_diagnostic_item(sym::os_str_to_os_string, fn_def_id));
if !from_borrow && !from_deref {
continue;

View file

@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::VecArgs;
use clippy_utils::macros::matching_root_macro_call;
use clippy_utils::source::snippet;
use clippy_utils::{expr_or_init, fn_def_id, match_def_path, paths};
use clippy_utils::{expr_or_init, fn_def_id};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@ -67,7 +67,7 @@ fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, s
fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) {
if matching_root_macro_call(cx, expr.span, sym::vec_macro).is_some()
&& let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr)
&& fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY))
&& fn_def_id(cx, repeat_expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::vec_with_capacity, did))
&& !len_expr.span.from_expansion()
&& let Some(Constant::Int(2..)) = ConstEvalCtxt::new(cx).eval(expr_or_init(cx, len_expr))
{
@ -91,7 +91,7 @@ fn check_repeat_fn(cx: &LateContext<'_>, expr: &Expr<'_>) {
if !expr.span.from_expansion()
&& fn_def_id(cx, expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::iter_repeat, did))
&& let ExprKind::Call(_, [repeat_expr]) = expr.kind
&& fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY))
&& fn_def_id(cx, repeat_expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::vec_with_capacity, did))
&& !repeat_expr.span.from_expansion()
{
emit_lint(

View file

@ -2,8 +2,8 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::matching_root_macro_call;
use clippy_utils::sugg::Sugg;
use clippy_utils::{
get_enclosing_block, is_expr_path_def_path, is_integer_literal, is_path_diagnostic_item, path_to_local,
path_to_local_id, paths, SpanlessEq,
get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local,
path_to_local_id, SpanlessEq,
};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor};
@ -150,10 +150,10 @@ impl SlowVectorInit {
}
if let ExprKind::Call(func, [len_expr]) = expr.kind
&& is_expr_path_def_path(cx, func, &paths::VEC_WITH_CAPACITY)
&& is_path_diagnostic_item(cx, func, sym::vec_with_capacity)
{
Some(InitializedSize::Initialized(len_expr))
} else if matches!(expr.kind, ExprKind::Call(func, _) if is_expr_path_def_path(cx, func, &paths::VEC_NEW)) {
} else if matches!(expr.kind, ExprKind::Call(func, _) if is_path_diagnostic_item(cx, func, sym::vec_new)) {
Some(InitializedSize::Uninitialized)
} else {
None

View file

@ -619,10 +619,10 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
| transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
| transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, &self.msrv)
| transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
| transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context)
| transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context, &self.msrv)
| transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg)
| transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
| transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
| transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context, &self.msrv)
| transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context, &self.msrv)
| (unsound_collection_transmute::check(cx, e, from_ty, to_ty)
|| transmute_undefined_repr::check(cx, e, from_ty, to_ty))
| (eager_transmute::check(cx, e, arg, from_ty, to_ty));

View file

@ -1,4 +1,5 @@
use super::TRANSMUTE_FLOAT_TO_INT;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg;
use rustc_ast as ast;
@ -16,9 +17,12 @@ pub(super) fn check<'tcx>(
to_ty: Ty<'tcx>,
mut arg: &'tcx Expr<'_>,
const_context: bool,
msrv: &Msrv,
) -> bool {
match (&from_ty.kind(), &to_ty.kind()) {
(ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) if !const_context => {
(ty::Float(float_ty), ty::Int(_) | ty::Uint(_))
if !const_context || msrv.meets(msrvs::CONST_FLOAT_BITS_CONV) =>
{
span_lint_and_then(
cx,
TRANSMUTE_FLOAT_TO_INT,

View file

@ -1,4 +1,5 @@
use super::TRANSMUTE_INT_TO_FLOAT;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg;
use rustc_errors::Applicability;
@ -15,9 +16,10 @@ pub(super) fn check<'tcx>(
to_ty: Ty<'tcx>,
arg: &'tcx Expr<'_>,
const_context: bool,
msrv: &Msrv,
) -> bool {
match (&from_ty.kind(), &to_ty.kind()) {
(ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context => {
(ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context || msrv.meets(msrvs::CONST_FLOAT_BITS_CONV) => {
span_lint_and_then(
cx,
TRANSMUTE_INT_TO_FLOAT,

View file

@ -1,4 +1,5 @@
use super::TRANSMUTE_NUM_TO_BYTES;
use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg;
use rustc_errors::Applicability;
@ -15,15 +16,14 @@ pub(super) fn check<'tcx>(
to_ty: Ty<'tcx>,
arg: &'tcx Expr<'_>,
const_context: bool,
msrv: &Msrv,
) -> bool {
match (&from_ty.kind(), &to_ty.kind()) {
(ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => {
if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) {
return false;
}
if matches!(from_ty.kind(), ty::Float(_)) && const_context {
// TODO: Remove when const_float_bits_conv is stabilized
// rust#72447
if matches!(from_ty.kind(), ty::Float(_)) && const_context && !msrv.meets(msrvs::CONST_FLOAT_BITS_CONV) {
return false;
}

View file

@ -75,11 +75,9 @@ impl UnnecessaryBoxReturns {
.instantiate_bound_regions_with_erased(cx.tcx.fn_sig(def_id).skip_binder())
.output();
if !return_ty.is_box() {
let Some(boxed_ty) = return_ty.boxed_ty() else {
return;
}
let boxed_ty = return_ty.boxed_ty();
};
// It's sometimes useful to return Box<T> if T is unsized, so don't lint those.
// Also, don't lint if we know that T is very large, in which case returning

View file

@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{match_def_path, paths};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
@ -42,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings {
&& let ty::Ref(_, inner_str, _) = cx.typeck_results().expr_ty_adjusted(expr).kind()
&& inner_str.is_str()
{
if match_def_path(cx, fun_def_id, &paths::STRING_NEW) {
if cx.tcx.is_diagnostic_item(sym::string_new, fun_def_id) {
span_lint_and_sugg(
cx,
UNNECESSARY_OWNED_EMPTY_STRINGS,

View file

@ -221,7 +221,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
) => {
eq_closure_binder(lb, rb)
&& lc == rc
&& la.map_or(false, CoroutineKind::is_async) == ra.map_or(false, CoroutineKind::is_async)
&& eq_coroutine_kind(*la, *ra)
&& lm == rm
&& eq_fn_decl(lf, rf)
&& eq_expr(le, re)
@ -241,6 +241,16 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
}
}
fn eq_coroutine_kind(a: Option<CoroutineKind>, b: Option<CoroutineKind>) -> bool {
match (a, b) {
(Some(CoroutineKind::Async { .. }), Some(CoroutineKind::Async { .. }))
| (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. }))
| (Some(CoroutineKind::AsyncGen { .. }), Some(CoroutineKind::AsyncGen { .. }))
| (None, None) => true,
_ => false,
}
}
pub fn eq_field(l: &ExprField, r: &ExprField) -> bool {
l.is_placeholder == r.is_placeholder
&& eq_id(l.ident, r.ident)

View file

@ -4,7 +4,7 @@
use crate::consts::{ConstEvalCtxt, Constant};
use crate::ty::is_type_diagnostic_item;
use crate::{is_expn_of, match_def_path, paths};
use crate::is_expn_of;
use rustc_ast::ast;
use rustc_hir as hir;
@ -297,10 +297,10 @@ impl<'a> VecArgs<'a> {
&& is_expn_of(fun.span, "vec").is_some()
&& let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
{
return if match_def_path(cx, fun_def_id, &paths::VEC_FROM_ELEM) && args.len() == 2 {
return if cx.tcx.is_diagnostic_item(sym::vec_from_elem, fun_def_id) && args.len() == 2 {
// `vec![elem; size]` case
Some(VecArgs::Repeat(&args[0], &args[1]))
} else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
} else if cx.tcx.is_diagnostic_item(sym::slice_into_vec, fun_def_id) && args.len() == 1 {
// `vec![a, b, c]` case
if let ExprKind::Call(_, [arg]) = &args[0].kind
&& let ExprKind::Array(args) = arg.kind
@ -309,7 +309,7 @@ impl<'a> VecArgs<'a> {
} else {
None
}
} else if match_def_path(cx, fun_def_id, &paths::VEC_NEW) && args.is_empty() {
} else if cx.tcx.is_diagnostic_item(sym::vec_new, fun_def_id) && args.is_empty() {
Some(VecArgs::Vec(&[]))
} else {
None

View file

@ -263,24 +263,18 @@ pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) ->
}
}
pub fn is_res_diagnostic_ctor(cx: &LateContext<'_>, res: Res, diag_item: Symbol) -> bool {
if let Res::Def(DefKind::Ctor(..), id) = res
&& let Some(id) = cx.tcx.opt_parent(id)
{
cx.tcx.is_diagnostic_item(diag_item, id)
} else {
false
}
}
/// Checks if a `QPath` resolves to a constructor of a diagnostic item.
pub fn is_diagnostic_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, diagnostic_item: Symbol) -> bool {
if let QPath::Resolved(_, path) = qpath {
if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res {
return cx.tcx.is_diagnostic_item(diagnostic_item, cx.tcx.parent(ctor_id));
}
}
false
/// Checks if `{ctor_call_id}(...)` is `{enum_item}::{variant_name}(...)`.
pub fn is_enum_variant_ctor(cx: &LateContext<'_>, enum_item: Symbol, variant_name: Symbol, ctor_call_id: DefId) -> bool {
let Some(enum_def_id) = cx.tcx.get_diagnostic_item(enum_item) else {
return false;
};
let variants = cx.tcx.adt_def(enum_def_id).variants().iter();
variants
.filter(|variant| variant.name == variant_name)
.filter_map(|variant| variant.ctor.as_ref())
.any(|(_, ctor_def_id)| *ctor_def_id == ctor_call_id)
}
/// Checks if the `DefId` matches the given diagnostic item or it's constructor.
@ -595,14 +589,11 @@ fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<It
"f32" => SimplifiedType::Float(FloatTy::F32),
"f64" => SimplifiedType::Float(FloatTy::F64),
_ => {
return Result::<&[_], rustc_errors::ErrorGuaranteed>::Ok(&[])
.into_iter()
.flatten()
.copied();
return [].iter().copied();
},
};
tcx.incoherent_impls(ty).into_iter().flatten().copied()
tcx.incoherent_impls(ty).into_iter().copied()
}
fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
@ -727,7 +718,6 @@ pub fn def_path_res(tcx: TyCtxt<'_>, path: &[&str]) -> Vec<Res> {
let inherent_impl_children = tcx
.inherent_impls(def_id)
.into_iter()
.flatten()
.flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment));
let direct_children = item_children_by_name(tcx, def_id, segment);

View file

@ -30,7 +30,7 @@ pub fn visit_local_usage(locals: &[Local], mir: &Body<'_>, location: Location) -
locals.len()
];
traversal::Postorder::new(&mir.basic_blocks, location.block)
traversal::Postorder::new(&mir.basic_blocks, location.block, ())
.collect::<Vec<_>>()
.into_iter()
.rev()

View file

@ -4,6 +4,7 @@
//! Whenever possible, please consider diagnostic items over hardcoded paths.
//! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.
// Paths inside rustc
pub const APPLICABILITY: [&str; 2] = ["rustc_lint_defs", "Applicability"];
pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [
["rustc_lint_defs", "Applicability", "Unspecified"],
@ -12,56 +13,36 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [
["rustc_lint_defs", "Applicability", "MachineApplicable"],
];
pub const DIAG: [&str; 2] = ["rustc_errors", "Diag"];
pub const BINARYHEAP_ITER: [&str; 5] = ["alloc", "collections", "binary_heap", "BinaryHeap", "iter"];
pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"];
pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"];
pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"];
pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"];
pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"];
pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"];
pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"];
pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"];
pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"];
pub const FILE_OPTIONS: [&str; 4] = ["std", "fs", "File", "options"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"];
pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"];
pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"];
pub const HASHMAP_ITER: [&str; 5] = ["std", "collections", "hash", "map", "Iter"];
pub const HASHMAP_ITER_MUT: [&str; 5] = ["std", "collections", "hash", "map", "IterMut"];
pub const HASHMAP_KEYS: [&str; 5] = ["std", "collections", "hash", "map", "Keys"];
pub const HASHMAP_VALUES: [&str; 5] = ["std", "collections", "hash", "map", "Values"];
pub const HASHMAP_DRAIN: [&str; 5] = ["std", "collections", "hash", "map", "Drain"];
pub const HASHMAP_VALUES_MUT: [&str; 5] = ["std", "collections", "hash", "map", "ValuesMut"];
pub const HASHSET_ITER_TY: [&str; 5] = ["std", "collections", "hash", "set", "Iter"];
pub const HASHSET_ITER: [&str; 6] = ["std", "collections", "hash", "set", "HashSet", "iter"];
pub const HASHSET_DRAIN: [&str; 5] = ["std", "collections", "hash", "set", "Drain"];
pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"];
pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"];
pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"];
pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"];
pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"];
pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
// Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items.
// ... none currently!
// Paths in clippy itself
pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"];
pub const OPEN_OPTIONS_NEW: [&str; 4] = ["std", "fs", "OpenOptions", "new"];
pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
// Paths in external crates
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"];
pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"];
pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"];
pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"];
pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
pub const PATH_MAIN_SEPARATOR: [&str; 3] = ["std", "path", "MAIN_SEPARATOR"];
pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
#[cfg_attr(not(unix), allow(clippy::invalid_paths))]
pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"];
pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
pub const REGEX_BUILDER_NEW: [&str; 3] = ["regex", "RegexBuilder", "new"];
pub const REGEX_BYTES_BUILDER_NEW: [&str; 4] = ["regex", "bytes", "RegexBuilder", "new"];
pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "bytes", "Regex", "new"];
@ -70,24 +51,6 @@ pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"];
pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"];
pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
pub const SLICE_INTO: [&str; 4] = ["core", "slice", "<impl [T]>", "iter"];
pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"];
pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"];
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"];
pub const STR_CHARS: [&str; 4] = ["core", "str", "<impl str>", "chars"];
pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"];
pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"];
pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"];
pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"];
pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"];
pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
pub const STRING_FROM_UTF8: [&str; 4] = ["alloc", "string", "String", "from_utf8"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const TOKIO_FILE_OPTIONS: [&str; 5] = ["tokio", "fs", "file", "File", "options"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
@ -98,16 +61,3 @@ pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_wri
pub const TOKIO_IO_OPEN_OPTIONS: [&str; 4] = ["tokio", "fs", "open_options", "OpenOptions"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const TOKIO_IO_OPEN_OPTIONS_NEW: [&str; 5] = ["tokio", "fs", "open_options", "OpenOptions", "new"];
pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"];
pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"];
pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"];
pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"];
pub const WAKER: [&str; 4] = ["core", "task", "wake", "Waker"];
pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
pub const BOOL_THEN: [&str; 4] = ["core", "bool", "<impl bool>", "then"];

View file

@ -123,7 +123,7 @@ fn check_rvalue<'tcx>(
| CastKind::FloatToFloat
| CastKind::FnPtrToPtr
| CastKind::PtrToPtr
| CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer),
| CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _),
operand,
_,
) => check_operand(tcx, operand, span, body, msrv),
@ -131,12 +131,12 @@ fn check_rvalue<'tcx>(
CastKind::PointerCoercion(
PointerCoercion::UnsafeFnPointer
| PointerCoercion::ClosureFnPointer(_)
| PointerCoercion::ReifyFnPointer,
| PointerCoercion::ReifyFnPointer, _
),
_,
_,
) => Err((span, "function pointer casts are not allowed in const fn".into())),
Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), op, cast_ty) => {
Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize, _), op, cast_ty) => {
let Some(pointee_ty) = cast_ty.builtin_deref(true) else {
// We cannot allow this for now.
return Err((span, "unsizing casts are only allowed for references right now".into()));
@ -154,7 +154,7 @@ fn check_rvalue<'tcx>(
Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => {
Err((span, "casting pointers to ints is unstable in const fn".into()))
},
Rvalue::Cast(CastKind::DynStar, _, _) => {
Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::DynStar, _), _, _) => {
// FIXME(dyn-star)
unimplemented!()
},

View file

@ -704,8 +704,8 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS
/// If the type is function like, get the signature for it.
pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
if ty.is_box() {
return ty_sig(cx, ty.boxed_ty());
if let Some(boxed_ty) = ty.boxed_ty() {
return ty_sig(cx, boxed_ty);
}
match *ty.kind() {
ty::Closure(id, subs) => {
@ -1316,7 +1316,7 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl
/// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`.
pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> {
if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) {
cx.tcx.inherent_impls(ty_did).into_iter().flatten().find_map(|&did| {
cx.tcx.inherent_impls(ty_did).into_iter().find_map(|&did| {
cx.tcx
.associated_items(did)
.filter_by_name_unhygienic(method_name)

View file

@ -1,5 +1,8 @@
//@aux-build:proc_macro_derive.rs
#![feature(f128)]
#![feature(f16)]
#![allow(
clippy::assign_op_pattern,
clippy::erasing_op,
@ -10,9 +13,6 @@
arithmetic_overflow,
unconditional_panic
)]
#![feature(const_mut_refs)]
#![feature(f128)]
#![feature(f16)]
#![warn(clippy::arithmetic_side_effects)]
extern crate proc_macro_derive;

View file

@ -236,5 +236,16 @@ LL | if result.is_ok() {
LL | result.as_mut().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 25 previous errors
error: creating a shared reference to mutable static is discouraged
--> tests/ui/checked_unwrap/simple_conditionals.rs:174:12
|
LL | if X.is_some() {
| ^^^^^^^^^^^ shared reference to mutable static
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
= note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
= note: `-D static-mut-refs` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(static_mut_refs)]`
error: aborting due to 26 previous errors

View file

@ -13,6 +13,14 @@ error: this lint expectation is unfulfilled
LL | #[expect(invalid_nan_comparisons)]
| ^^^^^^^^^^^^^^^^^^^^^^^
error: this lint expectation is unfulfilled
--> tests/ui/expect_tool_lint_rfc_2383.rs:36:18
|
LL | #[expect(invalid_nan_comparisons)]
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: this lint expectation is unfulfilled
--> tests/ui/expect_tool_lint_rfc_2383.rs:107:14
|
@ -37,5 +45,5 @@ error: this lint expectation is unfulfilled
LL | #[expect(clippy::overly_complex_bool_expr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 6 previous errors
error: aborting due to 7 previous errors

View file

@ -186,12 +186,6 @@ mod msrv {
extern "C" fn c() {}
}
mod with_extern {
extern "C-unwind" fn c_unwind() {}
extern "system" fn system() {}
extern "system-unwind" fn system_unwind() {}
}
mod with_ty_alias {
type Foo = impl std::fmt::Debug;

View file

@ -1,6 +1,6 @@
#![warn(clippy::missing_const_for_fn)]
#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)]
#![feature(const_mut_refs)]
#![allow(unsupported_calling_conventions)]
#![feature(const_trait_impl)]
use std::mem::transmute;
@ -204,3 +204,16 @@ mod with_ty_alias {
// in this test.
const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
}
mod extern_fn {
const extern "C-unwind" fn c_unwind() {}
//~^ ERROR: this could be a `const fn`
const extern "system" fn system() {}
//~^ ERROR: this could be a `const fn`
const extern "system-unwind" fn system_unwind() {}
//~^ ERROR: this could be a `const fn`
pub const extern "stdcall" fn std_call() {}
//~^ ERROR: this could be a `const fn`
pub const extern "stdcall-unwind" fn std_call_unwind() {}
//~^ ERROR: this could be a `const fn`
}

View file

@ -1,6 +1,6 @@
#![warn(clippy::missing_const_for_fn)]
#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)]
#![feature(const_mut_refs)]
#![allow(unsupported_calling_conventions)]
#![feature(const_trait_impl)]
use std::mem::transmute;
@ -204,3 +204,16 @@ mod with_ty_alias {
// in this test.
fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
}
mod extern_fn {
extern "C-unwind" fn c_unwind() {}
//~^ ERROR: this could be a `const fn`
extern "system" fn system() {}
//~^ ERROR: this could be a `const fn`
extern "system-unwind" fn system_unwind() {}
//~^ ERROR: this could be a `const fn`
pub extern "stdcall" fn std_call() {}
//~^ ERROR: this could be a `const fn`
pub extern "stdcall-unwind" fn std_call_unwind() {}
//~^ ERROR: this could be a `const fn`
}

View file

@ -283,5 +283,60 @@ help: make the function `const`
LL | const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
| +++++
error: aborting due to 21 previous errors
error: this could be a `const fn`
--> tests/ui/missing_const_for_fn/could_be_const.rs:209:5
|
LL | extern "C-unwind" fn c_unwind() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: make the function `const`
|
LL | const extern "C-unwind" fn c_unwind() {}
| +++++
error: this could be a `const fn`
--> tests/ui/missing_const_for_fn/could_be_const.rs:211:5
|
LL | extern "system" fn system() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: make the function `const`
|
LL | const extern "system" fn system() {}
| +++++
error: this could be a `const fn`
--> tests/ui/missing_const_for_fn/could_be_const.rs:213:5
|
LL | extern "system-unwind" fn system_unwind() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: make the function `const`
|
LL | const extern "system-unwind" fn system_unwind() {}
| +++++
error: this could be a `const fn`
--> tests/ui/missing_const_for_fn/could_be_const.rs:215:5
|
LL | pub extern "stdcall" fn std_call() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: make the function `const`
|
LL | pub const extern "stdcall" fn std_call() {}
| +++++
error: this could be a `const fn`
--> tests/ui/missing_const_for_fn/could_be_const.rs:217:5
|
LL | pub extern "stdcall-unwind" fn std_call_unwind() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: make the function `const`
|
LL | pub const extern "stdcall-unwind" fn std_call_unwind() {}
| +++++
error: aborting due to 26 previous errors

View file

@ -1,14 +0,0 @@
#![warn(clippy::missing_const_for_fn)]
#![allow(unsupported_calling_conventions)]
#![feature(const_extern_fn)]
const extern "C-unwind" fn c_unwind() {}
//~^ ERROR: this could be a `const fn`
const extern "system" fn system() {}
//~^ ERROR: this could be a `const fn`
const extern "system-unwind" fn system_unwind() {}
//~^ ERROR: this could be a `const fn`
pub const extern "stdcall" fn std_call() {}
//~^ ERROR: this could be a `const fn`
pub const extern "stdcall-unwind" fn std_call_unwind() {}
//~^ ERROR: this could be a `const fn`

View file

@ -1,14 +0,0 @@
#![warn(clippy::missing_const_for_fn)]
#![allow(unsupported_calling_conventions)]
#![feature(const_extern_fn)]
extern "C-unwind" fn c_unwind() {}
//~^ ERROR: this could be a `const fn`
extern "system" fn system() {}
//~^ ERROR: this could be a `const fn`
extern "system-unwind" fn system_unwind() {}
//~^ ERROR: this could be a `const fn`
pub extern "stdcall" fn std_call() {}
//~^ ERROR: this could be a `const fn`
pub extern "stdcall-unwind" fn std_call_unwind() {}
//~^ ERROR: this could be a `const fn`

View file

@ -1,59 +0,0 @@
error: this could be a `const fn`
--> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:5:1
|
LL | extern "C-unwind" fn c_unwind() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::missing-const-for-fn` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]`
help: make the function `const`
|
LL | const extern "C-unwind" fn c_unwind() {}
| +++++
error: this could be a `const fn`
--> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:7:1
|
LL | extern "system" fn system() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: make the function `const`
|
LL | const extern "system" fn system() {}
| +++++
error: this could be a `const fn`
--> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:9:1
|
LL | extern "system-unwind" fn system_unwind() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: make the function `const`
|
LL | const extern "system-unwind" fn system_unwind() {}
| +++++
error: this could be a `const fn`
--> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:11:1
|
LL | pub extern "stdcall" fn std_call() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: make the function `const`
|
LL | pub const extern "stdcall" fn std_call() {}
| +++++
error: this could be a `const fn`
--> tests/ui/missing_const_for_fn/could_be_const_with_const_extern_fn.rs:13:1
|
LL | pub extern "stdcall-unwind" fn std_call_unwind() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: make the function `const`
|
LL | pub const extern "stdcall-unwind" fn std_call_unwind() {}
| +++++
error: aborting due to 5 previous errors

View file

@ -4,6 +4,7 @@
#![allow(deref_nullptr)]
#![allow(clippy::unnecessary_operation)]
#![allow(dropping_copy_types)]
#![allow(clippy::assign_op_pattern)]
#![warn(clippy::multiple_unsafe_ops_per_block)]
extern crate proc_macros;

View file

@ -1,5 +1,5 @@
error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:37:5
--> tests/ui/multiple_unsafe_ops_per_block.rs:38:5
|
LL | / unsafe {
LL | | STATIC += 1;
@ -8,12 +8,12 @@ LL | | }
| |_____^
|
note: modification of a mutable static occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:38:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:39:9
|
LL | STATIC += 1;
| ^^^^^^^^^^^
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:39:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:40:9
|
LL | not_very_safe();
| ^^^^^^^^^^^^^^^
@ -21,7 +21,7 @@ LL | not_very_safe();
= help: to override `-D warnings` add `#[allow(clippy::multiple_unsafe_ops_per_block)]`
error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:46:5
--> tests/ui/multiple_unsafe_ops_per_block.rs:47:5
|
LL | / unsafe {
LL | | drop(u.u);
@ -30,18 +30,18 @@ LL | | }
| |_____^
|
note: union field access occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:47:14
--> tests/ui/multiple_unsafe_ops_per_block.rs:48:14
|
LL | drop(u.u);
| ^^^
note: raw pointer dereference occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:48:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:49:9
|
LL | *raw_ptr();
| ^^^^^^^^^^
error: this `unsafe` block contains 3 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:53:5
--> tests/ui/multiple_unsafe_ops_per_block.rs:54:5
|
LL | / unsafe {
LL | | asm!("nop");
@ -51,23 +51,23 @@ LL | | }
| |_____^
|
note: inline assembly used here
--> tests/ui/multiple_unsafe_ops_per_block.rs:54:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:55:9
|
LL | asm!("nop");
| ^^^^^^^^^^^
note: unsafe method call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:55:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:56:9
|
LL | sample.not_very_safe();
| ^^^^^^^^^^^^^^^^^^^^^^
note: modification of a mutable static occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:56:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:57:9
|
LL | STATIC = 0;
| ^^^^^^^^^^
error: this `unsafe` block contains 6 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:62:5
--> tests/ui/multiple_unsafe_ops_per_block.rs:63:5
|
LL | / unsafe {
LL | | drop(u.u);
@ -79,55 +79,55 @@ LL | | }
| |_____^
|
note: union field access occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:63:14
--> tests/ui/multiple_unsafe_ops_per_block.rs:64:14
|
LL | drop(u.u);
| ^^^
note: access of a mutable static occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:64:14
--> tests/ui/multiple_unsafe_ops_per_block.rs:65:14
|
LL | drop(STATIC);
| ^^^^^^
note: unsafe method call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:65:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:66:9
|
LL | sample.not_very_safe();
| ^^^^^^^^^^^^^^^^^^^^^^
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:66:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:67:9
|
LL | not_very_safe();
| ^^^^^^^^^^^^^^^
note: raw pointer dereference occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:67:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:68:9
|
LL | *raw_ptr();
| ^^^^^^^^^^
note: inline assembly used here
--> tests/ui/multiple_unsafe_ops_per_block.rs:68:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:69:9
|
LL | asm!("nop");
| ^^^^^^^^^^^
error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:106:5
--> tests/ui/multiple_unsafe_ops_per_block.rs:107:5
|
LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:106:14
--> tests/ui/multiple_unsafe_ops_per_block.rs:107:14
|
LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: raw pointer dereference occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:106:39
--> tests/ui/multiple_unsafe_ops_per_block.rs:107:39
|
LL | unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
| ^^^^^^^^^^^^^^^^^^
error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:124:5
--> tests/ui/multiple_unsafe_ops_per_block.rs:125:5
|
LL | / unsafe {
LL | | x();
@ -136,18 +136,18 @@ LL | | }
| |_____^
|
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:125:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:126:9
|
LL | x();
| ^^^
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:126:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:127:9
|
LL | x();
| ^^^
error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:135:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:136:9
|
LL | / unsafe {
LL | | T::X();
@ -156,18 +156,18 @@ LL | | }
| |_________^
|
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:136:13
--> tests/ui/multiple_unsafe_ops_per_block.rs:137:13
|
LL | T::X();
| ^^^^^^
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:137:13
--> tests/ui/multiple_unsafe_ops_per_block.rs:138:13
|
LL | T::X();
| ^^^^^^
error: this `unsafe` block contains 2 unsafe operations, expected only one
--> tests/ui/multiple_unsafe_ops_per_block.rs:145:5
--> tests/ui/multiple_unsafe_ops_per_block.rs:146:5
|
LL | / unsafe {
LL | | x.0();
@ -176,12 +176,12 @@ LL | | }
| |_____^
|
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:146:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:147:9
|
LL | x.0();
| ^^^^^
note: unsafe function call occurs here
--> tests/ui/multiple_unsafe_ops_per_block.rs:147:9
--> tests/ui/multiple_unsafe_ops_per_block.rs:148:9
|
LL | x.0();
| ^^^^^

View file

@ -1,5 +1,10 @@
#![feature(never_type)]
#![allow(unused_mut, clippy::redundant_allocation, clippy::needless_pass_by_ref_mut)]
#![allow(
unused_mut,
clippy::redundant_allocation,
clippy::needless_pass_by_ref_mut,
static_mut_refs
)]
#![warn(clippy::must_use_candidate)]
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};

View file

@ -1,5 +1,10 @@
#![feature(never_type)]
#![allow(unused_mut, clippy::redundant_allocation, clippy::needless_pass_by_ref_mut)]
#![allow(
unused_mut,
clippy::redundant_allocation,
clippy::needless_pass_by_ref_mut,
static_mut_refs
)]
#![warn(clippy::must_use_candidate)]
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};

View file

@ -1,5 +1,5 @@
error: this function could have a `#[must_use]` attribute
--> tests/ui/must_use_candidates.rs:11:1
--> tests/ui/must_use_candidates.rs:16:1
|
LL | pub fn pure(i: u8) -> u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8`
@ -8,25 +8,25 @@ LL | pub fn pure(i: u8) -> u8 {
= help: to override `-D warnings` add `#[allow(clippy::must_use_candidate)]`
error: this method could have a `#[must_use]` attribute
--> tests/ui/must_use_candidates.rs:16:5
--> tests/ui/must_use_candidates.rs:21:5
|
LL | pub fn inherent_pure(&self) -> u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn inherent_pure(&self) -> u8`
error: this function could have a `#[must_use]` attribute
--> tests/ui/must_use_candidates.rs:47:1
--> tests/ui/must_use_candidates.rs:52:1
|
LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool`
error: this function could have a `#[must_use]` attribute
--> tests/ui/must_use_candidates.rs:59:1
--> tests/ui/must_use_candidates.rs:64:1
|
LL | pub fn rcd(_x: Rc<u32>) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn rcd(_x: Rc<u32>) -> bool`
error: this function could have a `#[must_use]` attribute
--> tests/ui/must_use_candidates.rs:67:1
--> tests/ui/must_use_candidates.rs:72:1
|
LL | pub fn arcd(_x: Arc<u32>) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc<u32>) -> bool`

View file

@ -1,3 +1,14 @@
error: elided lifetime has a name
--> tests/ui/needless_lifetimes.rs:266:52
|
LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
| -- ^ this elided lifetime gets resolved as `'a`
| |
| lifetime `'a` declared here
|
= note: `-D elided-named-lifetimes` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]`
error: the following explicit lifetimes could be elided: 'a, 'b
--> tests/ui/needless_lifetimes.rs:17:23
|
@ -553,5 +564,5 @@ LL - fn one_input<'a>(x: &'a u8) -> &'a u8 {
LL + fn one_input(x: &u8) -> &u8 {
|
error: aborting due to 46 previous errors
error: aborting due to 47 previous errors

View file

@ -1,3 +1,12 @@
error: elided lifetime has a name
--> tests/ui/ptr_arg.rs:295:56
|
LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
= note: `-D elided-named-lifetimes` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]`
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
--> tests/ui/ptr_arg.rs:13:14
|
@ -212,5 +221,5 @@ error: using a reference to `Cow` is not recommended
LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str {
| ^^^^^^^^^^^^^^^^ help: change this to: `&str`
error: aborting due to 24 previous errors
error: aborting due to 25 previous errors

View file

@ -1,4 +1,6 @@
#![allow(unused)]
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]
#[derive(Debug)]
struct Foo;

View file

@ -1,4 +1,6 @@
#![allow(unused)]
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]
#[derive(Debug)]
struct Foo;

View file

@ -1,5 +1,5 @@
error: constants have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:6:17
--> tests/ui/redundant_static_lifetimes.rs:8:17
|
LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR: Consider removing 'static.
| -^^^^^^^---- help: consider removing `'static`: `&str`
@ -8,103 +8,103 @@ LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR: Consider removi
= help: to override `-D warnings` add `#[allow(clippy::redundant_static_lifetimes)]`
error: constants have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:10:21
--> tests/ui/redundant_static_lifetimes.rs:12:21
|
LL | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR: Consider removing 'static
| -^^^^^^^---- help: consider removing `'static`: `&str`
error: constants have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:12:32
--> tests/ui/redundant_static_lifetimes.rs:14:32
|
LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static
| -^^^^^^^---- help: consider removing `'static`: `&str`
error: constants have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:12:47
--> tests/ui/redundant_static_lifetimes.rs:14:47
|
LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static
| -^^^^^^^---- help: consider removing `'static`: `&str`
error: constants have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:14:17
--> tests/ui/redundant_static_lifetimes.rs:16:17
|
LL | const VAR_SIX: &'static u8 = &5;
| -^^^^^^^--- help: consider removing `'static`: `&u8`
error: constants have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:16:20
--> tests/ui/redundant_static_lifetimes.rs:18:20
|
LL | const VAR_HEIGHT: &'static Foo = &Foo {};
| -^^^^^^^---- help: consider removing `'static`: `&Foo`
error: constants have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:18:19
--> tests/ui/redundant_static_lifetimes.rs:20:19
|
LL | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR: Consider removing 'static.
| -^^^^^^^----- help: consider removing `'static`: `&[u8]`
error: constants have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:20:19
--> tests/ui/redundant_static_lifetimes.rs:22:19
|
LL | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR: Consider removing 'static.
| -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
error: constants have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:22:19
--> tests/ui/redundant_static_lifetimes.rs:24:19
|
LL | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR: Consider removing 'static.
| -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
error: statics have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:24:25
--> tests/ui/redundant_static_lifetimes.rs:26:25
|
LL | static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR: Consider removing 'static.
| -^^^^^^^---- help: consider removing `'static`: `&str`
error: statics have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:28:29
--> tests/ui/redundant_static_lifetimes.rs:30:29
|
LL | static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR: Consider removing 'static
| -^^^^^^^---- help: consider removing `'static`: `&str`
error: statics have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:30:25
--> tests/ui/redundant_static_lifetimes.rs:32:25
|
LL | static STATIC_VAR_SIX: &'static u8 = &5;
| -^^^^^^^--- help: consider removing `'static`: `&u8`
error: statics have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:32:28
--> tests/ui/redundant_static_lifetimes.rs:34:28
|
LL | static STATIC_VAR_HEIGHT: &'static Foo = &Foo {};
| -^^^^^^^---- help: consider removing `'static`: `&Foo`
error: statics have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:34:27
--> tests/ui/redundant_static_lifetimes.rs:36:27
|
LL | static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR: Consider removing 'static.
| -^^^^^^^----- help: consider removing `'static`: `&[u8]`
error: statics have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:36:27
--> tests/ui/redundant_static_lifetimes.rs:38:27
|
LL | static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR: Consider removing 'static.
| -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
error: statics have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:38:27
--> tests/ui/redundant_static_lifetimes.rs:40:27
|
LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR: Consider removing 'static.
| -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
error: statics have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:40:31
--> tests/ui/redundant_static_lifetimes.rs:42:31
|
LL | static mut STATIC_MUT_SLICE: &'static mut [u32] = &mut [0];
| -^^^^^^^---------- help: consider removing `'static`: `&mut [u32]`
error: statics have by default a `'static` lifetime
--> tests/ui/redundant_static_lifetimes.rs:69:16
--> tests/ui/redundant_static_lifetimes.rs:71:16
|
LL | static V: &'static u8 = &17;
| -^^^^^^^--- help: consider removing `'static`: `&u8`

View file

@ -140,24 +140,32 @@ mod int_to_float {
mod issue_5747 {
const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) };
//~^ ERROR: transmute from a `u16` to a `f16`
const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) };
//~^ ERROR: transmute from a `u32` to a `f32`
const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) };
//~^ ERROR: transmute from a `i64` to a `f64`
const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) };
//~^ ERROR: transmute from a `i128` to a `f128`
const fn from_bits_16(v: i16) -> f16 {
unsafe { std::mem::transmute(v) }
//~^ ERROR: transmute from a `i16` to a `f16`
}
const fn from_bits_32(v: i32) -> f32 {
unsafe { std::mem::transmute(v) }
//~^ ERROR: transmute from a `i32` to a `f32`
}
const fn from_bits_64(v: u64) -> f64 {
unsafe { std::mem::transmute(v) }
//~^ ERROR: transmute from a `u64` to a `f64`
}
const fn from_bits_128(v: u128) -> f128 {
unsafe { std::mem::transmute(v) }
//~^ ERROR: transmute from a `u128` to a `f128`
}
}
}
@ -205,9 +213,13 @@ mod num_to_bytes {
//~^ ERROR: transmute from a `i128` to a `[u8; 16]`
let _: [u8; 2] = std::mem::transmute(0.0f16);
//~^ ERROR: transmute from a `f16` to a `[u8; 2]`
let _: [u8; 4] = std::mem::transmute(0.0f32);
//~^ ERROR: transmute from a `f32` to a `[u8; 4]`
let _: [u8; 8] = std::mem::transmute(0.0f64);
//~^ ERROR: transmute from a `f64` to a `[u8; 8]`
let _: [u8; 16] = std::mem::transmute(0.0f128);
//~^ ERROR: transmute from a `f128` to a `[u8; 16]`
}
}
}

View file

@ -148,8 +148,56 @@ error: transmute from a `i128` to a `f128`
LL | let _: f128 = unsafe { std::mem::transmute(0_i128) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)`
error: transmute from a `u16` to a `f16`
--> tests/ui/transmute.rs:142:39
|
LL | const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)`
error: transmute from a `u32` to a `f32`
--> tests/ui/transmute.rs:144:39
|
LL | const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
error: transmute from a `i64` to a `f64`
--> tests/ui/transmute.rs:146:39
|
LL | const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
error: transmute from a `i128` to a `f128`
--> tests/ui/transmute.rs:148:41
|
LL | const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)`
error: transmute from a `i16` to a `f16`
--> tests/ui/transmute.rs:152:22
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(v as u16)`
error: transmute from a `i32` to a `f32`
--> tests/ui/transmute.rs:157:22
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(v as u32)`
error: transmute from a `u64` to a `f64`
--> tests/ui/transmute.rs:162:22
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(v)`
error: transmute from a `u128` to a `f128`
--> tests/ui/transmute.rs:167:22
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(v)`
error: transmute from a `u8` to a `[u8; 1]`
--> tests/ui/transmute.rs:168:30
--> tests/ui/transmute.rs:176:30
|
LL | let _: [u8; 1] = std::mem::transmute(0u8);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
@ -158,97 +206,121 @@ LL | let _: [u8; 1] = std::mem::transmute(0u8);
= help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]`
error: transmute from a `u32` to a `[u8; 4]`
--> tests/ui/transmute.rs:171:30
--> tests/ui/transmute.rs:179:30
|
LL | let _: [u8; 4] = std::mem::transmute(0u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
error: transmute from a `u128` to a `[u8; 16]`
--> tests/ui/transmute.rs:173:31
--> tests/ui/transmute.rs:181:31
|
LL | let _: [u8; 16] = std::mem::transmute(0u128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
error: transmute from a `i8` to a `[u8; 1]`
--> tests/ui/transmute.rs:175:30
--> tests/ui/transmute.rs:183:30
|
LL | let _: [u8; 1] = std::mem::transmute(0i8);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
error: transmute from a `i32` to a `[u8; 4]`
--> tests/ui/transmute.rs:177:30
--> tests/ui/transmute.rs:185:30
|
LL | let _: [u8; 4] = std::mem::transmute(0i32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
error: transmute from a `i128` to a `[u8; 16]`
--> tests/ui/transmute.rs:179:31
--> tests/ui/transmute.rs:187:31
|
LL | let _: [u8; 16] = std::mem::transmute(0i128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
error: transmute from a `f16` to a `[u8; 2]`
--> tests/ui/transmute.rs:182:30
--> tests/ui/transmute.rs:190:30
|
LL | let _: [u8; 2] = std::mem::transmute(0.0f16);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()`
error: transmute from a `f32` to a `[u8; 4]`
--> tests/ui/transmute.rs:184:30
--> tests/ui/transmute.rs:192:30
|
LL | let _: [u8; 4] = std::mem::transmute(0.0f32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
error: transmute from a `f64` to a `[u8; 8]`
--> tests/ui/transmute.rs:186:30
--> tests/ui/transmute.rs:194:30
|
LL | let _: [u8; 8] = std::mem::transmute(0.0f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
error: transmute from a `f128` to a `[u8; 16]`
--> tests/ui/transmute.rs:188:31
--> tests/ui/transmute.rs:196:31
|
LL | let _: [u8; 16] = std::mem::transmute(0.0f128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()`
error: transmute from a `u8` to a `[u8; 1]`
--> tests/ui/transmute.rs:194:30
--> tests/ui/transmute.rs:202:30
|
LL | let _: [u8; 1] = std::mem::transmute(0u8);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
error: transmute from a `u32` to a `[u8; 4]`
--> tests/ui/transmute.rs:196:30
--> tests/ui/transmute.rs:204:30
|
LL | let _: [u8; 4] = std::mem::transmute(0u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
error: transmute from a `u128` to a `[u8; 16]`
--> tests/ui/transmute.rs:198:31
--> tests/ui/transmute.rs:206:31
|
LL | let _: [u8; 16] = std::mem::transmute(0u128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
error: transmute from a `i8` to a `[u8; 1]`
--> tests/ui/transmute.rs:200:30
--> tests/ui/transmute.rs:208:30
|
LL | let _: [u8; 1] = std::mem::transmute(0i8);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
error: transmute from a `i32` to a `[u8; 4]`
--> tests/ui/transmute.rs:202:30
--> tests/ui/transmute.rs:210:30
|
LL | let _: [u8; 4] = std::mem::transmute(0i32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
error: transmute from a `i128` to a `[u8; 16]`
--> tests/ui/transmute.rs:204:31
--> tests/ui/transmute.rs:212:31
|
LL | let _: [u8; 16] = std::mem::transmute(0i128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
error: transmute from a `f16` to a `[u8; 2]`
--> tests/ui/transmute.rs:215:30
|
LL | let _: [u8; 2] = std::mem::transmute(0.0f16);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()`
error: transmute from a `f32` to a `[u8; 4]`
--> tests/ui/transmute.rs:217:30
|
LL | let _: [u8; 4] = std::mem::transmute(0.0f32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
error: transmute from a `f64` to a `[u8; 8]`
--> tests/ui/transmute.rs:219:30
|
LL | let _: [u8; 8] = std::mem::transmute(0.0f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
error: transmute from a `f128` to a `[u8; 16]`
--> tests/ui/transmute.rs:221:31
|
LL | let _: [u8; 16] = std::mem::transmute(0.0f128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()`
error: transmute from a `&[u8]` to a `&str`
--> tests/ui/transmute.rs:218:28
--> tests/ui/transmute.rs:230:28
|
LL | let _: &str = unsafe { std::mem::transmute(B) };
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()`
@ -257,16 +329,16 @@ LL | let _: &str = unsafe { std::mem::transmute(B) };
= help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]`
error: transmute from a `&mut [u8]` to a `&mut str`
--> tests/ui/transmute.rs:221:32
--> tests/ui/transmute.rs:233:32
|
LL | let _: &mut str = unsafe { std::mem::transmute(mb) };
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
error: transmute from a `&[u8]` to a `&str`
--> tests/ui/transmute.rs:223:30
--> tests/ui/transmute.rs:235:30
|
LL | const _: &str = unsafe { std::mem::transmute(B) };
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)`
error: aborting due to 42 previous errors
error: aborting due to 54 previous errors

View file

@ -1,7 +1,7 @@
#![warn(clippy::transmute_float_to_int)]
#![allow(clippy::missing_transmute_annotations)]
#![feature(f128)]
#![feature(f16)]
#![feature(f128, f128_const)]
#![feature(f16, f16_const)]
fn float_to_int() {
let _: u32 = unsafe { 1f32.to_bits() };
@ -20,25 +20,33 @@ fn float_to_int() {
}
mod issue_5747 {
const VALUE16: i16 = unsafe { std::mem::transmute(1f16) };
const VALUE32: i32 = unsafe { std::mem::transmute(1f32) };
const VALUE64: u64 = unsafe { std::mem::transmute(1f64) };
const VALUE128: u128 = unsafe { std::mem::transmute(1f128) };
const VALUE16: i16 = unsafe { 1f16.to_bits() as i16 };
//~^ ERROR: transmute from a `f16` to a `i16`
const VALUE32: i32 = unsafe { 1f32.to_bits() as i32 };
//~^ ERROR: transmute from a `f32` to a `i32`
const VALUE64: u64 = unsafe { 1f64.to_bits() };
//~^ ERROR: transmute from a `f64` to a `u64`
const VALUE128: u128 = unsafe { 1f128.to_bits() };
//~^ ERROR: transmute from a `f128` to a `u128`
const fn to_bits_16(v: f16) -> u16 {
unsafe { std::mem::transmute(v) }
unsafe { v.to_bits() }
//~^ ERROR: transmute from a `f16` to a `u16`
}
const fn to_bits_32(v: f32) -> u32 {
unsafe { std::mem::transmute(v) }
unsafe { v.to_bits() }
//~^ ERROR: transmute from a `f32` to a `u32`
}
const fn to_bits_64(v: f64) -> i64 {
unsafe { std::mem::transmute(v) }
unsafe { v.to_bits() as i64 }
//~^ ERROR: transmute from a `f64` to a `i64`
}
const fn to_bits_128(v: f128) -> i128 {
unsafe { std::mem::transmute(v) }
unsafe { v.to_bits() as i128 }
//~^ ERROR: transmute from a `f128` to a `i128`
}
}

View file

@ -1,7 +1,7 @@
#![warn(clippy::transmute_float_to_int)]
#![allow(clippy::missing_transmute_annotations)]
#![feature(f128)]
#![feature(f16)]
#![feature(f128, f128_const)]
#![feature(f16, f16_const)]
fn float_to_int() {
let _: u32 = unsafe { std::mem::transmute(1f32) };
@ -21,24 +21,32 @@ fn float_to_int() {
mod issue_5747 {
const VALUE16: i16 = unsafe { std::mem::transmute(1f16) };
//~^ ERROR: transmute from a `f16` to a `i16`
const VALUE32: i32 = unsafe { std::mem::transmute(1f32) };
//~^ ERROR: transmute from a `f32` to a `i32`
const VALUE64: u64 = unsafe { std::mem::transmute(1f64) };
//~^ ERROR: transmute from a `f64` to a `u64`
const VALUE128: u128 = unsafe { std::mem::transmute(1f128) };
//~^ ERROR: transmute from a `f128` to a `u128`
const fn to_bits_16(v: f16) -> u16 {
unsafe { std::mem::transmute(v) }
//~^ ERROR: transmute from a `f16` to a `u16`
}
const fn to_bits_32(v: f32) -> u32 {
unsafe { std::mem::transmute(v) }
//~^ ERROR: transmute from a `f32` to a `u32`
}
const fn to_bits_64(v: f64) -> i64 {
unsafe { std::mem::transmute(v) }
//~^ ERROR: transmute from a `f64` to a `i64`
}
const fn to_bits_128(v: f128) -> i128 {
unsafe { std::mem::transmute(v) }
//~^ ERROR: transmute from a `f128` to a `i128`
}
}

View file

@ -37,5 +37,53 @@ error: transmute from a `f64` to a `u64`
LL | let _: u64 = unsafe { std::mem::transmute(-1.0) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()`
error: aborting due to 6 previous errors
error: transmute from a `f16` to a `i16`
--> tests/ui/transmute_float_to_int.rs:23:35
|
LL | const VALUE16: i16 = unsafe { std::mem::transmute(1f16) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f16.to_bits() as i16`
error: transmute from a `f32` to a `i32`
--> tests/ui/transmute_float_to_int.rs:25:35
|
LL | const VALUE32: i32 = unsafe { std::mem::transmute(1f32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f32.to_bits() as i32`
error: transmute from a `f64` to a `u64`
--> tests/ui/transmute_float_to_int.rs:27:35
|
LL | const VALUE64: u64 = unsafe { std::mem::transmute(1f64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()`
error: transmute from a `f128` to a `u128`
--> tests/ui/transmute_float_to_int.rs:29:37
|
LL | const VALUE128: u128 = unsafe { std::mem::transmute(1f128) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f128.to_bits()`
error: transmute from a `f16` to a `u16`
--> tests/ui/transmute_float_to_int.rs:33:18
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()`
error: transmute from a `f32` to a `u32`
--> tests/ui/transmute_float_to_int.rs:38:18
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()`
error: transmute from a `f64` to a `i64`
--> tests/ui/transmute_float_to_int.rs:43:18
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i64`
error: transmute from a `f128` to a `i128`
--> tests/ui/transmute_float_to_int.rs:48:18
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i128`
error: aborting due to 14 previous errors

View file

@ -1,5 +1,7 @@
#![deny(clippy::useless_conversion)]
#![allow(clippy::needless_if, clippy::unnecessary_wraps)]
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]
fn test_generic<T: Copy>(val: T) -> T {
let _ = val;

View file

@ -1,5 +1,7 @@
#![deny(clippy::useless_conversion)]
#![allow(clippy::needless_if, clippy::unnecessary_wraps)]
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]
fn test_generic<T: Copy>(val: T) -> T {
let _ = T::from(val);

View file

@ -1,5 +1,5 @@
error: useless conversion to the same type: `T`
--> tests/ui/useless_conversion.rs:5:13
--> tests/ui/useless_conversion.rs:7:13
|
LL | let _ = T::from(val);
| ^^^^^^^^^^^^ help: consider removing `T::from()`: `val`
@ -11,217 +11,217 @@ LL | #![deny(clippy::useless_conversion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: useless conversion to the same type: `T`
--> tests/ui/useless_conversion.rs:6:5
--> tests/ui/useless_conversion.rs:8:5
|
LL | val.into()
| ^^^^^^^^^^ help: consider removing `.into()`: `val`
error: useless conversion to the same type: `i32`
--> tests/ui/useless_conversion.rs:18:22
--> tests/ui/useless_conversion.rs:20:22
|
LL | let _: i32 = 0i32.into();
| ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
error: useless conversion to the same type: `std::str::Lines<'_>`
--> tests/ui/useless_conversion.rs:48:22
--> tests/ui/useless_conversion.rs:50:22
|
LL | if Some("ok") == lines.into_iter().next() {}
| ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines`
error: useless conversion to the same type: `std::str::Lines<'_>`
--> tests/ui/useless_conversion.rs:53:21
--> tests/ui/useless_conversion.rs:55:21
|
LL | let mut lines = text.lines().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()`
error: useless conversion to the same type: `std::str::Lines<'_>`
--> tests/ui/useless_conversion.rs:59:22
--> tests/ui/useless_conversion.rs:61:22
|
LL | if Some("ok") == text.lines().into_iter().next() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()`
error: useless conversion to the same type: `std::ops::Range<i32>`
--> tests/ui/useless_conversion.rs:65:13
--> tests/ui/useless_conversion.rs:67:13
|
LL | let _ = NUMBERS.into_iter().next();
| ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS`
error: useless conversion to the same type: `std::ops::Range<i32>`
--> tests/ui/useless_conversion.rs:70:17
--> tests/ui/useless_conversion.rs:72:17
|
LL | let mut n = NUMBERS.into_iter();
| ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS`
error: useless conversion to the same type: `std::string::String`
--> tests/ui/useless_conversion.rs:132:21
--> tests/ui/useless_conversion.rs:134:21
|
LL | let _: String = "foo".to_string().into();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
error: useless conversion to the same type: `std::string::String`
--> tests/ui/useless_conversion.rs:133:21
--> tests/ui/useless_conversion.rs:135:21
|
LL | let _: String = From::from("foo".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
error: useless conversion to the same type: `std::string::String`
--> tests/ui/useless_conversion.rs:134:13
--> tests/ui/useless_conversion.rs:136:13
|
LL | let _ = String::from("foo".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
error: useless conversion to the same type: `std::string::String`
--> tests/ui/useless_conversion.rs:135:13
--> tests/ui/useless_conversion.rs:137:13
|
LL | let _ = String::from(format!("A: {:04}", 123));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
error: useless conversion to the same type: `std::str::Lines<'_>`
--> tests/ui/useless_conversion.rs:136:13
--> tests/ui/useless_conversion.rs:138:13
|
LL | let _ = "".lines().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
error: useless conversion to the same type: `std::vec::IntoIter<i32>`
--> tests/ui/useless_conversion.rs:137:13
--> tests/ui/useless_conversion.rs:139:13
|
LL | let _ = vec![1, 2, 3].into_iter().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
error: useless conversion to the same type: `std::string::String`
--> tests/ui/useless_conversion.rs:138:21
--> tests/ui/useless_conversion.rs:140:21
|
LL | let _: String = format!("Hello {}", "world").into();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
error: useless conversion to the same type: `i32`
--> tests/ui/useless_conversion.rs:143:13
--> tests/ui/useless_conversion.rs:145:13
|
LL | let _ = i32::from(a + b) * 3;
| ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)`
error: useless conversion to the same type: `Foo<'a'>`
--> tests/ui/useless_conversion.rs:149:23
--> tests/ui/useless_conversion.rs:151:23
|
LL | let _: Foo<'a'> = s2.into();
| ^^^^^^^^^ help: consider removing `.into()`: `s2`
error: useless conversion to the same type: `Foo<'a'>`
--> tests/ui/useless_conversion.rs:151:13
--> tests/ui/useless_conversion.rs:153:13
|
LL | let _ = Foo::<'a'>::from(s3);
| ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3`
error: useless conversion to the same type: `std::vec::IntoIter<Foo<'a'>>`
--> tests/ui/useless_conversion.rs:153:13
--> tests/ui/useless_conversion.rs:155:13
|
LL | let _ = vec![s4, s4, s4].into_iter().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()`
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:185:7
--> tests/ui/useless_conversion.rs:187:7
|
LL | b(vec![1, 2].into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:175:13
--> tests/ui/useless_conversion.rs:177:13
|
LL | fn b<T: IntoIterator<Item = i32>>(_: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:186:7
--> tests/ui/useless_conversion.rs:188:7
|
LL | c(vec![1, 2].into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:176:18
--> tests/ui/useless_conversion.rs:178:18
|
LL | fn c(_: impl IntoIterator<Item = i32>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:187:7
--> tests/ui/useless_conversion.rs:189:7
|
LL | d(vec![1, 2].into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:179:12
--> tests/ui/useless_conversion.rs:181:12
|
LL | T: IntoIterator<Item = i32>,
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:190:7
--> tests/ui/useless_conversion.rs:192:7
|
LL | b(vec![1, 2].into_iter().into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:175:13
--> tests/ui/useless_conversion.rs:177:13
|
LL | fn b<T: IntoIterator<Item = i32>>(_: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:191:7
--> tests/ui/useless_conversion.rs:193:7
|
LL | b(vec![1, 2].into_iter().into_iter().into_iter());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:175:13
--> tests/ui/useless_conversion.rs:177:13
|
LL | fn b<T: IntoIterator<Item = i32>>(_: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:237:24
--> tests/ui/useless_conversion.rs:239:24
|
LL | foo2::<i32, _>([1, 2, 3].into_iter());
| ^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2, 3]`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:216:12
--> tests/ui/useless_conversion.rs:218:12
|
LL | I: IntoIterator<Item = i32> + Helper<X>,
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:245:14
--> tests/ui/useless_conversion.rs:247:14
|
LL | foo3([1, 2, 3].into_iter());
| ^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2, 3]`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:225:12
--> tests/ui/useless_conversion.rs:227:12
|
LL | I: IntoIterator<Item = i32>,
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:254:16
--> tests/ui/useless_conversion.rs:256:16
|
LL | S1.foo([1, 2].into_iter());
| ^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `[1, 2]`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:251:27
--> tests/ui/useless_conversion.rs:253:27
|
LL | pub fn foo<I: IntoIterator>(&self, _: I) {}
| ^^^^^^^^^^^^
error: explicit call to `.into_iter()` in function argument accepting `IntoIterator`
--> tests/ui/useless_conversion.rs:273:44
--> tests/ui/useless_conversion.rs:275:44
|
LL | v0.into_iter().interleave_shortest(v1.into_iter());
| ^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `v1`
|
note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`
--> tests/ui/useless_conversion.rs:260:20
--> tests/ui/useless_conversion.rs:262:20
|
LL | J: IntoIterator,
| ^^^^^^^^^^^^

View file

@ -136,6 +136,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
"min-llvm-version",
"min-system-llvm-version",
"needs-asm-support",
"needs-deterministic-layouts",
"needs-dlltool",
"needs-dynamic-linking",
"needs-force-clang-based-tests",

View file

@ -11,7 +11,7 @@ use serde::de::{Deserialize, Deserializer, Error as _};
use test::{ColorConfig, OutputFormat};
pub use self::Mode::*;
use crate::util::{add_dylib_path, PathBufExt};
use crate::util::{PathBufExt, add_dylib_path};
macro_rules! string_enum {
($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => {
@ -183,6 +183,9 @@ pub struct Config {
/// The rustc executable.
pub rustc_path: PathBuf,
/// The cargo executable.
pub cargo_path: Option<PathBuf>,
/// The rustdoc executable.
pub rustdoc_path: Option<PathBuf>,
@ -274,6 +277,9 @@ pub struct Config {
/// Flags to pass to the compiler when building for the target
pub target_rustcflags: Vec<String>,
/// Whether the compiler and stdlib has been built with randomized struct layouts
pub rust_randomized_layout: bool,
/// Whether tests should be optimized by default. Individual test-suites and test files may
/// override this setting.
pub optimize_tests: bool,
@ -381,6 +387,7 @@ pub struct Config {
// Needed both to construct build_helper::git::GitConfig
pub git_repository: String,
pub nightly_branch: String,
pub git_merge_commit_email: String,
/// True if the profiler runtime is enabled for this target.
/// Used by the "needs-profiler-support" header in test files.
@ -458,7 +465,11 @@ impl Config {
}
pub fn git_config(&self) -> GitConfig<'_> {
GitConfig { git_repository: &self.git_repository, nightly_branch: &self.nightly_branch }
GitConfig {
git_repository: &self.git_repository,
nightly_branch: &self.nightly_branch,
git_merge_commit_email: &self.git_merge_commit_email,
}
}
}

View file

@ -1,7 +1,7 @@
use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;
use std::str::FromStr;
use std::sync::OnceLock;

View file

@ -1,8 +1,8 @@
use std::collections::HashSet;
use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::OnceLock;
@ -11,7 +11,7 @@ use regex::Regex;
use tracing::*;
use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
use crate::header::cfg::{parse_cfg_name_directive, MatchOutcome};
use crate::header::cfg::{MatchOutcome, parse_cfg_name_directive};
use crate::header::needs::CachedNeedsConditions;
use crate::util::static_regex;
use crate::{extract_cdb_version, extract_gdb_version};
@ -125,7 +125,7 @@ pub struct TestProps {
// Build documentation for all specified aux-builds as well
pub build_aux_docs: bool,
/// Build the documentation for each crate in a unique output directory.
/// Uses <root output directory>/docs/<test name>/doc
/// Uses `<root output directory>/docs/<test name>/doc`.
pub unique_doc_out_dir: bool,
// Flag to force a crate to be built with the host architecture
pub force_host: bool,
@ -1304,12 +1304,12 @@ pub fn llvm_has_libzstd(config: &Config) -> bool {
false
}
/// Takes a directive of the form "<version1> [- <version2>]",
/// returns the numeric representation of <version1> and <version2> as
/// tuple: (<version1> as u32, <version2> as u32)
/// Takes a directive of the form `"<version1> [- <version2>]"`,
/// returns the numeric representation of `<version1>` and `<version2>` as
/// tuple: `(<version1> as u32, <version2> as u32)`.
///
/// If the <version2> part is omitted, the second component of the tuple
/// is the same as <version1>.
/// If the `<version2>` part is omitted, the second component of the tuple
/// is the same as `<version1>`.
fn extract_version_range<F>(line: &str, parse: F) -> Option<(u32, u32)>
where
F: Fn(&str) -> Option<u32>,

View file

@ -1,5 +1,5 @@
use crate::common::{Config, Sanitizer};
use crate::header::{llvm_has_libzstd, IgnoreDecision};
use crate::header::{IgnoreDecision, llvm_has_libzstd};
pub(super) fn handle_needs(
cache: &CachedNeedsConditions,
@ -134,6 +134,11 @@ pub(super) fn handle_needs(
condition: config.target_cfg().relocation_model == "pic",
ignore_reason: "ignored on targets without PIC relocation model",
},
Need {
name: "needs-deterministic-layouts",
condition: !config.rust_randomized_layout,
ignore_reason: "ignored when randomizing layouts",
},
Need {
name: "needs-wasmtime",
condition: config.runner.as_ref().is_some_and(|r| r.contains("wasmtime")),

View file

@ -4,7 +4,7 @@ use std::str::FromStr;
use super::iter_header;
use crate::common::{Config, Debugger, Mode};
use crate::header::{parse_normalize_rule, EarlyProps, HeadersCache};
use crate::header::{EarlyProps, HeadersCache, parse_normalize_rule};
fn make_test_description<R: Read>(
config: &Config,
@ -148,6 +148,7 @@ impl ConfigBuilder {
self.target.as_deref().unwrap_or("x86_64-unknown-linux-gnu"),
"--git-repository=",
"--nightly-branch=",
"--git-merge-commit-email=",
];
let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();
@ -225,10 +226,9 @@ fn revisions() {
let config: Config = cfg().build();
assert_eq!(parse_rs(&config, "//@ revisions: a b c").revisions, vec!["a", "b", "c"],);
assert_eq!(
parse_makefile(&config, "# revisions: hello there").revisions,
vec!["hello", "there"],
);
assert_eq!(parse_makefile(&config, "# revisions: hello there").revisions, vec![
"hello", "there"
],);
}
#[test]

View file

@ -34,10 +34,10 @@ use test::ColorConfig;
use tracing::*;
use walkdir::WalkDir;
use self::header::{make_test_description, EarlyProps};
use self::header::{EarlyProps, make_test_description};
use crate::common::{
expected_output_path, output_base_dir, output_relative_path, Config, Debugger, Mode, PassMode,
TestPaths, UI_EXTENSIONS,
Config, Debugger, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path,
output_base_dir, output_relative_path,
};
use crate::header::HeadersCache;
use crate::util::logv;
@ -47,6 +47,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH")
.reqopt("", "run-lib-path", "path to target shared libraries", "PATH")
.reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH")
.optopt("", "cargo-path", "path to cargo to use for compiling", "PATH")
.optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH")
.optopt("", "coverage-dump-path", "path to coverage-dump to use in tests", "PATH")
.reqopt("", "python", "path to python to use for doc tests", "PATH")
@ -99,6 +100,11 @@ pub fn parse_config(args: Vec<String>) -> Config {
)
.optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS")
.optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS")
.optflag(
"",
"rust-randomized-layout",
"set this when rustc/stdlib were compiled with randomized layouts",
)
.optflag("", "optimize-tests", "run tests with optimizations enabled")
.optflag("", "verbose", "run tests verbosely, showing all output")
.optflag(
@ -158,7 +164,13 @@ pub fn parse_config(args: Vec<String>) -> Config {
)
.optopt("", "edition", "default Rust edition", "EDITION")
.reqopt("", "git-repository", "name of the git repository", "ORG/REPO")
.reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH");
.reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH")
.reqopt(
"",
"git-merge-commit-email",
"email address used for finding merge commits",
"EMAIL",
);
let (argv0, args_) = args.split_first().unwrap();
if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
@ -249,6 +261,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
rustc_path: opt_path(matches, "rustc-path"),
cargo_path: matches.opt_str("cargo-path").map(PathBuf::from),
rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from),
coverage_dump_path: matches.opt_str("coverage-dump-path").map(PathBuf::from),
python: matches.opt_str("python").unwrap(),
@ -286,6 +299,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
host_rustcflags: matches.opt_strs("host-rustcflags"),
target_rustcflags: matches.opt_strs("target-rustcflags"),
optimize_tests: matches.opt_present("optimize-tests"),
rust_randomized_layout: matches.opt_present("rust-randomized-layout"),
target,
host: opt_str2(matches.opt_str("host")),
cdb,
@ -340,6 +354,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
git_repository: matches.opt_str("git-repository").unwrap(),
nightly_branch: matches.opt_str("nightly-branch").unwrap(),
git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(),
profiler_support: matches.opt_present("profiler-support"),
}
@ -351,6 +366,7 @@ pub fn log_config(config: &Config) {
logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path));
logv(c, format!("run_lib_path: {:?}", config.run_lib_path));
logv(c, format!("rustc_path: {:?}", config.rustc_path.display()));
logv(c, format!("cargo_path: {:?}", config.cargo_path));
logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path));
logv(c, format!("src_base: {:?}", config.src_base.display()));
logv(c, format!("build_base: {:?}", config.build_base.display()));
@ -634,6 +650,12 @@ fn common_inputs_stamp(config: &Config) -> Stamp {
stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py"));
}
// Re-run coverage tests if the `coverage-dump` tool was modified,
// because its output format might have changed.
if let Some(coverage_dump_path) = &config.coverage_dump_path {
stamp.add_path(coverage_dump_path)
}
stamp.add_dir(&rust_src_dir.join("src/tools/run-make-support"));
// Compiletest itself.
@ -802,8 +824,12 @@ fn make_test(
&config, cache, test_name, &test_path, src_file, revision, poisoned,
);
// Ignore tests that already run and are up to date with respect to inputs.
if !config.force_rerun {
desc.ignore |= is_up_to_date(&config, testpaths, &early_props, revision, inputs);
if !config.force_rerun
&& is_up_to_date(&config, testpaths, &early_props, revision, inputs)
{
desc.ignore = true;
// Keep this in sync with the "up-to-date" message detected by bootstrap.
desc.ignore_message = Some("up-to-date");
}
test::TestDescAndFn {
desc,

View file

@ -232,9 +232,9 @@ mod imp {
use std::process::{ChildStderr, ChildStdout};
use std::{io, slice};
use miow::Overlapped;
use miow::iocp::{CompletionPort, CompletionStatus};
use miow::pipe::NamedPipe;
use miow::Overlapped;
use windows::Win32::Foundation::ERROR_BROKEN_PIPE;
struct Pipe<'a> {

View file

@ -1,6 +1,6 @@
use std::io::Write;
use crate::read2::{ProcOutput, FILTERED_PATHS_PLACEHOLDER_LEN, MAX_OUT_LEN};
use crate::read2::{FILTERED_PATHS_PLACEHOLDER_LEN, MAX_OUT_LEN, ProcOutput};
#[test]
fn test_abbreviate_short_string() {

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,19 @@
use super::TestCx;
impl TestCx<'_> {
pub(super) fn run_assembly_test(&self) {
if self.config.llvm_filecheck.is_none() {
self.fatal("missing --llvm-filecheck");
}
let (proc_res, output_path) = self.compile_test_and_save_assembly();
if !proc_res.status.success() {
self.fatal_proc_rec("compilation failed!", &proc_res);
}
let proc_res = self.verify_with_filecheck(&output_path);
if !proc_res.status.success() {
self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res);
}
}
}

View file

@ -0,0 +1,22 @@
use super::{PassMode, TestCx};
impl TestCx<'_> {
pub(super) fn run_codegen_test(&self) {
if self.config.llvm_filecheck.is_none() {
self.fatal("missing --llvm-filecheck");
}
let (proc_res, output_path) = self.compile_test_and_save_ir();
if !proc_res.status.success() {
self.fatal_proc_rec("compilation failed!", &proc_res);
}
if let Some(PassMode::Build) = self.pass_mode() {
return;
}
let proc_res = self.verify_with_filecheck(&output_path);
if !proc_res.status.success() {
self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res);
}
}
}

View file

@ -0,0 +1,191 @@
use std::collections::HashSet;
use super::{Emit, TestCx, WillExecute};
use crate::errors;
use crate::util::static_regex;
impl TestCx<'_> {
pub(super) fn run_codegen_units_test(&self) {
assert!(self.revision.is_none(), "revisions not relevant here");
let proc_res = self.compile_test(WillExecute::No, Emit::None);
if !proc_res.status.success() {
self.fatal_proc_rec("compilation failed!", &proc_res);
}
self.check_no_compiler_crash(&proc_res, self.props.should_ice);
const PREFIX: &str = "MONO_ITEM ";
const CGU_MARKER: &str = "@@";
// Some MonoItems can contain {closure@/path/to/checkout/tests/codgen-units/test.rs}
// To prevent the current dir from leaking, we just replace the entire path to the test
// file with TEST_PATH.
let actual: Vec<MonoItem> = proc_res
.stdout
.lines()
.filter(|line| line.starts_with(PREFIX))
.map(|line| {
line.replace(&self.testpaths.file.display().to_string(), "TEST_PATH").to_string()
})
.map(|line| str_to_mono_item(&line, true))
.collect();
let expected: Vec<MonoItem> = errors::load_errors(&self.testpaths.file, None)
.iter()
.map(|e| str_to_mono_item(&e.msg[..], false))
.collect();
let mut missing = Vec::new();
let mut wrong_cgus = Vec::new();
for expected_item in &expected {
let actual_item_with_same_name = actual.iter().find(|ti| ti.name == expected_item.name);
if let Some(actual_item) = actual_item_with_same_name {
if !expected_item.codegen_units.is_empty() &&
// Also check for codegen units
expected_item.codegen_units != actual_item.codegen_units
{
wrong_cgus.push((expected_item.clone(), actual_item.clone()));
}
} else {
missing.push(expected_item.string.clone());
}
}
let unexpected: Vec<_> = actual
.iter()
.filter(|acgu| !expected.iter().any(|ecgu| acgu.name == ecgu.name))
.map(|acgu| acgu.string.clone())
.collect();
if !missing.is_empty() {
missing.sort();
println!("\nThese items should have been contained but were not:\n");
for item in &missing {
println!("{}", item);
}
println!("\n");
}
if !unexpected.is_empty() {
let sorted = {
let mut sorted = unexpected.clone();
sorted.sort();
sorted
};
println!("\nThese items were contained but should not have been:\n");
for item in sorted {
println!("{}", item);
}
println!("\n");
}
if !wrong_cgus.is_empty() {
wrong_cgus.sort_by_key(|pair| pair.0.name.clone());
println!("\nThe following items were assigned to wrong codegen units:\n");
for &(ref expected_item, ref actual_item) in &wrong_cgus {
println!("{}", expected_item.name);
println!(" expected: {}", codegen_units_to_str(&expected_item.codegen_units));
println!(" actual: {}", codegen_units_to_str(&actual_item.codegen_units));
println!();
}
}
if !(missing.is_empty() && unexpected.is_empty() && wrong_cgus.is_empty()) {
panic!();
}
#[derive(Clone, Eq, PartialEq)]
struct MonoItem {
name: String,
codegen_units: HashSet<String>,
string: String,
}
// [MONO_ITEM] name [@@ (cgu)+]
fn str_to_mono_item(s: &str, cgu_has_crate_disambiguator: bool) -> MonoItem {
let s = if s.starts_with(PREFIX) { (&s[PREFIX.len()..]).trim() } else { s.trim() };
let full_string = format!("{}{}", PREFIX, s);
let parts: Vec<&str> =
s.split(CGU_MARKER).map(str::trim).filter(|s| !s.is_empty()).collect();
let name = parts[0].trim();
let cgus = if parts.len() > 1 {
let cgus_str = parts[1];
cgus_str
.split(' ')
.map(str::trim)
.filter(|s| !s.is_empty())
.map(|s| {
if cgu_has_crate_disambiguator {
remove_crate_disambiguators_from_set_of_cgu_names(s)
} else {
s.to_string()
}
})
.collect()
} else {
HashSet::new()
};
MonoItem { name: name.to_owned(), codegen_units: cgus, string: full_string }
}
fn codegen_units_to_str(cgus: &HashSet<String>) -> String {
let mut cgus: Vec<_> = cgus.iter().collect();
cgus.sort();
let mut string = String::new();
for cgu in cgus {
string.push_str(&cgu[..]);
string.push(' ');
}
string
}
// Given a cgu-name-prefix of the form <crate-name>.<crate-disambiguator> or
// the form <crate-name1>.<crate-disambiguator1>-in-<crate-name2>.<crate-disambiguator2>,
// remove all crate-disambiguators.
fn remove_crate_disambiguator_from_cgu(cgu: &str) -> String {
let Some(captures) =
static_regex!(r"^[^\.]+(?P<d1>\.[[:alnum:]]+)(-in-[^\.]+(?P<d2>\.[[:alnum:]]+))?")
.captures(cgu)
else {
panic!("invalid cgu name encountered: {cgu}");
};
let mut new_name = cgu.to_owned();
if let Some(d2) = captures.name("d2") {
new_name.replace_range(d2.start()..d2.end(), "");
}
let d1 = captures.name("d1").unwrap();
new_name.replace_range(d1.start()..d1.end(), "");
new_name
}
// The name of merged CGUs is constructed as the names of the original
// CGUs joined with "--". This function splits such composite CGU names
// and handles each component individually.
fn remove_crate_disambiguators_from_set_of_cgu_names(cgus: &str) -> String {
cgus.split("--").map(remove_crate_disambiguator_from_cgu).collect::<Vec<_>>().join("--")
}
}
}

View file

@ -18,7 +18,7 @@ impl<'test> TestCx<'test> {
.unwrap_or_else(|| self.fatal("missing --coverage-dump"))
}
pub(crate) fn run_coverage_map_test(&self) {
pub(super) fn run_coverage_map_test(&self) {
let coverage_dump_path = self.coverage_dump_path();
let (proc_res, llvm_ir_path) = self.compile_test_and_save_ir();
@ -50,7 +50,7 @@ impl<'test> TestCx<'test> {
}
}
pub(crate) fn run_coverage_run_test(&self) {
pub(super) fn run_coverage_run_test(&self) {
let should_run = self.run_if_enabled();
let proc_res = self.compile_test(should_run, Emit::None);

View file

@ -0,0 +1,26 @@
use super::{TestCx, WillExecute};
impl TestCx<'_> {
pub(super) fn run_crash_test(&self) {
let pm = self.pass_mode();
let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm));
if std::env::var("COMPILETEST_VERBOSE_CRASHES").is_ok() {
eprintln!("{}", proc_res.status);
eprintln!("{}", proc_res.stdout);
eprintln!("{}", proc_res.stderr);
eprintln!("{}", proc_res.cmdline);
}
// if a test does not crash, consider it an error
if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) {
self.fatal(&format!(
"crashtest no longer crashes/triggers ICE, horray! Please give it a meaningful \
name, add a doc-comment to the start of the test explaining why it exists and \
move it to tests/ui or wherever you see fit. Adding 'Fixes #<issueNr>' to your PR \
description ensures that the corresponding ticket is auto-closed upon merge. \
If you want to see verbose output, set `COMPILETEST_VERBOSE_CRASHES=1`."
));
}
}
}

View file

@ -0,0 +1,509 @@
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io::{BufRead, BufReader, Read};
use std::path::Path;
use std::process::{Command, Output, Stdio};
use tracing::debug;
use super::debugger::DebuggerCommands;
use super::{Debugger, Emit, ProcRes, TestCx, Truncated, WillExecute};
use crate::common::Config;
use crate::util::logv;
use crate::{extract_gdb_version, is_android_gdb_target};
impl TestCx<'_> {
pub(super) fn run_debuginfo_test(&self) {
match self.config.debugger.unwrap() {
Debugger::Cdb => self.run_debuginfo_cdb_test(),
Debugger::Gdb => self.run_debuginfo_gdb_test(),
Debugger::Lldb => self.run_debuginfo_lldb_test(),
}
}
fn run_debuginfo_cdb_test(&self) {
let config = Config {
target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
..self.config.clone()
};
let test_cx = TestCx { config: &config, ..*self };
test_cx.run_debuginfo_cdb_test_no_opt();
}
fn run_debuginfo_cdb_test_no_opt(&self) {
let exe_file = self.make_exe_name();
// Existing PDB files are update in-place. When changing the debuginfo
// the compiler generates for something, this can lead to the situation
// where both the old and the new version of the debuginfo for the same
// type is present in the PDB, which is very confusing.
// Therefore we delete any existing PDB file before compiling the test
// case.
// FIXME: If can reliably detect that MSVC's link.exe is used, then
// passing `/INCREMENTAL:NO` might be a cleaner way to do this.
let pdb_file = exe_file.with_extension(".pdb");
if pdb_file.exists() {
std::fs::remove_file(pdb_file).unwrap();
}
// compile test file (it should have 'compile-flags:-g' in the header)
let should_run = self.run_if_enabled();
let compile_result = self.compile_test(should_run, Emit::None);
if !compile_result.status.success() {
self.fatal_proc_rec("compilation failed!", &compile_result);
}
if let WillExecute::Disabled = should_run {
return;
}
let prefixes = {
static PREFIXES: &[&str] = &["cdb", "cdbg"];
// No "native rust support" variation for CDB yet.
PREFIXES
};
// Parse debugger commands etc from test files
let dbg_cmds = DebuggerCommands::parse_from(
&self.testpaths.file,
self.config,
prefixes,
self.revision,
)
.unwrap_or_else(|e| self.fatal(&e));
// https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
let mut script_str = String::with_capacity(2048);
script_str.push_str("version\n"); // List CDB (and more) version info in test output
script_str.push_str(".nvlist\n"); // List loaded `*.natvis` files, bulk of custom MSVC debug
// If a .js file exists next to the source file being tested, then this is a JavaScript
// debugging extension that needs to be loaded.
let mut js_extension = self.testpaths.file.clone();
js_extension.set_extension("cdb.js");
if js_extension.exists() {
script_str.push_str(&format!(".scriptload \"{}\"\n", js_extension.to_string_lossy()));
}
// Set breakpoints on every line that contains the string "#break"
let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy();
for line in &dbg_cmds.breakpoint_lines {
script_str.push_str(&format!("bp `{}:{}`\n", source_file_name, line));
}
// Append the other `cdb-command:`s
for line in &dbg_cmds.commands {
script_str.push_str(line);
script_str.push('\n');
}
script_str.push_str("qq\n"); // Quit the debugger (including remote debugger, if any)
// Write the script into a file
debug!("script_str = {}", script_str);
self.dump_output_file(&script_str, "debugger.script");
let debugger_script = self.make_out_name("debugger.script");
let cdb_path = &self.config.cdb.as_ref().unwrap();
let mut cdb = Command::new(cdb_path);
cdb.arg("-lines") // Enable source line debugging.
.arg("-cf")
.arg(&debugger_script)
.arg(&exe_file);
let debugger_run_result = self.compose_and_run(
cdb,
self.config.run_lib_path.to_str().unwrap(),
None, // aux_path
None, // input
);
if !debugger_run_result.status.success() {
self.fatal_proc_rec("Error while running CDB", &debugger_run_result);
}
if let Err(e) = dbg_cmds.check_output(&debugger_run_result) {
self.fatal_proc_rec(&e, &debugger_run_result);
}
}
fn run_debuginfo_gdb_test(&self) {
let config = Config {
target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
..self.config.clone()
};
let test_cx = TestCx { config: &config, ..*self };
test_cx.run_debuginfo_gdb_test_no_opt();
}
fn run_debuginfo_gdb_test_no_opt(&self) {
let dbg_cmds = DebuggerCommands::parse_from(
&self.testpaths.file,
self.config,
&["gdb"],
self.revision,
)
.unwrap_or_else(|e| self.fatal(&e));
let mut cmds = dbg_cmds.commands.join("\n");
// compile test file (it should have 'compile-flags:-g' in the header)
let should_run = self.run_if_enabled();
let compiler_run_result = self.compile_test(should_run, Emit::None);
if !compiler_run_result.status.success() {
self.fatal_proc_rec("compilation failed!", &compiler_run_result);
}
if let WillExecute::Disabled = should_run {
return;
}
let exe_file = self.make_exe_name();
let debugger_run_result;
if is_android_gdb_target(&self.config.target) {
cmds = cmds.replace("run", "continue");
let tool_path = match self.config.android_cross_path.to_str() {
Some(x) => x.to_owned(),
None => self.fatal("cannot find android cross path"),
};
// write debugger script
let mut script_str = String::with_capacity(2048);
script_str.push_str(&format!("set charset {}\n", Self::charset()));
script_str.push_str(&format!("set sysroot {}\n", tool_path));
script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap()));
script_str.push_str("target remote :5039\n");
script_str.push_str(&format!(
"set solib-search-path \
./{}/stage2/lib/rustlib/{}/lib/\n",
self.config.host, self.config.target
));
for line in &dbg_cmds.breakpoint_lines {
script_str.push_str(
format!(
"break {:?}:{}\n",
self.testpaths.file.file_name().unwrap().to_string_lossy(),
*line
)
.as_str(),
);
}
script_str.push_str(&cmds);
script_str.push_str("\nquit\n");
debug!("script_str = {}", script_str);
self.dump_output_file(&script_str, "debugger.script");
let adb_path = &self.config.adb_path;
Command::new(adb_path)
.arg("push")
.arg(&exe_file)
.arg(&self.config.adb_test_dir)
.status()
.unwrap_or_else(|e| panic!("failed to exec `{adb_path:?}`: {e:?}"));
Command::new(adb_path)
.args(&["forward", "tcp:5039", "tcp:5039"])
.status()
.unwrap_or_else(|e| panic!("failed to exec `{adb_path:?}`: {e:?}"));
let adb_arg = format!(
"export LD_LIBRARY_PATH={}; \
gdbserver{} :5039 {}/{}",
self.config.adb_test_dir.clone(),
if self.config.target.contains("aarch64") { "64" } else { "" },
self.config.adb_test_dir.clone(),
exe_file.file_name().unwrap().to_str().unwrap()
);
debug!("adb arg: {}", adb_arg);
let mut adb = Command::new(adb_path)
.args(&["shell", &adb_arg])
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.spawn()
.unwrap_or_else(|e| panic!("failed to exec `{adb_path:?}`: {e:?}"));
// Wait for the gdbserver to print out "Listening on port ..."
// at which point we know that it's started and then we can
// execute the debugger below.
let mut stdout = BufReader::new(adb.stdout.take().unwrap());
let mut line = String::new();
loop {
line.truncate(0);
stdout.read_line(&mut line).unwrap();
if line.starts_with("Listening on port 5039") {
break;
}
}
drop(stdout);
let mut debugger_script = OsString::from("-command=");
debugger_script.push(self.make_out_name("debugger.script"));
let debugger_opts: &[&OsStr] =
&["-quiet".as_ref(), "-batch".as_ref(), "-nx".as_ref(), &debugger_script];
let gdb_path = self.config.gdb.as_ref().unwrap();
let Output { status, stdout, stderr } = Command::new(&gdb_path)
.args(debugger_opts)
.output()
.unwrap_or_else(|e| panic!("failed to exec `{gdb_path:?}`: {e:?}"));
let cmdline = {
let mut gdb = Command::new(&format!("{}-gdb", self.config.target));
gdb.args(debugger_opts);
let cmdline = self.make_cmdline(&gdb, "");
logv(self.config, format!("executing {}", cmdline));
cmdline
};
debugger_run_result = ProcRes {
status,
stdout: String::from_utf8(stdout).unwrap(),
stderr: String::from_utf8(stderr).unwrap(),
truncated: Truncated::No,
cmdline,
};
if adb.kill().is_err() {
println!("Adb process is already finished.");
}
} else {
let rust_src_root =
self.config.find_rust_src_root().expect("Could not find Rust source root");
let rust_pp_module_rel_path = Path::new("./src/etc");
let rust_pp_module_abs_path =
rust_src_root.join(rust_pp_module_rel_path).to_str().unwrap().to_owned();
// write debugger script
let mut script_str = String::with_capacity(2048);
script_str.push_str(&format!("set charset {}\n", Self::charset()));
script_str.push_str("show version\n");
match self.config.gdb_version {
Some(version) => {
println!("NOTE: compiletest thinks it is using GDB version {}", version);
if version > extract_gdb_version("7.4").unwrap() {
// Add the directory containing the pretty printers to
// GDB's script auto loading safe path
script_str.push_str(&format!(
"add-auto-load-safe-path {}\n",
rust_pp_module_abs_path.replace(r"\", r"\\")
));
let output_base_dir = self.output_base_dir().to_str().unwrap().to_owned();
// Add the directory containing the output binary to
// include embedded pretty printers to GDB's script
// auto loading safe path
script_str.push_str(&format!(
"add-auto-load-safe-path {}\n",
output_base_dir.replace(r"\", r"\\")
));
}
}
_ => {
println!(
"NOTE: compiletest does not know which version of \
GDB it is using"
);
}
}
// The following line actually doesn't have to do anything with
// pretty printing, it just tells GDB to print values on one line:
script_str.push_str("set print pretty off\n");
// Add the pretty printer directory to GDB's source-file search path
script_str
.push_str(&format!("directory {}\n", rust_pp_module_abs_path.replace(r"\", r"\\")));
// Load the target executable
script_str
.push_str(&format!("file {}\n", exe_file.to_str().unwrap().replace(r"\", r"\\")));
// Force GDB to print values in the Rust format.
script_str.push_str("set language rust\n");
// Add line breakpoints
for line in &dbg_cmds.breakpoint_lines {
script_str.push_str(&format!(
"break '{}':{}\n",
self.testpaths.file.file_name().unwrap().to_string_lossy(),
*line
));
}
script_str.push_str(&cmds);
script_str.push_str("\nquit\n");
debug!("script_str = {}", script_str);
self.dump_output_file(&script_str, "debugger.script");
let mut debugger_script = OsString::from("-command=");
debugger_script.push(self.make_out_name("debugger.script"));
let debugger_opts: &[&OsStr] =
&["-quiet".as_ref(), "-batch".as_ref(), "-nx".as_ref(), &debugger_script];
let mut gdb = Command::new(self.config.gdb.as_ref().unwrap());
let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") {
format!("{pp}:{rust_pp_module_abs_path}")
} else {
rust_pp_module_abs_path
};
gdb.args(debugger_opts).env("PYTHONPATH", pythonpath);
debugger_run_result =
self.compose_and_run(gdb, self.config.run_lib_path.to_str().unwrap(), None, None);
}
if !debugger_run_result.status.success() {
self.fatal_proc_rec("gdb failed to execute", &debugger_run_result);
}
if let Err(e) = dbg_cmds.check_output(&debugger_run_result) {
self.fatal_proc_rec(&e, &debugger_run_result);
}
}
fn run_debuginfo_lldb_test(&self) {
if self.config.lldb_python_dir.is_none() {
self.fatal("Can't run LLDB test because LLDB's python path is not set.");
}
let config = Config {
target_rustcflags: self.cleanup_debug_info_options(&self.config.target_rustcflags),
host_rustcflags: self.cleanup_debug_info_options(&self.config.host_rustcflags),
..self.config.clone()
};
let test_cx = TestCx { config: &config, ..*self };
test_cx.run_debuginfo_lldb_test_no_opt();
}
fn run_debuginfo_lldb_test_no_opt(&self) {
// compile test file (it should have 'compile-flags:-g' in the header)
let should_run = self.run_if_enabled();
let compile_result = self.compile_test(should_run, Emit::None);
if !compile_result.status.success() {
self.fatal_proc_rec("compilation failed!", &compile_result);
}
if let WillExecute::Disabled = should_run {
return;
}
let exe_file = self.make_exe_name();
match self.config.lldb_version {
Some(ref version) => {
println!("NOTE: compiletest thinks it is using LLDB version {}", version);
}
_ => {
println!(
"NOTE: compiletest does not know which version of \
LLDB it is using"
);
}
}
// Parse debugger commands etc from test files
let dbg_cmds = DebuggerCommands::parse_from(
&self.testpaths.file,
self.config,
&["lldb"],
self.revision,
)
.unwrap_or_else(|e| self.fatal(&e));
// Write debugger script:
// We don't want to hang when calling `quit` while the process is still running
let mut script_str = String::from("settings set auto-confirm true\n");
// Make LLDB emit its version, so we have it documented in the test output
script_str.push_str("version\n");
// Switch LLDB into "Rust mode"
let rust_src_root =
self.config.find_rust_src_root().expect("Could not find Rust source root");
let rust_pp_module_rel_path = Path::new("./src/etc");
let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path);
script_str.push_str(&format!(
"command script import {}/lldb_lookup.py\n",
rust_pp_module_abs_path.to_str().unwrap()
));
File::open(rust_pp_module_abs_path.join("lldb_commands"))
.and_then(|mut file| file.read_to_string(&mut script_str))
.expect("Failed to read lldb_commands");
// Set breakpoints on every line that contains the string "#break"
let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy();
for line in &dbg_cmds.breakpoint_lines {
script_str.push_str(&format!(
"breakpoint set --file '{}' --line {}\n",
source_file_name, line
));
}
// Append the other commands
for line in &dbg_cmds.commands {
script_str.push_str(line);
script_str.push('\n');
}
// Finally, quit the debugger
script_str.push_str("\nquit\n");
// Write the script into a file
debug!("script_str = {}", script_str);
self.dump_output_file(&script_str, "debugger.script");
let debugger_script = self.make_out_name("debugger.script");
// Let LLDB execute the script via lldb_batchmode.py
let debugger_run_result = self.run_lldb(&exe_file, &debugger_script, &rust_src_root);
if !debugger_run_result.status.success() {
self.fatal_proc_rec("Error while running LLDB", &debugger_run_result);
}
if let Err(e) = dbg_cmds.check_output(&debugger_run_result) {
self.fatal_proc_rec(&e, &debugger_run_result);
}
}
fn run_lldb(
&self,
test_executable: &Path,
debugger_script: &Path,
rust_src_root: &Path,
) -> ProcRes {
// Prepare the lldb_batchmode which executes the debugger script
let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") {
format!("{pp}:{}", self.config.lldb_python_dir.as_ref().unwrap())
} else {
self.config.lldb_python_dir.as_ref().unwrap().to_string()
};
self.run_command_to_procres(
Command::new(&self.config.python)
.arg(&lldb_script_path)
.arg(test_executable)
.arg(debugger_script)
.env("PYTHONUNBUFFERED", "1") // Help debugging #78665
.env("PYTHONPATH", pythonpath),
)
}
fn cleanup_debug_info_options(&self, options: &Vec<String>) -> Vec<String> {
// Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
let options_to_remove = ["-O".to_owned(), "-g".to_owned(), "--debuginfo".to_owned()];
options.iter().filter(|x| !options_to_remove.contains(x)).cloned().collect()
}
}

View file

@ -0,0 +1,128 @@
use super::{TestCx, WillExecute};
use crate::errors;
// FIXME(jieyouxu): `run_rpass_test` got hoisted out of this because apparently valgrind falls back
// to `run_rpass_test` if valgrind isn't available, which is questionable, but keeping it for
// refactoring changes to preserve current behavior.
impl TestCx<'_> {
pub(super) fn run_incremental_test(&self) {
// Basic plan for a test incremental/foo/bar.rs:
// - load list of revisions rpass1, cfail2, rpass3
// - each should begin with `cpass`, `rpass`, `cfail`, or `rfail`
// - if `cpass`, expect compilation to succeed, don't execute
// - if `rpass`, expect compilation and execution to succeed
// - if `cfail`, expect compilation to fail
// - if `rfail`, expect compilation to succeed and execution to fail
// - create a directory build/foo/bar.incremental
// - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass1
// - because name of revision starts with "rpass", expect success
// - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C cfail2
// - because name of revision starts with "cfail", expect an error
// - load expected errors as usual, but filter for those that end in `[rfail2]`
// - compile foo/bar.rs with -C incremental=.../foo/bar.incremental and -C rpass3
// - because name of revision starts with "rpass", expect success
// - execute build/foo/bar.exe and save output
//
// FIXME -- use non-incremental mode as an oracle? That doesn't apply
// to #[rustc_dirty] and clean tests I guess
let revision = self.revision.expect("incremental tests require a list of revisions");
// Incremental workproduct directory should have already been created.
let incremental_dir = self.props.incremental_dir.as_ref().unwrap();
assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir");
if self.config.verbose {
print!("revision={:?} props={:#?}", revision, self.props);
}
if revision.starts_with("cpass") {
if self.props.should_ice {
self.fatal("can only use should-ice in cfail tests");
}
self.run_cpass_test();
} else if revision.starts_with("rpass") {
if self.props.should_ice {
self.fatal("can only use should-ice in cfail tests");
}
self.run_rpass_test();
} else if revision.starts_with("rfail") {
if self.props.should_ice {
self.fatal("can only use should-ice in cfail tests");
}
self.run_rfail_test();
} else if revision.starts_with("cfail") {
self.run_cfail_test();
} else {
self.fatal("revision name must begin with cpass, rpass, rfail, or cfail");
}
}
fn run_cpass_test(&self) {
let emit_metadata = self.should_emit_metadata(self.pass_mode());
let proc_res = self.compile_test(WillExecute::No, emit_metadata);
if !proc_res.status.success() {
self.fatal_proc_rec("compilation failed!", &proc_res);
}
// FIXME(#41968): Move this check to tidy?
if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() {
self.fatal("compile-pass tests with expected warnings should be moved to ui/");
}
}
fn run_cfail_test(&self) {
let pm = self.pass_mode();
let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm));
self.check_if_test_should_compile(&proc_res, pm);
self.check_no_compiler_crash(&proc_res, self.props.should_ice);
let output_to_check = self.get_output(&proc_res);
let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
if !expected_errors.is_empty() {
if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty()
{
self.fatal("both error pattern and expected errors specified");
}
self.check_expected_errors(expected_errors, &proc_res);
} else {
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
}
if self.props.should_ice {
match proc_res.status.code() {
Some(101) => (),
_ => self.fatal("expected ICE"),
}
}
self.check_forbid_output(&output_to_check, &proc_res);
}
fn run_rfail_test(&self) {
let pm = self.pass_mode();
let should_run = self.run_if_enabled();
let proc_res = self.compile_test(should_run, self.should_emit_metadata(pm));
if !proc_res.status.success() {
self.fatal_proc_rec("compilation failed!", &proc_res);
}
if let WillExecute::Disabled = should_run {
return;
}
let proc_res = self.exec_compiled_test();
// The value our Makefile configures valgrind to return on failure
const VALGRIND_ERR: i32 = 100;
if proc_res.status.code() == Some(VALGRIND_ERR) {
self.fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res);
}
let output_to_check = self.get_output(&proc_res);
self.check_correct_failure_status(&proc_res);
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
}
}

View file

@ -0,0 +1,32 @@
use std::process::Command;
use super::TestCx;
impl TestCx<'_> {
pub(super) fn run_js_doc_test(&self) {
if let Some(nodejs) = &self.config.nodejs {
let out_dir = self.output_base_dir();
self.document(&out_dir, &self.testpaths);
let root = self.config.find_rust_src_root().unwrap();
let file_stem =
self.testpaths.file.file_stem().and_then(|f| f.to_str()).expect("no file stem");
let res = self.run_command_to_procres(
Command::new(&nodejs)
.arg(root.join("src/tools/rustdoc-js/tester.js"))
.arg("--doc-folder")
.arg(out_dir)
.arg("--crate-name")
.arg(file_stem.replace("-", "_"))
.arg("--test-file")
.arg(self.testpaths.file.with_extension("js")),
);
if !res.status.success() {
self.fatal_proc_rec("rustdoc-js test failed!", &res);
}
} else {
self.fatal("no nodeJS");
}
}
}

View file

@ -0,0 +1,155 @@
use std::fs;
use std::path::{Path, PathBuf};
use glob::glob;
use miropt_test_tools::{MiroptTest, MiroptTestFile, files_for_miropt_test};
use tracing::debug;
use super::{Emit, TestCx, WillExecute};
use crate::compute_diff::write_diff;
impl TestCx<'_> {
pub(super) fn run_mir_opt_test(&self) {
let pm = self.pass_mode();
let should_run = self.should_run(pm);
let mut test_info = files_for_miropt_test(
&self.testpaths.file,
self.config.get_pointer_width(),
self.config.target_cfg().panic.for_miropt_test_tools(),
);
let passes = std::mem::take(&mut test_info.passes);
let proc_res = self.compile_test_with_passes(should_run, Emit::Mir, passes);
if !proc_res.status.success() {
self.fatal_proc_rec("compilation failed!", &proc_res);
}
self.check_mir_dump(test_info);
if let WillExecute::Yes = should_run {
let proc_res = self.exec_compiled_test();
if !proc_res.status.success() {
self.fatal_proc_rec("test run failed!", &proc_res);
}
}
}
fn check_mir_dump(&self, test_info: MiroptTest) {
let test_dir = self.testpaths.file.parent().unwrap();
let test_crate =
self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace('-', "_");
let MiroptTest { run_filecheck, suffix, files, passes: _ } = test_info;
if self.config.bless {
for e in
glob(&format!("{}/{}.*{}.mir", test_dir.display(), test_crate, suffix)).unwrap()
{
fs::remove_file(e.unwrap()).unwrap();
}
for e in
glob(&format!("{}/{}.*{}.diff", test_dir.display(), test_crate, suffix)).unwrap()
{
fs::remove_file(e.unwrap()).unwrap();
}
}
for MiroptTestFile { from_file, to_file, expected_file } in files {
let dumped_string = if let Some(after) = to_file {
self.diff_mir_files(from_file.into(), after.into())
} else {
let mut output_file = PathBuf::new();
output_file.push(self.get_mir_dump_dir());
output_file.push(&from_file);
debug!(
"comparing the contents of: {} with {}",
output_file.display(),
expected_file.display()
);
if !output_file.exists() {
panic!(
"Output file `{}` from test does not exist, available files are in `{}`",
output_file.display(),
output_file.parent().unwrap().display()
);
}
self.check_mir_test_timestamp(&from_file, &output_file);
let dumped_string = fs::read_to_string(&output_file).unwrap();
self.normalize_output(&dumped_string, &[])
};
if self.config.bless {
let _ = fs::remove_file(&expected_file);
fs::write(expected_file, dumped_string.as_bytes()).unwrap();
} else {
if !expected_file.exists() {
panic!("Output file `{}` from test does not exist", expected_file.display());
}
let expected_string = fs::read_to_string(&expected_file).unwrap();
if dumped_string != expected_string {
print!("{}", write_diff(&expected_string, &dumped_string, 3));
panic!(
"Actual MIR output differs from expected MIR output {}",
expected_file.display()
);
}
}
}
if run_filecheck {
let output_path = self.output_base_name().with_extension("mir");
let proc_res = self.verify_with_filecheck(&output_path);
if !proc_res.status.success() {
self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res);
}
}
}
fn diff_mir_files(&self, before: PathBuf, after: PathBuf) -> String {
let to_full_path = |path: PathBuf| {
let full = self.get_mir_dump_dir().join(&path);
if !full.exists() {
panic!(
"the mir dump file for {} does not exist (requested in {})",
path.display(),
self.testpaths.file.display(),
);
}
full
};
let before = to_full_path(before);
let after = to_full_path(after);
debug!("comparing the contents of: {} with {}", before.display(), after.display());
let before = fs::read_to_string(before).unwrap();
let after = fs::read_to_string(after).unwrap();
let before = self.normalize_output(&before, &[]);
let after = self.normalize_output(&after, &[]);
let mut dumped_string = String::new();
for result in diff::lines(&before, &after) {
use std::fmt::Write;
match result {
diff::Result::Left(s) => writeln!(dumped_string, "- {}", s).unwrap(),
diff::Result::Right(s) => writeln!(dumped_string, "+ {}", s).unwrap(),
diff::Result::Both(s, _) => writeln!(dumped_string, " {}", s).unwrap(),
}
}
dumped_string
}
fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) {
let t = |file| fs::metadata(file).unwrap().modified().unwrap();
let source_file = &self.testpaths.file;
let output_time = t(output_file);
let source_time = t(source_file);
if source_time > output_time {
debug!("source file time: {:?} output file time: {:?}", source_time, output_time);
panic!(
"test source file `{}` is newer than potentially stale output file `{}`.",
source_file.display(),
test_name
);
}
}
}

View file

@ -0,0 +1,104 @@
use std::fs;
use super::{ProcRes, ReadFrom, TestCx};
use crate::util::logv;
impl TestCx<'_> {
pub(super) fn run_pretty_test(&self) {
if self.props.pp_exact.is_some() {
logv(self.config, "testing for exact pretty-printing".to_owned());
} else {
logv(self.config, "testing for converging pretty-printing".to_owned());
}
let rounds = match self.props.pp_exact {
Some(_) => 1,
None => 2,
};
let src = fs::read_to_string(&self.testpaths.file).unwrap();
let mut srcs = vec![src];
let mut round = 0;
while round < rounds {
logv(
self.config,
format!("pretty-printing round {} revision {:?}", round, self.revision),
);
let read_from =
if round == 0 { ReadFrom::Path } else { ReadFrom::Stdin(srcs[round].to_owned()) };
let proc_res = self.print_source(read_from, &self.props.pretty_mode);
if !proc_res.status.success() {
self.fatal_proc_rec(
&format!(
"pretty-printing failed in round {} revision {:?}",
round, self.revision
),
&proc_res,
);
}
let ProcRes { stdout, .. } = proc_res;
srcs.push(stdout);
round += 1;
}
let mut expected = match self.props.pp_exact {
Some(ref file) => {
let filepath = self.testpaths.file.parent().unwrap().join(file);
fs::read_to_string(&filepath).unwrap()
}
None => srcs[srcs.len() - 2].clone(),
};
let mut actual = srcs[srcs.len() - 1].clone();
if self.props.pp_exact.is_some() {
// Now we have to care about line endings
let cr = "\r".to_owned();
actual = actual.replace(&cr, "");
expected = expected.replace(&cr, "");
}
if !self.config.bless {
self.compare_source(&expected, &actual);
} else if expected != actual {
let filepath_buf;
let filepath = match &self.props.pp_exact {
Some(file) => {
filepath_buf = self.testpaths.file.parent().unwrap().join(file);
&filepath_buf
}
None => &self.testpaths.file,
};
fs::write(filepath, &actual).unwrap();
}
// If we're only making sure that the output matches then just stop here
if self.props.pretty_compare_only {
return;
}
// Finally, let's make sure it actually appears to remain valid code
let proc_res = self.typecheck_source(actual);
if !proc_res.status.success() {
self.fatal_proc_rec("pretty-printed source does not typecheck", &proc_res);
}
if !self.props.pretty_expanded {
return;
}
// additionally, run `-Zunpretty=expanded` and try to build it.
let proc_res = self.print_source(ReadFrom::Path, "expanded");
if !proc_res.status.success() {
self.fatal_proc_rec("pretty-printing (expanded) failed", &proc_res);
}
let ProcRes { stdout: expanded_src, .. } = proc_res;
let proc_res = self.typecheck_source(expanded_src);
if !proc_res.status.success() {
self.fatal_proc_rec("pretty-printed source (expanded) does not typecheck", &proc_res);
}
}
}

Some files were not shown because too many files have changed in this diff Show more