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:
bors 2021-02-23 17:24:33 +00:00
commit fe1bf8e05c
66 changed files with 1160 additions and 157 deletions

View File

@ -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 {

View File

@ -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).

View File

@ -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
// -------------------------------------------------------------------------

View File

@ -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();

View File

@ -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

View File

@ -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 {

View File

@ -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(

View File

@ -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;
}

View File

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

View File

@ -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

View File

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

View File

@ -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)*));

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

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

View File

@ -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
}

View File

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

View File

@ -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;

View File

@ -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)));
}
})
});
}
}

View File

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

View File

@ -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
{

View File

@ -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.

View File

@ -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(),
}

View File

@ -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;
}

View 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() {}

View 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`.

View 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() {}

View 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`.

View 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() {}

View 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`.

View 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() {}

View 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`.

View 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() {}

View 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`.

View 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() {}

View 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`.

View 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() {}

View 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`.

View 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() {}

View 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`.

View 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() {}

View 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`.

View 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() {}

View 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`.

View 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() {}

View 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`.

View File

@ -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());
}

View File

@ -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

View 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() {}

View File

@ -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`.

View 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 == "" {}
}

View File

@ -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 });
}

View File

@ -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

View 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() {}

View 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

View 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() {}

View 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`.

View 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() {}

View File

@ -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 {

View File

@ -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

View 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;
}
}

View 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

View File

@ -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,
}
}

View File

@ -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())
}
}