Auto merge of #98612 - Dylan-DPC:rollup-7tasikc, r=Dylan-DPC

Rollup of 9 pull requests

Successful merges:

 - #97346 (Remove a back-compat hack on lazy TAIT)
 - #98261 (Remove `MAX_SUGGESTION_HIGHLIGHT_LINES`)
 - #98337 ([RFC 2011] Optimize non-consuming operators)
 - #98384 (Fix RSS reporting on macOS)
 - #98420 (translation: lint fix + more migration)
 - #98430 (Refactor iter adapters with less macros)
 - #98555 (Hermit: Fix initializing lazy locks)
 - #98595 (Implement `Send` and `Sync` for `ThinBox<T>`)
 - #98597 (Remove unstable CStr/CString change from 1.62 release note)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-06-28 13:46:43 +00:00
commit 00ebeb87ac
42 changed files with 652 additions and 446 deletions

View File

@ -4280,6 +4280,7 @@ dependencies = [
"rustc_data_structures",
"rustc_errors",
"rustc_hir",
"rustc_macros",
"rustc_middle",
"rustc_session",
"rustc_span",

View File

@ -29,7 +29,6 @@ Compiler
Libraries
---------
- [Move `CStr` to libcore, and `CString` to liballoc][94079]
- [Windows: Use a pipe relay for chaining pipes][95841]
- [Replace Linux Mutex and Condvar with futex based ones.][95035]
- [Replace RwLock by a futex based one on Linux][95801]
@ -90,7 +89,6 @@ and related tools.
[93313]: https://github.com/rust-lang/rust/pull/93313/
[93969]: https://github.com/rust-lang/rust/pull/93969/
[94079]: https://github.com/rust-lang/rust/pull/94079/
[94206]: https://github.com/rust-lang/rust/pull/94206/
[94457]: https://github.com/rust-lang/rust/pull/94457/
[94775]: https://github.com/rust-lang/rust/pull/94775/

View File

@ -1,4 +1,6 @@
use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed, MultiSpan};
use rustc_errors::{
struct_span_err, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
@ -476,10 +478,11 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
fn struct_span_err_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
msg: &str,
msg: impl Into<DiagnosticMessage>,
code: DiagnosticId,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
self.infcx.tcx.sess.struct_span_err_with_code(sp, msg, code)

View File

@ -6,6 +6,7 @@
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
#![feature(trusted_step)]
#![feature(try_blocks)]

View File

@ -1,11 +1,10 @@
use crate::assert::expr_if_not;
use rustc_ast::{
attr,
ptr::P,
token,
tokenstream::{DelimSpan, TokenStream, TokenTree},
BorrowKind, Expr, ExprKind, ItemKind, MacArgs, MacCall, MacDelimiter, Mutability, Path,
PathSegment, Stmt, StructRest, UseTree, UseTreeKind, DUMMY_NODE_ID,
BinOpKind, BorrowKind, Expr, ExprKind, ItemKind, MacArgs, MacCall, MacDelimiter, Mutability,
Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID,
};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
@ -16,11 +15,19 @@ use rustc_span::{
};
pub(super) struct Context<'cx, 'a> {
// An optimization.
//
// Elements that aren't consumed (PartialEq, PartialOrd, ...) can be copied **after** the
// `assert!` expression fails rather than copied on-the-fly.
best_case_captures: Vec<Stmt>,
// Top-level `let captureN = Capture::new()` statements
capture_decls: Vec<Capture>,
cx: &'cx ExtCtxt<'a>,
// Formatting string used for debugging
fmt_string: String,
// If the current expression being visited consumes itself. Used to construct
// `best_case_captures`.
is_consumed: bool,
// Top-level `let __local_bindN = &expr` statements
local_bind_decls: Vec<Stmt>,
// Used to avoid capturing duplicated paths
@ -36,9 +43,11 @@ pub(super) struct Context<'cx, 'a> {
impl<'cx, 'a> Context<'cx, 'a> {
pub(super) fn new(cx: &'cx ExtCtxt<'a>, span: Span) -> Self {
Self {
best_case_captures: <_>::default(),
capture_decls: <_>::default(),
cx,
fmt_string: <_>::default(),
is_consumed: true,
local_bind_decls: <_>::default(),
paths: <_>::default(),
span,
@ -69,14 +78,22 @@ impl<'cx, 'a> Context<'cx, 'a> {
self.manage_cond_expr(&mut cond_expr);
let initial_imports = self.build_initial_imports();
let panic = self.build_panic(&expr_str, panic_path);
let cond_expr_with_unlikely = self.build_unlikely(cond_expr);
let Self { capture_decls, cx, local_bind_decls, span, .. } = self;
let Self { best_case_captures, capture_decls, cx, local_bind_decls, span, .. } = self;
let mut assert_then_stmts = Vec::with_capacity(2);
assert_then_stmts.extend(best_case_captures);
assert_then_stmts.push(self.cx.stmt_expr(panic));
let assert_then = self.cx.block(span, assert_then_stmts);
let mut stmts = Vec::with_capacity(4);
stmts.push(initial_imports);
stmts.extend(capture_decls.into_iter().map(|c| c.decl));
stmts.extend(local_bind_decls);
stmts.push(cx.stmt_expr(expr_if_not(cx, span, cond_expr, panic, None)));
stmts.push(
cx.stmt_expr(cx.expr(span, ExprKind::If(cond_expr_with_unlikely, assert_then, None))),
);
cx.expr_block(cx.block(span, stmts))
}
@ -115,6 +132,16 @@ impl<'cx, 'a> Context<'cx, 'a> {
)
}
/// Takes the conditional expression of `assert!` and then wraps it inside `unlikely`
fn build_unlikely(&self, cond_expr: P<Expr>) -> P<Expr> {
let unlikely_path = self.cx.std_path(&[sym::intrinsics, sym::unlikely]);
self.cx.expr_call(
self.span,
self.cx.expr_path(self.cx.path(self.span, unlikely_path)),
vec![self.cx.expr(self.span, ExprKind::Unary(UnOp::Not, cond_expr))],
)
}
/// The necessary custom `panic!(...)` expression.
///
/// panic!(
@ -167,17 +194,39 @@ impl<'cx, 'a> Context<'cx, 'a> {
/// See [Self::manage_initial_capture] and [Self::manage_try_capture]
fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
match (*expr).kind {
ExprKind::AddrOf(_, _, ref mut local_expr) => {
self.manage_cond_expr(local_expr);
ExprKind::AddrOf(_, mutability, ref mut local_expr) => {
self.with_is_consumed_management(
matches!(mutability, Mutability::Mut),
|this| this.manage_cond_expr(local_expr)
);
}
ExprKind::Array(ref mut local_exprs) => {
for local_expr in local_exprs {
self.manage_cond_expr(local_expr);
}
}
ExprKind::Binary(_, ref mut lhs, ref mut rhs) => {
self.manage_cond_expr(lhs);
self.manage_cond_expr(rhs);
ExprKind::Binary(ref op, ref mut lhs, ref mut rhs) => {
self.with_is_consumed_management(
matches!(
op.node,
BinOpKind::Add
| BinOpKind::And
| BinOpKind::BitAnd
| BinOpKind::BitOr
| BinOpKind::BitXor
| BinOpKind::Div
| BinOpKind::Mul
| BinOpKind::Or
| BinOpKind::Rem
| BinOpKind::Shl
| BinOpKind::Shr
| BinOpKind::Sub
),
|this| {
this.manage_cond_expr(lhs);
this.manage_cond_expr(rhs);
}
);
}
ExprKind::Call(_, ref mut local_exprs) => {
for local_expr in local_exprs {
@ -228,8 +277,11 @@ impl<'cx, 'a> Context<'cx, 'a> {
self.manage_cond_expr(local_expr);
}
}
ExprKind::Unary(_, ref mut local_expr) => {
self.manage_cond_expr(local_expr);
ExprKind::Unary(un_op, ref mut local_expr) => {
self.with_is_consumed_management(
matches!(un_op, UnOp::Neg | UnOp::Not),
|this| this.manage_cond_expr(local_expr)
);
}
// Expressions that are not worth or can not be captured.
//
@ -337,9 +389,23 @@ impl<'cx, 'a> Context<'cx, 'a> {
))
.add_trailing_semicolon();
let local_bind_path = self.cx.expr_path(Path::from_ident(local_bind));
let ret = self.cx.stmt_expr(local_bind_path);
let block = self.cx.expr_block(self.cx.block(self.span, vec![try_capture_call, ret]));
*expr = self.cx.expr_deref(self.span, block);
let rslt = if self.is_consumed {
let ret = self.cx.stmt_expr(local_bind_path);
self.cx.expr_block(self.cx.block(self.span, vec![try_capture_call, ret]))
} else {
self.best_case_captures.push(try_capture_call);
local_bind_path
};
*expr = self.cx.expr_deref(self.span, rslt);
}
// Calls `f` with the internal `is_consumed` set to `curr_is_consumed` and then
// sets the internal `is_consumed` back to its original value.
fn with_is_consumed_management(&mut self, curr_is_consumed: bool, f: impl FnOnce(&mut Self)) {
let prev_is_consumed = self.is_consumed;
self.is_consumed = curr_is_consumed;
f(self);
self.is_consumed = prev_is_consumed;
}
}

View File

@ -826,6 +826,24 @@ cfg_if! {
}
}
}
} else if #[cfg(target_os = "macos")] {
pub fn get_resident_set_size() -> Option<usize> {
use libc::{c_int, c_void, getpid, proc_pidinfo, proc_taskinfo, PROC_PIDTASKINFO};
use std::mem;
const PROC_TASKINFO_SIZE: c_int = mem::size_of::<proc_taskinfo>() as c_int;
unsafe {
let mut info: proc_taskinfo = mem::zeroed();
let info_ptr = &mut info as *mut proc_taskinfo as *mut c_void;
let pid = getpid() as c_int;
let ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, info_ptr, PROC_TASKINFO_SIZE);
if ret == PROC_TASKINFO_SIZE {
Some(info.pti_resident_size as usize)
} else {
None
}
}
}
} else if #[cfg(unix)] {
pub fn get_resident_set_size() -> Option<usize> {
let field = 1;

View File

@ -0,0 +1,12 @@
privacy-field-is-private = field `{$field_name}` of {$variant_descr} `{$def_path_str}` is private
privacy-field-is-private-is-update-syntax-label = field `{$field_name}` is private
privacy-field-is-private-label = private field
privacy-item-is-private = {$kind} `{$descr}` is private
.label = private {$kind}
privacy-unnamed-item-is-private = {$kind} is private
.label = private {$kind}
privacy-in-public-interface = {$vis_descr} {$kind} `{$descr}` in public interface
.label = can't leak {$vis_descr} {$kind}
.visibility-label = `{$descr}` declared as {$vis_descr}

View File

@ -32,6 +32,7 @@ pub use unic_langid::{langid, LanguageIdentifier};
// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
fluent_messages! {
parser => "../locales/en-US/parser.ftl",
privacy => "../locales/en-US/privacy.ftl",
typeck => "../locales/en-US/typeck.ftl",
builtin_macros => "../locales/en-US/builtin_macros.ftl",
}

View File

@ -656,11 +656,6 @@ impl Emitter for SilentEmitter {
}
}
/// Maximum number of lines we will print for a multiline suggestion; arbitrary.
///
/// This should be replaced with a more involved mechanism to output multiline suggestions that
/// more closely mimics the regular diagnostic output, where irrelevant code lines are elided.
pub const MAX_SUGGESTION_HIGHLIGHT_LINES: usize = 6;
/// Maximum number of suggestions to be shown
///
/// Arbitrary, but taken from trait import suggestion limit

View File

@ -1077,6 +1077,7 @@ impl<'a> ExtCtxt<'a> {
self.current_expansion.id.expansion_cause()
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,
@ -1101,9 +1102,11 @@ impl<'a> ExtCtxt<'a> {
///
/// Compilation will be stopped in the near future (at the end of
/// the macro expansion phase).
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.sess.parse_sess.span_diagnostic.span_err(sp, msg);
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.sess.parse_sess.span_diagnostic.span_warn(sp, msg);
}

View File

@ -9,6 +9,7 @@
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_span)]
#![feature(rustc_attrs)]
#![feature(try_blocks)]
#![recursion_limit = "256"]

View File

@ -39,21 +39,19 @@ pub struct OpaqueTypeDecl<'tcx> {
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// This is a backwards compatibility hack to prevent breaking changes from
/// lazy TAIT around RPIT handling.
pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<'tcx>>(
pub fn replace_opaque_types_with_inference_vars(
&self,
value: T,
ty: Ty<'tcx>,
body_id: HirId,
span: Span,
code: ObligationCauseCode<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> InferOk<'tcx, T> {
if !value.has_opaque_types() {
return InferOk { value, obligations: vec![] };
) -> InferOk<'tcx, Ty<'tcx>> {
if !ty.has_opaque_types() {
return InferOk { value: ty, obligations: vec![] };
}
let mut obligations = vec![];
let value = value.fold_with(&mut ty::fold::BottomUpFolder {
let value = ty.fold_with(&mut ty::fold::BottomUpFolder {
tcx: self.tcx,
lt_op: |lt| lt,
ct_op: |ct| ct,

View File

@ -406,9 +406,12 @@ impl LateLintPass<'_> for Diagnostics {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
let Some((span, def_id, substs)) = typeck_results_of_method_fn(cx, expr) else { return };
debug!(?span, ?def_id, ?substs);
if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) &&
!cx.tcx.has_attr(instance.def_id(), sym::rustc_lint_diagnostics)
{
let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs)
.ok()
.and_then(|inst| inst)
.map(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics))
.unwrap_or(false);
if !has_attr {
return;
}

View File

@ -6,6 +6,7 @@
#![feature(let_chains)]
#![feature(let_else)]
#![feature(never_type)]
#![feature(rustc_attrs)]
#![recursion_limit = "256"]
#[macro_use]

View File

@ -357,6 +357,7 @@ impl<'a> DerefMut for SnapshotParser<'a> {
}
impl<'a> Parser<'a> {
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub(super) fn span_err<S: Into<MultiSpan>>(
&self,
sp: S,
@ -365,6 +366,7 @@ impl<'a> Parser<'a> {
err.span_err(sp, self.diagnostic())
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,

View File

@ -4,14 +4,15 @@ version = "0.0.0"
edition = "2021"
[dependencies]
rustc_middle = { path = "../rustc_middle" }
rustc_ast = { path = "../rustc_ast" }
rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
rustc_typeck = { path = "../rustc_typeck" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_typeck = { path = "../rustc_typeck" }
tracing = "0.1"

View File

@ -0,0 +1,75 @@
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
use rustc_span::{Span, Symbol};
#[derive(SessionDiagnostic)]
#[error(privacy::field_is_private, code = "E0451")]
pub struct FieldIsPrivate {
#[primary_span]
pub span: Span,
pub field_name: Symbol,
pub variant_descr: &'static str,
pub def_path_str: String,
#[subdiagnostic]
pub label: FieldIsPrivateLabel,
}
#[derive(SessionSubdiagnostic)]
pub enum FieldIsPrivateLabel {
#[label(privacy::field_is_private_is_update_syntax_label)]
IsUpdateSyntax {
#[primary_span]
span: Span,
field_name: Symbol,
},
#[label(privacy::field_is_private_label)]
Other {
#[primary_span]
span: Span,
},
}
#[derive(SessionDiagnostic)]
#[error(privacy::item_is_private)]
pub struct ItemIsPrivate<'a> {
#[primary_span]
#[label]
pub span: Span,
pub kind: &'a str,
pub descr: String,
}
#[derive(SessionDiagnostic)]
#[error(privacy::unnamed_item_is_private)]
pub struct UnnamedItemIsPrivate {
#[primary_span]
pub span: Span,
pub kind: &'static str,
}
// Duplicate of `InPublicInterface` but with a different error code, shares the same slug.
#[derive(SessionDiagnostic)]
#[error(privacy::in_public_interface, code = "E0445")]
pub struct InPublicInterfaceTraits<'a> {
#[primary_span]
#[label]
pub span: Span,
pub vis_descr: &'static str,
pub kind: &'a str,
pub descr: String,
#[label(privacy::visibility_label)]
pub vis_span: Span,
}
// Duplicate of `InPublicInterfaceTraits` but with a different error code, shares the same slug.
#[derive(SessionDiagnostic)]
#[error(privacy::in_public_interface, code = "E0446")]
pub struct InPublicInterface<'a> {
#[primary_span]
#[label]
pub span: Span,
pub vis_descr: &'static str,
pub kind: &'a str,
pub descr: String,
#[label(privacy::visibility_label)]
pub vis_span: Span,
}

View File

@ -1,15 +1,19 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(control_flow_enum)]
#![feature(try_blocks)]
#![feature(associated_type_defaults)]
#![feature(control_flow_enum)]
#![feature(rustc_private)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
#![cfg_attr(not(bootstrap), deny(rustc::untranslatable_diagnostic))]
#![cfg_attr(not(bootstrap), deny(rustc::diagnostic_outside_of_impl))]
mod errors;
use rustc_ast::MacroDef;
use rustc_attr as attr;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::intern::Interned;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
@ -34,6 +38,11 @@ use std::marker::PhantomData;
use std::ops::ControlFlow;
use std::{cmp, fmt, mem};
use errors::{
FieldIsPrivate, FieldIsPrivateLabel, InPublicInterface, InPublicInterfaceTraits, ItemIsPrivate,
UnnamedItemIsPrivate,
};
////////////////////////////////////////////////////////////////////////////////
/// Generic infrastructure used to implement specific visitors below.
////////////////////////////////////////////////////////////////////////////////
@ -935,23 +944,17 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
let hir_id = self.tcx.hir().local_def_id_to_hir_id(self.current_item);
let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1;
if !field.vis.is_accessible_from(def_id, self.tcx) {
let label = if in_update_syntax {
format!("field `{}` is private", field.name)
} else {
"private field".to_string()
};
struct_span_err!(
self.tcx.sess,
self.tcx.sess.emit_err(FieldIsPrivate {
span,
E0451,
"field `{}` of {} `{}` is private",
field.name,
def.variant_descr(),
self.tcx.def_path_str(def.did())
)
.span_label(span, label)
.emit();
field_name: field.name,
variant_descr: def.variant_descr(),
def_path_str: self.tcx.def_path_str(def.did()),
label: if in_update_syntax {
FieldIsPrivateLabel::IsUpdateSyntax { span, field_name: field.name }
} else {
FieldIsPrivateLabel::Other { span }
},
});
}
}
}
@ -1075,11 +1078,11 @@ impl<'tcx> TypePrivacyVisitor<'tcx> {
fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
let is_error = !self.item_is_accessible(def_id);
if is_error {
self.tcx
.sess
.struct_span_err(self.span, &format!("{} `{}` is private", kind, descr))
.span_label(self.span, &format!("private {}", kind))
.emit();
self.tcx.sess.emit_err(ItemIsPrivate {
span: self.span,
kind,
descr: descr.to_string(),
});
}
is_error
}
@ -1250,13 +1253,10 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
};
let kind = kind.descr(def_id);
let msg = match name {
Some(name) => format!("{} `{}` is private", kind, name),
None => format!("{} is private", kind),
let _ = match name {
Some(name) => sess.emit_err(ItemIsPrivate { span, kind, descr: name }),
None => sess.emit_err(UnnamedItemIsPrivate { span, kind }),
};
sess.struct_span_err(span, &msg)
.span_label(span, &format!("private {}", kind))
.emit();
return;
}
}
@ -1753,22 +1753,31 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
}
}
};
let make_msg = || format!("{} {} `{}` in public interface", vis_descr, kind, descr);
let span = self.tcx.def_span(self.item_def_id.to_def_id());
if self.has_old_errors
|| self.in_assoc_ty
|| self.tcx.resolutions(()).has_pub_restricted
{
let mut err = if kind == "trait" {
struct_span_err!(self.tcx.sess, span, E0445, "{}", make_msg())
} else {
struct_span_err!(self.tcx.sess, span, E0446, "{}", make_msg())
};
let descr = descr.to_string();
let vis_span =
self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id));
err.span_label(span, format!("can't leak {} {}", vis_descr, kind));
err.span_label(vis_span, format!("`{}` declared as {}", descr, vis_descr));
err.emit();
if kind == "trait" {
self.tcx.sess.emit_err(InPublicInterfaceTraits {
span,
vis_descr,
kind,
descr,
vis_span,
});
} else {
self.tcx.sess.emit_err(InPublicInterface {
span,
vis_descr,
kind,
descr,
vis_span,
});
}
} else {
let err_code = if kind == "trait" { "E0445" } else { "E0446" };
self.tcx.struct_span_lint_hir(
@ -1776,7 +1785,12 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
hir_id,
span,
|lint| {
lint.build(&format!("{} (error {})", make_msg(), err_code)).emit();
lint.build(&format!(
"{} (error {})",
format!("{} {} `{}` in public interface", vis_descr, kind, descr),
err_code
))
.emit();
},
);
}

View File

@ -280,6 +280,7 @@ impl Session {
self.crate_types.set(crate_types).expect("`crate_types` was initialized twice")
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_span_warn<S: Into<MultiSpan>>(
&self,
sp: S,
@ -287,6 +288,7 @@ impl Session {
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_span_warn(sp, msg)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>(
&self,
sp: S,
@ -295,6 +297,7 @@ impl Session {
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_span_warn_with_expectation(sp, msg, id)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
@ -303,9 +306,11 @@ impl Session {
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_span_warn_with_code(sp, msg, code)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_warn(msg)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_warn_with_expectation(
&self,
msg: impl Into<DiagnosticMessage>,
@ -313,6 +318,7 @@ impl Session {
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_warn_with_expectation(msg, id)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_span_allow<S: Into<MultiSpan>>(
&self,
sp: S,
@ -320,9 +326,11 @@ impl Session {
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_span_allow(sp, msg)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_allow(msg)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_expect(
&self,
msg: impl Into<DiagnosticMessage>,
@ -330,6 +338,7 @@ impl Session {
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_expect(msg, id)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,
@ -337,6 +346,7 @@ impl Session {
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
self.diagnostic().struct_span_err(sp, msg)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
@ -346,12 +356,14 @@ impl Session {
self.diagnostic().struct_span_err_with_code(sp, msg, code)
}
// FIXME: This method should be removed (every error should have an associated error code).
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_err(
&self,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
self.parse_sess.struct_err(msg)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_err_with_code(
&self,
msg: impl Into<DiagnosticMessage>,
@ -359,6 +371,7 @@ impl Session {
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
self.diagnostic().struct_err_with_code(msg, code)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_warn_with_code(
&self,
msg: impl Into<DiagnosticMessage>,
@ -366,6 +379,7 @@ impl Session {
) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_warn_with_code(msg, code)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_span_fatal<S: Into<MultiSpan>>(
&self,
sp: S,
@ -373,6 +387,7 @@ impl Session {
) -> DiagnosticBuilder<'_, !> {
self.diagnostic().struct_span_fatal(sp, msg)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
@ -381,13 +396,16 @@ impl Session {
) -> DiagnosticBuilder<'_, !> {
self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
self.diagnostic().struct_fatal(msg)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
self.diagnostic().span_fatal(sp, msg)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn span_fatal_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
@ -396,9 +414,11 @@ impl Session {
) -> ! {
self.diagnostic().span_fatal_with_code(sp, msg, code)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
self.diagnostic().fatal(msg).raise()
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn span_err_or_warn<S: Into<MultiSpan>>(
&self,
is_warning: bool,
@ -411,6 +431,7 @@ impl Session {
self.span_err(sp, msg);
}
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn span_err<S: Into<MultiSpan>>(
&self,
sp: S,
@ -418,6 +439,7 @@ impl Session {
) -> ErrorGuaranteed {
self.diagnostic().span_err(sp, msg)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn span_err_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
@ -426,6 +448,7 @@ impl Session {
) {
self.diagnostic().span_err_with_code(sp, msg, code)
}
#[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.diagnostic().err(msg)
}

View File

@ -28,7 +28,6 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::traits::select::OverflowError;
use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::subst::Subst;
@ -252,22 +251,10 @@ fn project_and_unify_type<'cx, 'tcx>(
Err(InProgress) => return ProjectAndUnifyResult::Recursive,
};
debug!(?normalized, ?obligations, "project_and_unify_type result");
let actual = obligation.predicate.term;
// HACK: lazy TAIT would regress src/test/ui/impl-trait/nested-return-type2.rs, so we add
// a back-compat hack hat converts the RPITs into inference vars, just like they were before
// lazy TAIT.
// This does not affect TAITs in general, as tested in the nested-return-type-tait* tests.
let InferOk { value: actual, obligations: new } =
selcx.infcx().replace_opaque_types_with_inference_vars(
actual,
obligation.cause.body_id,
obligation.cause.span,
ObligationCauseCode::MiscObligation,
obligation.param_env,
);
obligations.extend(new);
match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) {
match infcx
.at(&obligation.cause, obligation.param_env)
.eq(normalized, obligation.predicate.term)
{
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations);
ProjectAndUnifyResult::Holds(obligations)

View File

@ -33,6 +33,14 @@ pub struct ThinBox<T: ?Sized> {
_marker: PhantomData<T>,
}
/// `ThinBox<T>` is `Send` if `T` is `Send` because the data is owned.
#[unstable(feature = "thin_box", issue = "92791")]
unsafe impl<T: ?Sized + Send> Send for ThinBox<T> {}
/// `ThinBox<T>` is `Sync` if `T` is `Sync` because the data is owned.
#[unstable(feature = "thin_box", issue = "92791")]
unsafe impl<T: ?Sized + Sync> Sync for ThinBox<T> {}
#[unstable(feature = "thin_box", issue = "92791")]
impl<T> ThinBox<T> {
/// Moves a type to the heap with its `Metadata` stored in the heap allocation instead of on

View File

@ -37,33 +37,6 @@ impl<A, B> Chain<A, B> {
}
}
/// Fuse the iterator if the expression is `None`.
macro_rules! fuse {
($self:ident . $iter:ident . $($call:tt)+) => {
match $self.$iter {
Some(ref mut iter) => match iter.$($call)+ {
None => {
$self.$iter = None;
None
}
item => item,
},
None => None,
}
};
}
/// Try an iterator method without fusing,
/// like an inline `.as_mut().and_then(...)`
macro_rules! maybe {
($self:ident . $iter:ident . $($call:tt)+) => {
match $self.$iter {
Some(ref mut iter) => iter.$($call)+,
None => None,
}
};
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B> Iterator for Chain<A, B>
where
@ -74,10 +47,7 @@ where
#[inline]
fn next(&mut self) -> Option<A::Item> {
match fuse!(self.a.next()) {
None => maybe!(self.b.next()),
item => item,
}
and_then_or_clear(&mut self.a, Iterator::next).or_else(|| self.b.as_mut()?.next())
}
#[inline]
@ -161,7 +131,7 @@ where
self.a = None;
}
maybe!(self.b.nth(n))
self.b.as_mut()?.nth(n)
}
#[inline]
@ -169,23 +139,15 @@ where
where
P: FnMut(&Self::Item) -> bool,
{
match fuse!(self.a.find(&mut predicate)) {
None => maybe!(self.b.find(predicate)),
item => item,
}
and_then_or_clear(&mut self.a, |a| a.find(&mut predicate))
.or_else(|| self.b.as_mut()?.find(predicate))
}
#[inline]
fn last(self) -> Option<A::Item> {
// Must exhaust a before b.
let a_last = match self.a {
Some(a) => a.last(),
None => None,
};
let b_last = match self.b {
Some(b) => b.last(),
None => None,
};
let a_last = self.a.and_then(Iterator::last);
let b_last = self.b.and_then(Iterator::last);
b_last.or(a_last)
}
@ -220,10 +182,7 @@ where
{
#[inline]
fn next_back(&mut self) -> Option<A::Item> {
match fuse!(self.b.next_back()) {
None => maybe!(self.a.next_back()),
item => item,
}
and_then_or_clear(&mut self.b, |b| b.next_back()).or_else(|| self.a.as_mut()?.next_back())
}
#[inline]
@ -263,7 +222,7 @@ where
self.b = None;
}
maybe!(self.a.nth_back(n))
self.a.as_mut()?.nth_back(n)
}
#[inline]
@ -271,10 +230,8 @@ where
where
P: FnMut(&Self::Item) -> bool,
{
match fuse!(self.b.rfind(&mut predicate)) {
None => maybe!(self.a.rfind(predicate)),
item => item,
}
and_then_or_clear(&mut self.b, |b| b.rfind(&mut predicate))
.or_else(|| self.a.as_mut()?.rfind(predicate))
}
fn try_rfold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
@ -324,3 +281,12 @@ where
B: TrustedLen<Item = A::Item>,
{
}
#[inline]
fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option<U>) -> Option<U> {
let x = f(opt.as_mut()?);
if x.is_none() {
*opt = None;
}
x
}

View File

@ -290,20 +290,11 @@ where
#[inline]
fn next(&mut self) -> Option<U::Item> {
loop {
if let Some(ref mut inner) = self.frontiter {
match inner.next() {
None => self.frontiter = None,
elt @ Some(_) => return elt,
}
if let elt @ Some(_) = and_then_or_clear(&mut self.frontiter, Iterator::next) {
return elt;
}
match self.iter.next() {
None => match self.backiter.as_mut()?.next() {
None => {
self.backiter = None;
return None;
}
elt @ Some(_) => return elt,
},
None => return and_then_or_clear(&mut self.backiter, Iterator::next),
Some(inner) => self.frontiter = Some(inner.into_iter()),
}
}
@ -436,21 +427,12 @@ where
#[inline]
fn next_back(&mut self) -> Option<U::Item> {
loop {
if let Some(ref mut inner) = self.backiter {
match inner.next_back() {
None => self.backiter = None,
elt @ Some(_) => return elt,
}
if let elt @ Some(_) = and_then_or_clear(&mut self.backiter, |b| b.next_back()) {
return elt;
}
match self.iter.next_back() {
None => match self.frontiter.as_mut()?.next_back() {
None => {
self.frontiter = None;
return None;
}
elt @ Some(_) => return elt,
},
next => self.backiter = next.map(IntoIterator::into_iter),
None => return and_then_or_clear(&mut self.frontiter, |f| f.next_back()),
Some(inner) => self.backiter = Some(inner.into_iter()),
}
}
}
@ -606,3 +588,12 @@ unsafe impl<T, const N: usize> TrustedConstSize for [T; N] {}
unsafe impl<T, const N: usize> TrustedConstSize for &'_ [T; N] {}
#[unstable(feature = "std_internals", issue = "none")]
unsafe impl<T, const N: usize> TrustedConstSize for &'_ mut [T; N] {}
#[inline]
fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option<U>) -> Option<U> {
let x = f(opt.as_mut()?);
if x.is_none() {
*opt = None;
}
x
}

View File

@ -29,33 +29,6 @@ impl<I> Fuse<I> {
#[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Fuse<I> where I: Iterator {}
/// Fuse the iterator if the expression is `None`.
macro_rules! fuse {
($self:ident . iter . $($call:tt)+) => {
match $self.iter {
Some(ref mut iter) => match iter.$($call)+ {
None => {
$self.iter = None;
None
}
item => item,
},
None => None,
}
};
}
/// Specialized macro that doesn't check if the expression is `None`.
/// (We trust that a `FusedIterator` will fuse itself.)
macro_rules! spec {
($self:ident . iter . $($call:tt)+) => {
match $self.iter {
Some(ref mut iter) => iter.$($call)+,
None => None,
}
};
}
// Any specialized implementation here is made internal
// to avoid exposing default fns outside this trait.
#[stable(feature = "rust1", since = "1.0.0")]
@ -281,12 +254,12 @@ where
#[inline]
default fn next(&mut self) -> Option<<I as Iterator>::Item> {
fuse!(self.iter.next())
and_then_or_clear(&mut self.iter, Iterator::next)
}
#[inline]
default fn nth(&mut self, n: usize) -> Option<I::Item> {
fuse!(self.iter.nth(n))
and_then_or_clear(&mut self.iter, |iter| iter.nth(n))
}
#[inline]
@ -308,7 +281,7 @@ where
where
P: FnMut(&Self::Item) -> bool,
{
fuse!(self.iter.find(predicate))
and_then_or_clear(&mut self.iter, |iter| iter.find(predicate))
}
#[inline]
@ -316,7 +289,7 @@ where
where
I: DoubleEndedIterator,
{
fuse!(self.iter.next_back())
and_then_or_clear(&mut self.iter, |iter| iter.next_back())
}
#[inline]
@ -324,7 +297,7 @@ where
where
I: DoubleEndedIterator,
{
fuse!(self.iter.nth_back(n))
and_then_or_clear(&mut self.iter, |iter| iter.nth_back(n))
}
#[inline]
@ -348,7 +321,7 @@ where
P: FnMut(&Self::Item) -> bool,
I: DoubleEndedIterator,
{
fuse!(self.iter.rfind(predicate))
and_then_or_clear(&mut self.iter, |iter| iter.rfind(predicate))
}
}
@ -361,12 +334,12 @@ where
{
#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
spec!(self.iter.next())
self.iter.as_mut()?.next()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<I::Item> {
spec!(self.iter.nth(n))
self.iter.as_mut()?.nth(n)
}
#[inline]
@ -387,7 +360,7 @@ where
where
P: FnMut(&Self::Item) -> bool,
{
spec!(self.iter.find(predicate))
self.iter.as_mut()?.find(predicate)
}
#[inline]
@ -395,7 +368,7 @@ where
where
I: DoubleEndedIterator,
{
spec!(self.iter.next_back())
self.iter.as_mut()?.next_back()
}
#[inline]
@ -403,7 +376,7 @@ where
where
I: DoubleEndedIterator,
{
spec!(self.iter.nth_back(n))
self.iter.as_mut()?.nth_back(n)
}
#[inline]
@ -426,6 +399,15 @@ where
P: FnMut(&Self::Item) -> bool,
I: DoubleEndedIterator,
{
spec!(self.iter.rfind(predicate))
self.iter.as_mut()?.rfind(predicate)
}
}
#[inline]
fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option<U>) -> Option<U> {
let x = f(opt.as_mut()?);
if x.is_none() {
*opt = None;
}
x
}

View File

@ -3,6 +3,7 @@ use crate::ptr;
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use crate::sys::hermit::abi;
use crate::sys::locks::Mutex;
use crate::sys_common::lazy_box::{LazyBox, LazyInit};
use crate::time::Duration;
// The implementation is inspired by Andrew D. Birrell's paper
@ -14,14 +15,26 @@ pub struct Condvar {
sem2: *const c_void,
}
pub type MovableCondvar = Condvar;
pub(crate) type MovableCondvar = LazyBox<Condvar>;
impl LazyInit for Condvar {
fn init() -> Box<Self> {
Box::new(Self::new())
}
}
unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}
impl Condvar {
pub const fn new() -> Condvar {
Condvar { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() }
pub fn new() -> Self {
let mut condvar =
Self { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() };
unsafe {
let _ = abi::sem_init(&mut condvar.sem1, 0);
let _ = abi::sem_init(&mut condvar.sem2, 0);
}
condvar
}
pub unsafe fn notify_one(&self) {

View File

@ -175,9 +175,7 @@ impl Mutex {
}
#[inline]
pub unsafe fn init(&mut self) {
self.inner = Spinlock::new(MutexInner::new());
}
pub unsafe fn init(&mut self) {}
#[inline]
pub unsafe fn lock(&self) {

View File

@ -1,9 +1,10 @@
use crate::cell::UnsafeCell;
use crate::sys::locks::{Condvar, Mutex};
use crate::sys::locks::{MovableCondvar, Mutex};
use crate::sys_common::lazy_box::{LazyBox, LazyInit};
pub struct RwLock {
lock: Mutex,
cond: Condvar,
cond: MovableCondvar,
state: UnsafeCell<State>,
}
@ -28,7 +29,11 @@ unsafe impl Sync for RwLock {}
impl RwLock {
pub const fn new() -> RwLock {
RwLock { lock: Mutex::new(), cond: Condvar::new(), state: UnsafeCell::new(State::Unlocked) }
RwLock {
lock: Mutex::new(),
cond: MovableCondvar::new(),
state: UnsafeCell::new(State::Unlocked),
}
}
#[inline]

View File

@ -1,5 +1,3 @@
// check-pass
trait Duh {}
impl Duh for i32 {}
@ -20,11 +18,9 @@ impl<R: Duh, F: FnMut() -> R> Trait for F {
// the hidden type. We already have obligations registered on the inference
// var to make it uphold the `: Duh` bound on `Trait::Assoc`. The opaque
// type does not implement `Duh`, even if its hidden type does.
// Lazy TAIT would error out, but we inserted a hack to make it work again,
// keeping backwards compatibility.
fn foo() -> impl Trait<Assoc = impl Send> {
//~^ ERROR `impl Send: Duh` is not satisfied
|| 42
}
fn main() {
}
fn main() {}

View File

@ -0,0 +1,16 @@
error[E0277]: the trait bound `impl Send: Duh` is not satisfied
--> $DIR/nested-return-type2.rs:21:13
|
LL | fn foo() -> impl Trait<Assoc = impl Send> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Duh` is not implemented for `impl Send`
|
= help: the trait `Duh` is implemented for `i32`
note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2.rs:23:5: 23:10]`
--> $DIR/nested-return-type2.rs:12:31
|
LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
| ^^^^^ ^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,9 +0,0 @@
// check-pass
// compile-flags: -Z unpretty=expanded
#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
fn main() {
let elem = 1i32;
assert!(elem == 1);
}

View File

@ -1,29 +0,0 @@
#![feature(prelude_import)]
#![no_std]
// check-pass
// compile-flags: -Z unpretty=expanded
#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
fn main() {
let elem = 1i32;
{
#[allow(unused_imports)]
use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
let mut __capture0 = ::core::asserting::Capture::new();
let __local_bind0 = &elem;
if !(*{
(&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
__local_bind0
} == 1) {
{
::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n elem = ",
"\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
}
}
};
}

View File

@ -0,0 +1,32 @@
// check-pass
// compile-flags: -Z unpretty=expanded
#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
fn arbitrary_consuming_method_for_demonstration_purposes() {
let elem = 1i32;
assert!(elem as usize);
}
fn addr_of() {
let elem = 1i32;
assert!(&elem);
}
fn binary() {
let elem = 1i32;
assert!(elem == 1);
assert!(elem >= 1);
assert!(elem > 0);
assert!(elem < 3);
assert!(elem <= 3);
assert!(elem != 3);
}
fn unary() {
let elem = &1i32;
assert!(*elem);
}
fn main() {
}

View File

@ -0,0 +1,147 @@
#![feature(prelude_import)]
#![no_std]
// check-pass
// compile-flags: -Z unpretty=expanded
#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
#[prelude_import]
use ::std::prelude::rust_2015::*;
#[macro_use]
extern crate std;
fn arbitrary_consuming_method_for_demonstration_purposes() {
let elem = 1i32;
{
#[allow(unused_imports)]
use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
let mut __capture0 = ::core::asserting::Capture::new();
let __local_bind0 = &elem;
if ::core::intrinsics::unlikely(!(*{
(&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
__local_bind0
} as usize)) {
{
::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem as usize\nWith captures:\n elem = ",
"\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
}
}
};
}
fn addr_of() {
let elem = 1i32;
{
#[allow(unused_imports)]
use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
let mut __capture0 = ::core::asserting::Capture::new();
let __local_bind0 = &elem;
if ::core::intrinsics::unlikely(!&*__local_bind0) {
(&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
{
::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: &elem\nWith captures:\n elem = ",
"\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
}
}
};
}
fn binary() {
let elem = 1i32;
{
#[allow(unused_imports)]
use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
let mut __capture0 = ::core::asserting::Capture::new();
let __local_bind0 = &elem;
if ::core::intrinsics::unlikely(!(*__local_bind0 == 1)) {
(&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
{
::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n elem = ",
"\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
}
}
};
{
#[allow(unused_imports)]
use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
let mut __capture0 = ::core::asserting::Capture::new();
let __local_bind0 = &elem;
if ::core::intrinsics::unlikely(!(*__local_bind0 >= 1)) {
(&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
{
::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem >= 1\nWith captures:\n elem = ",
"\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
}
}
};
{
#[allow(unused_imports)]
use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
let mut __capture0 = ::core::asserting::Capture::new();
let __local_bind0 = &elem;
if ::core::intrinsics::unlikely(!(*__local_bind0 > 0)) {
(&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
{
::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem > 0\nWith captures:\n elem = ",
"\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
}
}
};
{
#[allow(unused_imports)]
use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
let mut __capture0 = ::core::asserting::Capture::new();
let __local_bind0 = &elem;
if ::core::intrinsics::unlikely(!(*__local_bind0 < 3)) {
(&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
{
::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem < 3\nWith captures:\n elem = ",
"\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
}
}
};
{
#[allow(unused_imports)]
use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
let mut __capture0 = ::core::asserting::Capture::new();
let __local_bind0 = &elem;
if ::core::intrinsics::unlikely(!(*__local_bind0 <= 3)) {
(&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
{
::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem <= 3\nWith captures:\n elem = ",
"\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
}
}
};
{
#[allow(unused_imports)]
use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
let mut __capture0 = ::core::asserting::Capture::new();
let __local_bind0 = &elem;
if ::core::intrinsics::unlikely(!(*__local_bind0 != 3)) {
(&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
{
::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem != 3\nWith captures:\n elem = ",
"\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
}
}
};
}
fn unary() {
let elem = &1i32;
{
#[allow(unused_imports)]
use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
let mut __capture0 = ::core::asserting::Capture::new();
let __local_bind0 = &elem;
if ::core::intrinsics::unlikely(!**__local_bind0) {
(&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
{
::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: *elem\nWith captures:\n elem = ",
"\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
}
}
};
}
fn main() {}

View File

@ -1,4 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg_for_edges;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
@ -14,17 +14,14 @@ use super::MAP_FLATTEN;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_arg: &Expr<'_>, map_span: Span) {
if let Some((caller_ty_name, method_to_use)) = try_get_caller_ty_name_and_method_name(cx, expr, recv, map_arg) {
let mut applicability = Applicability::MachineApplicable;
let help_msgs = [
&format!("try replacing `map` with `{}`", method_to_use),
"and remove the `.flatten()`",
];
let closure_snippet = snippet_with_applicability(cx, map_arg.span, "..", &mut applicability);
span_lint_and_sugg_for_edges(
span_lint_and_sugg(
cx,
MAP_FLATTEN,
expr.span.with_lo(map_span.lo()),
&format!("called `map(..).flatten()` on `{}`", caller_ty_name),
&help_msgs,
&format!("try replacing `map` with `{}` and remove the `.flatten()`", method_to_use),
format!("{}({})", method_to_use, closure_snippet),
applicability,
);

View File

@ -4,7 +4,6 @@ use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_mac
use clippy_utils::ty::{implements_trait, match_type};
use clippy_utils::{contains_return, is_trait_item, last_path_segment, paths};
use if_chain::if_chain;
use rustc_errors::emitter::MAX_SUGGESTION_HIGHLIGHT_LINES;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@ -33,7 +32,6 @@ pub(super) fn check<'tcx>(
arg: &hir::Expr<'_>,
or_has_args: bool,
span: Span,
method_span: Span,
) -> bool {
let is_default_default = || is_trait_item(cx, fun, sym::Default);
@ -56,19 +54,14 @@ pub(super) fn check<'tcx>(
then {
let mut applicability = Applicability::MachineApplicable;
let hint = "unwrap_or_default()";
let mut sugg_span = span;
let sugg_span = span;
let mut sugg: String = format!(
let sugg: String = format!(
"{}.{}",
snippet_with_applicability(cx, self_expr.span, "..", &mut applicability),
hint
);
if sugg.lines().count() > MAX_SUGGESTION_HIGHLIGHT_LINES {
sugg_span = method_span.with_hi(span.hi());
sugg = hint.to_string();
}
span_lint_and_sugg(
cx,
OR_FUN_CALL,
@ -178,7 +171,7 @@ pub(super) fn check<'tcx>(
match inner_arg.kind {
hir::ExprKind::Call(fun, or_args) => {
let or_has_args = !or_args.is_empty();
if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span, method_span) {
if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span) {
let fun_span = if or_has_args { None } else { Some(fun.span) };
check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span);
}

View File

@ -112,7 +112,6 @@ const LINT_EMISSION_FUNCTIONS: [&[&str]; 8] = [
&["clippy_utils", "diagnostics", "span_lint_and_sugg"],
&["clippy_utils", "diagnostics", "span_lint_and_then"],
&["clippy_utils", "diagnostics", "span_lint_hir_and_then"],
&["clippy_utils", "diagnostics", "span_lint_and_sugg_for_edges"],
];
const SUGGESTION_DIAGNOSTIC_BUILDER_METHODS: [(&str, bool); 9] = [
("span_suggestion", false),

View File

@ -8,7 +8,7 @@
//! Thank you!
//! ~The `INTERNAL_METADATA_COLLECTOR` lint
use rustc_errors::{emitter::MAX_SUGGESTION_HIGHLIGHT_LINES, Applicability, Diagnostic, MultiSpan};
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir::HirId;
use rustc_lint::{LateContext, Lint, LintContext};
use rustc_span::source_map::Span;
@ -219,95 +219,6 @@ pub fn span_lint_and_sugg<'a, T: LintContext>(
});
}
/// Like [`span_lint_and_sugg`] with a focus on the edges. The output will either
/// emit single span or multispan suggestion depending on the number of its lines.
///
/// If the given suggestion string has more lines than the maximum display length defined by
/// [`MAX_SUGGESTION_HIGHLIGHT_LINES`][`rustc_errors::emitter::MAX_SUGGESTION_HIGHLIGHT_LINES`],
/// this function will split the suggestion and span to showcase the change for the top and
/// bottom edge of the code. For normal suggestions, in one display window, the help message
/// will be combined with a colon.
///
/// Multipart suggestions like the one being created here currently cannot be
/// applied by rustfix (See [rustfix#141](https://github.com/rust-lang/rustfix/issues/141)).
/// Testing rustfix with this lint emission function might require a file with
/// suggestions that can be fixed and those that can't. See
/// [clippy#8520](https://github.com/rust-lang/rust-clippy/pull/8520/files) for
/// an example and of this.
///
/// # Example for a long suggestion
///
/// ```text
/// error: called `map(..).flatten()` on `Option`
/// --> $DIR/map_flatten.rs:8:10
/// |
/// LL | .map(|x| {
/// | __________^
/// LL | | if x <= 5 {
/// LL | | Some(x)
/// LL | | } else {
/// ... |
/// LL | | })
/// LL | | .flatten();
/// | |__________________^
/// |
/// = note: `-D clippy::map-flatten` implied by `-D warnings`
/// help: try replacing `map` with `and_then`
/// |
/// LL ~ .and_then(|x| {
/// LL + if x <= 5 {
/// LL + Some(x)
/// |
/// help: and remove the `.flatten()`
/// |
/// LL + None
/// LL + }
/// LL ~ });
/// |
/// ```
pub fn span_lint_and_sugg_for_edges(
cx: &LateContext<'_>,
lint: &'static Lint,
sp: Span,
msg: &str,
helps: &[&str; 2],
sugg: String,
applicability: Applicability,
) {
span_lint_and_then(cx, lint, sp, msg, |diag| {
let sugg_lines_count = sugg.lines().count();
if sugg_lines_count > MAX_SUGGESTION_HIGHLIGHT_LINES {
let sm = cx.sess().source_map();
if let (Ok(line_upper), Ok(line_bottom)) =
(sm.lookup_line(sp.lo()), sm.lookup_line(sp.hi()))
{
let split_idx = MAX_SUGGESTION_HIGHLIGHT_LINES / 2;
let span_upper = sm.span_until_char(
sp.with_hi(line_upper.sf.lines(|lines| lines[line_upper.line + split_idx])),
'\n',
);
let span_bottom = sp.with_lo(line_bottom.sf.lines(|lines| lines[line_bottom.line - split_idx]));
let sugg_lines_vec = sugg.lines().collect::<Vec<&str>>();
let sugg_upper = sugg_lines_vec[..split_idx].join("\n");
let sugg_bottom = sugg_lines_vec[sugg_lines_count - split_idx..].join("\n");
diag.span_suggestion(span_upper, helps[0], sugg_upper, applicability);
diag.span_suggestion(span_bottom, helps[1], sugg_bottom, applicability);
return;
}
}
diag.span_suggestion_with_style(
sp,
&helps.join(", "),
sugg,
applicability,
rustc_errors::SuggestionStyle::ShowAlways,
);
});
}
/// Create a suggestion made from several `span → replacement`.
///
/// Note: in the JSON format (used by `compiletest_rs`), the help message will

View File

@ -12,14 +12,12 @@ LL | | .flatten();
| |__________________^
|
= note: `-D clippy::map-flatten` implied by `-D warnings`
help: try replacing `map` with `and_then`
help: try replacing `map` with `and_then` and remove the `.flatten()`
|
LL ~ .and_then(|x| {
LL + if x <= 5 {
LL + Some(x)
|
help: and remove the `.flatten()`
|
LL + } else {
LL + None
LL + }
LL ~ });
@ -38,14 +36,12 @@ LL | | })
LL | | .flatten();
| |__________________^
|
help: try replacing `map` with `and_then`
help: try replacing `map` with `and_then` and remove the `.flatten()`
|
LL ~ .and_then(|x| {
LL + if x == 1 {
LL + Ok(x)
|
help: and remove the `.flatten()`
|
LL + } else {
LL + Err(0)
LL + }
LL ~ });
@ -64,14 +60,13 @@ LL | | })
LL | | .flatten();
| |__________________^
|
help: try replacing `map` with `and_then`
help: try replacing `map` with `and_then` and remove the `.flatten()`
|
LL ~ .and_then(|res| {
LL + if res > 0 {
LL + do_something();
|
help: and remove the `.flatten()`
|
LL + Ok(res)
LL + } else {
LL + Err(0)
LL + }
LL ~ });
@ -90,14 +85,12 @@ LL | | })
LL | | .flatten()
| |__________________^
|
help: try replacing `map` with `filter_map`
help: try replacing `map` with `filter_map` and remove the `.flatten()`
|
LL ~ .filter_map(|some_value| {
LL + if some_value > 3 {
LL + Some(some_value)
|
help: and remove the `.flatten()`
|
LL + } else {
LL + None
LL + }
LL + })

View File

@ -59,8 +59,6 @@ fn issue8878() {
.and_then(|_| {
// we need some newlines
// so that the span is big enough
// we need some newlines
// so that the span is big enough
// for a splitted output of the diagnostic
Some("")
// whitespace beforehand is important as well

View File

@ -2,79 +2,45 @@ error: called `map(..).flatten()` on `Iterator`
--> $DIR/map_flatten_fixable.rs:18:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id)`
|
= note: `-D clippy::map-flatten` implied by `-D warnings`
help: try replacing `map` with `filter_map`, and remove the `.flatten()`
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id).collect();
| ~~~~~~~~~~~~~~~~~~~~~
error: called `map(..).flatten()` on `Iterator`
--> $DIR/map_flatten_fixable.rs:19:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: try replacing `map` with `filter_map`, and remove the `.flatten()`
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_ref).collect();
| ~~~~~~~~~~~~~~~~~~~~~~~~~
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_ref)`
error: called `map(..).flatten()` on `Iterator`
--> $DIR/map_flatten_fixable.rs:20:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: try replacing `map` with `filter_map`, and remove the `.flatten()`
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_closure).collect();
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_closure)`
error: called `map(..).flatten()` on `Iterator`
--> $DIR/map_flatten_fixable.rs:21:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: try replacing `map` with `filter_map`, and remove the `.flatten()`
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(|x| x.checked_add(1)).collect();
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(|x| x.checked_add(1))`
error: called `map(..).flatten()` on `Iterator`
--> $DIR/map_flatten_fixable.rs:24:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: try replacing `map` with `flat_map`, and remove the `.flatten()`
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect();
| ~~~~~~~~~~~~~~~~~~
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| 0..x)`
error: called `map(..).flatten()` on `Option`
--> $DIR/map_flatten_fixable.rs:27:40
|
LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
| ^^^^^^^^^^^^^^^^^^^^
|
help: try replacing `map` with `and_then`, and remove the `.flatten()`
|
LL | let _: Option<_> = (Some(Some(1))).and_then(|x| x);
| ~~~~~~~~~~~~~~~
| ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)`
error: called `map(..).flatten()` on `Result`
--> $DIR/map_flatten_fixable.rs:30:42
|
LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
| ^^^^^^^^^^^^^^^^^^^^
|
help: try replacing `map` with `and_then`, and remove the `.flatten()`
|
LL | let _: Result<_, &str> = (Ok(Ok(1))).and_then(|x| x);
| ~~~~~~~~~~~~~~~
| ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)`
error: called `map(..).flatten()` on `Option`
--> $DIR/map_flatten_fixable.rs:59:10
@ -89,14 +55,12 @@ LL | | })
LL | | .flatten();
| |__________________^
|
help: try replacing `map` with `and_then`
help: try replacing `map` with `and_then` and remove the `.flatten()`
|
LL ~ .and_then(|_| {
LL + // we need some newlines
LL + // so that the span is big enough
|
help: and remove the `.flatten()`
|
LL + // for a splitted output of the diagnostic
LL + Some("")
LL + // whitespace beforehand is important as well
LL ~ });

View File

@ -185,8 +185,7 @@ mod issue8239 {
.reduce(|mut acc, f| {
acc.push_str(&f);
acc
})
.unwrap_or_default();
}).unwrap_or_default();
}
fn more_to_max_suggestion_highest_lines_1() {
@ -198,8 +197,7 @@ mod issue8239 {
let _ = "";
acc.push_str(&f);
acc
})
.unwrap_or_default();
}).unwrap_or_default();
}
fn equal_to_max_suggestion_highest_lines() {

View File

@ -109,16 +109,50 @@ LL | None.unwrap_or( unsafe { ptr_to_ref(s) } );
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
error: use of `unwrap_or` followed by a call to `new`
--> $DIR/or_fun_call.rs:189:14
--> $DIR/or_fun_call.rs:182:9
|
LL | / frames
LL | | .iter()
LL | | .map(|f: &String| f.to_lowercase())
LL | | .reduce(|mut acc, f| {
... |
LL | | })
LL | | .unwrap_or(String::new());
| |_____________________________________^
|
help: try this
|
LL ~ frames
LL + .iter()
LL + .map(|f: &String| f.to_lowercase())
LL + .reduce(|mut acc, f| {
LL + acc.push_str(&f);
LL + acc
LL ~ }).unwrap_or_default();
|
LL | .unwrap_or(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
error: use of `unwrap_or` followed by a call to `new`
--> $DIR/or_fun_call.rs:202:14
--> $DIR/or_fun_call.rs:195:9
|
LL | / iter.map(|f: &String| f.to_lowercase())
LL | | .reduce(|mut acc, f| {
LL | | let _ = "";
LL | | let _ = "";
... |
LL | | })
LL | | .unwrap_or(String::new());
| |_____________________________________^
|
help: try this
|
LL ~ iter.map(|f: &String| f.to_lowercase())
LL + .reduce(|mut acc, f| {
LL + let _ = "";
LL + let _ = "";
LL + acc.push_str(&f);
LL + acc
LL ~ }).unwrap_or_default();
|
LL | .unwrap_or(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
error: use of `unwrap_or` followed by a call to `new`
--> $DIR/or_fun_call.rs:208:9