message: Tell the user about stacked borrow debugging flags
diff: use std::cell::RefCell;
  use std::collections::{HashMap, HashSet};
  use std::fmt;
  +use std::fmt::Write;
  use std::num::NonZeroU64;
  use std::rc::Rc;
  @@ -278,10 +279,13 @@ impl<'tcx> Stack {
  if let Some(call) = item.protector {
  if global.is_active(call) {
  if let Some(tag) = tag {
  - throw_ub!(UbExperimental(format!(
  + return Err(err_ub_experimental(
  + tag,
  + format!(
  "not granting access to tag {:?} because incompatible item is protected: {:?}",
  tag, item
  - )));
  + ),
  + ));
  } else {
  throw_ub!(UbExperimental(format!(
  "deallocating while item is protected: {:?}",
  @@ -300,10 +304,10 @@ impl<'tcx> Stack {
  // Step 1: Find granting item.
  let granting_idx = self.find_granting(access, tag).ok_or_else(|| {
  - err_ub!(UbExperimental(format!(
  - "no item granting {} to tag {:?} found in borrow stack",
  - access, tag,
  - )))
  + err_ub_experimental(
  + tag,
  + format!("no item granting {} to tag {:?} found in borrow stack.", access, tag),
  + )
  })?;
  // Step 2: Remove incompatible items above them. Make sure we do not remove protected
  @@ -344,10 +348,11 @@ impl<'tcx> Stack {
  fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> {
  // Step 1: Find granting item.
  self.find_granting(AccessKind::Write, tag).ok_or_else(|| {
  - err_ub!(UbExperimental(format!(
  + err_ub_experimental(
  + tag,format!(
  "no item granting write access for deallocation to tag {:?} found in borrow stack",
  tag,
  - )))
  + ))
  })?;
  // Step 2: Remove all items. Also checks for protectors.
  @@ -369,9 +374,14 @@ impl<'tcx> Stack {
  // Now we figure out which item grants our parent (`derived_from`) this kind of access.
  // We use that to determine where to put the new item.
  let granting_idx = self.find_granting(access, derived_from)
  - .ok_or_else(|| err_ub!(UbExperimental(format!(
  - "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", new.perm, derived_from,
  - ))))?;
  + .ok_or_else(||
  + err_ub_experimental(
  + derived_from,
  + format!(
  + "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack",
  + new.perm, derived_from,
  + ),
  + ))?;
  // Compute where to put the new item.
  // Either way, we ensure that we insert the new item in a way such that between
  @@ -638,3 +648,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
  Ok(())
  }
  }
  +
  +fn err_ub_experimental(tag: Tag, mut msg: String) -> InterpErrorInfo<'static> {
  + if let Tag::Tagged(id) = tag {
  + // FIXME: do not add this message when the flag is already set
  + write!(msg, " Rerun with `-Zmiri-track-pointer-tag={}` for more information", id).unwrap();
  + }
  + err_ub!(UbExperimental(msg)).into()
  +}
  