Auto merge of #82443 - Dylan-DPC:rollup-yni7uio, r=Dylan-DPC
Rollup of 10 pull requests Successful merges: - #81629 (Point out implicit deref coercions in borrow) - #82113 (Improve non_fmt_panic lint.) - #82258 (Implement -Z hir-stats for nested foreign items) - #82296 (Support `pub` on `macro_rules`) - #82297 (Consider auto derefs before warning about write only fields) - #82305 (Remove many RefCells from DocContext) - #82308 (Lower condition of `if` expression before it's "then" block) - #82311 (Jsondocck improvements) - #82362 (Fix mir-cfg dumps) - #82391 (disable atomic_max/min tests in Miri) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
fe1bf8e05c
66 changed files with 1160 additions and 157 deletions
|
@ -347,8 +347,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
) -> hir::ExprKind<'hir> {
|
||||
macro_rules! make_if {
|
||||
($opt:expr) => {{
|
||||
let cond = self.lower_expr(cond);
|
||||
let then_expr = self.lower_block_expr(then);
|
||||
hir::ExprKind::If(self.lower_expr(cond), self.arena.alloc(then_expr), $opt)
|
||||
hir::ExprKind::If(cond, self.arena.alloc(then_expr), $opt)
|
||||
}};
|
||||
}
|
||||
if let Some(rslt) = else_opt {
|
||||
|
|
|
@ -665,6 +665,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
|||
// involved, so we only emit errors where there are no other parsing errors.
|
||||
gate_all!(destructuring_assignment, "destructuring assignments are unstable");
|
||||
}
|
||||
gate_all!(pub_macro_rules, "`pub` on `macro_rules` items is unstable");
|
||||
|
||||
// All uses of `gate_all!` below this point were added in #65742,
|
||||
// and subsequently disabled (with the non-early gating readded).
|
||||
|
|
|
@ -638,6 +638,9 @@ declare_features! (
|
|||
/// Allows macro attributes to observe output of `#[derive]`.
|
||||
(active, macro_attributes_in_derive_output, "1.51.0", Some(81119), None),
|
||||
|
||||
/// Allows `pub` on `macro_rules` items.
|
||||
(active, pub_macro_rules, "1.52.0", Some(78855), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
|
@ -69,23 +69,65 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
|||
|
||||
let (span, panic) = panic_call(cx, f);
|
||||
|
||||
cx.struct_span_lint(NON_FMT_PANIC, arg.span, |lint| {
|
||||
// Find the span of the argument to `panic!()`, before expansion in the
|
||||
// case of `panic!(some_macro!())`.
|
||||
// We don't use source_callsite(), because this `panic!(..)` might itself
|
||||
// be expanded from another macro, in which case we want to stop at that
|
||||
// expansion.
|
||||
let mut arg_span = arg.span;
|
||||
let mut arg_macro = None;
|
||||
while !span.contains(arg_span) {
|
||||
let expn = arg_span.ctxt().outer_expn_data();
|
||||
if expn.is_root() {
|
||||
break;
|
||||
}
|
||||
arg_macro = expn.macro_def_id;
|
||||
arg_span = expn.call_site;
|
||||
}
|
||||
|
||||
cx.struct_span_lint(NON_FMT_PANIC, arg_span, |lint| {
|
||||
let mut l = lint.build("panic message is not a string literal");
|
||||
l.note("this is no longer accepted in Rust 2021");
|
||||
if span.contains(arg.span) {
|
||||
if !span.contains(arg_span) {
|
||||
// No clue where this argument is coming from.
|
||||
l.emit();
|
||||
return;
|
||||
}
|
||||
if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
|
||||
// A case of `panic!(format!(..))`.
|
||||
l.note("the panic!() macro supports formatting, so there's no need for the format!() macro here");
|
||||
if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
|
||||
l.multipart_suggestion(
|
||||
"remove the `format!(..)` macro call",
|
||||
vec![
|
||||
(arg_span.until(open.shrink_to_hi()), "".into()),
|
||||
(close.until(arg_span.shrink_to_hi()), "".into()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
l.span_suggestion_verbose(
|
||||
arg.span.shrink_to_lo(),
|
||||
arg_span.shrink_to_lo(),
|
||||
"add a \"{}\" format string to Display the message",
|
||||
"\"{}\", ".into(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
if panic == sym::std_panic_macro {
|
||||
l.span_suggestion_verbose(
|
||||
span.until(arg.span),
|
||||
"or use std::panic::panic_any instead",
|
||||
"std::panic::panic_any(".into(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
if let Some((open, close, del)) = find_delimiters(cx, span) {
|
||||
l.multipart_suggestion(
|
||||
"or use std::panic::panic_any instead",
|
||||
if del == '(' {
|
||||
vec![(span.until(open), "std::panic::panic_any".into())]
|
||||
} else {
|
||||
vec![
|
||||
(span.until(open.shrink_to_hi()), "std::panic::panic_any(".into()),
|
||||
(close, ")".into()),
|
||||
]
|
||||
},
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
l.emit();
|
||||
|
@ -175,6 +217,19 @@ fn check_panic_str<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Given the span of `some_macro!(args);`, gives the span of `(` and `)`,
|
||||
/// and the type of (opening) delimiter used.
|
||||
fn find_delimiters<'tcx>(cx: &LateContext<'tcx>, span: Span) -> Option<(Span, Span, char)> {
|
||||
let snippet = cx.sess().parse_sess.source_map().span_to_snippet(span).ok()?;
|
||||
let (open, open_ch) = snippet.char_indices().find(|&(_, c)| "([{".contains(c))?;
|
||||
let close = snippet.rfind(|c| ")]}".contains(c))?;
|
||||
Some((
|
||||
span.from_inner(InnerSpan { start: open, end: open + 1 }),
|
||||
span.from_inner(InnerSpan { start: close, end: close + 1 }),
|
||||
open_ch,
|
||||
))
|
||||
}
|
||||
|
||||
fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span, Symbol) {
|
||||
let mut expn = f.span.ctxt().outer_expn_data();
|
||||
|
||||
|
|
|
@ -8,11 +8,10 @@ use rustc_index::vec::Idx;
|
|||
use rustc_middle::mir::{
|
||||
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
|
||||
FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
|
||||
ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
|
||||
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
|
||||
};
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
|
||||
use rustc_span::source_map::DesugaringKind;
|
||||
use rustc_span::Span;
|
||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Instance, Ty};
|
||||
use rustc_span::{source_map::DesugaringKind, symbol::sym, Span};
|
||||
|
||||
use crate::dataflow::drop_flag_effects;
|
||||
use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex};
|
||||
|
@ -1543,9 +1542,43 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
None,
|
||||
);
|
||||
|
||||
self.explain_deref_coercion(loan, &mut err);
|
||||
|
||||
err.buffer(&mut self.errors_buffer);
|
||||
}
|
||||
|
||||
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) {
|
||||
let tcx = self.infcx.tcx;
|
||||
if let (
|
||||
Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
|
||||
Some((method_did, method_substs)),
|
||||
) = (
|
||||
&self.body[loan.reserve_location.block].terminator,
|
||||
crate::util::find_self_call(
|
||||
tcx,
|
||||
self.body,
|
||||
loan.assigned_place.local,
|
||||
loan.reserve_location.block,
|
||||
),
|
||||
) {
|
||||
if tcx.is_diagnostic_item(sym::deref_method, method_did) {
|
||||
let deref_target =
|
||||
tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
|
||||
Instance::resolve(tcx, self.param_env, deref_target, method_substs)
|
||||
.transpose()
|
||||
});
|
||||
if let Some(Ok(instance)) = deref_target {
|
||||
let deref_target_ty = instance.ty(tcx, self.param_env);
|
||||
err.note(&format!(
|
||||
"borrow occurs due to deref coercion to `{}`",
|
||||
deref_target_ty
|
||||
));
|
||||
err.span_note(tcx.def_span(instance.def_id()), "deref defined here");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reports an illegal reassignment; for example, an assignment to
|
||||
/// (part of) a non-`mut` local that occurs potentially after that
|
||||
/// local has already been initialized. `place` is the path being
|
||||
|
|
|
@ -2,7 +2,7 @@ use gsgdt::GraphvizSettings;
|
|||
use rustc_graphviz as dot;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use std::fmt::Debug;
|
||||
use std::io::{self, Write};
|
||||
|
||||
|
@ -16,14 +16,27 @@ where
|
|||
{
|
||||
let def_ids = dump_mir_def_ids(tcx, single);
|
||||
|
||||
let use_subgraphs = def_ids.len() > 1;
|
||||
let mirs =
|
||||
def_ids
|
||||
.iter()
|
||||
.flat_map(|def_id| {
|
||||
if tcx.is_const_fn_raw(*def_id) {
|
||||
vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)]
|
||||
} else {
|
||||
vec![tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown(
|
||||
*def_id,
|
||||
)))]
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let use_subgraphs = mirs.len() > 1;
|
||||
if use_subgraphs {
|
||||
writeln!(w, "digraph __crate__ {{")?;
|
||||
}
|
||||
|
||||
for def_id in def_ids {
|
||||
let body = &tcx.optimized_mir(def_id);
|
||||
write_mir_fn_graphviz(tcx, body, use_subgraphs, w)?;
|
||||
for mir in mirs {
|
||||
write_mir_fn_graphviz(tcx, mir, use_subgraphs, w)?;
|
||||
}
|
||||
|
||||
if use_subgraphs {
|
||||
|
|
|
@ -1475,15 +1475,7 @@ impl<'a> Parser<'a> {
|
|||
let vstr = pprust::vis_to_string(vis);
|
||||
let vstr = vstr.trim_end();
|
||||
if macro_rules {
|
||||
let msg = format!("can't qualify macro_rules invocation with `{}`", vstr);
|
||||
self.struct_span_err(vis.span, &msg)
|
||||
.span_suggestion(
|
||||
vis.span,
|
||||
"try exporting the macro",
|
||||
"#[macro_export]".to_owned(),
|
||||
Applicability::MaybeIncorrect, // speculative
|
||||
)
|
||||
.emit();
|
||||
self.sess.gated_spans.gate(sym::pub_macro_rules, vis.span);
|
||||
} else {
|
||||
self.struct_span_err(vis.span, "can't qualify macro invocation with `pub`")
|
||||
.span_suggestion(
|
||||
|
|
|
@ -37,15 +37,6 @@ fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
|
|||
)
|
||||
}
|
||||
|
||||
fn base_expr<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
|
||||
loop {
|
||||
match expr.kind {
|
||||
hir::ExprKind::Field(base, ..) => expr = base,
|
||||
_ => return expr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MarkSymbolVisitor<'tcx> {
|
||||
worklist: Vec<hir::HirId>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -143,6 +134,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_assign(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
if self
|
||||
.typeck_results()
|
||||
.expr_adjustments(expr)
|
||||
.iter()
|
||||
.any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(_)))
|
||||
{
|
||||
self.visit_expr(expr);
|
||||
} else if let hir::ExprKind::Field(base, ..) = expr.kind {
|
||||
// Ignore write to field
|
||||
self.handle_assign(base);
|
||||
} else {
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_field_pattern_match(
|
||||
&mut self,
|
||||
lhs: &hir::Pat<'_>,
|
||||
|
@ -272,8 +279,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
|
|||
self.lookup_and_handle_method(expr.hir_id);
|
||||
}
|
||||
hir::ExprKind::Assign(ref left, ref right, ..) => {
|
||||
// Ignore write to field
|
||||
self.visit_expr(base_expr(left));
|
||||
self.handle_assign(left);
|
||||
self.visit_expr(right);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -114,6 +114,11 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
|||
self.visit_impl_item(nested_impl_item)
|
||||
}
|
||||
|
||||
fn visit_nested_foreign_item(&mut self, id: hir::ForeignItemId) {
|
||||
let nested_foreign_item = self.krate.unwrap().foreign_item(id);
|
||||
self.visit_foreign_item(nested_foreign_item);
|
||||
}
|
||||
|
||||
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
|
||||
let nested_body = self.krate.unwrap().body(body_id);
|
||||
self.visit_body(nested_body)
|
||||
|
|
|
@ -1230,13 +1230,13 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
};
|
||||
|
||||
let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id.to_def_id());
|
||||
let is_macro_export = self.r.session.contains_name(&item.attrs, sym::macro_export);
|
||||
self.r.macro_map.insert(def_id.to_def_id(), ext);
|
||||
self.r.local_macro_def_scopes.insert(def_id, parent_scope.module);
|
||||
|
||||
if macro_rules {
|
||||
if macro_rules && matches!(item.vis.kind, ast::VisibilityKind::Inherited) {
|
||||
let ident = ident.normalize_to_macros_2_0();
|
||||
self.r.macro_names.insert(ident);
|
||||
let is_macro_export = self.r.session.contains_name(&item.attrs, sym::macro_export);
|
||||
let vis = if is_macro_export {
|
||||
ty::Visibility::Public
|
||||
} else {
|
||||
|
@ -1261,6 +1261,11 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
}),
|
||||
))
|
||||
} else {
|
||||
if is_macro_export {
|
||||
let what = if macro_rules { "`macro_rules` with `pub`" } else { "`macro` items" };
|
||||
let msg = format!("`#[macro_export]` cannot be used on {what}");
|
||||
self.r.session.span_err(item.span, &msg);
|
||||
}
|
||||
let module = parent_scope.module;
|
||||
let vis = match item.kind {
|
||||
// Visibilities must not be resolved non-speculatively twice
|
||||
|
|
|
@ -560,6 +560,7 @@ symbols! {
|
|||
format_args,
|
||||
format_args_capture,
|
||||
format_args_nl,
|
||||
format_macro,
|
||||
freeze,
|
||||
freg,
|
||||
frem_fast,
|
||||
|
@ -880,6 +881,7 @@ symbols! {
|
|||
ptr_guaranteed_eq,
|
||||
ptr_guaranteed_ne,
|
||||
ptr_offset_from,
|
||||
pub_macro_rules,
|
||||
pub_restricted,
|
||||
pure,
|
||||
pushpop_unsafe,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue