Auto merge of #119837 - matthiaskrgr:rollup-l2olpad, r=matthiaskrgr

Rollup of 11 pull requests

Successful merges:

 - #115046 (Use version-sorting for all sorting)
 - #118915 (Add some comments, add `can_define_opaque_ty` check to `try_normalize_ty_recur`)
 - #119006 (Fix is_global special address handling)
 - #119637 (Pass LLVM error message back to pass wrapper.)
 - #119715 (Exhaustiveness: abort on type error)
 - #119763 (Cleanup things in and around `Diagnostic`)
 - #119788 (change function name in comments)
 - #119790 (Fix all_trait* methods to return all traits available in StableMIR)
 - #119803 (Silence some follow-up errors [1/x])
 - #119804 (Stabilize mutex_unpoison feature)
 - #119832 (Meta: Add project const traits to triagebot config)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-01-11 02:10:34 +00:00
commit 65b323b168
54 changed files with 690 additions and 303 deletions

View File

@ -315,7 +315,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
let mut failed = false;
let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| {
if let Some(ty::Dynamic(obj, _, ty::DynKind::Dyn)) = arg.as_type().map(Ty::kind) {
if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) {
let default = tcx.object_lifetime_default(param.def_id);
let re_static = tcx.lifetimes.re_static;
@ -339,7 +339,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
has_dyn = true;
Ty::new_dynamic(tcx, obj, implied_region, ty::DynKind::Dyn).into()
Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into()
} else {
arg
}

View File

@ -394,7 +394,7 @@ fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>)
let level = match item.map(|i| &i.kind) {
// These were a warning before #92959 and need to continue being that to avoid breaking
// stable user code (#94508).
Some(ast::ItemKind::MacCall(_)) => Level::Warning(None),
Some(ast::ItemKind::MacCall(_)) => Level::Warning,
_ => Level::Error,
};
let mut err = DiagnosticBuilder::<()>::new(dcx, level, msg);

View File

@ -417,7 +417,7 @@ fn report_inline_asm(
}
let level = match level {
llvm::DiagnosticLevel::Error => Level::Error,
llvm::DiagnosticLevel::Warning => Level::Warning(None),
llvm::DiagnosticLevel::Warning => Level::Warning,
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
};
cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source);

View File

@ -1847,14 +1847,9 @@ impl SharedEmitterMain {
dcx.emit_diagnostic(d);
}
Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
let err_level = match level {
Level::Error => Level::Error,
Level::Warning(_) => Level::Warning(None),
Level::Note => Level::Note,
_ => bug!("Invalid inline asm diagnostic level"),
};
assert!(matches!(level, Level::Error | Level::Warning | Level::Note));
let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string();
let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), err_level, msg);
let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), level, msg);
// If the cookie is 0 then we don't have span information.
if cookie != 0 {

View File

@ -87,7 +87,7 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String {
fn annotation_type_for_level(level: Level) -> AnnotationType {
match level {
Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error => AnnotationType::Error,
Level::Warning(_) => AnnotationType::Warning,
Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning,
Level::Note | Level::OnceNote => AnnotationType::Note,
Level::Help | Level::OnceHelp => AnnotationType::Help,
// FIXME(#59346): Not sure how to map this level

View File

@ -152,7 +152,6 @@ pub enum DiagnosticId {
name: String,
/// Indicates whether this lint should show up in cargo's future breakage report.
has_future_breakage: bool,
is_force_warn: bool,
},
}
@ -248,7 +247,8 @@ impl Diagnostic {
true
}
Level::Warning(_)
Level::ForceWarning(_)
| Level::Warning
| Level::Note
| Level::OnceNote
| Level::Help
@ -262,7 +262,7 @@ impl Diagnostic {
&mut self,
unstable_to_stable: &FxIndexMap<LintExpectationId, LintExpectationId>,
) {
if let Level::Expect(expectation_id) | Level::Warning(Some(expectation_id)) =
if let Level::Expect(expectation_id) | Level::ForceWarning(Some(expectation_id)) =
&mut self.level
{
if expectation_id.is_stable() {
@ -292,8 +292,11 @@ impl Diagnostic {
}
pub(crate) fn is_force_warn(&self) -> bool {
match self.code {
Some(DiagnosticId::Lint { is_force_warn, .. }) => is_force_warn,
match self.level {
Level::ForceWarning(_) => {
assert!(self.is_lint);
true
}
_ => false,
}
}
@ -472,7 +475,7 @@ impl Diagnostic {
/// Add a warning attached to this diagnostic.
#[rustc_lint_diagnostics]
pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
self.sub(Level::Warning(None), msg, MultiSpan::new());
self.sub(Level::Warning, msg, MultiSpan::new());
self
}
@ -484,7 +487,7 @@ impl Diagnostic {
sp: S,
msg: impl Into<SubdiagnosticMessage>,
) -> &mut Self {
self.sub(Level::Warning(None), msg, sp.into());
self.sub(Level::Warning, msg, sp.into());
self
}

View File

@ -198,7 +198,7 @@ impl Emitter for JsonEmitter {
.into_iter()
.map(|mut diag| {
if diag.level == crate::Level::Allow {
diag.level = crate::Level::Warning(None);
diag.level = crate::Level::Warning;
}
FutureBreakageItem {
diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic(

View File

@ -420,6 +420,7 @@ pub struct DiagCtxt {
/// as well as inconsistent state observation.
struct DiagCtxtInner {
flags: DiagCtxtFlags,
/// The number of lint errors that have been emitted.
lint_err_count: usize,
/// The number of errors that have been emitted, including duplicates.
@ -427,8 +428,13 @@ struct DiagCtxtInner {
/// This is not necessarily the count that's reported to the user once
/// compilation ends.
err_count: usize,
warn_count: usize,
deduplicated_err_count: usize,
/// The warning count, used for a recap upon finishing
deduplicated_warn_count: usize,
/// Has this diagnostic context printed any diagnostics? (I.e. has
/// `self.emitter.emit_diagnostic()` been called?
has_printed: bool,
emitter: Box<DynEmitter>,
span_delayed_bugs: Vec<DelayedDiagnostic>,
good_path_delayed_bugs: Vec<DelayedDiagnostic>,
@ -455,9 +461,6 @@ struct DiagCtxtInner {
/// When `.abort_if_errors()` is called, these are also emitted.
stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
/// The warning count, used for a recap upon finishing
deduplicated_warn_count: usize,
future_breakage_diagnostics: Vec<Diagnostic>,
/// The [`Self::unstable_expect_diagnostics`] should be empty when this struct is
@ -513,7 +516,7 @@ fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) {
(*f)(diag)
}
pub static TRACK_DIAGNOSTICS: AtomicRef<fn(Diagnostic, &mut dyn FnMut(Diagnostic))> =
pub static TRACK_DIAGNOSTIC: AtomicRef<fn(Diagnostic, &mut dyn FnMut(Diagnostic))> =
AtomicRef::new(&(default_track_diagnostic as _));
#[derive(Copy, Clone, Default)]
@ -547,8 +550,7 @@ impl Drop for DiagCtxtInner {
// instead of "require some error happened". Sadly that isn't ideal, as
// lints can be `#[allow]`'d, potentially leading to this triggering.
// Also, "good path" should be replaced with a better naming.
let has_any_message = self.err_count > 0 || self.lint_err_count > 0 || self.warn_count > 0;
if !has_any_message && !self.suppressed_expected_diag && !std::thread::panicking() {
if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new());
self.flush_delayed(
bugs,
@ -594,9 +596,9 @@ impl DiagCtxt {
flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
lint_err_count: 0,
err_count: 0,
warn_count: 0,
deduplicated_err_count: 0,
deduplicated_warn_count: 0,
has_printed: false,
emitter,
span_delayed_bugs: Vec::new(),
good_path_delayed_bugs: Vec::new(),
@ -647,10 +649,11 @@ impl DiagCtxt {
/// the overall count of emitted error diagnostics.
pub fn reset_err_count(&self) {
let mut inner = self.inner.borrow_mut();
inner.lint_err_count = 0;
inner.err_count = 0;
inner.warn_count = 0;
inner.deduplicated_err_count = 0;
inner.deduplicated_warn_count = 0;
inner.has_printed = false;
// actually free the underlying memory (which `clear` would not do)
inner.span_delayed_bugs = Default::default();
@ -669,16 +672,11 @@ impl DiagCtxt {
let key = (span.with_parent(None), key);
if diag.is_error() {
if diag.level == Error && diag.is_lint {
if diag.is_lint {
inner.lint_err_count += 1;
} else {
inner.err_count += 1;
}
} else {
// Warnings are only automatically flushed if they're forced.
if diag.is_force_warn() {
inner.warn_count += 1;
}
}
// FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
@ -693,15 +691,11 @@ impl DiagCtxt {
let key = (span.with_parent(None), key);
let diag = inner.stashed_diagnostics.remove(&key)?;
if diag.is_error() {
if diag.level == Error && diag.is_lint {
if diag.is_lint {
inner.lint_err_count -= 1;
} else {
inner.err_count -= 1;
}
} else {
if diag.is_force_warn() {
inner.warn_count -= 1;
}
}
Some(DiagnosticBuilder::new_diagnostic(self, diag))
}
@ -738,7 +732,7 @@ impl DiagCtxt {
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Warning(None), msg)
DiagnosticBuilder::new(self, Warning, msg)
}
/// Construct a builder at the `Allow` level with the `msg`.
@ -1005,7 +999,7 @@ impl DiagCtxt {
(0, 0) => return,
(0, _) => inner
.emitter
.emit_diagnostic(&Diagnostic::new(Warning(None), DiagnosticMessage::Str(warnings))),
.emit_diagnostic(&Diagnostic::new(Warning, DiagnosticMessage::Str(warnings))),
(_, 0) => {
inner.emit_diagnostic(Diagnostic::new(Fatal, errors));
}
@ -1094,7 +1088,7 @@ impl DiagCtxt {
&'a self,
warning: impl IntoDiagnostic<'a, ()>,
) -> DiagnosticBuilder<'a, ()> {
warning.into_diagnostic(self, Warning(None))
warning.into_diagnostic(self, Warning)
}
#[track_caller]
@ -1241,21 +1235,17 @@ impl DiagCtxtInner {
for diag in diags {
// Decrement the count tracking the stash; emitting will increment it.
if diag.is_error() {
if diag.level == Error && diag.is_lint {
if diag.is_lint {
self.lint_err_count -= 1;
} else {
self.err_count -= 1;
}
} else {
if diag.is_force_warn() {
self.warn_count -= 1;
} else {
// Unless they're forced, don't flush stashed warnings when
// there are errors, to avoid causing warning overload. The
// stash would've been stolen already if it were important.
if has_errors {
continue;
}
// Unless they're forced, don't flush stashed warnings when
// there are errors, to avoid causing warning overload. The
// stash would've been stolen already if it were important.
if !diag.is_force_warn() && has_errors {
continue;
}
}
let reported_this = self.emit_diagnostic(diag);
@ -1304,23 +1294,20 @@ impl DiagCtxtInner {
self.fulfilled_expectations.insert(expectation_id.normalize());
}
if matches!(diagnostic.level, Warning(_))
&& !self.flags.can_emit_warnings
&& !diagnostic.is_force_warn()
{
if diagnostic.level == Warning && !self.flags.can_emit_warnings {
if diagnostic.has_future_breakage() {
(*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
(*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
}
return None;
}
if matches!(diagnostic.level, Expect(_) | Allow) {
(*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
(*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
return None;
}
let mut guaranteed = None;
(*TRACK_DIAGNOSTICS)(diagnostic, &mut |mut diagnostic| {
(*TRACK_DIAGNOSTIC)(diagnostic, &mut |mut diagnostic| {
if let Some(ref code) = diagnostic.code {
self.emitted_diagnostic_codes.insert(code.clone());
}
@ -1359,12 +1346,13 @@ impl DiagCtxtInner {
self.emitter.emit_diagnostic(&diagnostic);
if diagnostic.is_error() {
self.deduplicated_err_count += 1;
} else if let Warning(_) = diagnostic.level {
} else if matches!(diagnostic.level, ForceWarning(_) | Warning) {
self.deduplicated_warn_count += 1;
}
self.has_printed = true;
}
if diagnostic.is_error() {
if diagnostic.level == Error && diagnostic.is_lint {
if diagnostic.is_lint {
self.bump_lint_err_count();
} else {
self.bump_err_count();
@ -1374,8 +1362,6 @@ impl DiagCtxtInner {
{
guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
}
} else {
self.bump_warn_count();
}
});
@ -1471,10 +1457,6 @@ impl DiagCtxtInner {
self.panic_if_treat_err_as_bug();
}
fn bump_warn_count(&mut self) {
self.warn_count += 1;
}
fn panic_if_treat_err_as_bug(&self) {
if self.treat_err_as_bug() {
match (
@ -1562,14 +1544,17 @@ pub enum Level {
/// Its `EmissionGuarantee` is `ErrorGuaranteed`.
Error,
/// A `force-warn` lint warning about the code being compiled. Does not prevent compilation
/// from finishing.
///
/// The [`LintExpectationId`] is used for expected lint diagnostics. In all other cases this
/// should be `None`.
ForceWarning(Option<LintExpectationId>),
/// A warning about the code being compiled. Does not prevent compilation from finishing.
///
/// This [`LintExpectationId`] is used for expected lint diagnostics, which should
/// also emit a warning due to the `force-warn` flag. In all other cases this should
/// be `None`.
///
/// Its `EmissionGuarantee` is `()`.
Warning(Option<LintExpectationId>),
Warning,
/// A message giving additional context. Rare, because notes are more commonly attached to other
/// diagnostics such as errors.
@ -1622,7 +1607,7 @@ impl Level {
Bug | DelayedBug | Fatal | Error => {
spec.set_fg(Some(Color::Red)).set_intense(true);
}
Warning(_) => {
ForceWarning(_) | Warning => {
spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
}
Note | OnceNote => {
@ -1641,7 +1626,7 @@ impl Level {
match self {
Bug | DelayedBug => "error: internal compiler error",
Fatal | Error => "error",
Warning(_) => "warning",
ForceWarning(_) | Warning => "warning",
Note | OnceNote => "note",
Help | OnceHelp => "help",
FailureNote => "failure-note",
@ -1655,7 +1640,7 @@ impl Level {
pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
match self {
Expect(id) | Warning(Some(id)) => Some(*id),
Expect(id) | ForceWarning(Some(id)) => Some(*id),
_ => None,
}
}

View File

@ -380,7 +380,7 @@ impl ToInternal<rustc_errors::Level> for Level {
fn to_internal(self) -> rustc_errors::Level {
match self {
Level::Error => rustc_errors::Level::Error,
Level::Warning => rustc_errors::Level::Warning(None),
Level::Warning => rustc_errors::Level::Warning,
Level::Note => rustc_errors::Level::Note,
Level::Help => rustc_errors::Level::Help,
_ => unreachable!("unknown proc_macro::Level variant: {:?}", self),

View File

@ -2405,6 +2405,39 @@ impl<'hir> Ty<'hir> {
my_visitor.visit_ty(self);
my_visitor.0
}
/// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to
/// use inference to provide suggestions for the appropriate type if possible.
pub fn is_suggestable_infer_ty(&self) -> bool {
fn are_suggestable_generic_args(generic_args: &[GenericArg<'_>]) -> bool {
generic_args.iter().any(|arg| match arg {
GenericArg::Type(ty) => ty.is_suggestable_infer_ty(),
GenericArg::Infer(_) => true,
_ => false,
})
}
debug!(?self);
match &self.kind {
TyKind::Infer => true,
TyKind::Slice(ty) => ty.is_suggestable_infer_ty(),
TyKind::Array(ty, length) => {
ty.is_suggestable_infer_ty() || matches!(length, ArrayLen::Infer(_, _))
}
TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty),
TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(),
TyKind::OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
TyKind::Path(QPath::TypeRelative(ty, segment)) => {
ty.is_suggestable_infer_ty() || are_suggestable_generic_args(segment.args().args)
}
TyKind::Path(QPath::Resolved(ty_opt, Path { segments, .. })) => {
ty_opt.is_some_and(Self::is_suggestable_infer_ty)
|| segments
.iter()
.any(|segment| are_suggestable_generic_args(segment.args().args))
}
_ => false,
}
}
}
/// Not represented directly in the AST; referred to by name through a `ty_path`.
@ -2735,7 +2768,7 @@ pub enum FnRetTy<'hir> {
Return(&'hir Ty<'hir>),
}
impl FnRetTy<'_> {
impl<'hir> FnRetTy<'hir> {
#[inline]
pub fn span(&self) -> Span {
match *self {
@ -2743,6 +2776,15 @@ impl FnRetTy<'_> {
Self::Return(ref ty) => ty.span,
}
}
pub fn get_infer_ret_ty(&self) -> Option<&'hir Ty<'hir>> {
if let Self::Return(ty) = self {
if ty.is_suggestable_infer_ty() {
return Some(*ty);
}
}
None
}
}
/// Represents `for<...>` binder before a closure

View File

@ -642,7 +642,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
if !is_suggestable_infer_ty(ty) {
if !ty.is_suggestable_infer_ty() {
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_item(it);
placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
@ -674,7 +674,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
hir::TraitItemKind::Const(ty, body_id) => {
tcx.ensure().type_of(def_id);
if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType)
&& !(is_suggestable_infer_ty(ty) && body_id.is_some())
&& !(ty.is_suggestable_infer_ty() && body_id.is_some())
{
// Account for `const C: _;`.
let mut visitor = HirPlaceholderCollector::default();
@ -726,7 +726,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
}
hir::ImplItemKind::Const(ty, _) => {
// Account for `const T: _ = ..;`
if !is_suggestable_infer_ty(ty) {
if !ty.is_suggestable_infer_ty() {
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_impl_item(impl_item);
placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant");
@ -1054,48 +1054,6 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
}
}
fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {
generic_args.iter().any(|arg| match arg {
hir::GenericArg::Type(ty) => is_suggestable_infer_ty(ty),
hir::GenericArg::Infer(_) => true,
_ => false,
})
}
/// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to
/// use inference to provide suggestions for the appropriate type if possible.
fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
debug!(?ty);
use hir::TyKind::*;
match &ty.kind {
Infer => true,
Slice(ty) => is_suggestable_infer_ty(ty),
Array(ty, length) => {
is_suggestable_infer_ty(ty) || matches!(length, hir::ArrayLen::Infer(_, _))
}
Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
Ptr(mut_ty) | Ref(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
Path(hir::QPath::TypeRelative(ty, segment)) => {
is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args)
}
Path(hir::QPath::Resolved(ty_opt, hir::Path { segments, .. })) => {
ty_opt.is_some_and(is_suggestable_infer_ty)
|| segments.iter().any(|segment| are_suggestable_generic_args(segment.args().args))
}
_ => false,
}
}
pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir hir::Ty<'hir>> {
if let hir::FnRetTy::Return(ty) = output {
if is_suggestable_infer_ty(ty) {
return Some(*ty);
}
}
None
}
#[instrument(level = "debug", skip(tcx))]
fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> {
use rustc_hir::Node::*;
@ -1188,7 +1146,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
) -> ty::PolyFnSig<'tcx> {
let hir_id = tcx.local_def_id_to_hir_id(def_id);
match get_infer_ret_ty(&sig.decl.output) {
match sig.decl.output.get_infer_ret_ty() {
Some(ty) => {
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
// Typeck doesn't expect erased regions to be returned from `type_of`.

View File

@ -9,8 +9,8 @@ use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, Ty
use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
use super::bad_placeholder;
use super::ItemCtxt;
use super::{bad_placeholder, is_suggestable_infer_ty};
pub use opaque::test_opaque_hidden_types;
mod opaque;
@ -368,7 +368,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
}
TraitItemKind::Const(ty, body_id) => body_id
.and_then(|body_id| {
is_suggestable_infer_ty(ty).then(|| {
ty.is_suggestable_infer_ty().then(|| {
infer_placeholder_type(
tcx,
def_id,
@ -392,7 +392,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
}
ImplItemKind::Const(ty, body_id) => {
if is_suggestable_infer_ty(ty) {
if ty.is_suggestable_infer_ty() {
infer_placeholder_type(
tcx,
def_id,
@ -416,7 +416,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
Node::Item(item) => match item.kind {
ItemKind::Static(ty, .., body_id) => {
if is_suggestable_infer_ty(ty) {
if ty.is_suggestable_infer_ty() {
infer_placeholder_type(
tcx,
def_id,
@ -430,7 +430,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
}
}
ItemKind::Const(ty, _, body_id) => {
if is_suggestable_infer_ty(ty) {
if ty.is_suggestable_infer_ty() {
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
} else {
icx.to_ty(ty)
@ -603,6 +603,8 @@ fn infer_placeholder_type<'a>(
}
err.emit();
// diagnostic stashing loses the information of whether something is a hard error.
Ty::new_error_with_message(tcx, span, "ItemNoType is a hard error")
}
None => {
let mut diag = bad_placeholder(tcx, vec![span], kind);
@ -623,15 +625,9 @@ fn infer_placeholder_type<'a>(
}
}
diag.emit();
Ty::new_error(tcx, diag.emit())
}
}
// Typeck doesn't expect erased regions to be returned from `type_of`.
tcx.fold_regions(ty, |r, _| match *r {
ty::ReErased => tcx.lifetimes.re_static,
_ => r,
})
}
fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {

View File

@ -134,6 +134,21 @@ impl TaitConstraintLocator<'_> {
debug!("no constraint: no typeck results");
return;
}
if let Some(hir_sig) = self.tcx.hir_node_by_def_id(item_def_id).fn_decl() {
if hir_sig.output.get_infer_ret_ty().is_some() {
let guar = self.tcx.dcx().span_delayed_bug(
hir_sig.output.span(),
"inferring return types and opaque types do not mix well",
);
self.found = Some(ty::OpaqueHiddenType {
span: DUMMY_SP,
ty: Ty::new_error(self.tcx, guar),
});
return;
}
}
// Calling `mir_borrowck` can lead to cycle errors through
// const-checking, avoid calling it if we don't have to.
// ```rust

View File

@ -181,7 +181,7 @@ fn typeck_with_fallback<'tcx>(
let mut fcx = FnCtxt::new(&inh, param_env, def_id);
if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
let fn_sig = if decl.output.get_infer_ret_ty().is_some() {
fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
} else {
tcx.fn_sig(def_id).instantiate_identity()

View File

@ -2348,11 +2348,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
ty::AliasKind::Projection | ty::AliasKind::Inherent => {
ty::Projection | ty::Inherent => {
format!("the associated type `{p}`")
}
ty::AliasKind::Weak => format!("the type alias `{p}`"),
ty::AliasKind::Opaque => format!("the opaque type `{p}`"),
ty::Weak => format!("the type alias `{p}`"),
ty::Opaque => format!("the opaque type `{p}`"),
},
};

View File

@ -510,7 +510,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
));
} else {
match a_ty.kind() {
&ty::Alias(ty::AliasKind::Projection, data) => {
&ty::Alias(ty::Projection, data) => {
// FIXME: This does not handle subtyping correctly, we could
// instead create a new inference variable for `a_ty`, emitting
// `Projection(a_ty, a_infer)` and `a_infer <: b_ty`.
@ -522,10 +522,9 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
))
}
// The old solver only accepts projection predicates for associated types.
ty::Alias(
ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque,
_,
) => return Err(TypeError::CyclicTy(a_ty)),
ty::Alias(ty::Inherent | ty::Weak | ty::Opaque, _) => {
return Err(TypeError::CyclicTy(a_ty));
}
_ => bug!("generalizated `{a_ty:?} to infer, not an alias"),
}
}

View File

@ -9,7 +9,7 @@
//! The functions in this file should fall back to the default set in their
//! origin crate when the `TyCtxt` is not present in TLS.
use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
use rustc_errors::{Diagnostic, TRACK_DIAGNOSTIC};
use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef};
use rustc_middle::ty::tls;
use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug;
@ -103,5 +103,5 @@ pub fn setup_callbacks() {
.swap(&(dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
rustc_query_system::dep_graph::dep_node::DEP_NODE_DEBUG
.swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _));
TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _));
}

View File

@ -29,7 +29,6 @@ use rustc_span::{Span, Symbol};
use rustc_target::abi::{Abi, Size, WrappingRange};
use rustc_target::abi::{Integer, TagEncoding, Variants};
use rustc_target::spec::abi::Abi as SpecAbi;
use rustc_type_ir::DynKind;
use std::iter;
use std::ops::ControlFlow;
@ -675,7 +674,7 @@ fn lint_wide_pointer<'tcx>(
}
match ty.kind() {
ty::RawPtr(TypeAndMut { mutbl: _, ty }) => (!ty.is_sized(cx.tcx, cx.param_env))
.then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, DynKind::Dyn)))),
.then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))),
_ => None,
}
};

View File

@ -787,7 +787,9 @@ LLVMRustOptimize(
for (auto PluginPath: Plugins) {
auto Plugin = PassPlugin::Load(PluginPath.str());
if (!Plugin) {
LLVMRustSetLastError(("Failed to load pass plugin" + PluginPath.str()).c_str());
auto Err = Plugin.takeError();
auto ErrMsg = llvm::toString(std::move(Err));
LLVMRustSetLastError(ErrMsg.c_str());
return LLVMRustResult::Failure;
}
Plugin->registerPassBuilderCallbacks(PB);

View File

@ -312,8 +312,9 @@ pub fn struct_lint_level(
// create a `DiagnosticBuilder` and continue as we would for warnings.
rustc_errors::Level::Expect(expect_id)
}
Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::Warning(Some(expect_id)),
Level::Warn | Level::ForceWarn(None) => rustc_errors::Level::Warning(None),
Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::ForceWarning(Some(expect_id)),
Level::ForceWarn(None) => rustc_errors::Level::ForceWarning(None),
Level::Warn => rustc_errors::Level::Warning,
Level::Deny | Level::Forbid => rustc_errors::Level::Error,
};
let mut err = DiagnosticBuilder::new(sess.dcx(), err_level, "");
@ -350,22 +351,19 @@ pub fn struct_lint_level(
// suppressed the lint due to macros.
err.primary_message(msg);
let name = lint.name_lower();
err.code(DiagnosticId::Lint { name, has_future_breakage });
// Lint diagnostics that are covered by the expect level will not be emitted outside
// the compiler. It is therefore not necessary to add any information for the user.
// This will therefore directly call the decorate function which will in turn emit
// the `Diagnostic`.
if let Level::Expect(_) = level {
let name = lint.name_lower();
err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn: false });
decorate(&mut err);
err.emit();
return;
}
let name = lint.name_lower();
let is_force_warn = matches!(level, Level::ForceWarn(_));
err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn });
if let Some(future_incompatible) = future_incompatible {
let explanation = match future_incompatible.reason {
FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps

View File

@ -1225,7 +1225,7 @@ impl<'tcx> AliasTy<'tcx> {
/// Whether this alias type is an opaque.
pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool {
matches!(self.opt_kind(tcx), Some(ty::AliasKind::Opaque))
matches!(self.opt_kind(tcx), Some(ty::Opaque))
}
/// FIXME: rename `AliasTy` to `AliasTerm` and always handle
@ -2745,7 +2745,7 @@ impl<'tcx> Ty<'tcx> {
// Extern types have metadata = ().
| ty::Foreign(..)
// `dyn*` has no metadata
| ty::Dynamic(_, _, DynKind::DynStar)
| ty::Dynamic(_, _, ty::DynStar)
// If returned by `struct_tail_without_normalization` this is a unit struct
// without any fields, or not a struct, and therefore is Sized.
| ty::Adt(..)
@ -2754,7 +2754,7 @@ impl<'tcx> Ty<'tcx> {
| ty::Tuple(..) => (tcx.types.unit, false),
ty::Str | ty::Slice(_) => (tcx.types.usize, false),
ty::Dynamic(_, _, DynKind::Dyn) => {
ty::Dynamic(_, _, ty::Dyn) => {
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false)
},

View File

@ -432,7 +432,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
}
let scrut_ty = scrut.ty;
let report = analyze_match(&cx, &tarms, scrut_ty);
let report = match analyze_match(&cx, &tarms, scrut_ty) {
Ok(report) => report,
Err(err) => {
self.error = Err(err);
return;
}
};
match source {
// Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
@ -546,7 +552,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
let cx = self.new_cx(refutability, None, scrut, pat.span);
let pat = self.lower_pattern(&cx, pat)?;
let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
let report = analyze_match(&cx, &arms, pat.ty().inner());
let report = analyze_match(&cx, &arms, pat.ty().inner())?;
Ok((cx, report))
}

View File

@ -24,6 +24,8 @@ use std::fmt;
use rustc_index::Idx;
#[cfg(feature = "rustc")]
use rustc_middle::ty::Ty;
#[cfg(feature = "rustc")]
use rustc_span::ErrorGuaranteed;
use crate::constructor::{Constructor, ConstructorSet};
#[cfg(feature = "rustc")]
@ -52,6 +54,8 @@ impl<'a, T: ?Sized> Captures<'a> for T {}
pub trait TypeCx: Sized + fmt::Debug {
/// The type of a pattern.
type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy
/// Errors that can abort analysis.
type Error: fmt::Debug;
/// The index of an enum variant.
type VariantIdx: Clone + Idx;
/// A string literal
@ -73,7 +77,7 @@ pub trait TypeCx: Sized + fmt::Debug {
/// The set of all the constructors for `ty`.
///
/// This must follow the invariants of `ConstructorSet`
fn ctors_for_ty(&self, ty: Self::Ty) -> ConstructorSet<Self>;
fn ctors_for_ty(&self, ty: Self::Ty) -> Result<ConstructorSet<Self>, Self::Error>;
/// Best-effort `Debug` implementation.
fn debug_pat(f: &mut fmt::Formatter<'_>, pat: &DeconstructedPat<'_, Self>) -> fmt::Result;
@ -109,25 +113,25 @@ pub fn analyze_match<'p, 'tcx>(
tycx: &RustcMatchCheckCtxt<'p, 'tcx>,
arms: &[rustc::MatchArm<'p, 'tcx>],
scrut_ty: Ty<'tcx>,
) -> rustc::UsefulnessReport<'p, 'tcx> {
) -> Result<rustc::UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
// Arena to store the extra wildcards we construct during analysis.
let wildcard_arena = tycx.pattern_arena;
let scrut_ty = tycx.reveal_opaque_ty(scrut_ty);
let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee);
let cx = MatchCtxt { tycx, wildcard_arena };
let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity);
let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity)?;
let pat_column = PatternColumn::new(arms);
// Lint on ranges that overlap on their endpoints, which is likely a mistake.
lint_overlapping_range_endpoints(cx, &pat_column);
lint_overlapping_range_endpoints(cx, &pat_column)?;
// Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
// `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)
lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)?;
}
report
Ok(report)
}

View File

@ -4,7 +4,7 @@ use rustc_data_structures::captures::Captures;
use rustc_middle::ty;
use rustc_session::lint;
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
use rustc_span::Span;
use rustc_span::{ErrorGuaranteed, Span};
use crate::constructor::{IntRange, MaybeInfiniteInt};
use crate::errors::{
@ -59,9 +59,13 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
}
/// Do constructor splitting on the constructors of the column.
fn analyze_ctors(&self, pcx: &PlaceCtxt<'_, 'p, 'tcx>) -> SplitConstructorSet<'p, 'tcx> {
fn analyze_ctors(
&self,
pcx: &PlaceCtxt<'_, 'p, 'tcx>,
) -> Result<SplitConstructorSet<'p, 'tcx>, ErrorGuaranteed> {
let column_ctors = self.patterns.iter().map(|p| p.ctor());
pcx.ctors_for_ty().split(pcx, column_ctors)
let ctors_for_ty = &pcx.ctors_for_ty()?;
Ok(ctors_for_ty.split(pcx, column_ctors))
}
fn iter(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, 'tcx>> + Captures<'_> {
@ -106,18 +110,18 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
cx: MatchCtxt<'a, 'p, 'tcx>,
column: &PatternColumn<'p, 'tcx>,
) -> Vec<WitnessPat<'p, 'tcx>> {
) -> Result<Vec<WitnessPat<'p, 'tcx>>, ErrorGuaranteed> {
let Some(ty) = column.head_ty() else {
return Vec::new();
return Ok(Vec::new());
};
let pcx = &PlaceCtxt::new_dummy(cx, ty);
let set = column.analyze_ctors(pcx);
let set = column.analyze_ctors(pcx)?;
if set.present.is_empty() {
// We can't consistently handle the case where no constructors are present (since this would
// require digging deep through any type in case there's a non_exhaustive enum somewhere),
// so for consistency we refuse to handle the top-level case, where we could handle it.
return vec![];
return Ok(Vec::new());
}
let mut witnesses = Vec::new();
@ -137,7 +141,7 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
let wild_pat = WitnessPat::wild_from_ctor(pcx, ctor);
for (i, col_i) in specialized_columns.iter().enumerate() {
// Compute witnesses for each column.
let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i);
let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i)?;
// For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`,
// adding enough wildcards to match `arity`.
for wit in wits_for_col_i {
@ -147,7 +151,7 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
}
}
}
witnesses
Ok(witnesses)
}
pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
@ -155,13 +159,13 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
arms: &[MatchArm<'p, 'tcx>],
pat_column: &PatternColumn<'p, 'tcx>,
scrut_ty: RevealedTy<'tcx>,
) {
) -> Result<(), ErrorGuaranteed> {
let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
if !matches!(
rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, rcx.match_lint_level).0,
rustc_session::lint::Level::Allow
) {
let witnesses = collect_nonexhaustive_missing_variants(cx, pat_column);
let witnesses = collect_nonexhaustive_missing_variants(cx, pat_column)?;
if !witnesses.is_empty() {
// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
// is not exhaustive enough.
@ -200,6 +204,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
}
}
}
Ok(())
}
/// Traverse the patterns to warn the user about ranges that overlap on their endpoints.
@ -207,14 +212,14 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
cx: MatchCtxt<'a, 'p, 'tcx>,
column: &PatternColumn<'p, 'tcx>,
) {
) -> Result<(), ErrorGuaranteed> {
let Some(ty) = column.head_ty() else {
return;
return Ok(());
};
let pcx = &PlaceCtxt::new_dummy(cx, ty);
let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
let set = column.analyze_ctors(pcx);
let set = column.analyze_ctors(pcx)?;
if matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_)) {
let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| {
@ -271,8 +276,9 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
// Recurse into the fields.
for ctor in set.present {
for col in column.specialize(pcx, &ctor) {
lint_overlapping_range_endpoints(cx, &col);
lint_overlapping_range_endpoints(cx, &col)?;
}
}
}
Ok(())
}

View File

@ -12,7 +12,9 @@ use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::{self, Const};
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange, PatRangeBoundary};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, VariantDef};
use rustc_span::ErrorGuaranteed;
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
use smallvec::SmallVec;
@ -302,7 +304,10 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
///
/// See [`crate::constructor`] for considerations of emptiness.
#[instrument(level = "debug", skip(self), ret)]
pub fn ctors_for_ty(&self, ty: RevealedTy<'tcx>) -> ConstructorSet<'p, 'tcx> {
pub fn ctors_for_ty(
&self,
ty: RevealedTy<'tcx>,
) -> Result<ConstructorSet<'p, 'tcx>, ErrorGuaranteed> {
let cx = self;
let make_uint_range = |start, end| {
IntRange::from_range(
@ -311,9 +316,11 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
RangeEnd::Included,
)
};
// Abort on type error.
ty.error_reported()?;
// This determines the set of all possible constructors for the type `ty`. For numbers,
// arrays and slices we use ranges and variable-length slices when appropriate.
match ty.kind() {
Ok(match ty.kind() {
ty::Bool => ConstructorSet::Bool,
ty::Char => {
// The valid Unicode Scalar Value ranges.
@ -423,7 +430,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
ty::CoroutineWitness(_, _) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) => {
bug!("Encountered unexpected type in `ConstructorSet::for_ty`: {ty:?}")
}
}
})
}
pub(crate) fn lower_pat_range_bdy(
@ -944,6 +951,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
type Ty = RevealedTy<'tcx>;
type Error = ErrorGuaranteed;
type VariantIdx = VariantIdx;
type StrLit = Const<'tcx>;
type ArmData = HirId;
@ -963,7 +971,10 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
) -> &[Self::Ty] {
self.ctor_sub_tys(ctor, ty)
}
fn ctors_for_ty(&self, ty: Self::Ty) -> crate::constructor::ConstructorSet<Self> {
fn ctors_for_ty(
&self,
ty: Self::Ty,
) -> Result<crate::constructor::ConstructorSet<Self>, Self::Error> {
self.ctors_for_ty(ty)
}

View File

@ -753,7 +753,7 @@ impl<'a, 'p, Cx: TypeCx> PlaceCtxt<'a, 'p, Cx> {
pub(crate) fn ctor_sub_tys(&self, ctor: &Constructor<Cx>) -> &[Cx::Ty] {
self.mcx.tycx.ctor_sub_tys(ctor, self.ty)
}
pub(crate) fn ctors_for_ty(&self) -> ConstructorSet<Cx> {
pub(crate) fn ctors_for_ty(&self) -> Result<ConstructorSet<Cx>, Cx::Error> {
self.mcx.tycx.ctors_for_ty(self.ty)
}
}
@ -1336,14 +1336,14 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
mcx: MatchCtxt<'a, 'p, Cx>,
matrix: &mut Matrix<'p, Cx>,
is_top_level: bool,
) -> WitnessMatrix<Cx> {
) -> Result<WitnessMatrix<Cx>, Cx::Error> {
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
if !matrix.wildcard_row_is_relevant && matrix.rows().all(|r| !r.pats.relevant) {
// Here we know that nothing will contribute further to exhaustiveness or usefulness. This
// is purely an optimization: skipping this check doesn't affect correctness. See the top of
// the file for details.
return WitnessMatrix::empty();
return Ok(WitnessMatrix::empty());
}
let Some(ty) = matrix.head_ty() else {
@ -1355,16 +1355,16 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
// When there's an unguarded row, the match is exhaustive and any subsequent row is not
// useful.
if !row.is_under_guard {
return WitnessMatrix::empty();
return Ok(WitnessMatrix::empty());
}
}
// No (unguarded) rows, so the match is not exhaustive. We return a new witness unless
// irrelevant.
return if matrix.wildcard_row_is_relevant {
WitnessMatrix::unit_witness()
Ok(WitnessMatrix::unit_witness())
} else {
// We choose to not report anything here; see at the top for details.
WitnessMatrix::empty()
Ok(WitnessMatrix::empty())
};
};
@ -1378,7 +1378,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
// Analyze the constructors present in this column.
let ctors = matrix.heads().map(|p| p.ctor());
let ctors_for_ty = pcx.ctors_for_ty();
let ctors_for_ty = pcx.ctors_for_ty()?;
let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); // For diagnostics.
let split_set = ctors_for_ty.split(pcx, ctors);
let all_missing = split_set.present.is_empty();
@ -1417,7 +1417,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant);
let mut witnesses = ensure_sufficient_stack(|| {
compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false)
});
})?;
// Transform witnesses for `spec_matrix` into witnesses for `matrix`.
witnesses.apply_constructor(pcx, &missing_ctors, &ctor, report_individual_missing_ctors);
@ -1438,7 +1438,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
}
}
ret
Ok(ret)
}
/// Indicates whether or not a given arm is useful.
@ -1469,9 +1469,10 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
arms: &[MatchArm<'p, Cx>],
scrut_ty: Cx::Ty,
scrut_validity: ValidityConstraint,
) -> UsefulnessReport<'p, Cx> {
) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> {
let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity);
let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(cx, &mut matrix, true);
let non_exhaustiveness_witnesses =
compute_exhaustiveness_and_usefulness(cx, &mut matrix, true)?;
let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column();
let arm_usefulness: Vec<_> = arms
@ -1488,5 +1489,5 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
(arm, usefulness)
})
.collect();
UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
Ok(UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses })
}

View File

@ -20,7 +20,7 @@
// separate step to be able to collapse the adjacent spans that rustfix
// will remove
//
// - `check_crate` finally emits the diagnostics based on the data generated
// - `check_unused` finally emits the diagnostics based on the data generated
// in the last step
use crate::imports::ImportKind;

View File

@ -143,11 +143,7 @@ pub fn feature_warn_issue(
// Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level
let lint = UNSTABLE_SYNTAX_PRE_EXPANSION;
let future_incompatible = lint.future_incompatible.as_ref().unwrap();
err.code(DiagnosticId::Lint {
name: lint.name_lower(),
has_future_breakage: false,
is_force_warn: false,
});
err.code(DiagnosticId::Lint { name: lint.name_lower(), has_future_breakage: false });
err.warn(lint.desc);
err.note(format!("for more information, see {}", future_incompatible.reference));

View File

@ -17,7 +17,7 @@ use stable_mir::ty::{
GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Region, RigidTy, Span, TermKind,
TraitRef, Ty, UintTy, VariantDef, VariantIdx,
};
use stable_mir::{CrateItem, DefId};
use stable_mir::{CrateItem, CrateNum, DefId};
use super::RustcInternal;
@ -28,6 +28,13 @@ impl<'tcx> RustcInternal<'tcx> for CrateItem {
}
}
impl<'tcx> RustcInternal<'tcx> for CrateNum {
type T = rustc_span::def_id::CrateNum;
fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
rustc_span::def_id::CrateNum::from_usize(*self)
}
}
impl<'tcx> RustcInternal<'tcx> for DefId {
type T = rustc_span::def_id::DefId;
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {

View File

@ -25,8 +25,9 @@ use stable_mir::ty::{
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, VariantDef,
};
use stable_mir::{Crate, CrateItem, DefId, Error, Filename, ItemKind, Symbol};
use stable_mir::{Crate, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol};
use std::cell::RefCell;
use std::iter;
use crate::rustc_internal::{internal, RustcInternal};
use crate::rustc_smir::builder::BodyBuilder;
@ -67,10 +68,15 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
}
fn all_trait_decls(&self) -> stable_mir::TraitDecls {
let mut tables = self.0.borrow_mut();
tables.tcx.all_traits().map(|trait_def_id| tables.trait_def(trait_def_id)).collect()
}
fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls {
let mut tables = self.0.borrow_mut();
tables
.tcx
.traits(LOCAL_CRATE)
.traits(crate_num.internal(&mut *tables))
.iter()
.map(|trait_def_id| tables.trait_def(*trait_def_id))
.collect()
@ -84,10 +90,20 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
}
fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
iter::once(LOCAL_CRATE)
.chain(tables.tcx.crates(()).iter().copied())
.flat_map(|cnum| tcx.trait_impls_in_crate(cnum).iter())
.map(|impl_def_id| tables.impl_def(*impl_def_id))
.collect()
}
fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls {
let mut tables = self.0.borrow_mut();
tables
.tcx
.trait_impls_in_crate(LOCAL_CRATE)
.trait_impls_in_crate(crate_num.internal(&mut *tables))
.iter()
.map(|impl_def_id| tables.impl_def(*impl_def_id))
.collect()

View File

@ -12,12 +12,11 @@ use crate::rustc_smir::{alloc, Stable, Tables};
impl<'tcx> Stable<'tcx> for ty::AliasKind {
type T = stable_mir::ty::AliasKind;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
use rustc_middle::ty::AliasKind::*;
match self {
Projection => stable_mir::ty::AliasKind::Projection,
Inherent => stable_mir::ty::AliasKind::Inherent,
Opaque => stable_mir::ty::AliasKind::Opaque,
Weak => stable_mir::ty::AliasKind::Weak,
ty::Projection => stable_mir::ty::AliasKind::Projection,
ty::Inherent => stable_mir::ty::AliasKind::Inherent,
ty::Opaque => stable_mir::ty::AliasKind::Opaque,
ty::Weak => stable_mir::ty::AliasKind::Weak,
}
}
}
@ -34,10 +33,9 @@ impl<'tcx> Stable<'tcx> for ty::DynKind {
type T = stable_mir::ty::DynKind;
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
use rustc_middle::ty::DynKind;
match self {
DynKind::Dyn => stable_mir::ty::DynKind::Dyn,
DynKind::DynStar => stable_mir::ty::DynKind::DynStar,
ty::Dyn => stable_mir::ty::DynKind::Dyn,
ty::DynStar => stable_mir::ty::DynKind::DynStar,
}
}
}

View File

@ -2,15 +2,29 @@
//! Doing this via a separate goal is called "deferred alias relation" and part
//! of our more general approach to "lazy normalization".
//!
//! This goal, e.g. `A alias-relate B`, may be satisfied by one of three branches:
//! * normalizes-to: If `A` is a projection, we can prove the equivalent
//! projection predicate with B as the right-hand side of the projection.
//! This goal is computed in both directions, if both are aliases.
//! * subst-relate: Equate `A` and `B` by their substs, if they're both
//! aliases with the same def-id.
//! * bidirectional-normalizes-to: If `A` and `B` are both projections, and both
//! may apply, then we can compute the "intersection" of both normalizes-to by
//! performing them together. This is used specifically to resolve ambiguities.
//! This is done by first normalizing both sides of the goal, ending up in
//! either a concrete type, rigid projection, opaque, or an infer variable.
//! These are related further according to the rules below:
//!
//! (1.) If we end up with a rigid projection and a rigid projection, then we
//! relate those projections structurally.
//!
//! (2.) If we end up with a rigid projection and an alias, then the opaque will
//! have its hidden type defined to be that rigid projection.
//!
//! (3.) If we end up with an opaque and an opaque, then we assemble two
//! candidates, one defining the LHS to be the hidden type of the RHS, and vice
//! versa.
//!
//! (4.) If we end up with an infer var and an opaque or rigid projection, then
//! we assign the alias to the infer var.
//!
//! (5.) If we end up with an opaque and a rigid (non-projection) type, then we
//! define the hidden type of the opaque to be the rigid type.
//!
//! (6.) Otherwise, if we end with two rigid (non-projection) or infer types,
//! relate them structurally.
use super::{EvalCtxt, GoalSource};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::query::NoSolution;
@ -50,6 +64,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.relate(param_env, lhs, variance, rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else if alias.is_opaque(tcx) {
// FIXME: This doesn't account for variance.
self.define_opaque(param_env, alias, rhs)
} else {
Err(NoSolution)
@ -60,6 +75,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
self.relate(param_env, lhs, variance, rhs)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else if alias.is_opaque(tcx) {
// FIXME: This doesn't account for variance.
self.define_opaque(param_env, alias, lhs)
} else {
Err(NoSolution)
@ -72,6 +88,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}
// FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var.
/// Normalize the `term` to equate it later. This does not define opaque types.
#[instrument(level = "debug", skip(self, param_env), ret)]
fn try_normalize_term(

View File

@ -22,6 +22,7 @@ use rustc_middle::traits::solve::{
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
QueryResult, Response,
};
use rustc_middle::traits::Reveal;
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
use rustc_middle::ty::{
CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
@ -316,19 +317,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
return Some(ty);
};
// We do no always define opaque types eagerly to allow non-defining uses in the defining scope.
if let (DefineOpaqueTypes::No, ty::AliasKind::Opaque) = (define_opaque_types, kind) {
if let Some(def_id) = alias.def_id.as_local() {
if self
.unify_existing_opaque_tys(
param_env,
OpaqueTypeKey { def_id, args: alias.args },
self.next_ty_infer(),
)
.is_empty()
{
return Some(ty);
}
// We do no always define opaque types eagerly to allow non-defining uses
// in the defining scope. However, if we can unify this opaque to an existing
// opaque, then we should attempt to eagerly reveal the opaque, and we fall
// through.
if let DefineOpaqueTypes::No = define_opaque_types
&& let Reveal::UserFacing = param_env.reveal()
&& let ty::Opaque = kind
&& let Some(def_id) = alias.def_id.as_local()
&& self.can_define_opaque_ty(def_id)
{
if self
.unify_existing_opaque_tys(
param_env,
OpaqueTypeKey { def_id, args: alias.args },
self.next_ty_infer(),
)
.is_empty()
{
return Some(ty);
}
}

View File

@ -16,8 +16,8 @@ use crate::ty::{
TraitDef, Ty, TyKind, VariantDef,
};
use crate::{
mir, Crate, CrateItem, CrateItems, DefId, Error, Filename, ImplTraitDecls, ItemKind, Symbol,
TraitDecls,
mir, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, ItemKind,
Symbol, TraitDecls,
};
/// This trait defines the interface between stable_mir and the Rust compiler.
@ -32,8 +32,10 @@ pub trait Context {
/// Check whether the body of a function is available.
fn has_body(&self, item: DefId) -> bool;
fn all_trait_decls(&self) -> TraitDecls;
fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls;
fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
fn all_trait_impls(&self) -> ImplTraitDecls;
fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls;
fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
fn generics_of(&self, def_id: DefId) -> Generics;
fn predicates_of(&self, def_id: DefId) -> GenericPredicates;

View File

@ -31,7 +31,7 @@ pub use crate::error::*;
use crate::mir::pretty::function_name;
use crate::mir::Body;
use crate::mir::Mutability;
use crate::ty::{ImplDef, ImplTrait, IndexedVal, Span, TraitDecl, TraitDef, Ty};
use crate::ty::{ImplDef, IndexedVal, Span, TraitDef, Ty};
pub mod abi;
#[macro_use]
@ -86,6 +86,18 @@ pub struct Crate {
pub is_local: bool,
}
impl Crate {
/// The list of traits declared in this crate.
pub fn trait_decls(&self) -> TraitDecls {
with(|cx| cx.trait_decls(self.id))
}
/// The list of trait implementations in this crate.
pub fn trait_impls(&self) -> ImplTraitDecls {
with(|cx| cx.trait_impls(self.id))
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum ItemKind {
Fn,
@ -169,18 +181,10 @@ pub fn all_trait_decls() -> TraitDecls {
with(|cx| cx.all_trait_decls())
}
pub fn trait_decl(trait_def: &TraitDef) -> TraitDecl {
with(|cx| cx.trait_decl(trait_def))
}
pub fn all_trait_impls() -> ImplTraitDecls {
with(|cx| cx.all_trait_impls())
}
pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait {
with(|cx| cx.trait_impl(trait_impl))
}
/// A type that provides internal information but that can still be used for debug purpose.
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Opaque(String);

View File

@ -714,9 +714,16 @@ crate_def! {
}
crate_def! {
/// A trait's definition.
pub TraitDef;
}
impl TraitDef {
pub fn declaration(trait_def: &TraitDef) -> TraitDecl {
with(|cx| cx.trait_decl(trait_def))
}
}
crate_def! {
pub GenericDef;
}
@ -726,9 +733,17 @@ crate_def! {
}
crate_def! {
/// A trait impl definition.
pub ImplDef;
}
impl ImplDef {
/// Retrieve information about this implementation.
pub fn trait_impl(&self) -> ImplTrait {
with(|cx| cx.trait_impl(self))
}
}
crate_def! {
pub RegionDef;
}

View File

@ -771,7 +771,11 @@ impl Ipv4Addr {
|| self.is_loopback()
|| self.is_link_local()
// addresses reserved for future protocols (`192.0.0.0/24`)
||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
// .9 and .10 are documented as globally reachable so they're excluded
|| (
self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0
&& self.octets()[3] != 9 && self.octets()[3] != 10
)
|| self.is_documentation()
|| self.is_benchmarking()
|| self.is_reserved()
@ -1515,8 +1519,12 @@ impl Ipv6Addr {
// AS112-v6 (`2001:4:112::/48`)
|| matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
// ORCHIDv2 (`2001:20::/28`)
|| matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
// Drone Remote ID Protocol Entity Tags (DETs) Prefix (`2001:30::/28`)`
|| matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x3F)
))
// 6to4 (`2002::/16`) it's not explicitly documented as globally reachable,
// IANA says N/A.
|| matches!(self.segments(), [0x2002, _, _, _, _, _, _, _])
|| self.is_documentation()
|| self.is_unique_local()
|| self.is_unicast_link_local())

View File

@ -461,6 +461,10 @@ fn ipv4_properties() {
check!("198.18.54.2", benchmarking);
check!("198.19.255.255", benchmarking);
check!("192.0.0.0");
check!("192.0.0.8");
check!("192.0.0.9", global);
check!("192.0.0.10", global);
check!("192.0.0.11");
check!("192.0.0.255");
check!("192.0.0.100");
check!("240.0.0.0", reserved);
@ -480,6 +484,10 @@ fn ipv6_properties() {
}
macro_rules! check {
($s:expr, &[$($octet:expr),*]) => {
check!($s, &[$($octet),*], 0);
};
($s:expr, &[$($octet:expr),*], $mask:expr) => {
assert_eq!($s, ip!($s).to_string());
let octets = &[$($octet),*];
@ -656,8 +664,8 @@ fn ipv6_properties() {
&[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
global | unicast_global
);
check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
check!("2001:40::", &[0x20, 1, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
check!(
"2001:200::",
@ -665,6 +673,8 @@ fn ipv6_properties() {
global | unicast_global
);
check!("2002::", &[0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
check!(

View File

@ -383,8 +383,6 @@ impl<T: ?Sized> Mutex<T> {
/// # Examples
///
/// ```
/// #![feature(mutex_unpoison)]
///
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
@ -406,7 +404,7 @@ impl<T: ?Sized> Mutex<T> {
/// assert_eq!(*x, 1);
/// ```
#[inline]
#[unstable(feature = "mutex_unpoison", issue = "96469")]
#[stable(feature = "mutex_unpoison", since = "CURRENT_RUSTC_VERSION")]
pub fn clear_poison(&self) {
self.poison.clear();
}

View File

@ -387,8 +387,6 @@ impl<T: ?Sized> RwLock<T> {
/// # Examples
///
/// ```
/// #![feature(mutex_unpoison)]
///
/// use std::sync::{Arc, RwLock};
/// use std::thread;
///
@ -410,7 +408,7 @@ impl<T: ?Sized> RwLock<T> {
/// assert_eq!(*guard, 1);
/// ```
#[inline]
#[unstable(feature = "mutex_unpoison", issue = "96469")]
#[stable(feature = "mutex_unpoison", since = "CURRENT_RUSTC_VERSION")]
pub fn clear_poison(&self) {
self.poison.clear();
}

View File

@ -112,6 +112,90 @@ fn bar() {}
fn baz() {}
```
### Sorting
In various cases, the default Rust style specifies to sort things. If not
otherwise specified, such sorting should be "version sorting", which ensures
that (for instance) `x8` comes before `x16` even though the character `1` comes
before the character `8`. (If not otherwise specified, version-sorting is
lexicographical.)
For the purposes of the Rust style, to compare two strings for version-sorting:
- Process both strings from beginning to end as two sequences of maximal-length
chunks, where each chunk consists either of a sequence of characters other
than ASCII digits, or a sequence of ASCII digits (a numeric chunk), and
compare corresponding chunks from the strings.
- To compare two numeric chunks, compare them by numeric value, ignoring
leading zeroes. If the two chunks have equal numeric value, but different
numbers of leading digits, and this is the first time this has happened for
these strings, treat the chunks as equal (moving on to the next chunk) but
remember which string had more leading zeroes.
- To compare two chunks if both are not numeric, compare them by Unicode
character lexicographically, except that `_` (underscore) sorts immediately
after ` ` (space) but before any other character. (This treats underscore as
a word separator, as commonly used in identifiers.)
- If the use of version sorting specifies further modifiers, such as sorting
non-lowercase before lowercase, apply those modifiers to the lexicographic
sort in this step.
- If the comparison reaches the end of the string and considers each pair of
chunks equal:
- If one of the numeric comparisons noted the earliest point at which one
string had more leading zeroes than the other, sort the string with more
leading zeroes first.
- Otherwise, the strings are equal.
Note that there exist various algorithms called "version sorting", which
generally try to solve the same problem, but which differ in various ways (such
as in their handling of numbers with leading zeroes). This algorithm
does not purport to precisely match the behavior of any particular other
algorithm, only to produce a simple and satisfying result for Rust formatting.
In particular, this algorithm aims to produce a satisfying result for a set of
symbols that have the same number of leading zeroes, and an acceptable and
easily understandable result for a set of symbols that has varying numbers of
leading zeroes.
As an example, version-sorting will sort the following strings in the order
given:
- `_ZYWX`
- `u_zzz`
- `u8`
- `u16`
- `u32`
- `u64`
- `u128`
- `u256`
- `ua`
- `usize`
- `uz`
- `v000`
- `v00`
- `v0`
- `v0s`
- `v00t`
- `v0u`
- `v001`
- `v01`
- `v1`
- `v009`
- `v09`
- `v9`
- `v010`
- `v10`
- `w005s09t`
- `w5s009t`
- `x64`
- `x86`
- `x86_32`
- `x86_64`
- `x86_128`
- `x87`
- `Z_YWX`
- `ZY_WX`
- `ZYW_X`
- `ZYWX`
- `ZYWX_`
### [Module-level items](items.md)
### [Statements](statements.md)

View File

@ -8,11 +8,11 @@ Put a blank line between the last key-value pair in a section and the header of
the next section. Do not place a blank line between section headers and the
key-value pairs in that section, or between key-value pairs in a section.
Sort key names alphabetically within each section, with the exception of the
Version-sort key names within each section, with the exception of the
`[package]` section. Put the `[package]` section at the top of the file; put
the `name` and `version` keys in that order at the top of that section,
followed by the remaining keys other than `description` in alphabetical order,
followed by the `description` at the end of that section.
followed by the remaining keys other than `description` in order, followed by
the `description` at the end of that section.
Don't use quotes around any standard key names; use bare keys. Only use quoted
keys for non-standard keys whose names require them, and avoid introducing such

View File

@ -37,6 +37,8 @@ history of the style guide. Notable changes in the Rust 2024 style edition
include:
- Miscellaneous `rustfmt` bugfixes.
- Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order).
- Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase".
## Rust 2015/2018/2021 style edition

View File

@ -9,8 +9,8 @@ an item appears at module level or within another item.
alphabetically.
`use` statements, and module *declarations* (`mod foo;`, not `mod { ... }`)
must come before other items. Put imports before module declarations. Sort each
alphabetically, except that `self` and `super` must come before any other
must come before other items. Put imports before module declarations.
Version-sort each, except that `self` and `super` must come before any other
names.
Don't automatically move module declarations annotated with `#[macro_use]`,
@ -467,8 +467,10 @@ foo::{
A *group* of imports is a set of imports on the same or sequential lines. One or
more blank lines or other items (e.g., a function) separate groups of imports.
Within a group of imports, imports must be sorted ASCIIbetically (uppercase
before lowercase). Groups of imports must not be merged or re-ordered.
Within a group of imports, imports must be version-sorted, except that
non-lowercase characters (characters that can start an `UpperCamelCase`
identifier) must be sorted before lowercase characters. Groups of imports must
not be merged or re-ordered.
E.g., input:
@ -495,10 +497,15 @@ re-ordering.
### Ordering list import
Names in a list import must be sorted ASCIIbetically, but with `self` and
`super` first, and groups and glob imports last. This applies recursively. For
example, `a::*` comes before `b::a` but `a::b` comes before `a::*`. E.g.,
`use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};`.
Names in a list import must be version-sorted, except that:
- `self` and `super` always come first if present,
- non-lowercase characters (characters that can start an `UpperCamelCase`
identifier) must be sorted before lowercase characters, and
- groups and glob imports always come last if present.
This applies recursively. For example, `a::*` comes before `b::a` but `a::b`
comes before `a::*`. E.g., `use foo::bar::{a, b::c, b::d, b::d::{x, y, z},
b::{self, r, s}};`.
### Normalisation

View File

@ -455,7 +455,7 @@ pub fn report_msg<'tcx>(
let sess = machine.tcx.sess;
let level = match diag_level {
DiagLevel::Error => Level::Error,
DiagLevel::Warning => Level::Warning(None),
DiagLevel::Warning => Level::Warning,
DiagLevel::Note => Level::Note,
};
let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), level, title);

View File

@ -446,7 +446,7 @@ mod tests {
Some(ignore_list),
);
let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(span));
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
emitter.emit_diagnostic(&non_fatal_diagnostic);
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0);
assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
@ -470,7 +470,7 @@ mod tests {
None,
);
let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(span));
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
emitter.emit_diagnostic(&non_fatal_diagnostic);
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1);
assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
@ -507,8 +507,8 @@ mod tests {
);
let bar_span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
let foo_span = MultiSpan::from_span(mk_sp(BytePos(21), BytePos(22)));
let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(bar_span));
let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(foo_span));
let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span));
let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span));
let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None);
emitter.emit_diagnostic(&bar_diagnostic);
emitter.emit_diagnostic(&foo_diagnostic);

View File

@ -0,0 +1,125 @@
// run-pass
//! Test that users are able to retrieve information about trait declarations and implementations.
// ignore-stage1
// ignore-cross-compile
// ignore-remote
// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
// edition: 2021
#![feature(rustc_private)]
#![feature(assert_matches)]
#![feature(control_flow_enum)]
extern crate rustc_middle;
#[macro_use]
extern crate rustc_smir;
extern crate rustc_driver;
extern crate rustc_interface;
extern crate stable_mir;
use rustc_middle::ty::TyCtxt;
use rustc_smir::rustc_internal;
use stable_mir::CrateDef;
use std::collections::HashSet;
use std::io::Write;
use std::ops::ControlFlow;
const CRATE_NAME: &str = "trait_test";
/// This function uses the Stable MIR APIs to get information about the test crate.
fn test_traits() -> ControlFlow<()> {
let local_crate = stable_mir::local_crate();
let local_traits = local_crate.trait_decls();
assert_eq!(local_traits.len(), 1, "Expected `Max` trait, but found {:?}", local_traits);
assert_eq!(&local_traits[0].name(), "Max");
let local_impls = local_crate.trait_impls();
let impl_names = local_impls.iter().map(|trait_impl| trait_impl.name()).collect::<HashSet<_>>();
assert_impl(&impl_names, "<Positive as Max>");
assert_impl(&impl_names, "<Positive as std::marker::Copy>");
assert_impl(&impl_names, "<Positive as std::clone::Clone>");
assert_impl(&impl_names, "<Positive as std::fmt::Debug>");
assert_impl(&impl_names, "<Positive as std::cmp::PartialEq>");
assert_impl(&impl_names, "<Positive as std::cmp::Eq>");
assert_impl(&impl_names, "<Positive as std::convert::TryFrom<u64>>");
assert_impl(&impl_names, "<u64 as Max>");
assert_impl(&impl_names, "<impl std::convert::From<Positive> for u64>");
let all_traits = stable_mir::all_trait_decls();
assert!(all_traits.len() > local_traits.len());
assert!(
local_traits.iter().all(|t| all_traits.contains(t)),
"Local: {local_traits:#?}, All: {all_traits:#?}"
);
let all_impls = stable_mir::all_trait_impls();
assert!(all_impls.len() > local_impls.len());
assert!(
local_impls.iter().all(|t| all_impls.contains(t)),
"Local: {local_impls:#?}, All: {all_impls:#?}"
);
ControlFlow::Continue(())
}
fn assert_impl(impl_names: &HashSet<String>, target: &str) {
assert!(
impl_names.contains(target),
"Failed to find `{target}`. Implementations available: {impl_names:?}",
);
}
/// This test will generate and analyze a dummy crate using the stable mir.
/// For that, it will first write the dummy crate into a file.
/// Then it will create a `StableMir` using custom arguments and then
/// it will run the compiler.
fn main() {
let path = "trait_queries.rs";
generate_input(&path).unwrap();
let args = vec![
"rustc".to_string(),
"--crate-type=lib".to_string(),
"--crate-name".to_string(),
CRATE_NAME.to_string(),
path.to_string(),
];
run!(args, test_traits()).unwrap();
}
fn generate_input(path: &str) -> std::io::Result<()> {
let mut file = std::fs::File::create(path)?;
write!(
file,
r#"
use std::convert::TryFrom;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Positive(u64);
impl TryFrom<u64> for Positive {{
type Error = ();
fn try_from(val: u64) -> Result<Positive, Self::Error> {{
if val > 0 {{ Ok(Positive(val)) }} else {{ Err(()) }}
}}
}}
impl From<Positive> for u64 {{
fn from(val: Positive) -> u64 {{ val.0 }}
}}
pub trait Max {{
fn is_max(&self) -> bool;
}}
impl Max for u64 {{
fn is_max(&self) -> bool {{ *self == u64::MAX }}
}}
impl Max for Positive {{
fn is_max(&self) -> bool {{ self.0.is_max() }}
}}
"#
)?;
Ok(())
}

View File

@ -0,0 +1,13 @@
fn main() {}
fn foo() {
#[derive(Copy, Clone)]
struct Foo(NonExistent);
//~^ ERROR cannot find type
//~| ERROR cannot find type
type U = impl Copy;
//~^ ERROR `impl Trait` in type aliases is unstable
let foo: U = Foo(());
let Foo(()) = foo;
}

View File

@ -0,0 +1,30 @@
error[E0412]: cannot find type `NonExistent` in this scope
--> $DIR/issue-119493-type-error-ice.rs:5:16
|
LL | struct Foo(NonExistent);
| ^^^^^^^^^^^ not found in this scope
error[E0412]: cannot find type `NonExistent` in this scope
--> $DIR/issue-119493-type-error-ice.rs:5:16
|
LL | struct Foo(NonExistent);
| ^^^^^^^^^^^ not found in this scope
|
help: you might be missing a type parameter
|
LL | struct Foo<NonExistent>(NonExistent);
| +++++++++++++
error[E0658]: `impl Trait` in type aliases is unstable
--> $DIR/issue-119493-type-error-ice.rs:9:14
|
LL | type U = impl Copy;
| ^^^^^^^^^
|
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
= help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0412, E0658.
For more information about an error, try `rustc --explain E0412`.

View File

@ -0,0 +1,13 @@
fn main() {}
fn foo() {
#[derive(Copy, Clone)]
struct Foo([u8; S]);
//~^ ERROR cannot find value `S`
//~| ERROR cannot find value `S`
type U = impl Copy;
//~^ ERROR `impl Trait` in type aliases is unstable
let foo: U = Foo(());
let Foo(()) = foo;
}

View File

@ -0,0 +1,35 @@
error[E0425]: cannot find value `S` in this scope
--> $DIR/issue-119778-type-error-ice.rs:5:21
|
LL | struct Foo([u8; S]);
| ^ not found in this scope
|
help: you might be missing a const parameter
|
LL | struct Foo<const S: /* Type */>([u8; S]);
| +++++++++++++++++++++
error[E0425]: cannot find value `S` in this scope
--> $DIR/issue-119778-type-error-ice.rs:5:21
|
LL | struct Foo([u8; S]);
| ^ not found in this scope
|
help: you might be missing a const parameter
|
LL | struct Foo<const S: /* Type */>([u8; S]);
| +++++++++++++++++++++
error[E0658]: `impl Trait` in type aliases is unstable
--> $DIR/issue-119778-type-error-ice.rs:9:14
|
LL | type U = impl Copy;
| ^^^^^^^^^
|
= note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
= help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0425, E0658.
For more information about an error, try `rustc --explain E0425`.

View File

@ -6,9 +6,7 @@ type Pointer<T> = impl std::ops::Deref<Target = T>;
fn test() -> Pointer<_> {
//~^ ERROR: the placeholder `_` is not allowed within types
//~| ERROR: non-defining opaque type use in defining scope
Box::new(1)
//~^ ERROR expected generic type parameter, found `i32`
}
fn main() {

View File

@ -7,28 +7,6 @@ LL | fn test() -> Pointer<_> {
| | not allowed in type signatures
| help: replace with the correct return type: `Pointer<i32>`
error[E0792]: non-defining opaque type use in defining scope
--> $DIR/issue-77179.rs:7:14
|
LL | fn test() -> Pointer<_> {
| ^^^^^^^^^^ argument `i32` is not a generic parameter
|
note: for this opaque type
--> $DIR/issue-77179.rs:5:19
|
LL | type Pointer<T> = impl std::ops::Deref<Target = T>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
error[E0792]: expected generic type parameter, found `i32`
--> $DIR/issue-77179.rs:10:5
|
LL | type Pointer<T> = impl std::ops::Deref<Target = T>;
| - this generic parameter must be used with a generic type parameter
...
LL | Box::new(1)
| ^^^^^^^^^^^
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0121, E0792.
For more information about an error, try `rustc --explain E0121`.
For more information about this error, try `rustc --explain E0121`.

View File

@ -744,6 +744,12 @@ style-team = [
"@yaahc",
]
project-const-traits = [
"@compiler-errors",
"@fee1-dead",
"@fmease",
"@oli-obk",
]
project-stable-mir = [
"@celinval",
"@oli-obk",