Skip to content

Commit

Permalink
Auto merge of rust-lang#82795 - m-ou-se:rollup-uzx0b92, r=m-ou-se
Browse files Browse the repository at this point in the history
Rollup of 10 pull requests

Successful merges:

 - rust-lang#80723 (Implement NOOP_METHOD_CALL lint)
 - rust-lang#80763 (resolve: Reduce scope of `pub_use_of_private_extern_crate` deprecation lint)
 - rust-lang#81136 (Improved IO Bytes Size Hint)
 - rust-lang#81939 (Add suggestion `.collect()` for iterators in iterators)
 - rust-lang#82289 (Fix underflow in specialized ZipImpl::size_hint)
 - rust-lang#82728 (Avoid unnecessary Vec construction in BufReader)
 - rust-lang#82764 (Add {BTreeMap,HashMap}::try_insert)
 - rust-lang#82770 (Add assert_matches macro.)
 - rust-lang#82773 (Add diagnostic item to `Default` trait)
 - rust-lang#82787 (Remove unused code from main.js)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Mar 5, 2021
2 parents 8ccc89b + 16518e7 commit 8fd946c
Show file tree
Hide file tree
Showing 46 changed files with 776 additions and 117 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/back/rpath.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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::*;
Expand Down Expand Up @@ -168,6 +170,7 @@ macro_rules! late_lint_passes {
DropTraitConstraints: DropTraitConstraints,
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
NonPanicFmt: NonPanicFmt,
NoopMethodCall: NoopMethodCall,
]
);
};
Expand Down
111 changes: 111 additions & 0 deletions compiler/rustc_lint/src/noop_method_call.rs
Original file line number Diff line number Diff line change
@@ -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()
});
}
}
}
}
2 changes: 0 additions & 2 deletions compiler/rustc_middle/src/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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);
Expand Down
33 changes: 29 additions & 4 deletions compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_mir/src/borrow_check/invalidation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -369,15 +369,15 @@ 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,
tcx,
body,
location,
(sd, place),
&borrow_set.clone(),
borrow_set,
indices,
|this, borrow_index, borrow| {
match (rw, borrow.kind) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/build/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
32 changes: 20 additions & 12 deletions compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)) }
};

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 \
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -129,6 +129,7 @@ symbols! {
BTreeMap,
BTreeSet,
BinaryHeap,
Borrow,
C,
CString,
Center,
Expand All @@ -141,6 +142,7 @@ symbols! {
Decodable,
Decoder,
Default,
Deref,
Encodable,
Encoder,
Eq,
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()],
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_traits/src/chalk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
);

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down
Loading

0 comments on commit 8fd946c

Please sign in to comment.