Auto merge of #116737 - matthiaskrgr:rollup-jftlnmt, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #115439 (rustdoc: hide `#[repr(transparent)]` if it isn't part of the public ABI) - #116591 (Don't accidentally detect the commit hash as an `fadd` instruction) - #116603 (Reorganize `bootstrap/Cargo.toml`) - #116715 (Prevent more spurious unreachable pattern lints) - #116723 (Fix broken build on ESP-IDF caused by #115108) - #116730 (Add some unsoundness tests for opaques capturing hidden regions not in substs) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
ee8c9d3c34
35 changed files with 441 additions and 168 deletions
|
@ -19,11 +19,12 @@ use rustc_middle::middle::region;
|
|||
use rustc_middle::mir::interpret::AllocId;
|
||||
use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp};
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::GenericArgsRef;
|
||||
use rustc_middle::ty::{self, AdtDef, FnSig, List, Ty, UpvarArgs};
|
||||
use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, List, Ty,
|
||||
UpvarArgs,
|
||||
};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
|
||||
use rustc_span::{sym, ErrorGuaranteed, Span, Symbol, DUMMY_SP};
|
||||
use rustc_target::abi::{FieldIdx, VariantIdx};
|
||||
use rustc_target::asm::InlineAsmRegOrRegClass;
|
||||
use std::fmt;
|
||||
|
@ -632,7 +633,7 @@ impl<'tcx> Pat<'tcx> {
|
|||
|
||||
use PatKind::*;
|
||||
match &self.kind {
|
||||
Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } => {}
|
||||
Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {}
|
||||
AscribeUserType { subpattern, .. }
|
||||
| Binding { subpattern: Some(subpattern), .. }
|
||||
| Deref { subpattern } => subpattern.walk_(it),
|
||||
|
@ -647,6 +648,21 @@ impl<'tcx> Pat<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether the pattern has a `PatKind::Error` nested within.
|
||||
pub fn pat_error_reported(&self) -> Result<(), ErrorGuaranteed> {
|
||||
let mut error = None;
|
||||
self.walk(|pat| {
|
||||
if let PatKind::Error(e) = pat.kind && error.is_none() {
|
||||
error = Some(e);
|
||||
}
|
||||
error.is_none()
|
||||
});
|
||||
match error {
|
||||
None => Ok(()),
|
||||
Some(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Walk the pattern in left-to-right order.
|
||||
///
|
||||
/// If you always want to recurse, prefer this method over `walk`.
|
||||
|
@ -771,6 +787,10 @@ pub enum PatKind<'tcx> {
|
|||
Or {
|
||||
pats: Box<[Box<Pat<'tcx>>]>,
|
||||
},
|
||||
|
||||
/// An error has been encountered during lowering. We probably shouldn't report more lints
|
||||
/// related to this pattern.
|
||||
Error(ErrorGuaranteed),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, HashStable, TypeVisitable)]
|
||||
|
@ -934,6 +954,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
PatKind::Error(_) => write!(f, "<error>"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -226,7 +226,7 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'
|
|||
is_primary: _,
|
||||
name: _,
|
||||
} => visitor.visit_pat(&subpattern),
|
||||
Binding { .. } | Wild => {}
|
||||
Binding { .. } | Wild | Error(_) => {}
|
||||
Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => {
|
||||
for subpattern in subpatterns {
|
||||
visitor.visit_pat(&subpattern.pattern);
|
||||
|
|
|
@ -814,7 +814,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
PatKind::Constant { .. } | PatKind::Range { .. } | PatKind::Wild => {}
|
||||
PatKind::Constant { .. }
|
||||
| PatKind::Range { .. }
|
||||
| PatKind::Wild
|
||||
| PatKind::Error(_) => {}
|
||||
|
||||
PatKind::Deref { ref subpattern } => {
|
||||
self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
|
||||
|
|
|
@ -168,7 +168,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
PatKind::Wild => {
|
||||
PatKind::Wild | PatKind::Error(_) => {
|
||||
// nothing left to do
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -77,7 +77,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
| PatKind::Wild
|
||||
| PatKind::Binding { .. }
|
||||
| PatKind::Leaf { .. }
|
||||
| PatKind::Deref { .. } => self.error_simplifiable(match_pair),
|
||||
| PatKind::Deref { .. }
|
||||
| PatKind::Error(_) => self.error_simplifiable(match_pair),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,7 +112,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
| PatKind::Binding { .. }
|
||||
| PatKind::AscribeUserType { .. }
|
||||
| PatKind::Leaf { .. }
|
||||
| PatKind::Deref { .. } => {
|
||||
| PatKind::Deref { .. }
|
||||
| PatKind::Error(_) => {
|
||||
// don't know how to add these patterns to a switch
|
||||
false
|
||||
}
|
||||
|
|
|
@ -224,7 +224,8 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
PatKind::Wild |
|
||||
// these just wrap other patterns
|
||||
PatKind::Or { .. } |
|
||||
PatKind::AscribeUserType { .. } => {}
|
||||
PatKind::AscribeUserType { .. } |
|
||||
PatKind::Error(_) => {}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ use rustc_hir::HirId;
|
|||
use rustc_middle::thir::visit::{self, Visitor};
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
|
||||
use rustc_session::lint::builtin::{
|
||||
BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
|
||||
};
|
||||
|
@ -231,6 +231,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
|||
if let LetSource::None = source {
|
||||
return;
|
||||
}
|
||||
if let Err(err) = pat.pat_error_reported() {
|
||||
self.error = Err(err);
|
||||
return;
|
||||
}
|
||||
self.check_patterns(pat, Refutable);
|
||||
let mut cx = self.new_cx(self.lint_level, true);
|
||||
let tpat = self.lower_pattern(&mut cx, pat);
|
||||
|
@ -252,6 +256,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
|||
self.with_lint_level(arm.lint_level, |this| {
|
||||
this.check_patterns(&arm.pattern, Refutable);
|
||||
});
|
||||
if let Err(err) = arm.pattern.pat_error_reported() {
|
||||
self.error = Err(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let tarms: Vec<_> = arms
|
||||
|
@ -334,7 +342,8 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
|||
// and record chain members that aren't let exprs.
|
||||
let mut chain_refutabilities = Vec::new();
|
||||
|
||||
let add = |expr: ExprId, mut local_lint_level| {
|
||||
let mut error = Ok(());
|
||||
let mut add = |expr: ExprId, mut local_lint_level| {
|
||||
// `local_lint_level` is the lint level enclosing the pattern inside `expr`.
|
||||
let mut expr = &self.thir[expr];
|
||||
debug!(?expr, ?local_lint_level, "add");
|
||||
|
@ -348,6 +357,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
|||
debug!(?expr, ?local_lint_level, "after scopes");
|
||||
match expr.kind {
|
||||
ExprKind::Let { box ref pat, expr: _ } => {
|
||||
if let Err(err) = pat.pat_error_reported() {
|
||||
error = Err(err);
|
||||
return None;
|
||||
}
|
||||
let mut ncx = self.new_cx(local_lint_level, true);
|
||||
let tpat = self.lower_pattern(&mut ncx, pat);
|
||||
let refutable = !is_let_irrefutable(&mut ncx, local_lint_level, tpat);
|
||||
|
@ -380,6 +393,11 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
|||
debug!(?chain_refutabilities);
|
||||
chain_refutabilities.reverse();
|
||||
|
||||
if error.is_err() {
|
||||
self.error = error;
|
||||
return;
|
||||
}
|
||||
|
||||
// Third, emit the actual warnings.
|
||||
if chain_refutabilities.iter().all(|r| matches!(*r, Some((_, false)))) {
|
||||
// The entire chain is made up of irrefutable `let` statements
|
||||
|
@ -426,6 +444,12 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
|||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn check_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) {
|
||||
// If we got errors while lowering, don't emit anything more.
|
||||
if let Err(err) = pat.pat_error_reported() {
|
||||
self.error = Err(err);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut cx = self.new_cx(self.lint_level, false);
|
||||
|
||||
let pattern = self.lower_pattern(&mut cx, pat);
|
||||
|
@ -682,12 +706,6 @@ fn non_exhaustive_match<'p, 'tcx>(
|
|||
arms: &[ArmId],
|
||||
expr_span: Span,
|
||||
) -> ErrorGuaranteed {
|
||||
for &arm in arms {
|
||||
if let Err(err) = thir[arm].pattern.error_reported() {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
let is_empty_match = arms.is_empty();
|
||||
let non_empty_enum = match scrut_ty.kind() {
|
||||
ty::Adt(def, _) => def.is_enum() && !def.variants().is_empty(),
|
||||
|
|
|
@ -196,9 +196,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
};
|
||||
// All branches above emitted an error. Don't print any more lints.
|
||||
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
|
||||
let kind = PatKind::Constant {
|
||||
value: mir::Const::Ty(ty::Const::new_error(self.tcx(), e, cv.ty())),
|
||||
};
|
||||
let kind = PatKind::Error(e);
|
||||
return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
|
||||
} else if !self.saw_const_match_lint.get() {
|
||||
if let Some(mir_structural_match_violation) = mir_structural_match_violation {
|
||||
|
@ -351,7 +349,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
let e = tcx.sess.emit_err(InvalidPattern { span, non_sm_ty: ty });
|
||||
self.saw_const_match_error.set(Some(e));
|
||||
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
|
||||
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) }
|
||||
PatKind::Error(e)
|
||||
}
|
||||
ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
|
||||
debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,);
|
||||
|
@ -359,7 +357,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
let e = tcx.sess.emit_err(err);
|
||||
self.saw_const_match_error.set(Some(e));
|
||||
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
|
||||
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) }
|
||||
PatKind::Error(e)
|
||||
}
|
||||
ty::Adt(adt_def, args) if adt_def.is_enum() => {
|
||||
let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap();
|
||||
|
@ -434,17 +432,13 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
} else {
|
||||
if let Some(e) = self.saw_const_match_error.get() {
|
||||
// We already errored. Signal that in the pattern, so that follow up errors can be silenced.
|
||||
PatKind::Constant {
|
||||
value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)),
|
||||
}
|
||||
PatKind::Error(e)
|
||||
} else {
|
||||
let err = TypeNotStructural { span, non_sm_ty: *pointee_ty };
|
||||
let e = tcx.sess.emit_err(err);
|
||||
self.saw_const_match_error.set(Some(e));
|
||||
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
|
||||
PatKind::Constant {
|
||||
value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)),
|
||||
}
|
||||
PatKind::Error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -456,9 +450,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
|
||||
let e = tcx.sess.emit_err(err);
|
||||
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
|
||||
PatKind::Constant {
|
||||
value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)),
|
||||
}
|
||||
PatKind::Error(e)
|
||||
} else {
|
||||
let old = self.behind_reference.replace(true);
|
||||
// `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
|
||||
|
@ -489,7 +481,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
let e = tcx.sess.emit_err(err);
|
||||
self.saw_const_match_error.set(Some(e));
|
||||
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
|
||||
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_error(tcx, e, ty)) }
|
||||
PatKind::Error(e)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1525,6 +1525,10 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
|
|||
let pats = expand_or_pat(pat);
|
||||
fields = Fields::from_iter(cx, pats.into_iter().map(mkpat));
|
||||
}
|
||||
PatKind::Error(_) => {
|
||||
ctor = Opaque;
|
||||
fields = Fields::empty();
|
||||
}
|
||||
}
|
||||
DeconstructedPat::new(ctor, fields, pat.ty, pat.span)
|
||||
}
|
||||
|
|
|
@ -252,10 +252,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
|
||||
hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
|
||||
let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
|
||||
// FIXME?: returning `_` can cause inaccurate "unreachable" warnings. This can be
|
||||
// fixed by returning `PatKind::Const(ConstKind::Error(...))` if #115937 gets
|
||||
// merged.
|
||||
self.lower_pattern_range(lo_expr, hi_expr, end, ty, span).unwrap_or(PatKind::Wild)
|
||||
self.lower_pattern_range(lo_expr, hi_expr, end, ty, span)
|
||||
.unwrap_or_else(PatKind::Error)
|
||||
}
|
||||
|
||||
hir::PatKind::Path(ref qpath) => {
|
||||
|
@ -423,9 +421,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
if adt_def.is_enum() {
|
||||
let args = match ty.kind() {
|
||||
ty::Adt(_, args) | ty::FnDef(_, args) => args,
|
||||
ty::Error(_) => {
|
||||
ty::Error(e) => {
|
||||
// Avoid ICE (#50585)
|
||||
return PatKind::Wild;
|
||||
return PatKind::Error(*e);
|
||||
}
|
||||
_ => bug!("inappropriate type for def: {:?}", ty),
|
||||
};
|
||||
|
@ -452,7 +450,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
| Res::SelfTyAlias { .. }
|
||||
| Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
|
||||
_ => {
|
||||
match res {
|
||||
let e = match res {
|
||||
Res::Def(DefKind::ConstParam, _) => {
|
||||
self.tcx.sess.emit_err(ConstParamInPattern { span })
|
||||
}
|
||||
|
@ -461,7 +459,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
}
|
||||
_ => self.tcx.sess.emit_err(NonConstPath { span }),
|
||||
};
|
||||
PatKind::Wild
|
||||
PatKind::Error(e)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -513,14 +511,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
// It should be assoc consts if there's no error but we cannot resolve it.
|
||||
debug_assert!(is_associated_const);
|
||||
|
||||
self.tcx.sess.emit_err(AssocConstInPattern { span });
|
||||
|
||||
return pat_from_kind(PatKind::Wild);
|
||||
let e = self.tcx.sess.emit_err(AssocConstInPattern { span });
|
||||
return pat_from_kind(PatKind::Error(e));
|
||||
}
|
||||
|
||||
Err(_) => {
|
||||
self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
|
||||
return pat_from_kind(PatKind::Wild);
|
||||
let e = self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
|
||||
return pat_from_kind(PatKind::Error(e));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -574,12 +571,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
Err(ErrorHandled::TooGeneric(_)) => {
|
||||
// While `Reported | Linted` cases will have diagnostics emitted already
|
||||
// it is not true for TooGeneric case, so we need to give user more information.
|
||||
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
||||
pat_from_kind(PatKind::Wild)
|
||||
let e = self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
||||
pat_from_kind(PatKind::Error(e))
|
||||
}
|
||||
Err(_) => {
|
||||
self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
|
||||
pat_from_kind(PatKind::Wild)
|
||||
let e = self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
|
||||
pat_from_kind(PatKind::Error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -629,7 +626,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
let uneval = mir::UnevaluatedConst { def: def_id.to_def_id(), args, promoted: None };
|
||||
debug_assert!(!args.has_free_regions());
|
||||
|
||||
let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args: args };
|
||||
let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
|
||||
// First try using a valtree in order to destructure the constant into a pattern.
|
||||
// FIXME: replace "try to do a thing, then fall back to another thing"
|
||||
// but something more principled, like a trait query checking whether this can be turned into a valtree.
|
||||
|
@ -649,10 +646,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind,
|
||||
Err(ErrorHandled::TooGeneric(_)) => {
|
||||
// If we land here it means the const can't be evaluated because it's `TooGeneric`.
|
||||
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
||||
PatKind::Wild
|
||||
let e = self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
||||
PatKind::Error(e)
|
||||
}
|
||||
Err(ErrorHandled::Reported(..)) => PatKind::Wild,
|
||||
Err(ErrorHandled::Reported(err, ..)) => PatKind::Error(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -685,7 +682,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
Ok(constant) => {
|
||||
self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind
|
||||
}
|
||||
Err(LitToConstError::Reported(_)) => PatKind::Wild,
|
||||
Err(LitToConstError::Reported(e)) => PatKind::Error(e),
|
||||
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
|
||||
}
|
||||
}
|
||||
|
@ -791,6 +788,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
|
|||
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
||||
match *self {
|
||||
PatKind::Wild => PatKind::Wild,
|
||||
PatKind::Error(e) => PatKind::Error(e),
|
||||
PatKind::AscribeUserType {
|
||||
ref subpattern,
|
||||
ascription: Ascription { ref annotation, variance },
|
||||
|
|
|
@ -757,6 +757,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
|||
print_indented!(self, "]", depth_lvl + 2);
|
||||
print_indented!(self, "}", depth_lvl + 1);
|
||||
}
|
||||
PatKind::Error(_) => {
|
||||
print_indented!(self, "Error", depth_lvl + 1);
|
||||
}
|
||||
}
|
||||
|
||||
print_indented!(self, "}", depth_lvl);
|
||||
|
|
|
@ -6,6 +6,9 @@ pub use crate::sys_common::process::CommandEnvs;
|
|||
#[cfg_attr(any(target_os = "espidf", target_os = "horizon"), allow(unused))]
|
||||
mod process_common;
|
||||
|
||||
#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))]
|
||||
mod process_unsupported;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_os = "fuchsia")] {
|
||||
#[path = "process_fuchsia.rs"]
|
||||
|
@ -15,8 +18,9 @@ cfg_if::cfg_if! {
|
|||
#[path = "process_vxworks.rs"]
|
||||
mod process_inner;
|
||||
} else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] {
|
||||
#[path = "process_unsupported.rs"]
|
||||
mod process_inner;
|
||||
mod process_inner {
|
||||
pub use super::process_unsupported::*;
|
||||
}
|
||||
} else {
|
||||
#[path = "process_unix.rs"]
|
||||
mod process_inner;
|
||||
|
|
|
@ -63,12 +63,12 @@ pub struct ExitStatusError(NonZero_c_int);
|
|||
|
||||
impl Into<ExitStatus> for ExitStatusError {
|
||||
fn into(self) -> ExitStatus {
|
||||
ExitStatus(self.0.into())
|
||||
ExitStatus::from(c_int::from(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl ExitStatusError {
|
||||
pub fn code(self) -> Option<NonZeroI32> {
|
||||
ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
|
||||
ExitStatus::from(c_int::from(self.0)).code().map(|st| st.try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
//! Emulated wait status for non-Unix #[cfg(unix) platforms
|
||||
//!
|
||||
//! Separate module to facilitate testing against a real Unix implementation.
|
||||
use core::ffi::NonZero_c_int;
|
||||
|
||||
use crate::ffi::c_int;
|
||||
use crate::fmt;
|
||||
|
||||
use super::ExitStatusError;
|
||||
|
||||
/// Emulated wait status for use by `process_unsupported.rs`
|
||||
///
|
||||
/// Uses the "traditional unix" encoding. For use on platfors which are `#[cfg(unix)]`
|
||||
|
@ -40,6 +43,19 @@ impl ExitStatus {
|
|||
if (w & 0x7f) == 0 { Some((w & 0xff00) >> 8) } else { None }
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
|
||||
// This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is
|
||||
// true on all actual versions of Unix, is widely assumed, and is specified in SuS
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not
|
||||
// true for a platform pretending to be Unix, the tests (our doctests, and also
|
||||
// process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too.
|
||||
match NonZero_c_int::try_from(self.wait_status) {
|
||||
/* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
|
||||
/* was zero, couldn't convert */ Err(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signal(&self) -> Option<i32> {
|
||||
let signal = self.wait_status & 0x007f;
|
||||
if signal > 0 && signal < 0x7f { Some(signal) } else { None }
|
||||
|
|
|
@ -5,6 +5,9 @@ edition = "2021"
|
|||
build = "build.rs"
|
||||
default-run = "bootstrap"
|
||||
|
||||
[features]
|
||||
build-metrics = ["sysinfo"]
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
doctest = false
|
||||
|
@ -31,12 +34,18 @@ test = false
|
|||
|
||||
[dependencies]
|
||||
build_helper = { path = "../tools/build_helper" }
|
||||
cc = "1.0.69"
|
||||
clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] }
|
||||
clap_complete = "4.2.2"
|
||||
cmake = "0.1.38"
|
||||
filetime = "0.2"
|
||||
cc = "1.0.69"
|
||||
libc = "0.2"
|
||||
hex = "0.4"
|
||||
ignore = "0.4.10"
|
||||
libc = "0.2"
|
||||
object = { version = "0.32.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] }
|
||||
once_cell = "1.7.2"
|
||||
opener = "0.5"
|
||||
semver = "1.0.17"
|
||||
serde = "1.0.137"
|
||||
# Directly use serde_derive rather than through the derive feature of serde to allow building both
|
||||
# in parallel and to allow serde_json and toml to start building as soon as serde has been built.
|
||||
|
@ -46,17 +55,11 @@ sha2 = "0.10"
|
|||
tar = "0.4"
|
||||
termcolor = "1.2.0"
|
||||
toml = "0.5"
|
||||
ignore = "0.4.10"
|
||||
opener = "0.5"
|
||||
once_cell = "1.7.2"
|
||||
xz2 = "0.1"
|
||||
walkdir = "2"
|
||||
xz2 = "0.1"
|
||||
|
||||
# Dependencies needed by the build-metrics feature
|
||||
sysinfo = { version = "0.26.0", optional = true }
|
||||
clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] }
|
||||
clap_complete = "4.2.2"
|
||||
semver = "1.0.17"
|
||||
|
||||
# Solaris doesn't support flock() and thus fd-lock is not option now
|
||||
[target.'cfg(not(target_os = "solaris"))'.dependencies]
|
||||
|
@ -80,9 +83,6 @@ features = [
|
|||
[dev-dependencies]
|
||||
pretty_assertions = "1.4"
|
||||
|
||||
[features]
|
||||
build-metrics = ["sysinfo"]
|
||||
|
||||
# We care a lot about bootstrap's compile times, so don't include debuginfo for
|
||||
# dependencies, only bootstrap itself.
|
||||
[profile.dev]
|
||||
|
|
|
@ -110,3 +110,23 @@ https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
|
|||
|
||||
This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
|
||||
to automatically go to the first result.
|
||||
|
||||
## `#[repr(transparent)]`: Documenting the transparent representation
|
||||
|
||||
You can read more about `#[repr(transparent)]` itself in the [Rust Reference][repr-trans-ref] and
|
||||
in the [Rustonomicon][repr-trans-nomicon].
|
||||
|
||||
Since this representation is only considered part of the public ABI if the single field with non-trivial
|
||||
size or alignment is public and if the documentation does not state otherwise, Rustdoc helpfully displays
|
||||
the attribute if and only if the non-1-ZST field is public or at least one field is public in case all
|
||||
fields are 1-ZST fields. The term *1-ZST* refers to types that are one-aligned and zero-sized.
|
||||
|
||||
It would seem that one can manually hide the attribute with `#[cfg_attr(not(doc), repr(transparent))]`
|
||||
if one wishes to declare the representation as private even if the non-1-ZST field is public.
|
||||
However, due to [current limitations][cross-crate-cfg-doc], this method is not always guaranteed to work.
|
||||
Therefore, if you would like to do so, you should always write it down in prose independently of whether
|
||||
you use `cfg_attr` or not.
|
||||
|
||||
[repr-trans-ref]: https://doc.rust-lang.org/reference/type-layout.html#the-transparent-representation
|
||||
[repr-trans-nomicon]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
|
||||
[cross-crate-cfg-doc]: https://github.com/rust-lang/rust/issues/114952
|
||||
|
|
|
@ -713,12 +713,16 @@ impl Item {
|
|||
Some(tcx.visibility(def_id))
|
||||
}
|
||||
|
||||
pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, keep_as_is: bool) -> Vec<String> {
|
||||
pub(crate) fn attributes(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
cache: &Cache,
|
||||
keep_as_is: bool,
|
||||
) -> Vec<String> {
|
||||
const ALLOWED_ATTRIBUTES: &[Symbol] =
|
||||
&[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
|
||||
&[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
|
||||
|
||||
use rustc_abi::IntegerType;
|
||||
use rustc_middle::ty::ReprFlags;
|
||||
|
||||
let mut attrs: Vec<String> = self
|
||||
.attrs
|
||||
|
@ -739,20 +743,38 @@ impl Item {
|
|||
}
|
||||
})
|
||||
.collect();
|
||||
if let Some(def_id) = self.def_id() &&
|
||||
!def_id.is_local() &&
|
||||
// This check is needed because `adt_def` will panic if not a compatible type otherwise...
|
||||
matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union)
|
||||
if !keep_as_is
|
||||
&& let Some(def_id) = self.def_id()
|
||||
&& let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_()
|
||||
{
|
||||
let repr = tcx.adt_def(def_id).repr();
|
||||
let adt = tcx.adt_def(def_id);
|
||||
let repr = adt.repr();
|
||||
let mut out = Vec::new();
|
||||
if repr.flags.contains(ReprFlags::IS_C) {
|
||||
if repr.c() {
|
||||
out.push("C");
|
||||
}
|
||||
if repr.flags.contains(ReprFlags::IS_TRANSPARENT) {
|
||||
out.push("transparent");
|
||||
if repr.transparent() {
|
||||
// Render `repr(transparent)` iff the non-1-ZST field is public or at least one
|
||||
// field is public in case all fields are 1-ZST fields.
|
||||
let render_transparent = cache.document_private
|
||||
|| adt
|
||||
.all_fields()
|
||||
.find(|field| {
|
||||
let ty =
|
||||
field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
|
||||
tcx.layout_of(tcx.param_env(field.did).and(ty))
|
||||
.is_ok_and(|layout| !layout.is_1zst())
|
||||
})
|
||||
.map_or_else(
|
||||
|| adt.all_fields().any(|field| field.vis.is_public()),
|
||||
|field| field.vis.is_public(),
|
||||
);
|
||||
|
||||
if render_transparent {
|
||||
out.push("transparent");
|
||||
}
|
||||
}
|
||||
if repr.flags.contains(ReprFlags::IS_SIMD) {
|
||||
if repr.simd() {
|
||||
out.push("simd");
|
||||
}
|
||||
let pack_s;
|
||||
|
@ -777,10 +799,9 @@ impl Item {
|
|||
};
|
||||
out.push(&int_s);
|
||||
}
|
||||
if out.is_empty() {
|
||||
return Vec::new();
|
||||
if !out.is_empty() {
|
||||
attrs.push(format!("#[repr({})]", out.join(", ")));
|
||||
}
|
||||
attrs.push(format!("#[repr({})]", out.join(", ")));
|
||||
}
|
||||
attrs
|
||||
}
|
||||
|
|
|
@ -868,10 +868,10 @@ fn assoc_method(
|
|||
let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
|
||||
header_len += 4;
|
||||
let indent_str = " ";
|
||||
write!(w, "{}", render_attributes_in_pre(meth, indent_str, tcx));
|
||||
write!(w, "{}", render_attributes_in_pre(meth, indent_str, cx));
|
||||
(4, indent_str, Ending::NoNewline)
|
||||
} else {
|
||||
render_attributes_in_code(w, meth, tcx);
|
||||
render_attributes_in_code(w, meth, cx);
|
||||
(0, "", Ending::Newline)
|
||||
};
|
||||
w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
|
||||
|
@ -1047,13 +1047,13 @@ fn render_assoc_item(
|
|||
|
||||
// When an attribute is rendered inside a `<pre>` tag, it is formatted using
|
||||
// a whitespace prefix and newline.
|
||||
fn render_attributes_in_pre<'a, 'b: 'a>(
|
||||
fn render_attributes_in_pre<'a, 'tcx: 'a>(
|
||||
it: &'a clean::Item,
|
||||
prefix: &'a str,
|
||||
tcx: TyCtxt<'b>,
|
||||
) -> impl fmt::Display + Captures<'a> + Captures<'b> {
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> impl fmt::Display + Captures<'a> + Captures<'tcx> {
|
||||
crate::html::format::display_fn(move |f| {
|
||||
for a in it.attributes(tcx, false) {
|
||||
for a in it.attributes(cx.tcx(), cx.cache(), false) {
|
||||
writeln!(f, "{prefix}{a}")?;
|
||||
}
|
||||
Ok(())
|
||||
|
@ -1062,8 +1062,8 @@ fn render_attributes_in_pre<'a, 'b: 'a>(
|
|||
|
||||
// When an attribute is rendered inside a <code> tag, it is formatted using
|
||||
// a div to produce a newline after it.
|
||||
fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, tcx: TyCtxt<'_>) {
|
||||
for attr in it.attributes(tcx, false) {
|
||||
fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) {
|
||||
for attr in it.attributes(cx.tcx(), cx.cache(), false) {
|
||||
write!(w, "<div class=\"code-attribute\">{attr}</div>").unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,8 +120,7 @@ macro_rules! item_template_methods {
|
|||
fn render_attributes_in_pre<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
let (item, cx) = self.item_and_mut_cx();
|
||||
let tcx = cx.tcx();
|
||||
let v = render_attributes_in_pre(item, "", tcx);
|
||||
let v = render_attributes_in_pre(item, "", &cx);
|
||||
write!(f, "{v}")
|
||||
})
|
||||
}
|
||||
|
@ -659,7 +658,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
|
|||
w,
|
||||
"{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \
|
||||
{name}{generics}{decl}{notable_traits}{where_clause}",
|
||||
attrs = render_attributes_in_pre(it, "", tcx),
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
vis = visibility,
|
||||
constness = constness,
|
||||
asyncness = asyncness,
|
||||
|
@ -694,7 +693,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
|
|||
write!(
|
||||
w,
|
||||
"{attrs}{vis}{unsafety}{is_auto}trait {name}{generics}{bounds}",
|
||||
attrs = render_attributes_in_pre(it, "", tcx),
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
|
||||
unsafety = t.unsafety(tcx).print_with_space(),
|
||||
is_auto = if t.is_auto(tcx) { "auto " } else { "" },
|
||||
|
@ -1173,7 +1172,7 @@ fn item_trait_alias(
|
|||
write!(
|
||||
w,
|
||||
"{attrs}trait {name}{generics}{where_b} = {bounds};",
|
||||
attrs = render_attributes_in_pre(it, "", cx.tcx()),
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
name = it.name.unwrap(),
|
||||
generics = t.generics.print(cx),
|
||||
where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline),
|
||||
|
@ -1201,7 +1200,7 @@ fn item_opaque_ty(
|
|||
write!(
|
||||
w,
|
||||
"{attrs}type {name}{generics}{where_clause} = impl {bounds};",
|
||||
attrs = render_attributes_in_pre(it, "", cx.tcx()),
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
name = it.name.unwrap(),
|
||||
generics = t.generics.print(cx),
|
||||
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
|
||||
|
@ -1226,7 +1225,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c
|
|||
write!(
|
||||
w,
|
||||
"{attrs}{vis}type {name}{generics}{where_clause} = {type_};",
|
||||
attrs = render_attributes_in_pre(it, "", cx.tcx()),
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
|
||||
name = it.name.unwrap(),
|
||||
generics = t.generics.print(cx),
|
||||
|
@ -1415,7 +1414,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
|
|||
let tcx = cx.tcx();
|
||||
let count_variants = e.variants().count();
|
||||
wrap_item(w, |w| {
|
||||
render_attributes_in_code(w, it, tcx);
|
||||
render_attributes_in_code(w, it, cx);
|
||||
write!(
|
||||
w,
|
||||
"{}enum {}{}",
|
||||
|
@ -1734,7 +1733,7 @@ fn item_primitive(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Ite
|
|||
fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) {
|
||||
wrap_item(w, |w| {
|
||||
let tcx = cx.tcx();
|
||||
render_attributes_in_code(w, it, tcx);
|
||||
render_attributes_in_code(w, it, cx);
|
||||
|
||||
write!(
|
||||
w,
|
||||
|
@ -1783,7 +1782,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
|
|||
|
||||
fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) {
|
||||
wrap_item(w, |w| {
|
||||
render_attributes_in_code(w, it, cx.tcx());
|
||||
render_attributes_in_code(w, it, cx);
|
||||
render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
|
||||
});
|
||||
|
||||
|
@ -1843,7 +1842,7 @@ fn item_fields(
|
|||
|
||||
fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
|
||||
wrap_item(w, |buffer| {
|
||||
render_attributes_in_code(buffer, it, cx.tcx());
|
||||
render_attributes_in_code(buffer, it, cx);
|
||||
write!(
|
||||
buffer,
|
||||
"{vis}static {mutability}{name}: {typ}",
|
||||
|
@ -1861,7 +1860,7 @@ fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item,
|
|||
fn item_foreign_type(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item) {
|
||||
wrap_item(w, |buffer| {
|
||||
buffer.write_str("extern {\n").unwrap();
|
||||
render_attributes_in_code(buffer, it, cx.tcx());
|
||||
render_attributes_in_code(buffer, it, cx);
|
||||
write!(
|
||||
buffer,
|
||||
" {}type {};\n}}",
|
||||
|
|
|
@ -18,6 +18,7 @@ use rustdoc_json_types::*;
|
|||
|
||||
use crate::clean::{self, ItemId};
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::formats::FormatRenderer;
|
||||
use crate::json::JsonRenderer;
|
||||
use crate::passes::collect_intra_doc_links::UrlFragment;
|
||||
|
||||
|
@ -41,7 +42,7 @@ impl JsonRenderer<'_> {
|
|||
})
|
||||
.collect();
|
||||
let docs = item.opt_doc_value();
|
||||
let attrs = item.attributes(self.tcx, true);
|
||||
let attrs = item.attributes(self.tcx, self.cache(), true);
|
||||
let span = item.span(self.tcx);
|
||||
let visibility = item.visibility(self.tcx);
|
||||
let clean::Item { name, item_id, .. } = item;
|
||||
|
|
|
@ -31,3 +31,7 @@ unsafe fn without_avx(x: __m256) -> __m256 {
|
|||
};
|
||||
add(x, x)
|
||||
}
|
||||
|
||||
// Don't allow the above CHECK-NOT to accidentally match a commit hash in the
|
||||
// compiler version.
|
||||
// CHECK-LABEL: rustc version
|
||||
|
|
7
tests/rustdoc/inline_cross/attributes.rs
Normal file
7
tests/rustdoc/inline_cross/attributes.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
// aux-crate:attributes=attributes.rs
|
||||
// edition:2021
|
||||
#![crate_name = "user"]
|
||||
|
||||
// @has 'user/struct.NonExhaustive.html'
|
||||
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[non_exhaustive]'
|
||||
pub use attributes::NonExhaustive;
|
2
tests/rustdoc/inline_cross/auxiliary/attributes.rs
Normal file
2
tests/rustdoc/inline_cross/auxiliary/attributes.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
#[non_exhaustive]
|
||||
pub struct NonExhaustive;
|
|
@ -10,7 +10,7 @@ pub struct ReprSimd {
|
|||
}
|
||||
#[repr(transparent)]
|
||||
pub struct ReprTransparent {
|
||||
field: u8,
|
||||
pub field: u8,
|
||||
}
|
||||
#[repr(isize)]
|
||||
pub enum ReprIsize {
|
||||
|
@ -20,3 +20,23 @@ pub enum ReprIsize {
|
|||
pub enum ReprU8 {
|
||||
Bla,
|
||||
}
|
||||
|
||||
#[repr(transparent)] // private
|
||||
pub struct ReprTransparentPrivField {
|
||||
field: u32, // non-1-ZST field
|
||||
}
|
||||
|
||||
#[repr(transparent)] // public
|
||||
pub struct ReprTransparentPriv1ZstFields {
|
||||
marker0: Marker,
|
||||
pub main: u64, // non-1-ZST field
|
||||
marker1: Marker,
|
||||
}
|
||||
|
||||
#[repr(transparent)] // private
|
||||
pub struct ReprTransparentPrivFieldPub1ZstFields {
|
||||
main: [u16; 0], // non-1-ZST field
|
||||
pub marker: Marker,
|
||||
}
|
||||
|
||||
pub struct Marker; // 1-ZST
|
||||
|
|
|
@ -9,21 +9,32 @@ extern crate repr;
|
|||
|
||||
// @has 'foo/struct.ReprC.html'
|
||||
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C, align(8))]'
|
||||
#[doc(inline)]
|
||||
pub use repr::ReprC;
|
||||
// @has 'foo/struct.ReprSimd.html'
|
||||
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]'
|
||||
#[doc(inline)]
|
||||
pub use repr::ReprSimd;
|
||||
// @has 'foo/struct.ReprTransparent.html'
|
||||
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
|
||||
#[doc(inline)]
|
||||
pub use repr::ReprTransparent;
|
||||
// @has 'foo/enum.ReprIsize.html'
|
||||
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]'
|
||||
#[doc(inline)]
|
||||
pub use repr::ReprIsize;
|
||||
// @has 'foo/enum.ReprU8.html'
|
||||
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u8)]'
|
||||
#[doc(inline)]
|
||||
pub use repr::ReprU8;
|
||||
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/90435>.
|
||||
// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one
|
||||
// field is public in case all fields are 1-ZST fields.
|
||||
|
||||
// @has 'foo/struct.ReprTransparentPrivField.html'
|
||||
// @!has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
|
||||
pub use repr::ReprTransparentPrivField;
|
||||
|
||||
// @has 'foo/struct.ReprTransparentPriv1ZstFields.html'
|
||||
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
|
||||
pub use repr::ReprTransparentPriv1ZstFields;
|
||||
|
||||
// @has 'foo/struct.ReprTransparentPrivFieldPub1ZstFields.html'
|
||||
// @!has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
|
||||
pub use repr::ReprTransparentPrivFieldPub1ZstFields;
|
||||
|
|
29
tests/rustdoc/repr.rs
Normal file
29
tests/rustdoc/repr.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Regression test for <https://github.com/rust-lang/rust/issues/90435>.
|
||||
// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one
|
||||
// field is public in case all fields are 1-ZST fields.
|
||||
|
||||
// @has 'repr/struct.ReprTransparentPrivField.html'
|
||||
// @!has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
|
||||
#[repr(transparent)] // private
|
||||
pub struct ReprTransparentPrivField {
|
||||
field: u32, // non-1-ZST field
|
||||
}
|
||||
|
||||
// @has 'repr/struct.ReprTransparentPriv1ZstFields.html'
|
||||
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
|
||||
#[repr(transparent)] // public
|
||||
pub struct ReprTransparentPriv1ZstFields {
|
||||
marker0: Marker,
|
||||
pub main: u64, // non-1-ZST field
|
||||
marker1: Marker,
|
||||
}
|
||||
|
||||
// @has 'repr/struct.ReprTransparentPub1ZstField.html'
|
||||
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
|
||||
#[repr(transparent)] // public
|
||||
pub struct ReprTransparentPub1ZstField {
|
||||
marker0: Marker,
|
||||
pub marker1: Marker,
|
||||
}
|
||||
|
||||
struct Marker; // 1-ZST
|
|
@ -7,17 +7,5 @@ LL | WHAT_A_TYPE => 0,
|
|||
= note: the traits must be derived, manual `impl`s are not sufficient
|
||||
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
|
||||
|
||||
error[E0015]: cannot match on `TypeId` in constant functions
|
||||
--> $DIR/typeid-equality-by-subtyping.rs:18:9
|
||||
|
|
||||
LL | WHAT_A_TYPE => 0,
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: `TypeId` cannot be compared in compile-time, and therefore cannot be used in `match`es
|
||||
note: impl defined here, but it is not `const`
|
||||
--> $SRC_DIR/core/src/any.rs:LL:COL
|
||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||
error: aborting due to previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0015`.
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// This test should never pass!
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
trait Captures<'a> {}
|
||||
impl<T> Captures<'_> for T {}
|
||||
|
||||
struct MyTy<'a, 'b>(Option<*mut &'a &'b ()>);
|
||||
unsafe impl Send for MyTy<'_, 'static> {}
|
||||
|
||||
fn step1<'a, 'b: 'a>() -> impl Sized + Captures<'b> + 'a {
|
||||
MyTy::<'a, 'b>(None)
|
||||
}
|
||||
|
||||
fn step2<'a, 'b: 'a>() -> impl Sized + 'a {
|
||||
step1::<'a, 'b>()
|
||||
//~^ ERROR hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds
|
||||
}
|
||||
|
||||
fn step3<'a, 'b: 'a>() -> impl Send + 'a {
|
||||
step2::<'a, 'b>()
|
||||
// This should not be Send unless `'b: 'static`
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,18 @@
|
|||
error[E0700]: hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds
|
||||
--> $DIR/rpit-hidden-erased-unsoundness.rs:16:5
|
||||
|
|
||||
LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a {
|
||||
| -- --------------- opaque type defined here
|
||||
| |
|
||||
| hidden type `impl Captures<'b> + 'a` captures the lifetime `'b` as defined here
|
||||
LL | step1::<'a, 'b>()
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: to declare that `impl Sized + 'a` captures `'b`, you can add an explicit `'b` lifetime bound
|
||||
|
|
||||
LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a + 'b {
|
||||
| ++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0700`.
|
|
@ -0,0 +1,32 @@
|
|||
// This test should never pass!
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
trait Swap: Sized {
|
||||
fn swap(self, other: Self);
|
||||
}
|
||||
|
||||
impl<T> Swap for Rc<RefCell<T>> {
|
||||
fn swap(self, other: Self) {
|
||||
<RefCell<T>>::swap(&self, &other);
|
||||
}
|
||||
}
|
||||
|
||||
fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
|
||||
x
|
||||
//~^ ERROR hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds
|
||||
}
|
||||
|
||||
fn dangle() -> &'static [i32; 3] {
|
||||
let long = Rc::new(RefCell::new(&[4, 5, 6]));
|
||||
let x = [1, 2, 3];
|
||||
let short = Rc::new(RefCell::new(&x));
|
||||
hide(long.clone()).swap(hide(short));
|
||||
let res: &'static [i32; 3] = *long.borrow();
|
||||
res
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", dangle());
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds
|
||||
--> $DIR/rpit-hide-lifetime-for-swap.rs:17:5
|
||||
|
|
||||
LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a {
|
||||
| -- -------------- opaque type defined here
|
||||
| |
|
||||
| hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here
|
||||
LL | x
|
||||
| ^
|
||||
|
|
||||
help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound
|
||||
|
|
||||
LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + 'b {
|
||||
| ++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0700`.
|
|
@ -0,0 +1,28 @@
|
|||
// This test should never pass!
|
||||
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
trait Captures<'a> {}
|
||||
impl<T> Captures<'_> for T {}
|
||||
|
||||
struct MyTy<'a, 'b>(Option<*mut &'a &'b ()>);
|
||||
unsafe impl Send for MyTy<'_, 'static> {}
|
||||
|
||||
fn step1<'a, 'b: 'a>() -> impl Sized + Captures<'b> + 'a {
|
||||
MyTy::<'a, 'b>(None)
|
||||
}
|
||||
|
||||
mod tait {
|
||||
type Tait<'a> = impl Sized + 'a;
|
||||
pub(super) fn step2<'a, 'b: 'a>() -> Tait<'a> {
|
||||
super::step1::<'a, 'b>()
|
||||
//~^ ERROR hidden type for `Tait<'a>` captures lifetime that does not appear in bounds
|
||||
}
|
||||
}
|
||||
|
||||
fn step3<'a, 'b: 'a>() -> impl Send + 'a {
|
||||
tait::step2::<'a, 'b>()
|
||||
// This should not be Send unless `'b: 'static`
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,13 @@
|
|||
error[E0700]: hidden type for `Tait<'a>` captures lifetime that does not appear in bounds
|
||||
--> $DIR/tait-hidden-erased-unsoundness.rs:18:9
|
||||
|
|
||||
LL | type Tait<'a> = impl Sized + 'a;
|
||||
| --------------- opaque type defined here
|
||||
LL | pub(super) fn step2<'a, 'b: 'a>() -> Tait<'a> {
|
||||
| -- hidden type `impl Captures<'b> + 'a` captures the lifetime `'b` as defined here
|
||||
LL | super::step1::<'a, 'b>()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0700`.
|
|
@ -52,7 +52,6 @@ fn main() {
|
|||
BAR => {}
|
||||
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
_ => {}
|
||||
//~^ ERROR unreachable pattern
|
||||
}
|
||||
|
||||
match BAR {
|
||||
|
@ -60,7 +59,6 @@ fn main() {
|
|||
//~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
Bar => {}
|
||||
_ => {}
|
||||
//~^ ERROR unreachable pattern
|
||||
}
|
||||
|
||||
match BAR {
|
||||
|
|
|
@ -38,7 +38,16 @@ LL | BAR => {}
|
|||
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
|
||||
|
||||
error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:59:9
|
||||
--> $DIR/consts-opaque.rs:58:9
|
||||
|
|
||||
LL | BAR => {}
|
||||
| ^^^
|
||||
|
|
||||
= note: the traits must be derived, manual `impl`s are not sufficient
|
||||
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
|
||||
|
||||
error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:65:9
|
||||
|
|
||||
LL | BAR => {}
|
||||
| ^^^
|
||||
|
@ -55,17 +64,8 @@ LL | BAR => {}
|
|||
= note: the traits must be derived, manual `impl`s are not sufficient
|
||||
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
|
||||
|
||||
error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:69:9
|
||||
|
|
||||
LL | BAR => {}
|
||||
| ^^^
|
||||
|
|
||||
= note: the traits must be derived, manual `impl`s are not sufficient
|
||||
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
|
||||
|
||||
error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:75:9
|
||||
--> $DIR/consts-opaque.rs:73:9
|
||||
|
|
||||
LL | BAZ => {}
|
||||
| ^^^
|
||||
|
@ -74,7 +74,7 @@ LL | BAZ => {}
|
|||
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
|
||||
|
||||
error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:83:9
|
||||
--> $DIR/consts-opaque.rs:81:9
|
||||
|
|
||||
LL | BAZ => {}
|
||||
| ^^^
|
||||
|
@ -83,7 +83,7 @@ LL | BAZ => {}
|
|||
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
|
||||
|
||||
error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
|
||||
--> $DIR/consts-opaque.rs:89:9
|
||||
--> $DIR/consts-opaque.rs:87:9
|
||||
|
|
||||
LL | BAZ => {}
|
||||
| ^^^
|
||||
|
@ -91,37 +91,14 @@ LL | BAZ => {}
|
|||
= note: the traits must be derived, manual `impl`s are not sufficient
|
||||
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:54:9
|
||||
|
|
||||
LL | Bar => {}
|
||||
| --- matches any value
|
||||
...
|
||||
LL | _ => {}
|
||||
| ^ unreachable pattern
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/consts-opaque.rs:6:9
|
||||
|
|
||||
LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/consts-opaque.rs:62:9
|
||||
|
|
||||
LL | Bar => {}
|
||||
| --- matches any value
|
||||
LL | _ => {}
|
||||
| ^ unreachable pattern
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Wrap(_)` not covered
|
||||
--> $DIR/consts-opaque.rs:124:11
|
||||
--> $DIR/consts-opaque.rs:122:11
|
||||
|
|
||||
LL | match WRAPQUUX {
|
||||
| ^^^^^^^^ pattern `Wrap(_)` not covered
|
||||
|
|
||||
note: `Wrap<fn(usize, usize) -> usize>` defined here
|
||||
--> $DIR/consts-opaque.rs:106:12
|
||||
--> $DIR/consts-opaque.rs:104:12
|
||||
|
|
||||
LL | struct Wrap<T>(T);
|
||||
| ^^^^
|
||||
|
@ -132,6 +109,6 @@ LL ~ WRAPQUUX => {},
|
|||
LL + Wrap(_) => todo!()
|
||||
|
|
||||
|
||||
error: aborting due to 12 previous errors; 1 warning emitted
|
||||
error: aborting due to 10 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0004`.
|
||||
|
|
Loading…
Add table
Reference in a new issue