1
Fork 0

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:
bors 2021-03-05 13:34:33 +00:00
commit 8fd946c63a
46 changed files with 781 additions and 122 deletions

View file

@ -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);

View file

@ -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,
]
);
};

View 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(&note)
.emit()
});
}
}
}
}

View file

@ -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);

View file

@ -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)

View file

@ -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) {

View file

@ -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) => {

View file

@ -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 \

View file

@ -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,

View file

@ -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()],

View file

@ -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),

View file

@ -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(),
);

View file

@ -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)),