Auto merge of #82795 - m-ou-se:rollup-uzx0b92, r=m-ou-se
Rollup of 10 pull requests Successful merges: - #80723 (Implement NOOP_METHOD_CALL lint) - #80763 (resolve: Reduce scope of `pub_use_of_private_extern_crate` deprecation lint) - #81136 (Improved IO Bytes Size Hint) - #81939 (Add suggestion `.collect()` for iterators in iterators) - #82289 (Fix underflow in specialized ZipImpl::size_hint) - #82728 (Avoid unnecessary Vec construction in BufReader) - #82764 (Add {BTreeMap,HashMap}::try_insert) - #82770 (Add assert_matches macro.) - #82773 (Add diagnostic item to `Default` trait) - #82787 (Remove unused code from main.js) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8fd946c63a
46 changed files with 781 additions and 122 deletions
|
@ -24,7 +24,7 @@ pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec<String> {
|
|||
|
||||
debug!("preparing the RPATH!");
|
||||
|
||||
let libs = config.used_crates.clone();
|
||||
let libs = config.used_crates;
|
||||
let libs = libs.iter().filter_map(|&(_, ref l)| l.option()).collect::<Vec<_>>();
|
||||
let rpaths = get_rpaths(config, &libs);
|
||||
let mut flags = rpaths_to_flags(&rpaths);
|
||||
|
|
|
@ -57,6 +57,7 @@ mod methods;
|
|||
mod non_ascii_idents;
|
||||
mod non_fmt_panic;
|
||||
mod nonstandard_style;
|
||||
mod noop_method_call;
|
||||
mod passes;
|
||||
mod redundant_semicolon;
|
||||
mod traits;
|
||||
|
@ -81,6 +82,7 @@ use methods::*;
|
|||
use non_ascii_idents::*;
|
||||
use non_fmt_panic::NonPanicFmt;
|
||||
use nonstandard_style::*;
|
||||
use noop_method_call::*;
|
||||
use redundant_semicolon::*;
|
||||
use traits::*;
|
||||
use types::*;
|
||||
|
@ -168,6 +170,7 @@ macro_rules! late_lint_passes {
|
|||
DropTraitConstraints: DropTraitConstraints,
|
||||
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
|
||||
NonPanicFmt: NonPanicFmt,
|
||||
NoopMethodCall: NoopMethodCall,
|
||||
]
|
||||
);
|
||||
};
|
||||
|
|
111
compiler/rustc_lint/src/noop_method_call.rs
Normal file
111
compiler/rustc_lint/src/noop_method_call.rs
Normal file
|
@ -0,0 +1,111 @@
|
|||
use crate::context::LintContext;
|
||||
use crate::rustc_middle::ty::TypeFoldable;
|
||||
use crate::LateContext;
|
||||
use crate::LateLintPass;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
declare_lint! {
|
||||
/// The `noop_method_call` lint detects specific calls to noop methods
|
||||
/// such as a calling `<&T as Clone>::clone` where `T: !Clone`.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(unused)]
|
||||
/// #![warn(noop_method_call)]
|
||||
/// struct Foo;
|
||||
/// let foo = &Foo;
|
||||
/// let clone: &Foo = foo.clone();
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Some method calls are noops meaning that they do nothing. Usually such methods
|
||||
/// are the result of blanket implementations that happen to create some method invocations
|
||||
/// that end up not doing anything. For instance, `Clone` is implemented on all `&T`, but
|
||||
/// calling `clone` on a `&T` where `T` does not implement clone, actually doesn't do anything
|
||||
/// as references are copy. This lint detects these calls and warns the user about them.
|
||||
pub NOOP_METHOD_CALL,
|
||||
Allow,
|
||||
"detects the use of well-known noop methods"
|
||||
}
|
||||
|
||||
declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
// We only care about method calls.
|
||||
let (call, elements) = match expr.kind {
|
||||
ExprKind::MethodCall(call, _, elements, _) => (call, elements),
|
||||
_ => return,
|
||||
};
|
||||
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
|
||||
// traits and ignore any other method call.
|
||||
let (trait_id, did) = match cx.typeck_results().type_dependent_def(expr.hir_id) {
|
||||
// Verify we are dealing with a method/associated function.
|
||||
Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) {
|
||||
// Check that we're dealing with a trait method for one of the traits we care about.
|
||||
Some(trait_id)
|
||||
if [sym::Clone, sym::Deref, sym::Borrow]
|
||||
.iter()
|
||||
.any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) =>
|
||||
{
|
||||
(trait_id, did)
|
||||
}
|
||||
_ => return,
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
let substs = cx.typeck_results().node_substs(expr.hir_id);
|
||||
if substs.needs_subst() {
|
||||
// We can't resolve on types that require monomorphization, so we don't handle them if
|
||||
// we need to perfom substitution.
|
||||
return;
|
||||
}
|
||||
let param_env = cx.tcx.param_env(trait_id);
|
||||
// Resolve the trait method instance.
|
||||
let i = match ty::Instance::resolve(cx.tcx, param_env, did, substs) {
|
||||
Ok(Some(i)) => i,
|
||||
_ => return,
|
||||
};
|
||||
// (Re)check that it implements the noop diagnostic.
|
||||
for s in [sym::noop_method_clone, sym::noop_method_deref, sym::noop_method_borrow].iter() {
|
||||
if cx.tcx.is_diagnostic_item(*s, i.def_id()) {
|
||||
let method = &call.ident.name;
|
||||
let receiver = &elements[0];
|
||||
let receiver_ty = cx.typeck_results().expr_ty(receiver);
|
||||
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
|
||||
if receiver_ty != expr_ty {
|
||||
// This lint will only trigger if the receiver type and resulting expression \
|
||||
// type are the same, implying that the method call is unnecessary.
|
||||
return;
|
||||
}
|
||||
let expr_span = expr.span;
|
||||
let note = format!(
|
||||
"the type `{:?}` which `{}` is being called on is the same as \
|
||||
the type returned from `{}`, so the method call does not do \
|
||||
anything and can be removed",
|
||||
receiver_ty, method, method,
|
||||
);
|
||||
|
||||
let span = expr_span.with_lo(receiver.span.hi());
|
||||
cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
|
||||
let method = &call.ident.name;
|
||||
let message = format!(
|
||||
"call to `.{}()` on a reference in this situation does nothing",
|
||||
&method,
|
||||
);
|
||||
lint.build(&message)
|
||||
.span_label(span, "unnecessary method call")
|
||||
.note(¬e)
|
||||
.emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,6 @@ use rustc_target::spec::abi;
|
|||
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
|
||||
pub struct ExpectedFound<T> {
|
||||
|
@ -548,7 +547,6 @@ impl<T> Trait<T> for X {
|
|||
TargetFeatureCast(def_id) => {
|
||||
let attrs = self.get_attrs(*def_id);
|
||||
let target_spans = attrs
|
||||
.deref()
|
||||
.iter()
|
||||
.filter(|attr| attr.has_name(sym::target_feature))
|
||||
.map(|attr| attr.span);
|
||||
|
|
|
@ -10,16 +10,18 @@ use rustc_middle::mir::{
|
|||
FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
|
||||
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
|
||||
};
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Instance, Ty};
|
||||
use rustc_span::{source_map::DesugaringKind, symbol::sym, Span};
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable};
|
||||
use rustc_span::source_map::DesugaringKind;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::dataflow::drop_flag_effects;
|
||||
use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex};
|
||||
use crate::util::borrowck_errors;
|
||||
|
||||
use crate::borrow_check::{
|
||||
borrow_set::BorrowData, prefixes::IsPrefixOf, InitializationRequiringAction, MirBorrowckCtxt,
|
||||
PrefixSet, WriteKind,
|
||||
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
|
||||
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
@ -1267,6 +1269,29 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
|
||||
if return_span != borrow_span {
|
||||
err.span_label(borrow_span, note);
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let ty_params = ty::List::empty();
|
||||
|
||||
let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
|
||||
let return_ty = tcx.erase_regions(return_ty);
|
||||
|
||||
// to avoid panics
|
||||
if !return_ty.has_infer_types() {
|
||||
if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) {
|
||||
if tcx.type_implements_trait((iter_trait, return_ty, ty_params, self.param_env))
|
||||
{
|
||||
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
|
||||
err.span_suggestion_hidden(
|
||||
return_span,
|
||||
"use `.collect()` to allocate the iterator",
|
||||
format!("{}{}", snippet, ".collect::<Vec<_>>()"),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(err)
|
||||
|
|
|
@ -165,7 +165,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
|||
self.consume_operand(location, value);
|
||||
|
||||
// Invalidate all borrows of local places
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
let borrow_set = self.borrow_set;
|
||||
let resume = self.location_table.start_index(resume.start_location());
|
||||
for (i, data) in borrow_set.iter_enumerated() {
|
||||
if borrow_of_local_data(data.borrowed_place) {
|
||||
|
@ -177,7 +177,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
|||
}
|
||||
TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
|
||||
// Invalidate all borrows of local places
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
let borrow_set = self.borrow_set;
|
||||
let start = self.location_table.start_index(location);
|
||||
for (i, data) in borrow_set.iter_enumerated() {
|
||||
if borrow_of_local_data(data.borrowed_place) {
|
||||
|
@ -369,7 +369,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
|||
);
|
||||
let tcx = self.tcx;
|
||||
let body = self.body;
|
||||
let borrow_set = self.borrow_set.clone();
|
||||
let borrow_set = self.borrow_set;
|
||||
let indices = self.borrow_set.indices();
|
||||
each_borrow_involving_path(
|
||||
self,
|
||||
|
@ -377,7 +377,7 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
|||
body,
|
||||
location,
|
||||
(sd, place),
|
||||
&borrow_set.clone(),
|
||||
borrow_set,
|
||||
indices,
|
||||
|this, borrow_index, borrow| {
|
||||
match (rw, borrow.kind) {
|
||||
|
|
|
@ -51,7 +51,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
PatKind::Constant { value } => Test {
|
||||
span: match_pair.pattern.span,
|
||||
kind: TestKind::Eq { value, ty: match_pair.pattern.ty.clone() },
|
||||
kind: TestKind::Eq { value, ty: match_pair.pattern.ty },
|
||||
},
|
||||
|
||||
PatKind::Range(range) => {
|
||||
|
|
|
@ -156,6 +156,21 @@ impl<'a> NameResolution<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;`
|
||||
// are permitted for backward-compatibility under a deprecation lint.
|
||||
fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBinding<'_>) -> bool {
|
||||
match (&import.kind, &binding.kind) {
|
||||
(
|
||||
ImportKind::Single { .. },
|
||||
NameBindingKind::Import {
|
||||
import: Import { kind: ImportKind::ExternCrate { .. }, .. },
|
||||
..
|
||||
},
|
||||
) => import.vis.get() == ty::Visibility::Public,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Resolver<'a> {
|
||||
crate fn resolve_ident_in_module_unadjusted(
|
||||
&mut self,
|
||||
|
@ -263,10 +278,7 @@ impl<'a> Resolver<'a> {
|
|||
return Err((Determined, Weak::No));
|
||||
}
|
||||
}
|
||||
// `extern crate` are always usable for backwards compatibility, see issue #37020,
|
||||
// remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`.
|
||||
let usable = this.is_accessible_from(binding.vis, parent_scope.module)
|
||||
|| binding.is_extern_crate();
|
||||
let usable = this.is_accessible_from(binding.vis, parent_scope.module);
|
||||
if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
|
||||
};
|
||||
|
||||
|
@ -309,10 +321,7 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if !(self.is_accessible_from(binding.vis, parent_scope.module) ||
|
||||
// Remove this together with `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
|
||||
(self.last_import_segment && binding.is_extern_crate()))
|
||||
{
|
||||
if !self.is_accessible_from(binding.vis, parent_scope.module) {
|
||||
self.privacy_errors.push(PrivacyError {
|
||||
ident,
|
||||
binding,
|
||||
|
@ -455,9 +464,8 @@ impl<'a> Resolver<'a> {
|
|||
binding: &'a NameBinding<'a>,
|
||||
import: &'a Import<'a>,
|
||||
) -> &'a NameBinding<'a> {
|
||||
let vis = if binding.vis.is_at_least(import.vis.get(), self) ||
|
||||
// cf. `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
|
||||
!import.is_glob() && binding.is_extern_crate()
|
||||
let vis = if binding.vis.is_at_least(import.vis.get(), self)
|
||||
|| pub_use_of_private_extern_crate_hack(import, binding)
|
||||
{
|
||||
import.vis.get()
|
||||
} else {
|
||||
|
@ -1188,7 +1196,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
|
|||
// All namespaces must be re-exported with extra visibility for an error to occur.
|
||||
if !any_successful_reexport {
|
||||
let (ns, binding) = reexport_error.unwrap();
|
||||
if ns == TypeNS && binding.is_extern_crate() {
|
||||
if pub_use_of_private_extern_crate_hack(import, binding) {
|
||||
let msg = format!(
|
||||
"extern crate `{}` is private, and cannot be \
|
||||
re-exported (error E0365), consider declaring with \
|
||||
|
|
|
@ -18,7 +18,7 @@ use crate::{Edition, Span, DUMMY_SP, SESSION_GLOBALS};
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
// The proc macro code for this is in `src/librustc_macros/src/symbols.rs`.
|
||||
// The proc macro code for this is in `compiler/rustc_macros/src/symbols.rs`.
|
||||
symbols! {
|
||||
// After modifying this list adjust `is_special`, `is_used_keyword`/`is_unused_keyword`,
|
||||
// this should be rarely necessary though if the keywords are kept in alphabetic order.
|
||||
|
@ -129,6 +129,7 @@ symbols! {
|
|||
BTreeMap,
|
||||
BTreeSet,
|
||||
BinaryHeap,
|
||||
Borrow,
|
||||
C,
|
||||
CString,
|
||||
Center,
|
||||
|
@ -141,6 +142,7 @@ symbols! {
|
|||
Decodable,
|
||||
Decoder,
|
||||
Default,
|
||||
Deref,
|
||||
Encodable,
|
||||
Encoder,
|
||||
Eq,
|
||||
|
@ -789,6 +791,9 @@ symbols! {
|
|||
none_error,
|
||||
nontemporal_store,
|
||||
nontrapping_dash_fptoint: "nontrapping-fptoint",
|
||||
noop_method_borrow,
|
||||
noop_method_clone,
|
||||
noop_method_deref,
|
||||
noreturn,
|
||||
nostack,
|
||||
not,
|
||||
|
|
|
@ -819,7 +819,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
sig.decl
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|arg| match arg.clone().kind {
|
||||
.map(|arg| match arg.kind {
|
||||
hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
|
||||
Some(arg.span),
|
||||
vec![("_".to_owned(), "_".to_owned()); tys.len()],
|
||||
|
|
|
@ -165,7 +165,7 @@ crate fn evaluate_goal<'tcx>(
|
|||
// let's just ignore that
|
||||
let sol = Canonical {
|
||||
max_universe: ty::UniverseIndex::from_usize(0),
|
||||
variables: obligation.variables.clone(),
|
||||
variables: obligation.variables,
|
||||
value: QueryResponse {
|
||||
var_values: CanonicalVarValues { var_values: IndexVec::new() }
|
||||
.make_identity(tcx),
|
||||
|
|
|
@ -465,7 +465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let expected_arg_tys = self.expected_inputs_for_expected_output(
|
||||
call_expr.span,
|
||||
expected,
|
||||
fn_sig.output().clone(),
|
||||
fn_sig.output(),
|
||||
fn_sig.inputs(),
|
||||
);
|
||||
|
||||
|
|
|
@ -711,7 +711,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
});
|
||||
|
||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
||||
let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty.clone());
|
||||
let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty);
|
||||
ret_coercion.borrow_mut().coerce(
|
||||
self,
|
||||
&self.cause(return_expr.span, ObligationCauseCode::ReturnValue(return_expr.hir_id)),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue