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

View File

@ -14,7 +14,7 @@ use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root};
use super::search::SearchResult::*;
mod entry;
pub use entry::{Entry, OccupiedEntry, VacantEntry};
pub use entry::{Entry, OccupiedEntry, OccupiedError, VacantEntry};
use Entry::*;
/// Minimum number of elements in nodes that are not a root.
@ -836,6 +836,40 @@ impl<K, V> BTreeMap<K, V> {
}
}
/// Tries to insert a key-value pair into the map, and returns
/// a mutable reference to the value in the entry.
///
/// If the map already had this key present, nothing is updated, and
/// an error containing the occupied entry and the value is returned.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(map_try_insert)]
///
/// use std::collections::BTreeMap;
///
/// let mut map = BTreeMap::new();
/// assert_eq!(map.try_insert(37, "a").unwrap(), &"a");
///
/// let err = map.try_insert(37, "b").unwrap_err();
/// assert_eq!(err.entry.key(), &37);
/// assert_eq!(err.entry.get(), &"a");
/// assert_eq!(err.value, "b");
/// ```
#[unstable(feature = "map_try_insert", issue = "82766")]
pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V>>
where
K: Ord,
{
match self.entry(key) {
Occupied(entry) => Err(OccupiedError { entry, value }),
Vacant(entry) => Ok(entry.insert(value)),
}
}
/// Removes a key from the map, returning the value at the key if the key
/// was previously in the map.
///

View File

@ -71,6 +71,41 @@ impl<K: Debug + Ord, V: Debug> Debug for OccupiedEntry<'_, K, V> {
}
}
/// The error returned by [`try_insert`](BTreeMap::try_insert) when the key already exists.
///
/// Contains the occupied entry, and the value that was not inserted.
#[unstable(feature = "map_try_insert", issue = "82766")]
pub struct OccupiedError<'a, K: 'a, V: 'a> {
/// The entry in the map that was already occupied.
pub entry: OccupiedEntry<'a, K, V>,
/// The value which was not inserted, because the entry was already occupied.
pub value: V,
}
#[unstable(feature = "map_try_insert", issue = "82766")]
impl<K: Debug + Ord, V: Debug> Debug for OccupiedError<'_, K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OccupiedError")
.field("key", self.entry.key())
.field("old_value", self.entry.get())
.field("new_value", &self.value)
.finish()
}
}
#[unstable(feature = "map_try_insert", issue = "82766")]
impl<'a, K: Debug + Ord, V: Debug> fmt::Display for OccupiedError<'a, K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"failed to insert {:?}, key {:?} already exists with value {:?}",
self.value,
self.entry.key(),
self.entry.get(),
)
}
}
impl<'a, K: Ord, V> Entry<'a, K, V> {
/// Ensures a value is in the entry by inserting the default if empty, and returns
/// a mutable reference to the value in the entry.

View File

@ -1801,11 +1801,11 @@ fn test_occupied_entry_key() {
let key = "hello there";
let value = "value goes here";
assert!(a.is_empty());
a.insert(key.clone(), value.clone());
a.insert(key, value);
assert_eq!(a.len(), 1);
assert_eq!(a[key], value);
match a.entry(key.clone()) {
match a.entry(key) {
Vacant(_) => panic!(),
Occupied(e) => assert_eq!(key, *e.key()),
}
@ -1821,11 +1821,11 @@ fn test_vacant_entry_key() {
let value = "value goes here";
assert!(a.is_empty());
match a.entry(key.clone()) {
match a.entry(key) {
Occupied(_) => panic!(),
Vacant(e) => {
assert_eq!(key, *e.key());
e.insert(value.clone());
e.insert(value);
}
}
assert_eq!(a.len(), 1);

View File

@ -153,6 +153,7 @@
/// [`HashMap<K, V>`]: ../../std/collections/struct.HashMap.html
/// [`String`]: ../../std/string/struct.String.html
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Borrow"]
pub trait Borrow<Borrowed: ?Sized> {
/// Immutably borrows from an owned value.
///
@ -205,6 +206,7 @@ pub trait BorrowMut<Borrowed: ?Sized>: Borrow<Borrowed> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Borrow<T> for T {
#[rustc_diagnostic_item = "noop_method_borrow"]
fn borrow(&self) -> &T {
self
}

View File

@ -104,12 +104,14 @@
/// [impls]: #implementors
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "clone"]
#[rustc_diagnostic_item = "Clone"]
pub trait Clone: Sized {
/// Returns a copy of the value.
///
/// # Examples
///
/// ```
/// # #![allow(noop_method_call)]
/// let hello = "Hello"; // &str implements Clone
///
/// assert_eq!("Hello", hello.clone());
@ -221,6 +223,7 @@ mod impls {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Clone for &T {
#[inline]
#[rustc_diagnostic_item = "noop_method_clone"]
fn clone(&self) -> Self {
*self
}

View File

@ -80,6 +80,7 @@
/// bar: f32,
/// }
/// ```
#[cfg_attr(not(test), rustc_diagnostic_item = "Default")]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Default: Sized {
/// Returns the "default value" for a type.

View File

@ -200,6 +200,7 @@ where
} else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a.size() {
let i = self.index;
self.index += 1;
self.len += 1;
// match the base implementation's potential side effects
// SAFETY: we just checked that `i` < `self.a.len()`
unsafe {
@ -258,7 +259,7 @@ where
if sz_a != sz_b {
let sz_a = self.a.size();
if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len {
for _ in 0..sz_a - cmp::max(self.len, self.index) {
for _ in 0..sz_a - self.len {
self.a.next_back();
}
}

View File

@ -93,6 +93,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
message = "`{Self}` is not an iterator"
)]
#[doc(spotlight)]
#[rustc_diagnostic_item = "Iterator"]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub trait Iterator {
/// The type of the elements being iterated over.

View File

@ -110,6 +110,60 @@ macro_rules! assert_ne {
});
}
/// Asserts that an expression matches any of the given patterns.
///
/// Like in a `match` expression, the pattern can be optionally followed by `if`
/// and a guard expression that has access to names bound by the pattern.
///
/// On panic, this macro will print the value of the expression with its
/// debug representation.
///
/// Like [`assert!`], this macro has a second form, where a custom
/// panic message can be provided.
///
/// # Examples
///
/// ```
/// #![feature(assert_matches)]
///
/// let a = 1u32.checked_add(2);
/// let b = 1u32.checked_sub(2);
/// assert_matches!(a, Some(_));
/// assert_matches!(b, None);
///
/// let c = Ok("abc".to_string());
/// assert_matches!(c, Ok(x) | Err(x) if x.len() < 100);
/// ```
#[macro_export]
#[unstable(feature = "assert_matches", issue = "82775")]
#[allow_internal_unstable(core_panic)]
macro_rules! assert_matches {
($left:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => ({
match $left {
$( $pattern )|+ $( if $guard )? => {}
ref left_val => {
$crate::panicking::assert_matches_failed(
left_val,
$crate::stringify!($($pattern)|+ $(if $guard)?),
$crate::option::Option::None
);
}
}
});
($left:expr, $( $pattern:pat )|+ $( if $guard: expr )?, $($arg:tt)+) => ({
match $left {
$( $pattern )|+ $( if $guard )? => {}
ref left_val => {
$crate::panicking::assert_matches_failed(
left_val,
$crate::stringify!($($pattern)|+ $(if $guard)?),
$crate::option::Option::Some($crate::format_args!($($arg)+))
);
}
}
});
}
/// Asserts that a boolean expression is `true` at runtime.
///
/// This will invoke the [`panic!`] macro if the provided expression cannot be
@ -208,6 +262,42 @@ macro_rules! debug_assert_ne {
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); })
}
/// Asserts that an expression matches any of the given patterns.
///
/// Like in a `match` expression, the pattern can be optionally followed by `if`
/// and a guard expression that has access to names bound by the pattern.
///
/// On panic, this macro will print the value of the expression with its
/// debug representation.
///
/// Unlike [`assert_matches!`], `debug_assert_matches!` statements are only
/// enabled in non optimized builds by default. An optimized build will not
/// execute `debug_assert_matches!` statements unless `-C debug-assertions` is
/// passed to the compiler. This makes `debug_assert_matches!` useful for
/// checks that are too expensive to be present in a release build but may be
/// helpful during development. The result of expanding `debug_assert_matches!`
/// is always type checked.
///
/// # Examples
///
/// ```
/// #![feature(assert_matches)]
///
/// let a = 1u32.checked_add(2);
/// let b = 1u32.checked_sub(2);
/// debug_assert_matches!(a, Some(_));
/// debug_assert_matches!(b, None);
///
/// let c = Ok("abc".to_string());
/// debug_assert_matches!(c, Ok(x) | Err(x) if x.len() < 100);
/// ```
#[macro_export]
#[unstable(feature = "assert_matches", issue = "82775")]
#[allow_internal_unstable(assert_matches)]
macro_rules! debug_assert_matches {
($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_matches!($($arg)*); })
}
/// Returns whether the given expression matches any of the given patterns.
///
/// Like in a `match` expression, the pattern can be optionally followed by `if`

View File

@ -60,6 +60,7 @@
#[doc(alias = "*")]
#[doc(alias = "&*")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Deref"]
pub trait Deref {
/// The resulting type after dereferencing.
#[stable(feature = "rust1", since = "1.0.0")]
@ -78,6 +79,7 @@ pub trait Deref {
impl<T: ?Sized> Deref for &T {
type Target = T;
#[rustc_diagnostic_item = "noop_method_deref"]
fn deref(&self) -> &T {
*self
}

View File

@ -97,6 +97,7 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
pub enum AssertKind {
Eq,
Ne,
Match,
}
/// Internal function for `assert_eq!` and `assert_ne!` macros
@ -113,32 +114,54 @@ where
T: fmt::Debug + ?Sized,
U: fmt::Debug + ?Sized,
{
#[track_caller]
fn inner(
kind: AssertKind,
left: &dyn fmt::Debug,
right: &dyn fmt::Debug,
args: Option<fmt::Arguments<'_>>,
) -> ! {
let op = match kind {
AssertKind::Eq => "==",
AssertKind::Ne => "!=",
};
assert_failed_inner(kind, &left, &right, args)
}
match args {
Some(args) => panic!(
r#"assertion failed: `(left {} right)`
left: `{:?}`,
right: `{:?}: {}`"#,
op, left, right, args
),
None => panic!(
r#"assertion failed: `(left {} right)`
left: `{:?}`,
right: `{:?}`"#,
op, left, right,
),
/// Internal function for `assert_match!`
#[cold]
#[track_caller]
#[doc(hidden)]
pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
left: &T,
right: &str,
args: Option<fmt::Arguments<'_>>,
) -> ! {
// Use the Display implementation to display the pattern.
struct Pattern<'a>(&'a str);
impl fmt::Debug for Pattern<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.0, f)
}
}
inner(kind, &left, &right, args)
assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
}
/// Non-generic version of the above functions, to avoid code bloat.
#[track_caller]
fn assert_failed_inner(
kind: AssertKind,
left: &dyn fmt::Debug,
right: &dyn fmt::Debug,
args: Option<fmt::Arguments<'_>>,
) -> ! {
let op = match kind {
AssertKind::Eq => "==",
AssertKind::Ne => "!=",
AssertKind::Match => "matches",
};
match args {
Some(args) => panic!(
r#"assertion failed: `(left {} right)`
left: `{:?}`,
right: `{:?}: {}`"#,
op, left, right, args
),
None => panic!(
r#"assertion failed: `(left {} right)`
left: `{:?}`,
right: `{:?}`"#,
op, left, right,
),
}
}

View File

@ -9,7 +9,7 @@ fn test_intersperse() {
assert_eq!(v, vec![1]);
let xs = ["a", "", "b", "c"];
let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect();
let v: Vec<&str> = xs.iter().map(|x| *x).intersperse(", ").collect();
let text: String = v.concat();
assert_eq!(text, "a, , b, c".to_string());
@ -24,7 +24,7 @@ fn test_intersperse_size_hint() {
assert_eq!(iter.size_hint(), (0, Some(0)));
let xs = ["a", "", "b", "c"];
let mut iter = xs.iter().map(|x| x.clone()).intersperse(", ");
let mut iter = xs.iter().map(|x| *x).intersperse(", ");
assert_eq!(iter.size_hint(), (7, Some(7)));
assert_eq!(iter.next(), Some("a"));

View File

@ -245,3 +245,23 @@ fn test_double_ended_zip() {
assert_eq!(it.next_back(), Some((3, 3)));
assert_eq!(it.next(), None);
}
#[test]
fn test_issue_82282() {
fn overflowed_zip(arr: &[i32]) -> impl Iterator<Item = (i32, &())> {
static UNIT_EMPTY_ARR: [(); 0] = [];
let mapped = arr.into_iter().map(|i| *i);
let mut zipped = mapped.zip(UNIT_EMPTY_ARR.iter());
zipped.next();
zipped
}
let arr = [1, 2, 3];
let zip = overflowed_zip(&arr).zip(overflowed_zip(&arr));
assert_eq!(zip.size_hint(), (0, Some(0)));
for _ in zip {
panic!();
}
}

View File

@ -1,3 +1,5 @@
// ignore-tidy-filelength
#[cfg(test)]
mod tests;
@ -842,6 +844,37 @@ where
self.base.insert(k, v)
}
/// Tries to insert a key-value pair into the map, and returns
/// a mutable reference to the value in the entry.
///
/// If the map already had this key present, nothing is updated, and
/// an error containing the occupied entry and the value is returned.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(map_try_insert)]
///
/// use std::collections::HashMap;
///
/// let mut map = HashMap::new();
/// assert_eq!(map.try_insert(37, "a").unwrap(), &"a");
///
/// let err = map.try_insert(37, "b").unwrap_err();
/// assert_eq!(err.entry.key(), &37);
/// assert_eq!(err.entry.get(), &"a");
/// assert_eq!(err.value, "b");
/// ```
#[unstable(feature = "map_try_insert", issue = "82766")]
pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V>> {
match self.entry(key) {
Occupied(entry) => Err(OccupiedError { entry, value }),
Vacant(entry) => Ok(entry.insert(value)),
}
}
/// Removes a key from the map, returning the value at the key if the key
/// was previously in the map.
///
@ -1851,6 +1884,41 @@ impl<K: Debug, V> Debug for VacantEntry<'_, K, V> {
}
}
/// The error returned by [`try_insert`](HashMap::try_insert) when the key already exists.
///
/// Contains the occupied entry, and the value that was not inserted.
#[unstable(feature = "map_try_insert", issue = "82766")]
pub struct OccupiedError<'a, K: 'a, V: 'a> {
/// The entry in the map that was already occupied.
pub entry: OccupiedEntry<'a, K, V>,
/// The value which was not inserted, because the entry was already occupied.
pub value: V,
}
#[unstable(feature = "map_try_insert", issue = "82766")]
impl<K: Debug, V: Debug> Debug for OccupiedError<'_, K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OccupiedError")
.field("key", self.entry.key())
.field("old_value", self.entry.get())
.field("new_value", &self.value)
.finish()
}
}
#[unstable(feature = "map_try_insert", issue = "82766")]
impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"failed to insert {:?}, key {:?} already exists with value {:?}",
self.value,
self.entry.key(),
self.entry.get(),
)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> {
type Item = (&'a K, &'a V);

View File

@ -774,11 +774,11 @@ fn test_occupied_entry_key() {
let key = "hello there";
let value = "value goes here";
assert!(a.is_empty());
a.insert(key.clone(), value.clone());
a.insert(key, value);
assert_eq!(a.len(), 1);
assert_eq!(a[key], value);
match a.entry(key.clone()) {
match a.entry(key) {
Vacant(_) => panic!(),
Occupied(e) => assert_eq!(key, *e.key()),
}
@ -793,11 +793,11 @@ fn test_vacant_entry_key() {
let value = "value goes here";
assert!(a.is_empty());
match a.entry(key.clone()) {
match a.entry(key) {
Occupied(_) => panic!(),
Vacant(e) => {
assert_eq!(key, *e.key());
e.insert(value.clone());
e.insert(value);
}
}
assert_eq!(a.len(), 1);

View File

@ -470,6 +470,24 @@ impl Error for char::DecodeUtf16Error {
}
}
#[unstable(feature = "map_try_insert", issue = "82766")]
impl<'a, K: Debug + Ord, V: Debug> Error
for crate::collections::btree_map::OccupiedError<'a, K, V>
{
#[allow(deprecated)]
fn description(&self) -> &str {
"key already exists"
}
}
#[unstable(feature = "map_try_insert", issue = "82766")]
impl<'a, K: Debug, V: Debug> Error for crate::collections::hash_map::OccupiedError<'a, K, V> {
#[allow(deprecated)]
fn description(&self) -> &str {
"key already exists"
}
}
#[stable(feature = "box_error", since = "1.8.0")]
impl<T: Error> Error for Box<T> {
#[allow(deprecated, deprecated_in_future)]

View File

@ -1,6 +1,8 @@
use crate::cmp;
use crate::fmt;
use crate::io::{self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, DEFAULT_BUF_SIZE};
use crate::io::{
self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
};
/// The `BufReader<R>` struct adds buffering to any reader.
///
@ -90,10 +92,9 @@ impl<R: Read> BufReader<R> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
unsafe {
let mut buffer = Vec::with_capacity(capacity);
buffer.set_len(capacity);
inner.initializer().initialize(&mut buffer);
BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 }
let mut buf = Box::new_uninit_slice(capacity).assume_init();
inner.initializer().initialize(&mut buf);
BufReader { inner, buf, pos: 0, cap: 0 }
}
}
}
@ -435,3 +436,9 @@ impl<R: Seek> Seek for BufReader<R> {
})
}
}
impl<T> SizeHint for BufReader<T> {
fn lower_bound(&self) -> usize {
self.buffer().len()
}
}

View File

@ -2238,6 +2238,19 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
}
}
impl<T, U> SizeHint for Chain<T, U> {
fn lower_bound(&self) -> usize {
SizeHint::lower_bound(&self.first) + SizeHint::lower_bound(&self.second)
}
fn upper_bound(&self) -> Option<usize> {
match (SizeHint::upper_bound(&self.first), SizeHint::upper_bound(&self.second)) {
(Some(first), Some(second)) => Some(first + second),
_ => None,
}
}
}
/// Reader adaptor which limits the bytes read from an underlying reader.
///
/// This struct is generally created by calling [`take`] on a reader.
@ -2464,6 +2477,30 @@ impl<R: Read> Iterator for Bytes<R> {
};
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
SizeHint::size_hint(&self.inner)
}
}
trait SizeHint {
fn lower_bound(&self) -> usize;
fn upper_bound(&self) -> Option<usize>;
fn size_hint(&self) -> (usize, Option<usize>) {
(self.lower_bound(), self.upper_bound())
}
}
impl<T> SizeHint for T {
default fn lower_bound(&self) -> usize {
0
}
default fn upper_bound(&self) -> Option<usize> {
None
}
}
/// An iterator over the contents of an instance of `BufRead` split on a

View File

@ -1,7 +1,7 @@
use super::{repeat, Cursor, SeekFrom};
use crate::cmp::{self, min};
use crate::io::{self, IoSlice, IoSliceMut};
use crate::io::{BufRead, Read, Seek, Write};
use crate::io::{BufRead, BufReader, Read, Seek, Write};
use crate::ops::Deref;
#[test]
@ -198,6 +198,53 @@ fn chain_bufread() {
cmp_bufread(chain1, chain2, &testdata[..]);
}
#[test]
fn bufreader_size_hint() {
let testdata = b"ABCDEFGHIJKL";
let mut buf_reader = BufReader::new(&testdata[..]);
assert_eq!(buf_reader.buffer().len(), 0);
let buffer_length = testdata.len();
buf_reader.fill_buf().unwrap();
// Check that size hint matches buffer contents
let mut buffered_bytes = buf_reader.bytes();
let (lower_bound, _upper_bound) = buffered_bytes.size_hint();
assert_eq!(lower_bound, buffer_length);
// Check that size hint matches buffer contents after advancing
buffered_bytes.next().unwrap().unwrap();
let (lower_bound, _upper_bound) = buffered_bytes.size_hint();
assert_eq!(lower_bound, buffer_length - 1);
}
#[test]
fn empty_size_hint() {
let size_hint = io::empty().bytes().size_hint();
assert_eq!(size_hint, (0, Some(0)));
}
#[test]
fn chain_empty_size_hint() {
let chain = io::empty().chain(io::empty());
let size_hint = chain.bytes().size_hint();
assert_eq!(size_hint, (0, Some(0)));
}
#[test]
fn chain_size_hint() {
let testdata = b"ABCDEFGHIJKL";
let mut buf_reader_1 = BufReader::new(&testdata[..6]);
let mut buf_reader_2 = BufReader::new(&testdata[6..]);
buf_reader_1.fill_buf().unwrap();
buf_reader_2.fill_buf().unwrap();
let chain = buf_reader_1.chain(buf_reader_2);
let size_hint = chain.bytes().size_hint();
assert_eq!(size_hint, (testdata.len(), None));
}
#[test]
fn chain_zero_length_read_is_not_eof() {
let a = b"A";

View File

@ -4,7 +4,9 @@
mod tests;
use crate::fmt;
use crate::io::{self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
use crate::io::{
self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write,
};
/// A reader which is always at EOF.
///
@ -80,6 +82,12 @@ impl fmt::Debug for Empty {
}
}
impl SizeHint for Empty {
fn upper_bound(&self) -> Option<usize> {
Some(0)
}
}
/// A reader which yields one byte over and over and over and over and over and...
///
/// This struct is generally created by calling [`repeat()`]. Please

View File

@ -228,6 +228,7 @@
#![feature(arbitrary_self_types)]
#![feature(array_error_internals)]
#![feature(asm)]
#![feature(assert_matches)]
#![feature(associated_type_bounds)]
#![feature(atomic_mut_ptr)]
#![feature(box_syntax)]
@ -281,6 +282,7 @@
#![feature(linkage)]
#![feature(llvm_asm)]
#![feature(log_syntax)]
#![feature(map_try_insert)]
#![feature(maybe_uninit_extra)]
#![feature(maybe_uninit_ref)]
#![feature(maybe_uninit_slice)]
@ -289,6 +291,7 @@
#![feature(needs_panic_runtime)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(new_uninit)]
#![feature(nll)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(once_cell)]
@ -550,8 +553,8 @@ pub use std_detect::detect;
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated, deprecated_in_future)]
pub use core::{
assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, matches, r#try, todo,
unimplemented, unreachable, write, writeln,
assert_eq, assert_matches, assert_ne, debug_assert, debug_assert_eq, debug_assert_matches,
debug_assert_ne, matches, r#try, todo, unimplemented, unreachable, write, writeln,
};
// Re-export built-in macros defined through libcore.

View File

@ -843,7 +843,6 @@ function defocusSearchBar() {
function checkGenerics(obj, val) {
// The names match, but we need to be sure that all generics kinda
// match as well.
var lev_distance = MAX_LEV_DISTANCE + 1;
if (val.generics.length > 0) {
if (obj.length > GENERICS_DATA &&
obj[GENERICS_DATA].length >= val.generics.length) {
@ -866,7 +865,6 @@ function defocusSearchBar() {
}
if (lev.pos !== -1) {
elems.splice(lev.pos, 1);
lev_distance = Math.min(lev.lev, lev_distance);
total += lev.lev;
done += 1;
} else {
@ -2054,24 +2052,6 @@ function defocusSearchBar() {
}
}
/**
* Convert HTML to plaintext:
*
* * Replace "<code>foo</code>" with "`foo`"
* * Strip all other HTML tags
*
* Used by the dynamic sidebar crate list renderer.
*
* @param {[string]} html [The HTML to convert]
* @return {[string]} [The resulting plaintext]
*/
function convertHTMLToPlaintext(html) {
var x = document.createElement("div");
x.innerHTML = html.replace('<code>', '`').replace('</code>', '`');
return x.innerText;
}
// delayed sidebar rendering.
window.initSidebarItems = function(items) {
var sidebar = document.getElementsByClassName("sidebar-elems")[0];

View File

@ -3,7 +3,7 @@
#![crate_name = "foo"]
extern crate extern_links;
pub extern crate extern_links;
// @!has foo/index.html '//a' 'extern_links'
#[doc(no_inline)]

View File

@ -2,5 +2,5 @@
// aux-build:issue-28927-1.rs
// ignore-cross-compile
extern crate issue_28927_1 as inner1;
pub extern crate issue_28927_1 as inner1;
pub use inner1 as foo;

View File

@ -0,0 +1,8 @@
// run-rustfix
fn main() {
let _ = vec![vec![0, 1], vec![2]]
.into_iter()
.map(|y| y.iter().map(|x| x + 1).collect::<Vec<_>>())
//~^ ERROR cannot return value referencing function parameter `y`
.collect::<Vec<_>>();
}

View File

@ -0,0 +1,8 @@
// run-rustfix
fn main() {
let _ = vec![vec![0, 1], vec![2]]
.into_iter()
.map(|y| y.iter().map(|x| x + 1))
//~^ ERROR cannot return value referencing function parameter `y`
.collect::<Vec<_>>();
}

View File

@ -0,0 +1,14 @@
error[E0515]: cannot return value referencing function parameter `y`
--> $DIR/issue-81584.rs:5:22
|
LL | .map(|y| y.iter().map(|x| x + 1))
| -^^^^^^^^^^^^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `y` is borrowed here
|
= help: use `.collect()` to allocate the iterator
error: aborting due to previous error
For more information about this error, try `rustc --explain E0515`.

View File

@ -0,0 +1,54 @@
// check-pass
#![allow(unused)]
#![warn(noop_method_call)]
use std::borrow::Borrow;
use std::ops::Deref;
struct PlainType<T>(T);
#[derive(Clone)]
struct CloneType<T>(T);
fn main() {
let non_clone_type_ref = &PlainType(1u32);
let non_clone_type_ref_clone: &PlainType<u32> = non_clone_type_ref.clone();
//~^ WARNING call to `.clone()` on a reference in this situation does nothing
let clone_type_ref = &CloneType(1u32);
let clone_type_ref_clone: CloneType<u32> = clone_type_ref.clone();
// Calling clone on a double reference doesn't warn since the method call itself
// peels the outer reference off
let clone_type_ref = &&CloneType(1u32);
let clone_type_ref_clone: &CloneType<u32> = clone_type_ref.clone();
let non_deref_type = &PlainType(1u32);
let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
//~^ WARNING call to `.deref()` on a reference in this situation does nothing
// Dereferencing a &&T does not warn since it has collapsed the double reference
let non_deref_type = &&PlainType(1u32);
let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
let non_borrow_type = &PlainType(1u32);
let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();
//~^ WARNING call to `.borrow()` on a reference in this situation does nothing
// Borrowing a &&T does not warn since it has collapsed the double reference
let non_borrow_type = &&PlainType(1u32);
let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();
let xs = ["a", "b", "c"];
let _v: Vec<&str> = xs.iter().map(|x| x.clone()).collect(); // ok, but could use `*x` instead
}
fn generic<T>(non_clone_type: &PlainType<T>) {
non_clone_type.clone();
}
fn non_generic(non_clone_type: &PlainType<u32>) {
non_clone_type.clone();
//~^ WARNING call to `.clone()` on a reference in this situation does nothing
}

View File

@ -0,0 +1,39 @@
warning: call to `.clone()` on a reference in this situation does nothing
--> $DIR/noop-method-call.rs:16:71
|
LL | let non_clone_type_ref_clone: &PlainType<u32> = non_clone_type_ref.clone();
| ^^^^^^^^ unnecessary method call
|
note: the lint level is defined here
--> $DIR/noop-method-call.rs:4:9
|
LL | #![warn(noop_method_call)]
| ^^^^^^^^^^^^^^^^
= note: the type `&PlainType<u32>` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed
warning: call to `.deref()` on a reference in this situation does nothing
--> $DIR/noop-method-call.rs:28:63
|
LL | let non_deref_type_deref: &PlainType<u32> = non_deref_type.deref();
| ^^^^^^^^ unnecessary method call
|
= note: the type `&PlainType<u32>` which `deref` is being called on is the same as the type returned from `deref`, so the method call does not do anything and can be removed
warning: call to `.borrow()` on a reference in this situation does nothing
--> $DIR/noop-method-call.rs:36:66
|
LL | let non_borrow_type_borrow: &PlainType<u32> = non_borrow_type.borrow();
| ^^^^^^^^^ unnecessary method call
|
= note: the type `&PlainType<u32>` which `borrow` is being called on is the same as the type returned from `borrow`, so the method call does not do anything and can be removed
warning: call to `.clone()` on a reference in this situation does nothing
--> $DIR/noop-method-call.rs:52:19
|
LL | non_clone_type.clone();
| ^^^^^^^^ unnecessary method call
|
= note: the type `&PlainType<u32>` which `clone` is being called on is the same as the type returned from `clone`, so the method call does not do anything and can be removed
warning: 4 warnings emitted

View File

@ -1,5 +1,3 @@
#![allow(unused)]
extern crate core;
pub use core as reexported_core; //~ ERROR `core` is private, and cannot be re-exported
//~^ WARN this was previously accepted
@ -9,16 +7,14 @@ mod foo1 {
}
mod foo2 {
use foo1::core; //~ ERROR `core` is private, and cannot be re-exported
//~^ WARN this was previously accepted
use foo1::core; //~ ERROR crate import `core` is private
pub mod bar {
extern crate core;
}
}
mod baz {
pub use foo2::bar::core; //~ ERROR `core` is private, and cannot be re-exported
//~^ WARN this was previously accepted
pub use foo2::bar::core; //~ ERROR crate import `core` is private
}
fn main() {}

View File

@ -1,5 +1,29 @@
error[E0603]: crate import `core` is private
--> $DIR/pub-reexport-priv-extern-crate.rs:10:15
|
LL | use foo1::core;
| ^^^^ private crate import
|
note: the crate import `core` is defined here
--> $DIR/pub-reexport-priv-extern-crate.rs:6:5
|
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^
error[E0603]: crate import `core` is private
--> $DIR/pub-reexport-priv-extern-crate.rs:17:24
|
LL | pub use foo2::bar::core;
| ^^^^ private crate import
|
note: the crate import `core` is defined here
--> $DIR/pub-reexport-priv-extern-crate.rs:12:9
|
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^
error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub`
--> $DIR/pub-reexport-priv-extern-crate.rs:4:9
--> $DIR/pub-reexport-priv-extern-crate.rs:2:9
|
LL | pub use core as reexported_core;
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -8,23 +32,6 @@ LL | pub use core as reexported_core;
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub`
--> $DIR/pub-reexport-priv-extern-crate.rs:12:9
|
LL | use foo1::core;
| ^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub`
--> $DIR/pub-reexport-priv-extern-crate.rs:20:13
|
LL | pub use foo2::bar::core;
| ^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0603`.

View File

@ -40,6 +40,8 @@ LL | | statefn: &id(state1 as StateMachineFunc)
| | ------------------------------ temporary value created here
LL | | }
| |_____^ returns a value referencing data owned by the current function
|
= help: use `.collect()` to allocate the iterator
error: aborting due to 4 previous errors

View File

@ -29,5 +29,6 @@ m!(y);
fn main() {
use crate::y::*;
#[allow(noop_method_call)]
(&()).deref();
}