Auto merge of #18183 - lnicola:sync-from-rust, r=lnicola
internal: Sync from downstream
This commit is contained in:
commit
34aff74fb0
4923 changed files with 72750 additions and 49766 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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"];
|
||||
|
|
|
|||
|
|
@ -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!()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
@ -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`
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
| ^^^^^
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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]`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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")),
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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
19
src/tools/compiletest/src/runtest/assembly.rs
Normal file
19
src/tools/compiletest/src/runtest/assembly.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/tools/compiletest/src/runtest/codegen.rs
Normal file
22
src/tools/compiletest/src/runtest/codegen.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
191
src/tools/compiletest/src/runtest/codegen_units.rs
Normal file
191
src/tools/compiletest/src/runtest/codegen_units.rs
Normal 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("--")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
26
src/tools/compiletest/src/runtest/crash.rs
Normal file
26
src/tools/compiletest/src/runtest/crash.rs
Normal 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`."
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
509
src/tools/compiletest/src/runtest/debuginfo.rs
Normal file
509
src/tools/compiletest/src/runtest/debuginfo.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
128
src/tools/compiletest/src/runtest/incremental.rs
Normal file
128
src/tools/compiletest/src/runtest/incremental.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
32
src/tools/compiletest/src/runtest/js_doc.rs
Normal file
32
src/tools/compiletest/src/runtest/js_doc.rs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
155
src/tools/compiletest/src/runtest/mir_opt.rs
Normal file
155
src/tools/compiletest/src/runtest/mir_opt.rs
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
104
src/tools/compiletest/src/runtest/pretty.rs
Normal file
104
src/tools/compiletest/src/runtest/pretty.rs
Normal 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
Loading…
Add table
Add a link
Reference in a new issue