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
@ -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,
|
||||
|
@ -107,6 +107,7 @@ macro_rules! vec {
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "format_macro")]
|
||||
macro_rules! format {
|
||||
($($arg:tt)*) => {{
|
||||
let res = $crate::fmt::format($crate::__export::format_args!($($arg)*));
|
||||
|
@ -61,6 +61,7 @@ fn uint_xor() {
|
||||
|
||||
#[test]
|
||||
#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
|
||||
#[cfg_attr(miri, ignore)] // FIXME: Miri does not support atomic_min
|
||||
fn uint_min() {
|
||||
let x = AtomicUsize::new(0xf731);
|
||||
assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731);
|
||||
@ -71,6 +72,7 @@ fn uint_min() {
|
||||
|
||||
#[test]
|
||||
#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
|
||||
#[cfg_attr(miri, ignore)] // FIXME: Miri does not support atomic_max
|
||||
fn uint_max() {
|
||||
let x = AtomicUsize::new(0x137f);
|
||||
assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f);
|
||||
@ -109,6 +111,7 @@ fn int_xor() {
|
||||
|
||||
#[test]
|
||||
#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
|
||||
#[cfg_attr(miri, ignore)] // FIXME: Miri does not support atomic_min
|
||||
fn int_min() {
|
||||
let x = AtomicIsize::new(0xf731);
|
||||
assert_eq!(x.fetch_min(0x137f, SeqCst), 0xf731);
|
||||
@ -119,6 +122,7 @@ fn int_min() {
|
||||
|
||||
#[test]
|
||||
#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
|
||||
#[cfg_attr(miri, ignore)] // FIXME: Miri does not support atomic_max
|
||||
fn int_max() {
|
||||
let x = AtomicIsize::new(0x137f);
|
||||
assert_eq!(x.fetch_max(0xf731, SeqCst), 0x137f);
|
||||
|
@ -41,7 +41,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||
) -> Option<Item> {
|
||||
let tcx = self.cx.tcx;
|
||||
let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) };
|
||||
if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) {
|
||||
if !self.cx.generated_synthetics.insert((ty, trait_def_id)) {
|
||||
debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref);
|
||||
return None;
|
||||
}
|
||||
|
@ -22,8 +22,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
|
||||
debug!("get_blanket_impls({:?})", ty);
|
||||
let mut impls = Vec::new();
|
||||
for &trait_def_id in self.cx.tcx.all_traits(LOCAL_CRATE).iter() {
|
||||
if !self.cx.renderinfo.borrow().access_levels.is_public(trait_def_id)
|
||||
|| self.cx.generated_synthetics.borrow_mut().get(&(ty, trait_def_id)).is_some()
|
||||
if !self.cx.renderinfo.access_levels.is_public(trait_def_id)
|
||||
|| self.cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -94,7 +94,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id));
|
||||
self.cx.generated_synthetics.insert((ty, trait_def_id));
|
||||
let provided_trait_methods = self
|
||||
.cx
|
||||
.tcx
|
||||
|
@ -122,7 +122,7 @@ crate fn try_inline(
|
||||
let target_attrs = load_attrs(cx, did);
|
||||
let attrs = box merge_attrs(cx, Some(parent_module), target_attrs, attrs_clone);
|
||||
|
||||
cx.renderinfo.borrow_mut().inlined.insert(did);
|
||||
cx.renderinfo.inlined.insert(did);
|
||||
let what_rustc_thinks = clean::Item::from_def_id_and_parts(did, Some(name), kind, cx);
|
||||
ret.push(clean::Item { attrs, ..what_rustc_thinks });
|
||||
Some(ret)
|
||||
@ -156,7 +156,7 @@ crate fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> {
|
||||
///
|
||||
/// These names are used later on by HTML rendering to generate things like
|
||||
/// source links back to the original item.
|
||||
crate fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKind) {
|
||||
crate fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: clean::TypeKind) {
|
||||
let crate_name = cx.tcx.crate_name(did.krate).to_string();
|
||||
|
||||
let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| {
|
||||
@ -181,9 +181,9 @@ crate fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKin
|
||||
};
|
||||
|
||||
if did.is_local() {
|
||||
cx.renderinfo.borrow_mut().exact_paths.insert(did, fqn);
|
||||
cx.renderinfo.exact_paths.insert(did, fqn);
|
||||
} else {
|
||||
cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind));
|
||||
cx.renderinfo.external_paths.insert(did, (fqn, kind));
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,7 +317,7 @@ crate fn build_impl(
|
||||
attrs: Option<Attrs<'_>>,
|
||||
ret: &mut Vec<clean::Item>,
|
||||
) {
|
||||
if !cx.renderinfo.borrow_mut().inlined.insert(did) {
|
||||
if !cx.renderinfo.inlined.insert(did) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -329,7 +329,7 @@ crate fn build_impl(
|
||||
if !did.is_local() {
|
||||
if let Some(traitref) = associated_trait {
|
||||
let did = traitref.def_id;
|
||||
if !cx.renderinfo.borrow().access_levels.is_public(did) {
|
||||
if !cx.renderinfo.access_levels.is_public(did) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -361,7 +361,7 @@ crate fn build_impl(
|
||||
// reachable in rustdoc generated documentation
|
||||
if !did.is_local() {
|
||||
if let Some(did) = for_.def_id() {
|
||||
if !cx.renderinfo.borrow().access_levels.is_public(did) {
|
||||
if !cx.renderinfo.access_levels.is_public(did) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -613,20 +613,19 @@ crate fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
|
||||
}
|
||||
|
||||
{
|
||||
if cx.external_traits.borrow().contains_key(&did)
|
||||
|| cx.active_extern_traits.borrow().contains(&did)
|
||||
if cx.external_traits.borrow().contains_key(&did) || cx.active_extern_traits.contains(&did)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
cx.active_extern_traits.borrow_mut().insert(did);
|
||||
cx.active_extern_traits.insert(did);
|
||||
}
|
||||
|
||||
debug!("record_extern_trait: {:?}", did);
|
||||
let trait_ = build_external_trait(cx, did);
|
||||
|
||||
cx.external_traits.borrow_mut().insert(did, trait_);
|
||||
cx.active_extern_traits.borrow_mut().remove(&did);
|
||||
cx.active_extern_traits.remove(&did);
|
||||
}
|
||||
|
@ -357,7 +357,7 @@ impl Clean<Lifetime> for hir::Lifetime {
|
||||
| rl::Region::LateBound(_, node_id, _)
|
||||
| rl::Region::Free(_, node_id),
|
||||
) => {
|
||||
if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() {
|
||||
if let Some(lt) = cx.lt_substs.get(&node_id).cloned() {
|
||||
return lt;
|
||||
}
|
||||
}
|
||||
@ -644,7 +644,7 @@ impl Clean<Generics> for hir::Generics<'_> {
|
||||
match param.kind {
|
||||
GenericParamDefKind::Lifetime => unreachable!(),
|
||||
GenericParamDefKind::Type { did, ref bounds, .. } => {
|
||||
cx.impl_trait_bounds.borrow_mut().insert(did.into(), bounds.clone());
|
||||
cx.impl_trait_bounds.insert(did.into(), bounds.clone());
|
||||
}
|
||||
GenericParamDefKind::Const { .. } => unreachable!(),
|
||||
}
|
||||
@ -803,7 +803,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
cx.impl_trait_bounds.borrow_mut().insert(param, bounds);
|
||||
cx.impl_trait_bounds.insert(param, bounds);
|
||||
}
|
||||
|
||||
// Now that `cx.impl_trait_bounds` is populated, we can process
|
||||
@ -1291,10 +1291,10 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
|
||||
match qpath {
|
||||
hir::QPath::Resolved(None, ref path) => {
|
||||
if let Res::Def(DefKind::TyParam, did) = path.res {
|
||||
if let Some(new_ty) = cx.ty_substs.borrow().get(&did).cloned() {
|
||||
if let Some(new_ty) = cx.ty_substs.get(&did).cloned() {
|
||||
return new_ty;
|
||||
}
|
||||
if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did.into()) {
|
||||
if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) {
|
||||
return ImplTrait(bounds);
|
||||
}
|
||||
}
|
||||
@ -1304,7 +1304,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
|
||||
// Substitute private type aliases
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
if !cx.renderinfo.borrow().access_levels.is_exported(def_id.to_def_id()) {
|
||||
if !cx.renderinfo.access_levels.is_exported(def_id.to_def_id()) {
|
||||
alias = Some(&cx.tcx.hir().expect_item(hir_id).kind);
|
||||
}
|
||||
}
|
||||
@ -1651,7 +1651,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
|
||||
ty::Projection(ref data) => data.clean(cx),
|
||||
|
||||
ty::Param(ref p) => {
|
||||
if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&p.index.into()) {
|
||||
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
|
||||
ImplTrait(bounds)
|
||||
} else {
|
||||
Generic(p.name)
|
||||
|
@ -23,10 +23,9 @@ crate fn krate(mut cx: &mut DocContext<'_>) -> Crate {
|
||||
let krate = cx.tcx.hir().krate();
|
||||
let module = crate::visit_ast::RustdocVisitor::new(&mut cx).visit(krate);
|
||||
|
||||
let mut r = cx.renderinfo.get_mut();
|
||||
r.deref_trait_did = cx.tcx.lang_items().deref_trait();
|
||||
r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait();
|
||||
r.owned_box_did = cx.tcx.lang_items().owned_box();
|
||||
cx.renderinfo.deref_trait_did = cx.tcx.lang_items().deref_trait();
|
||||
cx.renderinfo.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait();
|
||||
cx.renderinfo.owned_box_did = cx.tcx.lang_items().owned_box();
|
||||
|
||||
let mut externs = Vec::new();
|
||||
for &cnum in cx.tcx.crates().iter() {
|
||||
@ -494,10 +493,10 @@ crate fn enter_impl_trait<F, R>(cx: &mut DocContext<'_>, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut DocContext<'_>) -> R,
|
||||
{
|
||||
let old_bounds = mem::take(&mut *cx.impl_trait_bounds.get_mut());
|
||||
let old_bounds = mem::take(&mut cx.impl_trait_bounds);
|
||||
let r = f(cx);
|
||||
assert!(cx.impl_trait_bounds.borrow().is_empty());
|
||||
*cx.impl_trait_bounds.get_mut() = old_bounds;
|
||||
assert!(cx.impl_trait_bounds.is_empty());
|
||||
cx.impl_trait_bounds = old_bounds;
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -42,32 +42,37 @@ crate type ExternalPaths = FxHashMap<DefId, (Vec<String>, clean::TypeKind)>;
|
||||
|
||||
crate struct DocContext<'tcx> {
|
||||
crate tcx: TyCtxt<'tcx>,
|
||||
/// Name resolver. Used for intra-doc links.
|
||||
///
|
||||
/// The `Rc<RefCell<...>>` wrapping is needed because that is what's returned by
|
||||
/// [`Queries::expansion()`].
|
||||
// FIXME: see if we can get rid of this RefCell somehow
|
||||
crate resolver: Rc<RefCell<interface::BoxedResolver>>,
|
||||
/// Used for normalization.
|
||||
///
|
||||
/// Most of this logic is copied from rustc_lint::late.
|
||||
crate param_env: ParamEnv<'tcx>,
|
||||
/// Later on moved into `cache`
|
||||
crate renderinfo: RefCell<RenderInfo>,
|
||||
crate renderinfo: RenderInfo,
|
||||
/// Later on moved through `clean::Crate` into `cache`
|
||||
crate external_traits: Rc<RefCell<FxHashMap<DefId, clean::Trait>>>,
|
||||
/// Used while populating `external_traits` to ensure we don't process the same trait twice at
|
||||
/// the same time.
|
||||
crate active_extern_traits: RefCell<FxHashSet<DefId>>,
|
||||
crate active_extern_traits: FxHashSet<DefId>,
|
||||
// The current set of type and lifetime substitutions,
|
||||
// for expanding type aliases at the HIR level:
|
||||
/// Table `DefId` of type parameter -> substituted type
|
||||
crate ty_substs: RefCell<FxHashMap<DefId, clean::Type>>,
|
||||
crate ty_substs: FxHashMap<DefId, clean::Type>,
|
||||
/// Table `DefId` of lifetime parameter -> substituted lifetime
|
||||
crate lt_substs: RefCell<FxHashMap<DefId, clean::Lifetime>>,
|
||||
crate lt_substs: FxHashMap<DefId, clean::Lifetime>,
|
||||
/// Table `DefId` of const parameter -> substituted const
|
||||
crate ct_substs: RefCell<FxHashMap<DefId, clean::Constant>>,
|
||||
crate ct_substs: FxHashMap<DefId, clean::Constant>,
|
||||
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
|
||||
crate impl_trait_bounds: RefCell<FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>>,
|
||||
crate impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
|
||||
crate fake_def_ids: FxHashMap<CrateNum, DefIndex>,
|
||||
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
|
||||
// FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
|
||||
crate generated_synthetics: RefCell<FxHashSet<(Ty<'tcx>, DefId)>>,
|
||||
crate generated_synthetics: FxHashSet<(Ty<'tcx>, DefId)>,
|
||||
crate auto_traits: Vec<DefId>,
|
||||
/// The options given to rustdoc that could be relevant to a pass.
|
||||
crate render_options: RenderOptions,
|
||||
@ -112,14 +117,14 @@ impl<'tcx> DocContext<'tcx> {
|
||||
F: FnOnce(&mut Self) -> R,
|
||||
{
|
||||
let (old_tys, old_lts, old_cts) = (
|
||||
mem::replace(&mut *self.ty_substs.get_mut(), ty_substs),
|
||||
mem::replace(&mut *self.lt_substs.get_mut(), lt_substs),
|
||||
mem::replace(&mut *self.ct_substs.get_mut(), ct_substs),
|
||||
mem::replace(&mut self.ty_substs, ty_substs),
|
||||
mem::replace(&mut self.lt_substs, lt_substs),
|
||||
mem::replace(&mut self.ct_substs, ct_substs),
|
||||
);
|
||||
let r = f(self);
|
||||
*self.ty_substs.get_mut() = old_tys;
|
||||
*self.lt_substs.get_mut() = old_lts;
|
||||
*self.ct_substs.get_mut() = old_cts;
|
||||
self.ty_substs = old_tys;
|
||||
self.lt_substs = old_lts;
|
||||
self.ct_substs = old_cts;
|
||||
r
|
||||
}
|
||||
|
||||
@ -509,7 +514,7 @@ crate fn run_global_ctxt(
|
||||
param_env: ParamEnv::empty(),
|
||||
external_traits: Default::default(),
|
||||
active_extern_traits: Default::default(),
|
||||
renderinfo: RefCell::new(renderinfo),
|
||||
renderinfo,
|
||||
ty_substs: Default::default(),
|
||||
lt_substs: Default::default(),
|
||||
ct_substs: Default::default(),
|
||||
@ -642,7 +647,7 @@ crate fn run_global_ctxt(
|
||||
// The main crate doc comments are always collapsed.
|
||||
krate.collapsed = true;
|
||||
|
||||
(krate, ctxt.renderinfo.into_inner(), ctxt.render_options)
|
||||
(krate, ctxt.renderinfo, ctxt.render_options)
|
||||
}
|
||||
|
||||
/// Due to <https://github.com/rust-lang/rust/pull/73566>,
|
||||
|
@ -127,7 +127,7 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> {
|
||||
}
|
||||
|
||||
fn print_results(&self) {
|
||||
let output_format = self.ctx.renderinfo.borrow().output_format;
|
||||
let output_format = self.ctx.renderinfo.output_format;
|
||||
if output_format.is_json() {
|
||||
println!("{}", self.to_json());
|
||||
return;
|
||||
|
@ -48,11 +48,10 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
|
||||
if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
|
||||
let self_ty = cx.tcx.type_of(def_id);
|
||||
let impls = get_auto_trait_and_blanket_impls(cx, self_ty, def_id);
|
||||
let mut renderinfo = cx.renderinfo.borrow_mut();
|
||||
|
||||
new_items.extend(impls.filter(|i| renderinfo.inlined.insert(i.def_id)));
|
||||
new_items.extend(impls.filter(|i| cx.renderinfo.inlined.insert(i.def_id)));
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,8 +97,7 @@ crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
|
||||
|lint| lint.build("missing code example in this documentation").emit(),
|
||||
);
|
||||
}
|
||||
} else if tests.found_tests > 0 && !cx.renderinfo.borrow().access_levels.is_public(item.def_id)
|
||||
{
|
||||
} else if tests.found_tests > 0 && !cx.renderinfo.access_levels.is_public(item.def_id) {
|
||||
cx.tcx.struct_span_lint_hir(
|
||||
lint::builtin::PRIVATE_DOC_TESTS,
|
||||
hir_id,
|
||||
|
@ -17,7 +17,7 @@ crate const STRIP_PRIVATE: Pass = Pass {
|
||||
crate fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
|
||||
// This stripper collects all *retained* nodes.
|
||||
let mut retained = DefIdSet::default();
|
||||
let access_levels = cx.renderinfo.borrow().access_levels.clone();
|
||||
let access_levels = cx.renderinfo.access_levels.clone();
|
||||
|
||||
// strip all private items
|
||||
{
|
||||
|
@ -113,7 +113,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
assert_eq!(cur_mod_def_id, macro_parent_def_id);
|
||||
cur_mod.macros.push((def, None));
|
||||
}
|
||||
self.cx.renderinfo.get_mut().exact_paths = self.exact_paths;
|
||||
self.cx.renderinfo.exact_paths = self.exact_paths;
|
||||
top_level_module
|
||||
}
|
||||
|
||||
@ -199,12 +199,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
} else {
|
||||
// All items need to be handled here in case someone wishes to link
|
||||
// to them with intra-doc links
|
||||
self.cx
|
||||
.renderinfo
|
||||
.get_mut()
|
||||
.access_levels
|
||||
.map
|
||||
.insert(did, AccessLevel::Public);
|
||||
self.cx.renderinfo.access_levels.map.insert(did, AccessLevel::Public);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -216,7 +211,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let is_private = !self.cx.renderinfo.borrow().access_levels.is_public(res_did);
|
||||
let is_private = !self.cx.renderinfo.access_levels.is_public(res_did);
|
||||
let is_hidden = inherits_doc_hidden(self.cx, res_hir_id);
|
||||
|
||||
// Only inline if requested or if the item would otherwise be stripped.
|
||||
|
@ -25,7 +25,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> {
|
||||
crate fn new(cx: &'a mut crate::core::DocContext<'tcx>) -> LibEmbargoVisitor<'a, 'tcx> {
|
||||
LibEmbargoVisitor {
|
||||
tcx: cx.tcx,
|
||||
access_levels: &mut cx.renderinfo.get_mut().access_levels,
|
||||
access_levels: &mut cx.renderinfo.access_levels,
|
||||
prev_level: Some(AccessLevel::Public),
|
||||
visited_mods: FxHashSet::default(),
|
||||
}
|
||||
|
@ -1,24 +1,28 @@
|
||||
// edition:2018
|
||||
|
||||
// @has nested.json "$.index[*][?(@.name=='nested')].kind" \"module\"
|
||||
// @has - "$.index[*][?(@.name=='nested')].inner.is_crate" true
|
||||
// @is nested.json "$.index[*][?(@.name=='nested')].kind" \"module\"
|
||||
// @is - "$.index[*][?(@.name=='nested')].inner.is_crate" true
|
||||
// @count - "$.index[*][?(@.name=='nested')].inner.items[*]" 1
|
||||
|
||||
// @has nested.json "$.index[*][?(@.name=='l1')].kind" \"module\"
|
||||
// @has - "$.index[*][?(@.name=='l1')].inner.is_crate" false
|
||||
// @is nested.json "$.index[*][?(@.name=='l1')].kind" \"module\"
|
||||
// @is - "$.index[*][?(@.name=='l1')].inner.is_crate" false
|
||||
// @count - "$.index[*][?(@.name=='l1')].inner.items[*]" 2
|
||||
pub mod l1 {
|
||||
|
||||
// @has nested.json "$.index[*][?(@.name=='l3')].kind" \"module\"
|
||||
// @has - "$.index[*][?(@.name=='l3')].inner.is_crate" false
|
||||
// @is nested.json "$.index[*][?(@.name=='l3')].kind" \"module\"
|
||||
// @is - "$.index[*][?(@.name=='l3')].inner.is_crate" false
|
||||
// @count - "$.index[*][?(@.name=='l3')].inner.items[*]" 1
|
||||
// @set l3_id = - "$.index[*][?(@.name=='l3')].id"
|
||||
// @has - "$.index[*][?(@.name=='l1')].inner.items[*]" $l3_id
|
||||
pub mod l3 {
|
||||
|
||||
// @has nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\"
|
||||
// @has - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\"
|
||||
// @is nested.json "$.index[*][?(@.name=='L4')].kind" \"struct\"
|
||||
// @is - "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\"
|
||||
// @set l4_id = - "$.index[*][?(@.name=='L4')].id"
|
||||
// @has - "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id
|
||||
pub struct L4;
|
||||
}
|
||||
// @has nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\"
|
||||
// @has - "$.index[*][?(@.inner.span=='l3::L4')].inner.glob" false
|
||||
// @is nested.json "$.index[*][?(@.inner.span=='l3::L4')].kind" \"import\"
|
||||
// @is - "$.index[*][?(@.inner.span=='l3::L4')].inner.glob" false
|
||||
pub use l3::L4;
|
||||
}
|
||||
|
26
src/test/ui/borrowck/issue-81365-1.rs
Normal file
26
src/test/ui/borrowck/issue-81365-1.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
struct DerefTarget {
|
||||
target_field: bool,
|
||||
}
|
||||
struct Container {
|
||||
target: DerefTarget,
|
||||
container_field: bool,
|
||||
}
|
||||
|
||||
impl Deref for Container {
|
||||
type Target = DerefTarget;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.target
|
||||
}
|
||||
}
|
||||
|
||||
impl Container {
|
||||
fn bad_borrow(&mut self) {
|
||||
let first = &self.target_field;
|
||||
self.container_field = true; //~ ERROR E0506
|
||||
first;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
20
src/test/ui/borrowck/issue-81365-1.stderr
Normal file
20
src/test/ui/borrowck/issue-81365-1.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error[E0506]: cannot assign to `self.container_field` because it is borrowed
|
||||
--> $DIR/issue-81365-1.rs:21:9
|
||||
|
|
||||
LL | let first = &self.target_field;
|
||||
| ---- borrow of `self.container_field` occurs here
|
||||
LL | self.container_field = true;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
|
||||
LL | first;
|
||||
| ----- borrow later used here
|
||||
|
|
||||
= note: borrow occurs due to deref coercion to `DerefTarget`
|
||||
note: deref defined here
|
||||
--> $DIR/issue-81365-1.rs:12:5
|
||||
|
|
||||
LL | type Target = DerefTarget;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0506`.
|
26
src/test/ui/borrowck/issue-81365-10.rs
Normal file
26
src/test/ui/borrowck/issue-81365-10.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
struct DerefTarget {
|
||||
target_field: bool,
|
||||
}
|
||||
struct Container {
|
||||
target: DerefTarget,
|
||||
container_field: bool,
|
||||
}
|
||||
|
||||
impl Deref for Container {
|
||||
type Target = DerefTarget;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.target
|
||||
}
|
||||
}
|
||||
|
||||
impl Container {
|
||||
fn bad_borrow(&mut self) {
|
||||
let first = &self.deref().target_field;
|
||||
self.container_field = true; //~ ERROR E0506
|
||||
first;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
13
src/test/ui/borrowck/issue-81365-10.stderr
Normal file
13
src/test/ui/borrowck/issue-81365-10.stderr
Normal file
@ -0,0 +1,13 @@
|
||||
error[E0506]: cannot assign to `self.container_field` because it is borrowed
|
||||
--> $DIR/issue-81365-10.rs:21:9
|
||||
|
|
||||
LL | let first = &self.deref().target_field;
|
||||
| ---- borrow of `self.container_field` occurs here
|
||||
LL | self.container_field = true;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
|
||||
LL | first;
|
||||
| ----- borrow later used here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0506`.
|
32
src/test/ui/borrowck/issue-81365-11.rs
Normal file
32
src/test/ui/borrowck/issue-81365-11.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
struct DerefTarget {
|
||||
target_field: bool,
|
||||
}
|
||||
struct Container {
|
||||
target: DerefTarget,
|
||||
container_field: bool,
|
||||
}
|
||||
|
||||
impl Deref for Container {
|
||||
type Target = DerefTarget;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.target
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Container {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.target
|
||||
}
|
||||
}
|
||||
|
||||
impl Container {
|
||||
fn bad_borrow(&mut self) {
|
||||
let first = &mut self.target_field;
|
||||
self.container_field = true; //~ ERROR E0506
|
||||
first;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
13
src/test/ui/borrowck/issue-81365-11.stderr
Normal file
13
src/test/ui/borrowck/issue-81365-11.stderr
Normal file
@ -0,0 +1,13 @@
|
||||
error[E0506]: cannot assign to `self.container_field` because it is borrowed
|
||||
--> $DIR/issue-81365-11.rs:27:9
|
||||
|
|
||||
LL | let first = &mut self.target_field;
|
||||
| ---- borrow of `self.container_field` occurs here
|
||||
LL | self.container_field = true;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
|
||||
LL | first;
|
||||
| ----- borrow later used here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0506`.
|
30
src/test/ui/borrowck/issue-81365-2.rs
Normal file
30
src/test/ui/borrowck/issue-81365-2.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
struct DerefTarget {
|
||||
target_field: bool,
|
||||
}
|
||||
struct Container {
|
||||
target: DerefTarget,
|
||||
container_field: bool,
|
||||
}
|
||||
|
||||
impl Deref for Container {
|
||||
type Target = DerefTarget;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.target
|
||||
}
|
||||
}
|
||||
|
||||
struct Outer {
|
||||
container: Container,
|
||||
}
|
||||
|
||||
impl Outer {
|
||||
fn bad_borrow(&mut self) {
|
||||
let first = &self.container.target_field;
|
||||
self.container.container_field = true; //~ ERROR E0506
|
||||
first;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
20
src/test/ui/borrowck/issue-81365-2.stderr
Normal file
20
src/test/ui/borrowck/issue-81365-2.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error[E0506]: cannot assign to `self.container.container_field` because it is borrowed
|
||||
--> $DIR/issue-81365-2.rs:25:9
|
||||
|
|
||||
LL | let first = &self.container.target_field;
|
||||
| -------------- borrow of `self.container.container_field` occurs here
|
||||
LL | self.container.container_field = true;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here
|
||||
LL | first;
|
||||
| ----- borrow later used here
|
||||
|
|
||||
= note: borrow occurs due to deref coercion to `DerefTarget`
|
||||
note: deref defined here
|
||||
--> $DIR/issue-81365-2.rs:12:5
|
||||
|
|
||||
LL | type Target = DerefTarget;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0506`.
|
37
src/test/ui/borrowck/issue-81365-3.rs
Normal file
37
src/test/ui/borrowck/issue-81365-3.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
struct DerefTarget {
|
||||
target_field: bool,
|
||||
}
|
||||
struct Container {
|
||||
target: DerefTarget,
|
||||
container_field: bool,
|
||||
}
|
||||
|
||||
impl Deref for Container {
|
||||
type Target = DerefTarget;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.target
|
||||
}
|
||||
}
|
||||
|
||||
struct Outer {
|
||||
container: Container,
|
||||
}
|
||||
|
||||
impl Deref for Outer {
|
||||
type Target = Container;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.container
|
||||
}
|
||||
}
|
||||
|
||||
impl Outer {
|
||||
fn bad_borrow(&mut self) {
|
||||
let first = &self.target_field;
|
||||
self.container.container_field = true; //~ ERROR E0506
|
||||
first;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
20
src/test/ui/borrowck/issue-81365-3.stderr
Normal file
20
src/test/ui/borrowck/issue-81365-3.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error[E0506]: cannot assign to `self.container.container_field` because it is borrowed
|
||||
--> $DIR/issue-81365-3.rs:32:9
|
||||
|
|
||||
LL | let first = &self.target_field;
|
||||
| ---- borrow of `self.container.container_field` occurs here
|
||||
LL | self.container.container_field = true;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here
|
||||
LL | first;
|
||||
| ----- borrow later used here
|
||||
|
|
||||
= note: borrow occurs due to deref coercion to `Container`
|
||||
note: deref defined here
|
||||
--> $DIR/issue-81365-3.rs:23:5
|
||||
|
|
||||
LL | type Target = Container;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0506`.
|
38
src/test/ui/borrowck/issue-81365-4.rs
Normal file
38
src/test/ui/borrowck/issue-81365-4.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
struct DerefTarget {
|
||||
target_field: bool,
|
||||
}
|
||||
struct Container {
|
||||
target: DerefTarget,
|
||||
container_field: bool,
|
||||
}
|
||||
|
||||
impl Deref for Container {
|
||||
type Target = DerefTarget;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.target
|
||||
}
|
||||
}
|
||||
|
||||
struct Outer {
|
||||
container: Container,
|
||||
outer_field: bool,
|
||||
}
|
||||
|
||||
impl Deref for Outer {
|
||||
type Target = Container;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.container
|
||||
}
|
||||
}
|
||||
|
||||
impl Outer {
|
||||
fn bad_borrow(&mut self) {
|
||||
let first = &self.target_field;
|
||||
self.outer_field = true; //~ ERROR E0506
|
||||
first;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
20
src/test/ui/borrowck/issue-81365-4.stderr
Normal file
20
src/test/ui/borrowck/issue-81365-4.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error[E0506]: cannot assign to `self.outer_field` because it is borrowed
|
||||
--> $DIR/issue-81365-4.rs:33:9
|
||||
|
|
||||
LL | let first = &self.target_field;
|
||||
| ---- borrow of `self.outer_field` occurs here
|
||||
LL | self.outer_field = true;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.outer_field` occurs here
|
||||
LL | first;
|
||||
| ----- borrow later used here
|
||||
|
|
||||
= note: borrow occurs due to deref coercion to `Container`
|
||||
note: deref defined here
|
||||
--> $DIR/issue-81365-4.rs:24:5
|
||||
|
|
||||
LL | type Target = Container;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0506`.
|
33
src/test/ui/borrowck/issue-81365-5.rs
Normal file
33
src/test/ui/borrowck/issue-81365-5.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
struct DerefTarget {
|
||||
target_field: bool,
|
||||
}
|
||||
|
||||
impl DerefTarget {
|
||||
fn get(&self) -> &bool {
|
||||
&self.target_field
|
||||
}
|
||||
}
|
||||
|
||||
struct Container {
|
||||
target: DerefTarget,
|
||||
container_field: bool,
|
||||
}
|
||||
|
||||
impl Deref for Container {
|
||||
type Target = DerefTarget;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.target
|
||||
}
|
||||
}
|
||||
|
||||
impl Container {
|
||||
fn bad_borrow(&mut self) {
|
||||
let first = self.get();
|
||||
self.container_field = true; //~ ERROR E0506
|
||||
first;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
20
src/test/ui/borrowck/issue-81365-5.stderr
Normal file
20
src/test/ui/borrowck/issue-81365-5.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error[E0506]: cannot assign to `self.container_field` because it is borrowed
|
||||
--> $DIR/issue-81365-5.rs:28:9
|
||||
|
|
||||
LL | let first = self.get();
|
||||
| ---- borrow of `self.container_field` occurs here
|
||||
LL | self.container_field = true;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
|
||||
LL | first;
|
||||
| ----- borrow later used here
|
||||
|
|
||||
= note: borrow occurs due to deref coercion to `DerefTarget`
|
||||
note: deref defined here
|
||||
--> $DIR/issue-81365-5.rs:19:5
|
||||
|
|
||||
LL | type Target = DerefTarget;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0506`.
|
23
src/test/ui/borrowck/issue-81365-6.rs
Normal file
23
src/test/ui/borrowck/issue-81365-6.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
struct Container {
|
||||
target: Vec<()>,
|
||||
container_field: bool,
|
||||
}
|
||||
|
||||
impl Deref for Container {
|
||||
type Target = [()];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.target
|
||||
}
|
||||
}
|
||||
|
||||
impl Container {
|
||||
fn bad_borrow(&mut self) {
|
||||
let first = &self[0];
|
||||
self.container_field = true; //~ ERROR E0506
|
||||
first;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
20
src/test/ui/borrowck/issue-81365-6.stderr
Normal file
20
src/test/ui/borrowck/issue-81365-6.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error[E0506]: cannot assign to `self.container_field` because it is borrowed
|
||||
--> $DIR/issue-81365-6.rs:18:9
|
||||
|
|
||||
LL | let first = &self[0];
|
||||
| ---- borrow of `self.container_field` occurs here
|
||||
LL | self.container_field = true;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
|
||||
LL | first;
|
||||
| ----- borrow later used here
|
||||
|
|
||||
= note: borrow occurs due to deref coercion to `[()]`
|
||||
note: deref defined here
|
||||
--> $DIR/issue-81365-6.rs:9:5
|
||||
|
|
||||
LL | type Target = [()];
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0506`.
|
24
src/test/ui/borrowck/issue-81365-7.rs
Normal file
24
src/test/ui/borrowck/issue-81365-7.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
struct DerefTarget {
|
||||
target_field: bool,
|
||||
}
|
||||
struct Container {
|
||||
target: DerefTarget,
|
||||
container_field: bool,
|
||||
}
|
||||
|
||||
impl Deref for Container {
|
||||
type Target = DerefTarget;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.target
|
||||
}
|
||||
}
|
||||
|
||||
fn bad_borrow(c: &mut Container) {
|
||||
let first = &c.target_field;
|
||||
c.container_field = true; //~ ERROR E0506
|
||||
first;
|
||||
}
|
||||
|
||||
fn main() {}
|
20
src/test/ui/borrowck/issue-81365-7.stderr
Normal file
20
src/test/ui/borrowck/issue-81365-7.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error[E0506]: cannot assign to `c.container_field` because it is borrowed
|
||||
--> $DIR/issue-81365-7.rs:20:5
|
||||
|
|
||||
LL | let first = &c.target_field;
|
||||
| - borrow of `c.container_field` occurs here
|
||||
LL | c.container_field = true;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `c.container_field` occurs here
|
||||
LL | first;
|
||||
| ----- borrow later used here
|
||||
|
|
||||
= note: borrow occurs due to deref coercion to `DerefTarget`
|
||||
note: deref defined here
|
||||
--> $DIR/issue-81365-7.rs:12:5
|
||||
|
|
||||
LL | type Target = DerefTarget;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0506`.
|
26
src/test/ui/borrowck/issue-81365-8.rs
Normal file
26
src/test/ui/borrowck/issue-81365-8.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
struct DerefTarget {
|
||||
target_field: bool,
|
||||
}
|
||||
struct Container {
|
||||
target: DerefTarget,
|
||||
container_field: bool,
|
||||
}
|
||||
|
||||
impl Deref for Container {
|
||||
type Target = DerefTarget;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.target
|
||||
}
|
||||
}
|
||||
|
||||
impl Container {
|
||||
fn bad_borrow(&mut self) {
|
||||
let first = &(*self).target_field;
|
||||
self.container_field = true; //~ ERROR E0506
|
||||
first;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
20
src/test/ui/borrowck/issue-81365-8.stderr
Normal file
20
src/test/ui/borrowck/issue-81365-8.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error[E0506]: cannot assign to `self.container_field` because it is borrowed
|
||||
--> $DIR/issue-81365-8.rs:21:9
|
||||
|
|
||||
LL | let first = &(*self).target_field;
|
||||
| ------- borrow of `self.container_field` occurs here
|
||||
LL | self.container_field = true;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
|
||||
LL | first;
|
||||
| ----- borrow later used here
|
||||
|
|
||||
= note: borrow occurs due to deref coercion to `DerefTarget`
|
||||
note: deref defined here
|
||||
--> $DIR/issue-81365-8.rs:12:5
|
||||
|
|
||||
LL | type Target = DerefTarget;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0506`.
|
26
src/test/ui/borrowck/issue-81365-9.rs
Normal file
26
src/test/ui/borrowck/issue-81365-9.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
struct DerefTarget {
|
||||
target_field: bool,
|
||||
}
|
||||
struct Container {
|
||||
target: DerefTarget,
|
||||
container_field: bool,
|
||||
}
|
||||
|
||||
impl Deref for Container {
|
||||
type Target = DerefTarget;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.target
|
||||
}
|
||||
}
|
||||
|
||||
impl Container {
|
||||
fn bad_borrow(&mut self) {
|
||||
let first = &Deref::deref(self).target_field;
|
||||
self.container_field = true; //~ ERROR E0506
|
||||
first;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
13
src/test/ui/borrowck/issue-81365-9.stderr
Normal file
13
src/test/ui/borrowck/issue-81365-9.stderr
Normal file
@ -0,0 +1,13 @@
|
||||
error[E0506]: cannot assign to `self.container_field` because it is borrowed
|
||||
--> $DIR/issue-81365-9.rs:21:9
|
||||
|
|
||||
LL | let first = &Deref::deref(self).target_field;
|
||||
| ---- borrow of `self.container_field` occurs here
|
||||
LL | self.container_field = true;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
|
||||
LL | first;
|
||||
| ----- borrow later used here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0506`.
|
@ -1,16 +0,0 @@
|
||||
#[macro_use] mod bleh {
|
||||
pub macro_rules! foo { //~ ERROR can't qualify macro_rules invocation
|
||||
($n:ident) => (
|
||||
fn $n () -> i32 {
|
||||
1
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
foo!(meh);
|
||||
|
||||
fn main() {
|
||||
println!("{}", meh());
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
error: can't qualify macro_rules invocation with `pub`
|
||||
--> $DIR/pub-macro-rules.rs:2:5
|
||||
|
|
||||
LL | pub macro_rules! foo {
|
||||
| ^^^ help: try exporting the macro: `#[macro_export]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
10
src/test/ui/feature-gates/feature-gate-pub_macro_rules.rs
Normal file
10
src/test/ui/feature-gates/feature-gate-pub_macro_rules.rs
Normal file
@ -0,0 +1,10 @@
|
||||
pub macro_rules! m1 { () => {} } //~ ERROR `pub` on `macro_rules` items is unstable
|
||||
|
||||
#[cfg(FALSE)]
|
||||
pub macro_rules! m2 { () => {} } //~ ERROR `pub` on `macro_rules` items is unstable
|
||||
|
||||
pub(crate) macro_rules! m3 { () => {} } //~ ERROR `pub` on `macro_rules` items is unstable
|
||||
|
||||
pub(in self) macro_rules! m4 { () => {} } //~ ERROR `pub` on `macro_rules` items is unstable
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,39 @@
|
||||
error[E0658]: `pub` on `macro_rules` items is unstable
|
||||
--> $DIR/feature-gate-pub_macro_rules.rs:1:1
|
||||
|
|
||||
LL | pub macro_rules! m1 { () => {} }
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #78855 <https://github.com/rust-lang/rust/issues/78855> for more information
|
||||
= help: add `#![feature(pub_macro_rules)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: `pub` on `macro_rules` items is unstable
|
||||
--> $DIR/feature-gate-pub_macro_rules.rs:4:1
|
||||
|
|
||||
LL | pub macro_rules! m2 { () => {} }
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #78855 <https://github.com/rust-lang/rust/issues/78855> for more information
|
||||
= help: add `#![feature(pub_macro_rules)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: `pub` on `macro_rules` items is unstable
|
||||
--> $DIR/feature-gate-pub_macro_rules.rs:6:1
|
||||
|
|
||||
LL | pub(crate) macro_rules! m3 { () => {} }
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #78855 <https://github.com/rust-lang/rust/issues/78855> for more information
|
||||
= help: add `#![feature(pub_macro_rules)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: `pub` on `macro_rules` items is unstable
|
||||
--> $DIR/feature-gate-pub_macro_rules.rs:8:1
|
||||
|
|
||||
LL | pub(in self) macro_rules! m4 { () => {} }
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #78855 <https://github.com/rust-lang/rust/issues/78855> for more information
|
||||
= help: add `#![feature(pub_macro_rules)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
11
src/test/ui/issues/issue-81918.rs
Normal file
11
src/test/ui/issues/issue-81918.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// check-pass
|
||||
// dont-check-compiler-stdout
|
||||
// compile-flags: -Z unpretty=mir-cfg
|
||||
|
||||
// This checks that unpretty=mir-cfg does not panic. See #81918.
|
||||
|
||||
const TAG: &'static str = "ABCD";
|
||||
|
||||
fn main() {
|
||||
if TAG == "" {}
|
||||
}
|
@ -17,4 +17,53 @@ fn field_write(s: &mut S) {
|
||||
fn main() {
|
||||
let mut s = S { f: 0, sub: Sub { f: 0 } };
|
||||
field_write(&mut s);
|
||||
|
||||
auto_deref();
|
||||
nested_boxes();
|
||||
}
|
||||
|
||||
fn auto_deref() {
|
||||
struct E {
|
||||
x: bool,
|
||||
y: bool, //~ ERROR: field is never read
|
||||
}
|
||||
|
||||
struct P<'a> {
|
||||
e: &'a mut E
|
||||
}
|
||||
|
||||
impl P<'_> {
|
||||
fn f(&mut self) {
|
||||
self.e.x = true;
|
||||
self.e.y = true;
|
||||
}
|
||||
}
|
||||
|
||||
let mut e = E { x: false, y: false };
|
||||
let mut p = P { e: &mut e };
|
||||
p.f();
|
||||
assert!(e.x);
|
||||
}
|
||||
|
||||
fn nested_boxes() {
|
||||
struct A {
|
||||
b: Box<B>,
|
||||
}
|
||||
|
||||
struct B {
|
||||
c: Box<C>,
|
||||
}
|
||||
|
||||
struct C {
|
||||
u: u32, //~ ERROR: field is never read
|
||||
v: u32, //~ ERROR: field is never read
|
||||
}
|
||||
|
||||
let mut a = A {
|
||||
b: Box::new(B {
|
||||
c: Box::new(C { u: 0, v: 0 }),
|
||||
}),
|
||||
};
|
||||
a.b.c.v = 10;
|
||||
a.b.c = Box::new(C { u: 1, v: 2 });
|
||||
}
|
||||
|
@ -22,5 +22,23 @@ error: field is never read: `f`
|
||||
LL | f: i32,
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: field is never read: `y`
|
||||
--> $DIR/write-only-field.rs:28:9
|
||||
|
|
||||
LL | y: bool,
|
||||
| ^^^^^^^
|
||||
|
||||
error: field is never read: `u`
|
||||
--> $DIR/write-only-field.rs:58:9
|
||||
|
|
||||
LL | u: u32,
|
||||
| ^^^^^^
|
||||
|
||||
error: field is never read: `v`
|
||||
--> $DIR/write-only-field.rs:59:9
|
||||
|
|
||||
LL | v: u32,
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
11
src/test/ui/macros/macro-export-on-modularized-macros.rs
Normal file
11
src/test/ui/macros/macro-export-on-modularized-macros.rs
Normal file
@ -0,0 +1,11 @@
|
||||
#![feature(decl_macro)]
|
||||
#![feature(pub_macro_rules)]
|
||||
|
||||
#[macro_export]
|
||||
macro m1() {} //~ ERROR `#[macro_export]` cannot be used on `macro` items
|
||||
|
||||
#[macro_export]
|
||||
pub macro_rules! m2 { () => {} }
|
||||
//~^ ERROR `#[macro_export]` cannot be used on `macro_rules` with `pub`
|
||||
|
||||
fn main() {}
|
14
src/test/ui/macros/macro-export-on-modularized-macros.stderr
Normal file
14
src/test/ui/macros/macro-export-on-modularized-macros.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error: `#[macro_export]` cannot be used on `macro` items
|
||||
--> $DIR/macro-export-on-modularized-macros.rs:5:1
|
||||
|
|
||||
LL | macro m1() {}
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: `#[macro_export]` cannot be used on `macro_rules` with `pub`
|
||||
--> $DIR/macro-export-on-modularized-macros.rs:8:1
|
||||
|
|
||||
LL | pub macro_rules! m2 { () => {} }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
28
src/test/ui/macros/pub-macro-rules-fail.rs
Normal file
28
src/test/ui/macros/pub-macro-rules-fail.rs
Normal file
@ -0,0 +1,28 @@
|
||||
#![feature(pub_macro_rules)]
|
||||
|
||||
#[macro_use]
|
||||
mod m {
|
||||
pub macro_rules! mac { () => {} }
|
||||
|
||||
// `pub` `macro_rules` cannot be redefined in the same module.
|
||||
pub macro_rules! mac { () => {} } //~ ERROR the name `mac` is defined multiple times
|
||||
|
||||
pub(self) macro_rules! private_mac { () => {} }
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
pub macro_rules! block_mac { () => {} }
|
||||
};
|
||||
|
||||
mod n {
|
||||
// Scope of `pub` `macro_rules` is not extended by `#[macro_use]`.
|
||||
mac!(); //~ ERROR cannot find macro `mac` in this scope
|
||||
|
||||
// `pub` `macro_rules` doesn't put the macro into the root module, unlike `#[macro_export]`.
|
||||
crate::mac!(); //~ ERROR failed to resolve: maybe a missing crate `mac`
|
||||
crate::block_mac!(); //~ ERROR failed to resolve: maybe a missing crate `block_mac`
|
||||
|
||||
crate::m::private_mac!(); //~ ERROR macro `private_mac` is private
|
||||
}
|
||||
|
||||
fn main() {}
|
48
src/test/ui/macros/pub-macro-rules-fail.stderr
Normal file
48
src/test/ui/macros/pub-macro-rules-fail.stderr
Normal file
@ -0,0 +1,48 @@
|
||||
error[E0428]: the name `mac` is defined multiple times
|
||||
--> $DIR/pub-macro-rules-fail.rs:8:5
|
||||
|
|
||||
LL | pub macro_rules! mac { () => {} }
|
||||
| -------------------- previous definition of the macro `mac` here
|
||||
...
|
||||
LL | pub macro_rules! mac { () => {} }
|
||||
| ^^^^^^^^^^^^^^^^^^^^ `mac` redefined here
|
||||
|
|
||||
= note: `mac` must be defined only once in the macro namespace of this module
|
||||
|
||||
error[E0433]: failed to resolve: maybe a missing crate `mac`?
|
||||
--> $DIR/pub-macro-rules-fail.rs:22:12
|
||||
|
|
||||
LL | crate::mac!();
|
||||
| ^^^ maybe a missing crate `mac`?
|
||||
|
||||
error[E0433]: failed to resolve: maybe a missing crate `block_mac`?
|
||||
--> $DIR/pub-macro-rules-fail.rs:23:12
|
||||
|
|
||||
LL | crate::block_mac!();
|
||||
| ^^^^^^^^^ maybe a missing crate `block_mac`?
|
||||
|
||||
error: cannot find macro `mac` in this scope
|
||||
--> $DIR/pub-macro-rules-fail.rs:19:5
|
||||
|
|
||||
LL | mac!();
|
||||
| ^^^
|
||||
|
|
||||
= note: consider importing this macro:
|
||||
m::mac
|
||||
|
||||
error[E0603]: macro `private_mac` is private
|
||||
--> $DIR/pub-macro-rules-fail.rs:25:15
|
||||
|
|
||||
LL | crate::m::private_mac!();
|
||||
| ^^^^^^^^^^^ private macro
|
||||
|
|
||||
note: the macro `private_mac` is defined here
|
||||
--> $DIR/pub-macro-rules-fail.rs:10:5
|
||||
|
|
||||
LL | pub(self) macro_rules! private_mac { () => {} }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0428, E0433, E0603.
|
||||
For more information about an error, try `rustc --explain E0428`.
|
20
src/test/ui/macros/pub-macro-rules.rs
Normal file
20
src/test/ui/macros/pub-macro-rules.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(pub_macro_rules)]
|
||||
|
||||
mod m {
|
||||
// `pub` `macro_rules` can be used earlier in item order than they are defined.
|
||||
foo!();
|
||||
|
||||
pub macro_rules! foo { () => {} }
|
||||
|
||||
// `pub(...)` works too.
|
||||
pub(super) macro_rules! bar { () => {} }
|
||||
}
|
||||
|
||||
// `pub` `macro_rules` are available by module path.
|
||||
m::foo!();
|
||||
|
||||
m::bar!();
|
||||
|
||||
fn main() {}
|
@ -29,6 +29,17 @@ fn main() {
|
||||
fancy_panic::fancy_panic!(S);
|
||||
//~^ WARN panic message is not a string literal
|
||||
|
||||
macro_rules! a {
|
||||
() => { 123 };
|
||||
}
|
||||
|
||||
panic!(a!()); //~ WARN panic message is not a string literal
|
||||
|
||||
panic!(format!("{}", 1)); //~ WARN panic message is not a string literal
|
||||
|
||||
panic![123]; //~ WARN panic message is not a string literal
|
||||
panic!{123}; //~ WARN panic message is not a string literal
|
||||
|
||||
// Check that the lint only triggers for std::panic and core::panic,
|
||||
// not any panic macro:
|
||||
macro_rules! panic {
|
||||
|
@ -93,7 +93,7 @@ LL | panic!("{}", C);
|
||||
help: or use std::panic::panic_any instead
|
||||
|
|
||||
LL | std::panic::panic_any(C);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: panic message is not a string literal
|
||||
--> $DIR/non-fmt-panic.rs:20:12
|
||||
@ -109,7 +109,7 @@ LL | panic!("{}", S);
|
||||
help: or use std::panic::panic_any instead
|
||||
|
|
||||
LL | std::panic::panic_any(S);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: panic message is not a string literal
|
||||
--> $DIR/non-fmt-panic.rs:21:17
|
||||
@ -125,7 +125,7 @@ LL | std::panic!("{}", 123);
|
||||
help: or use std::panic::panic_any instead
|
||||
|
|
||||
LL | std::panic::panic_any(123);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: panic message is not a string literal
|
||||
--> $DIR/non-fmt-panic.rs:22:18
|
||||
@ -183,5 +183,66 @@ LL | fancy_panic::fancy_panic!(S);
|
||||
|
|
||||
= note: this is no longer accepted in Rust 2021
|
||||
|
||||
warning: 14 warnings emitted
|
||||
warning: panic message is not a string literal
|
||||
--> $DIR/non-fmt-panic.rs:36:12
|
||||
|
|
||||
LL | panic!(a!());
|
||||
| ^^^^
|
||||
|
|
||||
= note: this is no longer accepted in Rust 2021
|
||||
help: add a "{}" format string to Display the message
|
||||
|
|
||||
LL | panic!("{}", a!());
|
||||
| ^^^^^
|
||||
help: or use std::panic::panic_any instead
|
||||
|
|
||||
LL | std::panic::panic_any(a!());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: panic message is not a string literal
|
||||
--> $DIR/non-fmt-panic.rs:38:12
|
||||
|
|
||||
LL | panic!(format!("{}", 1));
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this is no longer accepted in Rust 2021
|
||||
= note: the panic!() macro supports formatting, so there's no need for the format!() macro here
|
||||
help: remove the `format!(..)` macro call
|
||||
|
|
||||
LL | panic!("{}", 1);
|
||||
| -- --
|
||||
|
||||
warning: panic message is not a string literal
|
||||
--> $DIR/non-fmt-panic.rs:40:12
|
||||
|
|
||||
LL | panic![123];
|
||||
| ^^^
|
||||
|
|
||||
= note: this is no longer accepted in Rust 2021
|
||||
help: add a "{}" format string to Display the message
|
||||
|
|
||||
LL | panic!["{}", 123];
|
||||
| ^^^^^
|
||||
help: or use std::panic::panic_any instead
|
||||
|
|
||||
LL | std::panic::panic_any(123);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ ^
|
||||
|
||||
warning: panic message is not a string literal
|
||||
--> $DIR/non-fmt-panic.rs:41:12
|
||||
|
|
||||
LL | panic!{123};
|
||||
| ^^^
|
||||
|
|
||||
= note: this is no longer accepted in Rust 2021
|
||||
help: add a "{}" format string to Display the message
|
||||
|
|
||||
LL | panic!{"{}", 123};
|
||||
| ^^^^^
|
||||
help: or use std::panic::panic_any instead
|
||||
|
|
||||
LL | std::panic::panic_any(123);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ ^
|
||||
|
||||
warning: 18 warnings emitted
|
||||
|
||||
|
7
src/test/ui/pattern/issue-82290.rs
Normal file
7
src/test/ui/pattern/issue-82290.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete
|
||||
|
||||
fn main() {
|
||||
if true && let x = 1 { //~ ERROR `let` expressions are not supported here
|
||||
let _ = x;
|
||||
}
|
||||
}
|
20
src/test/ui/pattern/issue-82290.stderr
Normal file
20
src/test/ui/pattern/issue-82290.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error: `let` expressions are not supported here
|
||||
--> $DIR/issue-82290.rs:4:16
|
||||
|
|
||||
LL | if true && let x = 1 {
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: only supported directly in conditions of `if`- and `while`-expressions
|
||||
= note: as well as when nested within `&&` and parenthesis in those conditions
|
||||
|
||||
warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/issue-82290.rs:1:12
|
||||
|
|
||||
LL | #![feature(let_chains)]
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
@ -9,6 +9,7 @@ pub struct Cache {
|
||||
root: PathBuf,
|
||||
files: HashMap<PathBuf, String>,
|
||||
values: HashMap<PathBuf, Value>,
|
||||
pub variables: HashMap<String, Value>,
|
||||
last_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
@ -19,6 +20,7 @@ impl Cache {
|
||||
root: Path::new(doc_dir).to_owned(),
|
||||
files: HashMap::new(),
|
||||
values: HashMap::new(),
|
||||
variables: HashMap::new(),
|
||||
last_path: None,
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ use jsonpath_lib::select;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::{Regex, RegexBuilder};
|
||||
use serde_json::Value;
|
||||
use std::borrow::Cow;
|
||||
use std::{env, fmt, fs};
|
||||
|
||||
mod cache;
|
||||
@ -48,13 +49,16 @@ pub struct Command {
|
||||
pub enum CommandKind {
|
||||
Has,
|
||||
Count,
|
||||
Is,
|
||||
Set,
|
||||
}
|
||||
|
||||
impl CommandKind {
|
||||
fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool {
|
||||
let count = match self {
|
||||
CommandKind::Has => (1..=3).contains(&args.len()),
|
||||
CommandKind::Count => 3 == args.len(),
|
||||
CommandKind::Count | CommandKind::Is => 3 == args.len(),
|
||||
CommandKind::Set => 4 == args.len(),
|
||||
};
|
||||
|
||||
if !count {
|
||||
@ -83,6 +87,8 @@ impl fmt::Display for CommandKind {
|
||||
let text = match self {
|
||||
CommandKind::Has => "has",
|
||||
CommandKind::Count => "count",
|
||||
CommandKind::Is => "is",
|
||||
CommandKind::Set => "set",
|
||||
};
|
||||
write!(f, "{}", text)
|
||||
}
|
||||
@ -127,6 +133,8 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
|
||||
let cmd = match cmd {
|
||||
"has" => CommandKind::Has,
|
||||
"count" => CommandKind::Count,
|
||||
"is" => CommandKind::Is,
|
||||
"set" => CommandKind::Set,
|
||||
_ => {
|
||||
print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
|
||||
errors = true;
|
||||
@ -180,6 +188,7 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
|
||||
/// Performs the actual work of ensuring a command passes. Generally assumes the command
|
||||
/// is syntactically valid.
|
||||
fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
|
||||
// FIXME: Be more granular about why, (e.g. syntax error, count not equal)
|
||||
let result = match command.kind {
|
||||
CommandKind::Has => {
|
||||
match command.args.len() {
|
||||
@ -188,23 +197,15 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
|
||||
// @has <path> <jsonpath> = check path exists
|
||||
2 => {
|
||||
let val = cache.get_value(&command.args[0])?;
|
||||
|
||||
match select(&val, &command.args[1]) {
|
||||
Ok(results) => !results.is_empty(),
|
||||
Err(_) => false,
|
||||
}
|
||||
let results = select(&val, &command.args[1]).unwrap();
|
||||
!results.is_empty()
|
||||
}
|
||||
// @has <path> <jsonpath> <value> = check *any* item matched by path equals value
|
||||
3 => {
|
||||
let val = cache.get_value(&command.args[0])?;
|
||||
match select(&val, &command.args[1]) {
|
||||
Ok(results) => {
|
||||
let pat: Value = serde_json::from_str(&command.args[2]).unwrap();
|
||||
|
||||
!results.is_empty() && results.into_iter().any(|val| *val == pat)
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
let results = select(&val, &command.args[1]).unwrap();
|
||||
let pat = string_to_value(&command.args[2], cache);
|
||||
results.contains(&pat.as_ref())
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
@ -215,9 +216,37 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
|
||||
let expected: usize = command.args[2].parse().unwrap();
|
||||
|
||||
let val = cache.get_value(&command.args[0])?;
|
||||
match select(&val, &command.args[1]) {
|
||||
Ok(results) => results.len() == expected,
|
||||
Err(_) => false,
|
||||
let results = select(&val, &command.args[1]).unwrap();
|
||||
results.len() == expected
|
||||
}
|
||||
CommandKind::Is => {
|
||||
// @has <path> <jsonpath> <value> = check *exactly one* item matched by path, and it equals value
|
||||
assert_eq!(command.args.len(), 3);
|
||||
let val = cache.get_value(&command.args[0])?;
|
||||
let results = select(&val, &command.args[1]).unwrap();
|
||||
let pat = string_to_value(&command.args[2], cache);
|
||||
results.len() == 1 && results[0] == pat.as_ref()
|
||||
}
|
||||
CommandKind::Set => {
|
||||
// @set <name> = <path> <jsonpath>
|
||||
assert_eq!(command.args.len(), 4);
|
||||
assert_eq!(command.args[1], "=", "Expected an `=`");
|
||||
let val = cache.get_value(&command.args[2])?;
|
||||
let results = select(&val, &command.args[3]).unwrap();
|
||||
assert_eq!(results.len(), 1);
|
||||
match results.len() {
|
||||
0 => false,
|
||||
1 => {
|
||||
let r = cache.variables.insert(command.args[0].clone(), results[0].clone());
|
||||
assert!(r.is_none(), "Name collision: {} is duplicated", command.args[0]);
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
panic!(
|
||||
"Got multiple results in `@set` for `{}`: {:?}",
|
||||
&command.args[3], results
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -247,3 +276,11 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> {
|
||||
if s.starts_with("$") {
|
||||
Cow::Borrowed(&cache.variables[&s[1..]])
|
||||
} else {
|
||||
Cow::Owned(serde_json::from_str(s).unwrap())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user