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:
bors 2023-10-14 18:46:19 +00:00
commit ee8c9d3c34
35 changed files with 441 additions and 168 deletions

View file

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

View file

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

View file

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

View file

@ -168,7 +168,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Ok(())
}
PatKind::Wild => {
PatKind::Wild | PatKind::Error(_) => {
// nothing left to do
Ok(())
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

@ -0,0 +1,2 @@
#[non_exhaustive]
pub struct NonExhaustive;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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