mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Auto merge of #154802 - matthiaskrgr:rollup-HWNmEyC, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - rust-lang/rust#154376 (Remove more BuiltinLintDiag variants - part 4) - rust-lang/rust#154731 (llvm: Fix array ABI test to not check equality implementation) - rust-lang/rust#127534 (feat(core): impl Step for NonZero<u*>) - rust-lang/rust#154703 (Fix trailing comma in lifetime suggestion for empty angle brackets) - rust-lang/rust#154776 (Fix ICE in read_discriminant for enums with non-contiguous discriminants)
This commit is contained in:
@@ -121,20 +121,20 @@ pub fn read_discriminant(
|
||||
// discriminants are int-like.
|
||||
let discr_val = self.int_to_int_or_float(&tag_val, discr_layout).unwrap();
|
||||
let discr_bits = discr_val.to_scalar().to_bits(discr_layout.size)?;
|
||||
// Convert discriminant to variant index. Since we validated the tag against the
|
||||
// layout range above, this cannot fail.
|
||||
// Convert discriminant to variant index. The tag may pass the layout range
|
||||
// check above but still not match any actual variant discriminant (e.g.,
|
||||
// non-contiguous discriminants with a wrapping valid_range).
|
||||
let index = match *ty.kind() {
|
||||
ty::Adt(adt, _) => {
|
||||
adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits).unwrap()
|
||||
adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits)
|
||||
}
|
||||
ty::Coroutine(def_id, args) => {
|
||||
let args = args.as_coroutine();
|
||||
args.discriminants(def_id, *self.tcx)
|
||||
.find(|(_, var)| var.val == discr_bits)
|
||||
.unwrap()
|
||||
args.discriminants(def_id, *self.tcx).find(|(_, var)| var.val == discr_bits)
|
||||
}
|
||||
_ => span_bug!(self.cur_span(), "tagged layout for non-adt non-coroutine"),
|
||||
};
|
||||
}
|
||||
.ok_or_else(|| err_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))))?;
|
||||
// Return the cast value, and the index.
|
||||
index.0
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::any::Any;
|
||||
|
||||
/// This module provides types and traits for buffering lints until later in compilation.
|
||||
use rustc_ast::node_id::NodeId;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
@@ -10,9 +12,11 @@
|
||||
/// We can't implement `Diagnostic` for `BuiltinLintDiag`, because decorating some of its
|
||||
/// variants requires types we don't have yet. So, handle that case separately.
|
||||
pub enum DecorateDiagCompat {
|
||||
/// The third argument of the closure is a `Session`. However, due to the dependency tree,
|
||||
/// we don't have access to `rustc_session` here, so we downcast it when needed.
|
||||
Dynamic(
|
||||
Box<
|
||||
dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()>
|
||||
dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()>
|
||||
+ DynSync
|
||||
+ DynSend
|
||||
+ 'static,
|
||||
@@ -30,7 +34,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
impl<D: for<'a> Diagnostic<'a, ()> + DynSync + DynSend + 'static> From<D> for DecorateDiagCompat {
|
||||
#[inline]
|
||||
fn from(d: D) -> Self {
|
||||
Self::Dynamic(Box::new(|dcx, level| d.into_diag(dcx, level)))
|
||||
Self::Dynamic(Box::new(|dcx, level, _| d.into_diag(dcx, level)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +101,26 @@ pub fn dyn_buffer_lint<
|
||||
node_id: NodeId,
|
||||
span: impl Into<MultiSpan>,
|
||||
callback: F,
|
||||
) {
|
||||
self.add_early_lint(BufferedEarlyLint {
|
||||
lint_id: LintId::of(lint),
|
||||
node_id,
|
||||
span: Some(span.into()),
|
||||
diagnostic: DecorateDiagCompat::Dynamic(Box::new(|dcx, level, _| callback(dcx, level))),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn dyn_buffer_lint_any<
|
||||
F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()>
|
||||
+ DynSend
|
||||
+ DynSync
|
||||
+ 'static,
|
||||
>(
|
||||
&mut self,
|
||||
lint: &'static Lint,
|
||||
node_id: NodeId,
|
||||
span: impl Into<MultiSpan>,
|
||||
callback: F,
|
||||
) {
|
||||
self.add_early_lint(BufferedEarlyLint {
|
||||
lint_id: LintId::of(lint),
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
use std::path::PathBuf;
|
||||
use std::thread::panicking;
|
||||
|
||||
use rustc_data_structures::sync::{DynSend, DynSync};
|
||||
use rustc_error_messages::{DiagArgMap, DiagArgName, DiagArgValue, IntoDiagArg};
|
||||
use rustc_lint_defs::{Applicability, LintExpectationId};
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
@@ -119,16 +118,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Diagnostic<'a, ()>
|
||||
for Box<
|
||||
dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSync + DynSend + 'static,
|
||||
>
|
||||
{
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
self(dcx, level)
|
||||
}
|
||||
}
|
||||
|
||||
/// Type used to emit diagnostic through a closure instead of implementing the `Diagnostic` trait.
|
||||
pub struct DiagDecorator<F: FnOnce(&mut Diag<'_, ()>)>(pub F);
|
||||
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
use rustc_span::{DUMMY_SP, Ident, Span};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::DecorateBuiltinLint;
|
||||
use crate::context::{EarlyContext, LintContext, LintStore};
|
||||
use crate::passes::{EarlyLintPass, EarlyLintPassObject};
|
||||
use crate::{DecorateBuiltinLint, DiagAndSess};
|
||||
|
||||
pub(super) mod diagnostics;
|
||||
|
||||
@@ -49,8 +49,12 @@ fn check_id(&mut self, id: ast::NodeId) {
|
||||
},
|
||||
);
|
||||
}
|
||||
DecorateDiagCompat::Dynamic(d) => {
|
||||
self.context.opt_span_lint(lint_id.lint, span, d);
|
||||
DecorateDiagCompat::Dynamic(callback) => {
|
||||
self.context.opt_span_lint(
|
||||
lint_id.lint,
|
||||
span,
|
||||
DiagAndSess { callback, sess: self.context.sess() },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use std::any::Any;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc_data_structures::sync::DynSend;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level,
|
||||
elided_lifetime_in_path_suggestion,
|
||||
@@ -8,12 +10,24 @@
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::lints;
|
||||
|
||||
mod check_cfg;
|
||||
|
||||
pub struct DiagAndSess<'sess> {
|
||||
pub callback: Box<
|
||||
dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level, &dyn Any) -> Diag<'b, ()> + DynSend + 'static,
|
||||
>,
|
||||
pub sess: &'sess Session,
|
||||
}
|
||||
|
||||
impl<'a> Diagnostic<'a, ()> for DiagAndSess<'_> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
(self.callback)(dcx, level, self.sess)
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a diagnostic struct that will decorate a `BuiltinLintDiag`
|
||||
/// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed.
|
||||
pub struct DecorateBuiltinLint<'sess, 'tcx> {
|
||||
@@ -25,28 +39,6 @@ pub struct DecorateBuiltinLint<'sess, 'tcx> {
|
||||
impl<'a> Diagnostic<'a, ()> for DecorateBuiltinLint<'_, '_> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
match self.diagnostic {
|
||||
BuiltinLintDiag::AbsPathWithModule(mod_span) => {
|
||||
let (replacement, applicability) =
|
||||
match self.sess.source_map().span_to_snippet(mod_span) {
|
||||
Ok(ref s) => {
|
||||
// FIXME(Manishearth) ideally the emitting code
|
||||
// can tell us whether or not this is global
|
||||
let opt_colon =
|
||||
if s.trim_start().starts_with("::") { "" } else { "::" };
|
||||
|
||||
(format!("crate{opt_colon}{s}"), Applicability::MachineApplicable)
|
||||
}
|
||||
Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders),
|
||||
};
|
||||
lints::AbsPathWithModule {
|
||||
sugg: lints::AbsPathWithModuleSugg {
|
||||
span: mod_span,
|
||||
applicability,
|
||||
replacement,
|
||||
},
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
}
|
||||
BuiltinLintDiag::ElidedLifetimesInPaths(
|
||||
n,
|
||||
path_span,
|
||||
@@ -87,36 +79,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
}
|
||||
BuiltinLintDiag::SingleUseLifetime {
|
||||
param_span,
|
||||
use_span,
|
||||
elidable,
|
||||
deletion_span,
|
||||
ident,
|
||||
} => {
|
||||
debug!(?param_span, ?use_span, ?deletion_span);
|
||||
let suggestion = if let Some(deletion_span) = deletion_span {
|
||||
let (use_span, replace_lt) = if elidable {
|
||||
let use_span =
|
||||
self.sess.source_map().span_extend_while_whitespace(use_span);
|
||||
(use_span, String::new())
|
||||
} else {
|
||||
(use_span, "'_".to_owned())
|
||||
};
|
||||
debug!(?deletion_span, ?use_span);
|
||||
|
||||
// issue 107998 for the case such as a wrong function pointer type
|
||||
// `deletion_span` is empty and there is no need to report lifetime uses here
|
||||
let deletion_span =
|
||||
if deletion_span.is_empty() { None } else { Some(deletion_span) };
|
||||
Some(lints::SingleUseLifetimeSugg { deletion_span, use_span, replace_lt })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
lints::SingleUseLifetime { suggestion, param_span, use_span, ident }
|
||||
.into_diag(dcx, level)
|
||||
}
|
||||
BuiltinLintDiag::NamedArgumentUsedPositionally {
|
||||
position_sp_to_replace,
|
||||
position_sp_for_msg,
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
#[rustfmt::skip]
|
||||
pub use builtin::{MissingDoc, SoftLints};
|
||||
pub use context::{EarlyContext, LateContext, LintContext, LintStore};
|
||||
pub use early::diagnostics::{DecorateAttrLint, DecorateBuiltinLint};
|
||||
pub use early::diagnostics::{DecorateAttrLint, DecorateBuiltinLint, DiagAndSess};
|
||||
pub use early::{EarlyCheckNode, check_ast_node};
|
||||
pub use late::{check_crate, late_lint_mod, unerased_lint_store};
|
||||
pub use levels::LintLevelsBuilder;
|
||||
|
||||
@@ -3011,25 +3011,6 @@ pub(crate) struct IllFormedAttributeInput {
|
||||
pub docs: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition"
|
||||
)]
|
||||
pub(crate) struct AbsPathWithModule {
|
||||
#[subdiagnostic]
|
||||
pub sugg: AbsPathWithModuleSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion("use `crate`", code = "{replacement}")]
|
||||
pub(crate) struct AbsPathWithModuleSugg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[applicability]
|
||||
pub applicability: Applicability,
|
||||
pub replacement: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("hidden lifetime parameters in types are deprecated")]
|
||||
pub(crate) struct ElidedLifetimesInPaths {
|
||||
@@ -3081,30 +3062,6 @@ pub(crate) enum UnusedImportsSugg {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("lifetime parameter `{$ident}` only used once")]
|
||||
pub(crate) struct SingleUseLifetime {
|
||||
#[label("this lifetime...")]
|
||||
pub param_span: Span,
|
||||
#[label("...is used only here")]
|
||||
pub use_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: Option<SingleUseLifetimeSugg>,
|
||||
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion("elide the single-use lifetime", applicability = "machine-applicable")]
|
||||
pub(crate) struct SingleUseLifetimeSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
pub deletion_span: Option<Span>,
|
||||
#[suggestion_part(code = "{replace_lt}")]
|
||||
pub use_span: Span,
|
||||
|
||||
pub replace_lt: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("named argument `{$named_arg_name}` is not used by name")]
|
||||
pub(crate) struct NamedArgumentUsedPositionally {
|
||||
|
||||
@@ -656,7 +656,6 @@ pub enum DeprecatedSinceKind {
|
||||
// becomes hacky (and it gets allocated).
|
||||
#[derive(Debug)]
|
||||
pub enum BuiltinLintDiag {
|
||||
AbsPathWithModule(Span),
|
||||
ElidedLifetimesInPaths(usize, Span, bool, Span),
|
||||
UnusedImports {
|
||||
remove_whole_use: bool,
|
||||
@@ -665,18 +664,6 @@ pub enum BuiltinLintDiag {
|
||||
test_module_span: Option<Span>,
|
||||
span_snippets: Vec<String>,
|
||||
},
|
||||
SingleUseLifetime {
|
||||
/// Span of the parameter which declares this lifetime.
|
||||
param_span: Span,
|
||||
/// Span of the code that should be removed when eliding this lifetime.
|
||||
/// This span should include leading or trailing comma.
|
||||
deletion_span: Option<Span>,
|
||||
/// Span of the single use, or None if the lifetime is never used.
|
||||
/// If true, the lifetime will be fully elided.
|
||||
use_span: Span,
|
||||
elidable: bool,
|
||||
ident: Ident,
|
||||
},
|
||||
NamedArgumentUsedPositionally {
|
||||
/// Span where the named argument is used by position and will be replaced with the named
|
||||
/// argument name
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle,
|
||||
Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, MultiSpan, SuggestionStyle,
|
||||
struct_span_code_err,
|
||||
};
|
||||
use rustc_feature::BUILTIN_ATTRIBUTES;
|
||||
@@ -23,7 +23,6 @@
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::{
|
||||
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS, AMBIGUOUS_IMPORT_VISIBILITIES,
|
||||
AMBIGUOUS_PANIC_IMPORTS, MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
|
||||
@@ -510,12 +509,35 @@ pub(crate) fn lint_if_path_starts_with_module(
|
||||
return;
|
||||
}
|
||||
|
||||
let diag = BuiltinLintDiag::AbsPathWithModule(root_span);
|
||||
self.lint_buffer.buffer_lint(
|
||||
self.lint_buffer.dyn_buffer_lint_any(
|
||||
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
|
||||
node_id,
|
||||
root_span,
|
||||
diag,
|
||||
move |dcx, level, sess| {
|
||||
let (replacement, applicability) = match sess
|
||||
.downcast_ref::<Session>()
|
||||
.expect("expected a `Session`")
|
||||
.source_map()
|
||||
.span_to_snippet(root_span)
|
||||
{
|
||||
Ok(ref s) => {
|
||||
// FIXME(Manishearth) ideally the emitting code
|
||||
// can tell us whether or not this is global
|
||||
let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" };
|
||||
|
||||
(format!("crate{opt_colon}{s}"), Applicability::MachineApplicable)
|
||||
}
|
||||
Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders),
|
||||
};
|
||||
errors::AbsPathWithModule {
|
||||
sugg: errors::AbsPathWithModuleSugg {
|
||||
span: root_span,
|
||||
applicability,
|
||||
replacement,
|
||||
},
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1697,3 +1697,46 @@ pub(crate) struct AssociatedConstElidedLifetime {
|
||||
#[note("cannot automatically infer `'static` because of other lifetimes in scope")]
|
||||
pub lifetimes_in_scope: MultiSpan,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("lifetime parameter `{$ident}` only used once")]
|
||||
pub(crate) struct SingleUseLifetime {
|
||||
#[label("this lifetime...")]
|
||||
pub param_span: Span,
|
||||
#[label("...is used only here")]
|
||||
pub use_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: Option<SingleUseLifetimeSugg>,
|
||||
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion("elide the single-use lifetime", applicability = "machine-applicable")]
|
||||
pub(crate) struct SingleUseLifetimeSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
pub deletion_span: Option<Span>,
|
||||
#[suggestion_part(code = "{replace_lt}")]
|
||||
pub use_span: Span,
|
||||
|
||||
pub replace_lt: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition"
|
||||
)]
|
||||
pub(crate) struct AbsPathWithModule {
|
||||
#[subdiagnostic]
|
||||
pub sugg: AbsPathWithModuleSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion("use `crate`", code = "{replacement}")]
|
||||
pub(crate) struct AbsPathWithModuleSugg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[applicability]
|
||||
pub applicability: Applicability,
|
||||
pub replacement: String,
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, ErrorGuaranteed, MultiSpan, SuggestionStyle, pluralize,
|
||||
Applicability, Diag, Diagnostic, ErrorGuaranteed, MultiSpan, SuggestionStyle, pluralize,
|
||||
struct_span_code_err,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
@@ -3642,22 +3642,52 @@ pub(crate) fn maybe_report_lifetime_uses(
|
||||
match use_set {
|
||||
Some(LifetimeUseSet::Many) => {}
|
||||
Some(LifetimeUseSet::One { use_span, use_ctxt }) => {
|
||||
debug!(?param.ident, ?param.ident.span, ?use_span);
|
||||
|
||||
let elidable = matches!(use_ctxt, LifetimeCtxt::Ref);
|
||||
let param_ident = param.ident;
|
||||
let deletion_span =
|
||||
if param.bounds.is_empty() { deletion_span() } else { None };
|
||||
|
||||
self.r.lint_buffer.buffer_lint(
|
||||
self.r.lint_buffer.dyn_buffer_lint_any(
|
||||
lint::builtin::SINGLE_USE_LIFETIMES,
|
||||
param.id,
|
||||
param.ident.span,
|
||||
lint::BuiltinLintDiag::SingleUseLifetime {
|
||||
param_span: param.ident.span,
|
||||
use_span,
|
||||
elidable,
|
||||
deletion_span,
|
||||
ident: param.ident,
|
||||
param_ident.span,
|
||||
move |dcx, level, sess| {
|
||||
debug!(?param_ident, ?param_ident.span, ?use_span);
|
||||
|
||||
let elidable = matches!(use_ctxt, LifetimeCtxt::Ref);
|
||||
let suggestion = if let Some(deletion_span) = deletion_span {
|
||||
let (use_span, replace_lt) = if elidable {
|
||||
let use_span = sess
|
||||
.downcast_ref::<Session>()
|
||||
.expect("expected a `Session`")
|
||||
.source_map()
|
||||
.span_extend_while_whitespace(use_span);
|
||||
(use_span, String::new())
|
||||
} else {
|
||||
(use_span, "'_".to_owned())
|
||||
};
|
||||
debug!(?deletion_span, ?use_span);
|
||||
|
||||
// issue 107998 for the case such as a wrong function pointer type
|
||||
// `deletion_span` is empty and there is no need to report lifetime uses here
|
||||
let deletion_span = if deletion_span.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(deletion_span)
|
||||
};
|
||||
Some(errors::SingleUseLifetimeSugg {
|
||||
deletion_span,
|
||||
use_span,
|
||||
replace_lt,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
errors::SingleUseLifetime {
|
||||
suggestion,
|
||||
param_span: param_ident.span,
|
||||
use_span,
|
||||
ident: param_ident,
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -4065,6 +4095,7 @@ fn add_missing_lifetime_specifiers_label<'a>(
|
||||
};
|
||||
|
||||
let mut spans_suggs: Vec<_> = Vec::new();
|
||||
let source_map = self.r.tcx.sess.source_map();
|
||||
let build_sugg = |lt: MissingLifetime| match lt.kind {
|
||||
MissingLifetimeKind::Underscore => {
|
||||
debug_assert_eq!(lt.count, 1);
|
||||
@@ -4075,9 +4106,12 @@ fn add_missing_lifetime_specifiers_label<'a>(
|
||||
(lt.span.shrink_to_hi(), format!("{existing_name} "))
|
||||
}
|
||||
MissingLifetimeKind::Comma => {
|
||||
let sugg: String = std::iter::repeat_n([existing_name.as_str(), ", "], lt.count)
|
||||
.flatten()
|
||||
let sugg: String = std::iter::repeat_n(existing_name.as_str(), lt.count)
|
||||
.intersperse(", ")
|
||||
.collect();
|
||||
let is_empty_brackets =
|
||||
source_map.span_look_ahead(lt.span, ">", Some(50)).is_some();
|
||||
let sugg = if is_empty_brackets { sugg } else { format!("{sugg}, ") };
|
||||
(lt.span.shrink_to_hi(), sugg)
|
||||
}
|
||||
MissingLifetimeKind::Brackets => {
|
||||
|
||||
@@ -344,7 +344,7 @@ pub fn dyn_buffer_lint<
|
||||
lint,
|
||||
Some(span.into()),
|
||||
node_id,
|
||||
DecorateDiagCompat::Dynamic(Box::new(callback)),
|
||||
DecorateDiagCompat::Dynamic(Box::new(|dcx, level, _| callback(dcx, level))),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+136
-10
@@ -15,6 +15,7 @@ unsafe impl TrustedStep for $type {}
|
||||
)*};
|
||||
}
|
||||
unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize Ipv4Addr Ipv6Addr];
|
||||
unsafe_impl_trusted_step![NonZero<u8> NonZero<u16> NonZero<u32> NonZero<u64> NonZero<u128> NonZero<usize>];
|
||||
|
||||
/// Objects that have a notion of *successor* and *predecessor* operations.
|
||||
///
|
||||
@@ -255,10 +256,8 @@ fn backward(start: Self, n: usize) -> Self {
|
||||
|
||||
macro_rules! step_integer_impls {
|
||||
{
|
||||
narrower than or same width as usize:
|
||||
$( [ $u_narrower:ident $i_narrower:ident ] ),+;
|
||||
wider than usize:
|
||||
$( [ $u_wider:ident $i_wider:ident ] ),+;
|
||||
[ $( [ $u_narrower:ident $i_narrower:ident ] ),+ ] <= usize <
|
||||
[ $( [ $u_wider:ident $i_wider:ident ] ),+ ]
|
||||
} => {
|
||||
$(
|
||||
#[allow(unreachable_patterns)]
|
||||
@@ -437,20 +436,138 @@ fn backward_checked(start: Self, n: usize) -> Option<Self> {
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
step_integer_impls! {
|
||||
narrower than or same width as usize: [u8 i8], [u16 i16], [u32 i32], [u64 i64], [usize isize];
|
||||
wider than usize: [u128 i128];
|
||||
[ [u8 i8], [u16 i16], [u32 i32], [u64 i64], [usize isize] ] <= usize < [ [u128 i128] ]
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
step_integer_impls! {
|
||||
narrower than or same width as usize: [u8 i8], [u16 i16], [u32 i32], [usize isize];
|
||||
wider than usize: [u64 i64], [u128 i128];
|
||||
[ [u8 i8], [u16 i16], [u32 i32], [usize isize] ] <= usize < [ [u64 i64], [u128 i128] ]
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
step_integer_impls! {
|
||||
narrower than or same width as usize: [u8 i8], [u16 i16], [usize isize];
|
||||
wider than usize: [u32 i32], [u64 i64], [u128 i128];
|
||||
[ [u8 i8], [u16 i16], [usize isize] ] <= usize < [ [u32 i32], [u64 i64], [u128 i128] ]
|
||||
}
|
||||
|
||||
// These are still macro-generated because the integer literals resolve to different types.
|
||||
macro_rules! step_nonzero_identical_methods {
|
||||
($int:ident) => {
|
||||
#[inline]
|
||||
unsafe fn forward_unchecked(start: Self, n: usize) -> Self {
|
||||
// SAFETY: the caller has to guarantee that `start + n` doesn't overflow.
|
||||
unsafe { Self::new_unchecked(start.get().unchecked_add(n as $int)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn backward_unchecked(start: Self, n: usize) -> Self {
|
||||
// SAFETY: the caller has to guarantee that `start - n` doesn't overflow or hit zero.
|
||||
unsafe { Self::new_unchecked(start.get().unchecked_sub(n as $int)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(arithmetic_overflow)]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn forward(start: Self, n: usize) -> Self {
|
||||
// In debug builds, trigger a panic on overflow.
|
||||
// This should optimize completely out in release builds.
|
||||
if Self::forward_checked(start, n).is_none() {
|
||||
let _ = $int::MAX + 1;
|
||||
}
|
||||
// Do saturating math (wrapping math causes UB if it wraps to Zero)
|
||||
start.saturating_add(n as $int)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(arithmetic_overflow)]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn backward(start: Self, n: usize) -> Self {
|
||||
// In debug builds, trigger a panic on overflow.
|
||||
// This should optimize completely out in release builds.
|
||||
if Self::backward_checked(start, n).is_none() {
|
||||
let _ = $int::MIN - 1;
|
||||
}
|
||||
// Do saturating math (wrapping math causes UB if it wraps to Zero)
|
||||
Self::new(start.get().saturating_sub(n as $int)).unwrap_or(Self::MIN)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
|
||||
if *start <= *end {
|
||||
#[allow(irrefutable_let_patterns, reason = "happens on usize or narrower")]
|
||||
if let Ok(steps) = usize::try_from(end.get() - start.get()) {
|
||||
(steps, Some(steps))
|
||||
} else {
|
||||
(usize::MAX, None)
|
||||
}
|
||||
} else {
|
||||
(0, None)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! step_nonzero_impls {
|
||||
{
|
||||
[$( $narrower:ident ),+] <= usize < [$( $wider:ident ),+]
|
||||
} => {
|
||||
$(
|
||||
#[allow(unreachable_patterns)]
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
impl Step for NonZero<$narrower> {
|
||||
step_nonzero_identical_methods!($narrower);
|
||||
|
||||
#[inline]
|
||||
fn forward_checked(start: Self, n: usize) -> Option<Self> {
|
||||
match $narrower::try_from(n) {
|
||||
Ok(n) => start.checked_add(n),
|
||||
Err(_) => None, // if n is out of range, `unsigned_start + n` is too
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn backward_checked(start: Self, n: usize) -> Option<Self> {
|
||||
match $narrower::try_from(n) {
|
||||
// *_sub() is not implemented on NonZero<T>
|
||||
Ok(n) => start.get().checked_sub(n).and_then(Self::new),
|
||||
Err(_) => None, // if n is out of range, `unsigned_start - n` is too
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
|
||||
$(
|
||||
#[allow(unreachable_patterns)]
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
impl Step for NonZero<$wider> {
|
||||
step_nonzero_identical_methods!($wider);
|
||||
|
||||
#[inline]
|
||||
fn forward_checked(start: Self, n: usize) -> Option<Self> {
|
||||
start.checked_add(n as $wider)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn backward_checked(start: Self, n: usize) -> Option<Self> {
|
||||
start.get().checked_sub(n as $wider).and_then(Self::new)
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
step_nonzero_impls! {
|
||||
[u8, u16, u32, u64, usize] <= usize < [u128]
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
step_nonzero_impls! {
|
||||
[u8, u16, u32, usize] <= usize < [u64, u128]
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
step_nonzero_impls! {
|
||||
[u8, u16, usize] <= usize < [u32, u64, u128]
|
||||
}
|
||||
|
||||
#[unstable(feature = "step_trait", issue = "42168")]
|
||||
@@ -944,6 +1061,7 @@ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
|
||||
range_exact_iter_impl! {
|
||||
usize u8 u16
|
||||
isize i8 i16
|
||||
NonZero<usize> NonZero<u8> NonZero<u16>
|
||||
|
||||
// These are incorrect per the reasoning above,
|
||||
// but removing them would be a breaking change as they were stabilized in Rust 1.0.0.
|
||||
@@ -956,22 +1074,30 @@ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
|
||||
unsafe_range_trusted_random_access_impl! {
|
||||
usize u8 u16
|
||||
isize i8 i16
|
||||
NonZero<usize> NonZero<u8> NonZero<u16>
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
unsafe_range_trusted_random_access_impl! {
|
||||
u32 i32
|
||||
NonZero<u32>
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
unsafe_range_trusted_random_access_impl! {
|
||||
u32 i32
|
||||
u64 i64
|
||||
NonZero<u32>
|
||||
NonZero<u64>
|
||||
}
|
||||
|
||||
range_incl_exact_iter_impl! {
|
||||
u8
|
||||
i8
|
||||
NonZero<u8>
|
||||
// Since RangeInclusive<NonZero<uN>> can only be 1..=uN::MAX the length of this range is always
|
||||
// <= uN::MAX, so they are always valid ExactSizeIterator unlike the ranges that include zero.
|
||||
NonZero<u16> NonZero<usize>
|
||||
|
||||
// These are incorrect per the reasoning above,
|
||||
// but removing them would be a breaking change as they were stabilized in Rust 1.26.0.
|
||||
|
||||
@@ -502,3 +502,142 @@ fn test_double_ended_range() {
|
||||
panic!("unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! nz {
|
||||
(NonZero<$type:ident>($val:literal)) => {
|
||||
::core::num::NonZero::<$type>::new($val).unwrap()
|
||||
};
|
||||
(NonZero<$type:ident>::MAX) => {
|
||||
::core::num::NonZero::<$type>::new($type::MAX).unwrap()
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! nonzero_array {
|
||||
(NonZero<$type:ident>[$($val:literal),*]) => {
|
||||
[$(nz!(NonZero<$type>($val))),*]
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! nonzero_range {
|
||||
(NonZero<$type:ident>($($left:literal)?..$($right:literal)?)) => {
|
||||
nz!(NonZero<$type>($($left)?))..nz!(NonZero<$type>($($right)?))
|
||||
};
|
||||
(NonZero<$type:ident>($($left:literal)?..MAX)) => {
|
||||
nz!(NonZero<$type>($($left)?))..nz!(NonZero<$type>::MAX)
|
||||
};
|
||||
(NonZero<$type:ident>($($left:literal)?..=$right:literal)) => {
|
||||
nz!(NonZero<$type>($($left)?))..=nz!(NonZero<$type>($right))
|
||||
};
|
||||
(NonZero<$type:ident>($($left:literal)?..=MAX)) => {
|
||||
nz!(NonZero<$type>($($left)?))..=nz!(NonZero<$type>::MAX)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nonzero_range() {
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<usize>(1..=21)).step_by(5).collect::<Vec<_>>(),
|
||||
nonzero_array!(NonZero<usize>[1, 6, 11, 16, 21])
|
||||
);
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<usize>(1..=20)).step_by(5).collect::<Vec<_>>(),
|
||||
nonzero_array!(NonZero<usize>[1, 6, 11, 16])
|
||||
);
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<usize>(1..20)).step_by(5).collect::<Vec<_>>(),
|
||||
nonzero_array!(NonZero<usize>[1, 6, 11, 16])
|
||||
);
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<usize>(1..21)).rev().step_by(5).collect::<Vec<_>>(),
|
||||
nonzero_array!(NonZero<usize>[20, 15, 10, 5])
|
||||
);
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<usize>(1..21)).rev().step_by(6).collect::<Vec<_>>(),
|
||||
nonzero_array!(NonZero<usize>[20, 14, 8, 2])
|
||||
);
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<u8>(200..255)).step_by(50).collect::<Vec<_>>(),
|
||||
nonzero_array!(NonZero<u8>[200, 250])
|
||||
);
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<usize>(200..5)).step_by(1).collect::<Vec<_>>(),
|
||||
nonzero_array!(NonZero<usize>[])
|
||||
);
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<usize>(200..200)).step_by(1).collect::<Vec<_>>(),
|
||||
nonzero_array!(NonZero<usize>[])
|
||||
);
|
||||
|
||||
assert_eq!(nonzero_range!(NonZero<u32>(10..20)).step_by(1).size_hint(), (10, Some(10)));
|
||||
assert_eq!(nonzero_range!(NonZero<u32>(10..20)).step_by(5).size_hint(), (2, Some(2)));
|
||||
assert_eq!(nonzero_range!(NonZero<u32>(1..21)).rev().step_by(5).size_hint(), (4, Some(4)));
|
||||
assert_eq!(nonzero_range!(NonZero<u32>(1..21)).rev().step_by(6).size_hint(), (4, Some(4)));
|
||||
assert_eq!(nonzero_range!(NonZero<u32>(20..1)).step_by(1).size_hint(), (0, Some(0)));
|
||||
assert_eq!(nonzero_range!(NonZero<u32>(20..20)).step_by(1).size_hint(), (0, Some(0)));
|
||||
|
||||
// ExactSizeIterator
|
||||
assert_eq!(nonzero_range!(NonZero<u8>(1..=MAX)).step_by(1).len(), usize::from(u8::MAX));
|
||||
assert_eq!(nonzero_range!(NonZero<u16>(1..=MAX)).step_by(1).len(), usize::from(u16::MAX));
|
||||
assert_eq!(nonzero_range!(NonZero<usize>(1..=MAX)).step_by(1).len(), usize::MAX);
|
||||
|
||||
// Limits (next)
|
||||
let mut range = nonzero_range!(NonZero<u8>(254..=MAX));
|
||||
assert_eq!(range.next(), Some(nz!(NonZero<u8>(254))));
|
||||
assert_eq!(range.next(), Some(nz!(NonZero<u8>(255))));
|
||||
assert_eq!(range.next(), None);
|
||||
|
||||
let mut range = nonzero_range!(NonZero<u16>(65534..=MAX));
|
||||
assert_eq!(range.next(), Some(nz!(NonZero<u16>(65534))));
|
||||
assert_eq!(range.next(), Some(nz!(NonZero<u16>(65535))));
|
||||
assert_eq!(range.next(), None);
|
||||
|
||||
// Limits (size_hint, exclusive range)
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<u8>(1..MAX)).step_by(1).size_hint(),
|
||||
(u8::MAX as usize - 1, Some(u8::MAX as usize - 1))
|
||||
);
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<u16>(1..MAX)).step_by(1).size_hint(),
|
||||
(u16::MAX as usize - 1, Some(u16::MAX as usize - 1))
|
||||
);
|
||||
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<u32>(1..MAX)).step_by(1).size_hint(),
|
||||
(u32::MAX as usize - 1, Some(u32::MAX as usize - 1))
|
||||
);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<u64>(1..MAX)).step_by(1).size_hint(),
|
||||
(u64::MAX as usize - 1, Some(u64::MAX as usize - 1))
|
||||
);
|
||||
assert_eq!(nonzero_range!(NonZero<u128>(1..MAX)).step_by(1).size_hint(), (usize::MAX, None));
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<usize>(1..MAX)).step_by(1).size_hint(),
|
||||
(usize::MAX - 1, Some(usize::MAX - 1))
|
||||
);
|
||||
|
||||
// Limits (size_hint, inclusive range)
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<u8>(1..=MAX)).step_by(1).size_hint(),
|
||||
(u8::MAX as usize, Some(u8::MAX as usize))
|
||||
);
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<u16>(1..=MAX)).step_by(1).size_hint(),
|
||||
(u16::MAX as usize, Some(u16::MAX as usize))
|
||||
);
|
||||
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<u32>(1..=MAX)).step_by(1).size_hint(),
|
||||
(u32::MAX as usize, Some(u32::MAX as usize))
|
||||
);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<u64>(1..=MAX)).step_by(1).size_hint(),
|
||||
(u64::MAX as usize, Some(u64::MAX as usize))
|
||||
);
|
||||
assert_eq!(nonzero_range!(NonZero<u128>(1..=MAX)).step_by(1).size_hint(), (usize::MAX, None));
|
||||
assert_eq!(
|
||||
nonzero_range!(NonZero<usize>(1..=MAX)).step_by(1).size_hint(),
|
||||
(usize::MAX, Some(usize::MAX))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//@ revisions: llvm-current llvm-next
|
||||
//@[llvm-current] ignore-llvm-version: 23-99
|
||||
//@[llvm-next] min-llvm-version: 23
|
||||
//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
|
||||
//@ only-x86_64
|
||||
#![crate_type = "lib"]
|
||||
@@ -26,9 +29,18 @@
|
||||
#[no_mangle]
|
||||
pub fn array_eq_value_still_passed_by_pointer(a: [u16; 9], b: [u16; 9]) -> bool {
|
||||
// CHECK-NEXT: start:
|
||||
// CHECK: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(ptr {{.*}} dereferenceable(18) %{{.+}}, ptr {{.*}} dereferenceable(18) %{{.+}}, i64 18)
|
||||
// CHECK-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0
|
||||
// CHECK-NEXT: ret i1 %[[EQ]]
|
||||
// CHECK-NOT: alloca
|
||||
// llvm-current-NEXT: %[[CMP:.+]] = tail call i32 @{{bcmp|memcmp}}(ptr
|
||||
// llvm-current-SAME: {{.*}} dereferenceable(18) %{{.+}}, ptr {{.*}} dereferenceable(18)
|
||||
// llvm-current-SAME: %{{.+}}, i64 18)
|
||||
// llvm-current-NEXT: %[[EQ:.+]] = icmp eq i32 %[[CMP]], 0
|
||||
// llvm-current-NEXT: ret i1 %[[EQ]]
|
||||
// CHECK-NOT: call
|
||||
// New LLVM expands the bcmp earlier, so this becomes wide reads + icmp
|
||||
// No allocas or calls, and at least one icmp
|
||||
// llvm-next: icmp
|
||||
// CHECK-NOT: alloca
|
||||
// CHECK-NOT: call
|
||||
a == b
|
||||
}
|
||||
|
||||
|
||||
@@ -108,4 +108,17 @@ enum UninhDiscriminant {
|
||||
};
|
||||
};
|
||||
|
||||
// # Regression test for https://github.com/rust-lang/rust/issues/153758
|
||||
// Discriminants at i64::MIN and i64::MAX produce a wrapping valid_range that covers
|
||||
// all values. A value like 0 passes the range check but doesn't match any variant.
|
||||
#[repr(i64)]
|
||||
#[derive(Copy, Clone)]
|
||||
enum WideRangeDiscriminants {
|
||||
A = i64::MIN,
|
||||
B = i64::MAX,
|
||||
}
|
||||
|
||||
const BAD_WIDE_RANGE_ENUM: WideRangeDiscriminants = unsafe { mem::transmute(0_i64) };
|
||||
//~^ ERROR expected a valid enum tag
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -129,6 +129,17 @@ LL | std::mem::discriminant(&*(&() as *const () as *const Never));
|
||||
note: inside `discriminant::<Never>`
|
||||
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
error[E0080]: constructing invalid value of type WideRangeDiscriminants: at .<enum-tag>, encountered 0x0, but expected a valid enum tag
|
||||
--> $DIR/ub-enum.rs:121:1
|
||||
|
|
||||
LL | const BAD_WIDE_RANGE_ENUM: WideRangeDiscriminants = unsafe { mem::transmute(0_i64) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ it is undefined behavior to use this value
|
||||
|
|
||||
= note: the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
|
||||
HEX_DUMP
|
||||
}
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
||||
@@ -28,8 +28,8 @@ LL | type E = Ty<>;
|
||||
|
|
||||
help: consider introducing a named lifetime parameter
|
||||
|
|
||||
LL | type E<'a> = Ty<'a, >;
|
||||
| ++++ +++
|
||||
LL | type E<'a> = Ty<'a>;
|
||||
| ++++ ++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/wrong-number-of-args.rs:120:22
|
||||
@@ -55,12 +55,12 @@ LL | type F = Box<dyn GenericLifetime<>>;
|
||||
|
|
||||
help: consider making the bound lifetime-generic with a new `'a` lifetime
|
||||
|
|
||||
LL | type F = Box<dyn for<'a> GenericLifetime<'a, >>;
|
||||
| +++++++ +++
|
||||
LL | type F = Box<dyn for<'a> GenericLifetime<'a>>;
|
||||
| +++++++ ++
|
||||
help: consider introducing a named lifetime parameter
|
||||
|
|
||||
LL | type F<'a> = Box<dyn GenericLifetime<'a, >>;
|
||||
| ++++ +++
|
||||
LL | type F<'a> = Box<dyn GenericLifetime<'a>>;
|
||||
| ++++ ++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/wrong-number-of-args.rs:163:43
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/154600>.
|
||||
//
|
||||
// When suggesting lifetime parameters for empty angle brackets like `Foo<>`,
|
||||
// the suggestion should not include a trailing comma (e.g., `Foo<'a>` not `Foo<'a, >`).
|
||||
// When there are other generic arguments like `Foo<T>`, the trailing comma is needed
|
||||
// (e.g., `Foo<'a, T>`).
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
struct Foo<'a>(&'a ());
|
||||
|
||||
type A = Foo<>;
|
||||
//~^ ERROR missing lifetime specifier [E0106]
|
||||
|
||||
struct Bar<'a, T>(&'a T);
|
||||
|
||||
type B = Bar<u8>;
|
||||
//~^ ERROR missing lifetime specifier [E0106]
|
||||
@@ -0,0 +1,25 @@
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/E0106-trailing-comma-in-lifetime-suggestion.rs:12:13
|
||||
|
|
||||
LL | type A = Foo<>;
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
help: consider introducing a named lifetime parameter
|
||||
|
|
||||
LL | type A<'a> = Foo<'a>;
|
||||
| ++++ ++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/E0106-trailing-comma-in-lifetime-suggestion.rs:17:13
|
||||
|
|
||||
LL | type B = Bar<u8>;
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
help: consider introducing a named lifetime parameter
|
||||
|
|
||||
LL | type B<'a> = Bar<'a, u8>;
|
||||
| ++++ +++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0106`.
|
||||
Reference in New Issue
Block a user