Auto merge of #3038 - rust-lang:rustup-2023-08-26, r=RalfJung
Automatic sync from rustc
This commit is contained in:
commit
adb16d5ebd
611 changed files with 8936 additions and 3431 deletions
50
Cargo.lock
50
Cargo.lock
|
|
@ -2,15 +2,6 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
|
||||
dependencies = [
|
||||
"gimli 0.27.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
|
|
@ -18,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"gimli 0.28.0",
|
||||
"gimli",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
|
@ -180,7 +171,7 @@ version = "0.1.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9792d37ca5173d7e7f4fe453739a0671d0557915a030a383d6b866476bbc3e71"
|
||||
dependencies = [
|
||||
"object 0.32.0",
|
||||
"object",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -246,16 +237,16 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.68"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
|
||||
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
||||
dependencies = [
|
||||
"addr2line 0.20.0",
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object 0.31.1",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
|
|
@ -1435,12 +1426,6 @@ dependencies = [
|
|||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.27.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.0"
|
||||
|
|
@ -2430,15 +2415,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.0"
|
||||
|
|
@ -3357,7 +3333,7 @@ dependencies = [
|
|||
"cstr",
|
||||
"libc",
|
||||
"measureme",
|
||||
"object 0.32.0",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
|
|
@ -3393,7 +3369,7 @@ dependencies = [
|
|||
"itertools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"object 0.32.0",
|
||||
"object",
|
||||
"pathdiff",
|
||||
"regex",
|
||||
"rustc_arena",
|
||||
|
|
@ -4327,7 +4303,7 @@ name = "rustc_target"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"object 0.32.0",
|
||||
"object",
|
||||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_feature",
|
||||
|
|
@ -4856,7 +4832,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
|||
name = "std"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"addr2line 0.21.0",
|
||||
"addr2line",
|
||||
"alloc",
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
|
|
@ -4867,7 +4843,7 @@ dependencies = [
|
|||
"hermit-abi 0.3.2",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object 0.32.0",
|
||||
"object",
|
||||
"panic_abort",
|
||||
"panic_unwind",
|
||||
"profiler_builtins",
|
||||
|
|
@ -5171,9 +5147,9 @@ version = "0.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4db52ee8fec06e119b692ef3dd2c4cf621a99204c1b8c47407870ed050305b9b"
|
||||
dependencies = [
|
||||
"gimli 0.28.0",
|
||||
"gimli",
|
||||
"hashbrown 0.14.0",
|
||||
"object 0.32.0",
|
||||
"object",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
|
|||
14
RELEASES.md
14
RELEASES.md
|
|
@ -65,16 +65,16 @@ Rustdoc
|
|||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`impl<T: Send> Sync for mpsc::Sender<T>`](https://doc.rust-lang.org/nightly/std/sync/mpsc/struct.Sender.html#impl-Sync-for-Sender%3CT%3E)
|
||||
- [`impl TryFrom<&OsStr> for &str`](https://doc.rust-lang.org/nightly/std/primitive.str.html#impl-TryFrom%3C%26'a+OsStr%3E-for-%26'a+str)
|
||||
- [`String::leak`](https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.leak)
|
||||
- [`impl<T: Send> Sync for mpsc::Sender<T>`](https://doc.rust-lang.org/stable/std/sync/mpsc/struct.Sender.html#impl-Sync-for-Sender%3CT%3E)
|
||||
- [`impl TryFrom<&OsStr> for &str`](https://doc.rust-lang.org/stable/std/primitive.str.html#impl-TryFrom%3C%26'a+OsStr%3E-for-%26'a+str)
|
||||
- [`String::leak`](https://doc.rust-lang.org/stable/alloc/string/struct.String.html#method.leak)
|
||||
|
||||
These APIs are now stable in const contexts:
|
||||
|
||||
- [`CStr::from_bytes_with_nul`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
|
||||
- [`CStr::to_bytes`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
|
||||
- [`CStr::to_bytes_with_nul`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
|
||||
- [`CStr::to_str`](https://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
|
||||
- [`CStr::from_bytes_with_nul`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#method.from_bytes_with_nul)
|
||||
- [`CStr::to_bytes`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#method.to_bytes)
|
||||
- [`CStr::to_bytes_with_nul`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#method.to_bytes_with_nul)
|
||||
- [`CStr::to_str`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#method.to_str)
|
||||
|
||||
<a id="1.72.0-Cargo"></a>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#![cfg_attr(feature = "nightly", feature(step_trait, rustc_attrs, min_specialization))]
|
||||
#![cfg_attr(all(not(bootstrap), feature = "nightly"), allow(internal_features))]
|
||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||
|
||||
use std::fmt;
|
||||
#[cfg(feature = "nightly")]
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![allow(internal_features)]
|
||||
#![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine.
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
|
|
|||
|
|
@ -2092,6 +2092,10 @@ pub enum TyKind {
|
|||
Never,
|
||||
/// A tuple (`(A, B, C, D,...)`).
|
||||
Tup(ThinVec<P<Ty>>),
|
||||
/// An anonymous struct type i.e. `struct { foo: Type }`
|
||||
AnonStruct(ThinVec<FieldDef>),
|
||||
/// An anonymous union type i.e. `union { bar: Type }`
|
||||
AnonUnion(ThinVec<FieldDef>),
|
||||
/// A path (`module::module::...::Type`), optionally
|
||||
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -510,6 +510,9 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
|
|||
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
|
||||
}
|
||||
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
|
||||
TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => {
|
||||
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
|
||||
}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
visit_lazy_tts(tokens, vis);
|
||||
|
|
|
|||
|
|
@ -486,6 +486,8 @@ impl Token {
|
|||
Lt | BinOp(Shl) | // associated path
|
||||
ModSep => true, // global path
|
||||
Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)),
|
||||
// For anonymous structs or unions, which only appear in specific positions
|
||||
// (type of struct fields or union fields), we don't consider them as regular types
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -438,6 +438,9 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
|
|||
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
|
||||
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
|
||||
TyKind::Never | TyKind::CVarArgs => {}
|
||||
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
|
||||
walk_list!(visitor, visit_field_def, fields)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1293,6 +1293,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
TyKind::Err => {
|
||||
hir::TyKind::Err(self.tcx.sess.delay_span_bug(t.span, "TyKind::Err lowered"))
|
||||
}
|
||||
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
TyKind::AnonStruct(ref _fields) => hir::TyKind::Err(
|
||||
self.tcx.sess.span_err(t.span, "anonymous structs are unimplemented"),
|
||||
),
|
||||
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
TyKind::AnonUnion(ref _fields) => hir::TyKind::Err(
|
||||
self.tcx.sess.span_err(t.span, "anonymous unions are unimplemented"),
|
||||
),
|
||||
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
|
||||
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
|
||||
TyKind::Ref(region, mt) => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
ast_passes_anon_struct_or_union_not_allowed =
|
||||
anonymous {$struct_or_union}s are not allowed outside of unnamed struct or union fields
|
||||
.label = anonymous {$struct_or_union} declared here
|
||||
|
||||
ast_passes_assoc_const_without_body =
|
||||
associated constant in `impl` without body
|
||||
.suggestion = provide a definition for the constant
|
||||
|
|
@ -162,6 +166,14 @@ ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
|
|||
ast_passes_invalid_label =
|
||||
invalid label name `{$name}`
|
||||
|
||||
ast_passes_invalid_unnamed_field =
|
||||
unnamed fields are not allowed outside of structs or unions
|
||||
.label = unnamed field declared here
|
||||
|
||||
ast_passes_invalid_unnamed_field_ty =
|
||||
unnamed fields can only have struct or union types
|
||||
.label = not a struct or union
|
||||
|
||||
ast_passes_item_underscore = `{$kind}` items in this context need a name
|
||||
.label = `_` is not a valid name for this `{$kind}` item
|
||||
|
||||
|
|
|
|||
|
|
@ -223,10 +223,27 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
|
||||
walk_list!(self, visit_field_def, fields)
|
||||
}
|
||||
_ => visit::walk_ty(self, t),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
|
||||
if let Some(ident) = field.ident &&
|
||||
ident.name == kw::Underscore {
|
||||
self.check_unnamed_field_ty(&field.ty, ident.span);
|
||||
self.visit_vis(&field.vis);
|
||||
self.visit_ident(ident);
|
||||
self.visit_ty_common(&field.ty);
|
||||
self.walk_ty(&field.ty);
|
||||
walk_list!(self, visit_attribute, &field.attrs);
|
||||
} else {
|
||||
self.visit_field_def(field);
|
||||
}
|
||||
}
|
||||
|
||||
fn err_handler(&self) -> &rustc_errors::Handler {
|
||||
&self.session.diagnostic()
|
||||
}
|
||||
|
|
@ -264,6 +281,42 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_unnamed_field_ty(&self, ty: &Ty, span: Span) {
|
||||
if matches!(
|
||||
&ty.kind,
|
||||
// We already checked for `kw::Underscore` before calling this function,
|
||||
// so skip the check
|
||||
TyKind::AnonStruct(..) | TyKind::AnonUnion(..)
|
||||
// If the anonymous field contains a Path as type, we can't determine
|
||||
// if the path is a valid struct or union, so skip the check
|
||||
| TyKind::Path(..)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
self.err_handler().emit_err(errors::InvalidUnnamedFieldTy { span, ty_span: ty.span });
|
||||
}
|
||||
|
||||
fn deny_anon_struct_or_union(&self, ty: &Ty) {
|
||||
let struct_or_union = match &ty.kind {
|
||||
TyKind::AnonStruct(..) => "struct",
|
||||
TyKind::AnonUnion(..) => "union",
|
||||
_ => return,
|
||||
};
|
||||
self.err_handler()
|
||||
.emit_err(errors::AnonStructOrUnionNotAllowed { struct_or_union, span: ty.span });
|
||||
}
|
||||
|
||||
fn deny_unnamed_field(&self, field: &FieldDef) {
|
||||
if let Some(ident) = field.ident &&
|
||||
ident.name == kw::Underscore {
|
||||
self.err_handler()
|
||||
.emit_err(errors::InvalidUnnamedField {
|
||||
span: field.span,
|
||||
ident_span: ident.span
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_const(&self, constness: Const) {
|
||||
if let Const::Yes(span) = constness {
|
||||
self.session.emit_err(errors::TraitFnConst { span });
|
||||
|
|
@ -789,6 +842,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
|
||||
fn visit_ty(&mut self, ty: &'a Ty) {
|
||||
self.visit_ty_common(ty);
|
||||
self.deny_anon_struct_or_union(ty);
|
||||
self.walk_ty(ty)
|
||||
}
|
||||
|
||||
|
|
@ -803,6 +857,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
|
||||
fn visit_field_def(&mut self, field: &'a FieldDef) {
|
||||
self.deny_unnamed_field(field);
|
||||
visit::walk_field_def(self, field)
|
||||
}
|
||||
|
||||
|
|
@ -995,10 +1050,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_mod_file_item_asciionly(item.ident);
|
||||
}
|
||||
}
|
||||
ItemKind::Union(vdata, ..) => {
|
||||
ItemKind::Struct(vdata, generics) => match vdata {
|
||||
// Duplicating the `Visitor` logic allows catching all cases
|
||||
// of `Anonymous(Struct, Union)` outside of a field struct or union.
|
||||
//
|
||||
// Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
|
||||
// encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
|
||||
// it uses `visit_ty_common`, which doesn't contain that specific check.
|
||||
VariantData::Struct(fields, ..) => {
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(item.ident);
|
||||
self.visit_generics(generics);
|
||||
walk_list!(self, visit_struct_field_def, fields);
|
||||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
ItemKind::Union(vdata, generics) => {
|
||||
if vdata.fields().is_empty() {
|
||||
self.err_handler().emit_err(errors::FieldlessUnion { span: item.span });
|
||||
}
|
||||
match vdata {
|
||||
VariantData::Struct(fields, ..) => {
|
||||
self.visit_vis(&item.vis);
|
||||
self.visit_ident(item.ident);
|
||||
self.visit_generics(generics);
|
||||
walk_list!(self, visit_struct_field_def, fields);
|
||||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ItemKind::Const(box ConstItem { defaultness, expr: None, .. }) => {
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
|
|
|
|||
|
|
@ -727,3 +727,30 @@ pub struct ConstraintOnNegativeBound {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_invalid_unnamed_field_ty)]
|
||||
pub struct InvalidUnnamedFieldTy {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub ty_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_invalid_unnamed_field)]
|
||||
pub struct InvalidUnnamedField {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub ident_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_anon_struct_or_union_not_allowed)]
|
||||
pub struct AnonStructOrUnionNotAllowed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub struct_or_union: &'static str,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -570,6 +570,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
||||
gate_all!(explicit_tail_calls, "`become` expression is experimental");
|
||||
gate_all!(generic_const_items, "generic const items are experimental");
|
||||
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
|
||||
|
||||
if !visitor.features.negative_bounds {
|
||||
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
|
||||
|
|
|
|||
|
|
@ -1064,6 +1064,14 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.pclose();
|
||||
}
|
||||
ast::TyKind::AnonStruct(fields) => {
|
||||
self.head("struct");
|
||||
self.print_record_struct_body(&fields, ty.span);
|
||||
}
|
||||
ast::TyKind::AnonUnion(fields) => {
|
||||
self.head("union");
|
||||
self.print_record_struct_body(&fields, ty.span);
|
||||
}
|
||||
ast::TyKind::Paren(typ) => {
|
||||
self.popen();
|
||||
self.print_type(typ);
|
||||
|
|
|
|||
|
|
@ -443,7 +443,11 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
|
||||
pub(crate) fn print_record_struct_body(
|
||||
&mut self,
|
||||
fields: &[ast::FieldDef],
|
||||
span: rustc_span::Span,
|
||||
) {
|
||||
self.nbsp();
|
||||
self.bopen();
|
||||
|
||||
|
|
|
|||
|
|
@ -937,6 +937,7 @@ pub fn find_deprecation(
|
|||
#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone)]
|
||||
pub enum ReprAttr {
|
||||
ReprInt(IntType),
|
||||
ReprRust,
|
||||
ReprC,
|
||||
ReprPacked(u32),
|
||||
ReprSimd,
|
||||
|
|
@ -985,6 +986,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
|
|||
let mut recognised = false;
|
||||
if item.is_word() {
|
||||
let hint = match item.name_or_empty() {
|
||||
sym::Rust => Some(ReprRust),
|
||||
sym::C => Some(ReprC),
|
||||
sym::packed => Some(ReprPacked(1)),
|
||||
sym::simd => Some(ReprSimd),
|
||||
|
|
|
|||
|
|
@ -225,17 +225,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
if suggest {
|
||||
borrow_spans.var_subdiag(
|
||||
None,
|
||||
&mut err,
|
||||
Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
|
||||
|_kind, var_span| {
|
||||
let place = self.describe_any_place(access_place.as_ref());
|
||||
crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
|
||||
place,
|
||||
var_span,
|
||||
}
|
||||
},
|
||||
);
|
||||
None,
|
||||
&mut err,
|
||||
Some(mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
|
||||
|_kind, var_span| {
|
||||
let place = self.describe_any_place(access_place.as_ref());
|
||||
crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
|
||||
place,
|
||||
var_span,
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
borrow_span
|
||||
}
|
||||
|
|
@ -262,11 +262,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
} => {
|
||||
err.span_label(span, format!("cannot {act}"));
|
||||
|
||||
if let Some(span) = get_mut_span_in_struct_field(
|
||||
self.infcx.tcx,
|
||||
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty,
|
||||
*field,
|
||||
) {
|
||||
let place = Place::ty_from(local, proj_base, self.body, self.infcx.tcx);
|
||||
if let Some(span) = get_mut_span_in_struct_field(self.infcx.tcx, place.ty, *field) {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
"consider changing this to be mutable",
|
||||
|
|
@ -781,83 +778,88 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
|
||||
// Attempt to search similar mutable associated items for suggestion.
|
||||
// In the future, attempt in all path but initially for RHS of for_loop
|
||||
fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diagnostic) {
|
||||
fn suggest_similar_mut_method_for_for_loop(&self, err: &mut Diagnostic, span: Span) {
|
||||
use hir::{
|
||||
Expr,
|
||||
ExprKind::{Block, Call, DropTemps, Match, MethodCall},
|
||||
BorrowKind, Expr,
|
||||
ExprKind::{AddrOf, Block, Call, MethodCall},
|
||||
};
|
||||
|
||||
let hir_map = self.infcx.tcx.hir();
|
||||
if let Some(body_id) = hir_map.maybe_body_owned_by(self.mir_def_id()) {
|
||||
if let Block(
|
||||
hir::Block {
|
||||
expr:
|
||||
Some(Expr {
|
||||
kind:
|
||||
DropTemps(Expr {
|
||||
kind:
|
||||
Match(
|
||||
Expr {
|
||||
kind:
|
||||
Call(
|
||||
_,
|
||||
[
|
||||
Expr {
|
||||
kind:
|
||||
MethodCall(path_segment, _, _, span),
|
||||
hir_id,
|
||||
..
|
||||
},
|
||||
..,
|
||||
],
|
||||
),
|
||||
..
|
||||
},
|
||||
..,
|
||||
),
|
||||
..
|
||||
}),
|
||||
..
|
||||
}),
|
||||
..
|
||||
},
|
||||
_,
|
||||
) = hir_map.body(body_id).value.kind
|
||||
{
|
||||
let opt_suggestions = self
|
||||
.infcx
|
||||
.tcx
|
||||
.typeck(path_segment.hir_id.owner.def_id)
|
||||
.type_dependent_def_id(*hir_id)
|
||||
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
|
||||
.map(|def_id| self.infcx.tcx.associated_items(def_id))
|
||||
.map(|assoc_items| {
|
||||
assoc_items
|
||||
.in_definition_order()
|
||||
.map(|assoc_item_def| assoc_item_def.ident(self.infcx.tcx))
|
||||
.filter(|&ident| {
|
||||
let original_method_ident = path_segment.ident;
|
||||
original_method_ident != ident
|
||||
&& ident
|
||||
.as_str()
|
||||
.starts_with(&original_method_ident.name.to_string())
|
||||
})
|
||||
.map(|ident| format!("{ident}()"))
|
||||
.peekable()
|
||||
});
|
||||
struct Finder<'tcx> {
|
||||
span: Span,
|
||||
expr: Option<&'tcx Expr<'tcx>>,
|
||||
}
|
||||
|
||||
if let Some(mut suggestions) = opt_suggestions
|
||||
&& suggestions.peek().is_some()
|
||||
{
|
||||
err.span_suggestions(
|
||||
*span,
|
||||
"use mutable method",
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
impl<'tcx> Visitor<'tcx> for Finder<'tcx> {
|
||||
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
|
||||
if e.span == self.span && self.expr.is_none() {
|
||||
self.expr = Some(e);
|
||||
}
|
||||
hir::intravisit::walk_expr(self, e);
|
||||
}
|
||||
}
|
||||
if let Some(body_id) = hir_map.maybe_body_owned_by(self.mir_def_id())
|
||||
&& let Block(block, _) = hir_map.body(body_id).value.kind
|
||||
{
|
||||
// `span` corresponds to the expression being iterated, find the `for`-loop desugared
|
||||
// expression with that span in order to identify potential fixes when encountering a
|
||||
// read-only iterator that should be mutable.
|
||||
let mut v = Finder {
|
||||
span,
|
||||
expr: None,
|
||||
};
|
||||
v.visit_block(block);
|
||||
if let Some(expr) = v.expr && let Call(_, [expr]) = expr.kind {
|
||||
match expr.kind {
|
||||
MethodCall(path_segment, _, _, span) => {
|
||||
// We have `for _ in iter.read_only_iter()`, try to
|
||||
// suggest `for _ in iter.mutable_iter()` instead.
|
||||
let opt_suggestions = self
|
||||
.infcx
|
||||
.tcx
|
||||
.typeck(path_segment.hir_id.owner.def_id)
|
||||
.type_dependent_def_id(expr.hir_id)
|
||||
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
|
||||
.map(|def_id| self.infcx.tcx.associated_items(def_id))
|
||||
.map(|assoc_items| {
|
||||
assoc_items
|
||||
.in_definition_order()
|
||||
.map(|assoc_item_def| assoc_item_def.ident(self.infcx.tcx))
|
||||
.filter(|&ident| {
|
||||
let original_method_ident = path_segment.ident;
|
||||
original_method_ident != ident
|
||||
&& ident.as_str().starts_with(
|
||||
&original_method_ident.name.to_string(),
|
||||
)
|
||||
})
|
||||
.map(|ident| format!("{ident}()"))
|
||||
.peekable()
|
||||
});
|
||||
|
||||
if let Some(mut suggestions) = opt_suggestions
|
||||
&& suggestions.peek().is_some()
|
||||
{
|
||||
err.span_suggestions(
|
||||
span,
|
||||
"use mutable method",
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
AddrOf(BorrowKind::Ref, Mutability::Not, expr) => {
|
||||
// We have `for _ in &i`, suggest `for _ in &mut i`.
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_lo(),
|
||||
"use a mutable iterator instead",
|
||||
"mut ".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
|
||||
|
|
@ -1003,9 +1005,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
|
||||
// on for loops, RHS points to the iterator part
|
||||
Some(DesugaringKind::ForLoop) => {
|
||||
self.suggest_similar_mut_method_for_for_loop(err);
|
||||
let span = opt_assignment_rhs_span.unwrap();
|
||||
self.suggest_similar_mut_method_for_for_loop(err, span);
|
||||
err.span_label(
|
||||
opt_assignment_rhs_span.unwrap(),
|
||||
span,
|
||||
format!("this iterator yields `{pointer_sigil}` {pointer_desc}s",),
|
||||
);
|
||||
None
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
TerminatorKind::Goto { target: _ }
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
|
||||
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
#![feature(trusted_step)]
|
||||
#![feature(try_blocks)]
|
||||
#![recursion_limit = "256"]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![allow(internal_features)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_middle;
|
||||
|
|
@ -770,7 +770,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
|
|||
}
|
||||
|
||||
TerminatorKind::Goto { target: _ }
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::Return
|
||||
|
|
@ -817,7 +817,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
|
|||
}
|
||||
}
|
||||
|
||||
TerminatorKind::UnwindTerminate
|
||||
TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::Call { .. }
|
||||
| TerminatorKind::Drop { .. }
|
||||
|
|
|
|||
|
|
@ -1334,7 +1334,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
match &term.kind {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::Unreachable
|
||||
|
|
@ -1613,7 +1613,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
span_mirbug!(self, block_data, "resume on non-cleanup block!")
|
||||
}
|
||||
}
|
||||
TerminatorKind::UnwindTerminate => {
|
||||
TerminatorKind::UnwindTerminate(_) => {
|
||||
if !is_cleanup {
|
||||
span_mirbug!(self, block_data, "abort on non-cleanup block!")
|
||||
}
|
||||
|
|
@ -1697,7 +1697,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
span_mirbug!(self, ctxt, "unwind on cleanup block")
|
||||
}
|
||||
}
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate => (),
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -474,8 +474,8 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||
*destination,
|
||||
);
|
||||
}
|
||||
TerminatorKind::UnwindTerminate => {
|
||||
codegen_panic_cannot_unwind(fx, source_info);
|
||||
TerminatorKind::UnwindTerminate(reason) => {
|
||||
codegen_unwind_terminate(fx, source_info, *reason);
|
||||
}
|
||||
TerminatorKind::UnwindResume => {
|
||||
// FIXME implement unwinding
|
||||
|
|
@ -971,13 +971,14 @@ pub(crate) fn codegen_panic_nounwind<'tcx>(
|
|||
codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, source_info.span);
|
||||
}
|
||||
|
||||
pub(crate) fn codegen_panic_cannot_unwind<'tcx>(
|
||||
pub(crate) fn codegen_unwind_terminate<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
source_info: mir::SourceInfo,
|
||||
reason: UnwindTerminateReason,
|
||||
) {
|
||||
let args = [];
|
||||
|
||||
codegen_panic_inner(fx, rustc_hir::LangItem::PanicCannotUnwind, &args, source_info.span);
|
||||
codegen_panic_inner(fx, reason.lang_item(), &args, source_info.span);
|
||||
}
|
||||
|
||||
fn codegen_panic_inner<'tcx>(
|
||||
|
|
|
|||
|
|
@ -551,7 +551,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
|||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::SwitchInt { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Drop { .. }
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
_llfn: RValue<'gcc>,
|
||||
_mir: &mir::Body<'tcx>,
|
||||
) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> {
|
||||
) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>> {
|
||||
// TODO(antoyo)
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ pub fn compute_mir_scopes<'ll, 'tcx>(
|
|||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
mir: &Body<'tcx>,
|
||||
debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
|
||||
debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
|
||||
) {
|
||||
// Find all scopes with variables defined in them.
|
||||
let variables = if cx.sess().opts.debuginfo == DebugInfo::Full {
|
||||
|
|
@ -51,7 +51,7 @@ fn make_mir_scope<'ll, 'tcx>(
|
|||
instance: Instance<'tcx>,
|
||||
mir: &Body<'tcx>,
|
||||
variables: &Option<BitSet<SourceScope>>,
|
||||
debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
|
||||
debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
|
||||
instantiated: &mut BitSet<SourceScope>,
|
||||
scope: SourceScope,
|
||||
) {
|
||||
|
|
@ -84,7 +84,6 @@ fn make_mir_scope<'ll, 'tcx>(
|
|||
}
|
||||
|
||||
let loc = cx.lookup_debug_loc(scope_data.span.lo());
|
||||
let file_metadata = file_metadata(cx, &loc.file);
|
||||
|
||||
let dbg_scope = match scope_data.inlined {
|
||||
Some((callee, _)) => {
|
||||
|
|
@ -95,18 +94,26 @@ fn make_mir_scope<'ll, 'tcx>(
|
|||
ty::ParamEnv::reveal_all(),
|
||||
ty::EarlyBinder::bind(callee),
|
||||
);
|
||||
let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
|
||||
cx.dbg_scope_fn(callee, callee_fn_abi, None)
|
||||
debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| {
|
||||
let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
|
||||
cx.dbg_scope_fn(callee, callee_fn_abi, None)
|
||||
})
|
||||
}
|
||||
None => {
|
||||
let file_metadata = file_metadata(cx, &loc.file);
|
||||
debug_context
|
||||
.lexical_blocks
|
||||
.entry((parent_scope.dbg_scope, loc.line, loc.col, file_metadata))
|
||||
.or_insert_with(|| unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateLexicalBlock(
|
||||
DIB(cx),
|
||||
parent_scope.dbg_scope,
|
||||
file_metadata,
|
||||
loc.line,
|
||||
loc.col,
|
||||
)
|
||||
})
|
||||
}
|
||||
None => unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateLexicalBlock(
|
||||
DIB(cx),
|
||||
parent_scope.dbg_scope,
|
||||
file_metadata,
|
||||
loc.line,
|
||||
loc.col,
|
||||
)
|
||||
},
|
||||
};
|
||||
|
||||
let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
|
|||
use self::metadata::{file_metadata, type_di_node};
|
||||
use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER};
|
||||
use self::namespace::mangled_name_of_instance;
|
||||
use self::utils::{create_DIArray, is_node_local_to_unit, DIB};
|
||||
use self::utils::{create_DIArray, debug_context, is_node_local_to_unit, DIB};
|
||||
|
||||
use crate::abi::FnAbi;
|
||||
use crate::builder::Builder;
|
||||
|
|
@ -67,6 +67,8 @@ pub struct CodegenUnitDebugContext<'ll, 'tcx> {
|
|||
type_map: metadata::TypeMap<'ll, 'tcx>,
|
||||
namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
|
||||
recursion_marker_type: OnceCell<&'ll DIType>,
|
||||
/// Maps a variable (name, scope, kind (argument or local), span) to its debug information.
|
||||
variables: RefCell<FxHashMap<(Symbol, &'ll DIScope, VariableKind, Span), &'ll DIVariable>>,
|
||||
}
|
||||
|
||||
impl Drop for CodegenUnitDebugContext<'_, '_> {
|
||||
|
|
@ -91,6 +93,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
|
|||
type_map: Default::default(),
|
||||
namespace_map: RefCell::new(Default::default()),
|
||||
recursion_marker_type: OnceCell::new(),
|
||||
variables: RefCell::new(Default::default()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -292,7 +295,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
llfn: &'ll Value,
|
||||
mir: &mir::Body<'tcx>,
|
||||
) -> Option<FunctionDebugContext<&'ll DIScope, &'ll DILocation>> {
|
||||
) -> Option<FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>> {
|
||||
if self.sess().opts.debuginfo == DebugInfo::None {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -304,8 +307,11 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
file_start_pos: BytePos(0),
|
||||
file_end_pos: BytePos(0),
|
||||
};
|
||||
let mut fn_debug_context =
|
||||
FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes) };
|
||||
let mut fn_debug_context = FunctionDebugContext {
|
||||
scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes),
|
||||
inlined_function_scopes: Default::default(),
|
||||
lexical_blocks: Default::default(),
|
||||
};
|
||||
|
||||
// Fill in all the scopes, with the information from the MIR body.
|
||||
compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
|
||||
|
|
@ -606,33 +612,39 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
variable_kind: VariableKind,
|
||||
span: Span,
|
||||
) -> &'ll DIVariable {
|
||||
let loc = self.lookup_debug_loc(span.lo());
|
||||
let file_metadata = file_metadata(self, &loc.file);
|
||||
debug_context(self)
|
||||
.variables
|
||||
.borrow_mut()
|
||||
.entry((variable_name, scope_metadata, variable_kind, span))
|
||||
.or_insert_with(|| {
|
||||
let loc = self.lookup_debug_loc(span.lo());
|
||||
let file_metadata = file_metadata(self, &loc.file);
|
||||
|
||||
let type_metadata = type_di_node(self, variable_type);
|
||||
let type_metadata = type_di_node(self, variable_type);
|
||||
|
||||
let (argument_index, dwarf_tag) = match variable_kind {
|
||||
ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
|
||||
LocalVariable => (0, DW_TAG_auto_variable),
|
||||
};
|
||||
let align = self.align_of(variable_type);
|
||||
let (argument_index, dwarf_tag) = match variable_kind {
|
||||
ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
|
||||
LocalVariable => (0, DW_TAG_auto_variable),
|
||||
};
|
||||
let align = self.align_of(variable_type);
|
||||
|
||||
let name = variable_name.as_str();
|
||||
unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateVariable(
|
||||
DIB(self),
|
||||
dwarf_tag,
|
||||
scope_metadata,
|
||||
name.as_ptr().cast(),
|
||||
name.len(),
|
||||
file_metadata,
|
||||
loc.line,
|
||||
type_metadata,
|
||||
true,
|
||||
DIFlags::FlagZero,
|
||||
argument_index,
|
||||
align.bytes() as u32,
|
||||
)
|
||||
}
|
||||
let name = variable_name.as_str();
|
||||
unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateVariable(
|
||||
DIB(self),
|
||||
dwarf_tag,
|
||||
scope_metadata,
|
||||
name.as_ptr().cast(),
|
||||
name.len(),
|
||||
file_metadata,
|
||||
loc.line,
|
||||
type_metadata,
|
||||
true,
|
||||
DIFlags::FlagZero,
|
||||
argument_index,
|
||||
align.bytes() as u32,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
|
|||
match data.terminator().kind {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::Unreachable
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use crate::MemFlags;
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_middle::mir::{self, AssertKind, SwitchTargets};
|
||||
use rustc_middle::mir::{self, AssertKind, SwitchTargets, UnwindTerminateReason};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
|
||||
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||
use rustc_middle::ty::{self, Instance, Ty};
|
||||
|
|
@ -178,7 +178,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
|
||||
mir::UnwindAction::Continue => None,
|
||||
mir::UnwindAction::Unreachable => None,
|
||||
mir::UnwindAction::Terminate => {
|
||||
mir::UnwindAction::Terminate(reason) => {
|
||||
if fx.mir[self.bb].is_cleanup && base::wants_new_eh_instructions(fx.cx.tcx().sess) {
|
||||
// MSVC SEH will abort automatically if an exception tries to
|
||||
// propagate out from cleanup.
|
||||
|
|
@ -191,7 +191,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||
|
||||
None
|
||||
} else {
|
||||
Some(fx.terminate_block())
|
||||
Some(fx.terminate_block(reason))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -264,7 +264,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
|
|||
) -> MergingSucc {
|
||||
let unwind_target = match unwind {
|
||||
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
|
||||
mir::UnwindAction::Terminate => Some(fx.terminate_block()),
|
||||
mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason)),
|
||||
mir::UnwindAction::Continue => None,
|
||||
mir::UnwindAction::Unreachable => None,
|
||||
};
|
||||
|
|
@ -649,12 +649,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
helper: TerminatorCodegenHelper<'tcx>,
|
||||
bx: &mut Bx,
|
||||
terminator: &mir::Terminator<'tcx>,
|
||||
reason: UnwindTerminateReason,
|
||||
) {
|
||||
let span = terminator.source_info.span;
|
||||
self.set_debug_loc(bx, terminator.source_info);
|
||||
|
||||
// Obtain the panic entry point.
|
||||
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicCannotUnwind);
|
||||
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), reason.lang_item());
|
||||
|
||||
// Codegen the actual panic invoke/call.
|
||||
let merging_succ = helper.do_call(
|
||||
|
|
@ -1229,8 +1230,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
MergingSucc::False
|
||||
}
|
||||
|
||||
mir::TerminatorKind::UnwindTerminate => {
|
||||
self.codegen_terminate_terminator(helper, bx, terminator);
|
||||
mir::TerminatorKind::UnwindTerminate(reason) => {
|
||||
self.codegen_terminate_terminator(helper, bx, terminator, reason);
|
||||
MergingSucc::False
|
||||
}
|
||||
|
||||
|
|
@ -1579,79 +1580,81 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
})
|
||||
}
|
||||
|
||||
fn terminate_block(&mut self) -> Bx::BasicBlock {
|
||||
self.terminate_block.unwrap_or_else(|| {
|
||||
let funclet;
|
||||
let llbb;
|
||||
let mut bx;
|
||||
if base::wants_msvc_seh(self.cx.sess()) {
|
||||
// This is a basic block that we're aborting the program for,
|
||||
// notably in an `extern` function. These basic blocks are inserted
|
||||
// so that we assert that `extern` functions do indeed not panic,
|
||||
// and if they do we abort the process.
|
||||
//
|
||||
// On MSVC these are tricky though (where we're doing funclets). If
|
||||
// we were to do a cleanuppad (like below) the normal functions like
|
||||
// `longjmp` would trigger the abort logic, terminating the
|
||||
// program. Instead we insert the equivalent of `catch(...)` for C++
|
||||
// which magically doesn't trigger when `longjmp` files over this
|
||||
// frame.
|
||||
//
|
||||
// Lots more discussion can be found on #48251 but this codegen is
|
||||
// modeled after clang's for:
|
||||
//
|
||||
// try {
|
||||
// foo();
|
||||
// } catch (...) {
|
||||
// bar();
|
||||
// }
|
||||
//
|
||||
// which creates an IR snippet like
|
||||
//
|
||||
// cs_terminate:
|
||||
// %cs = catchswitch within none [%cp_terminate] unwind to caller
|
||||
// cp_terminate:
|
||||
// %cp = catchpad within %cs [null, i32 64, null]
|
||||
// ...
|
||||
fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock {
|
||||
if let Some((cached_bb, cached_reason)) = self.terminate_block && reason == cached_reason {
|
||||
return cached_bb;
|
||||
}
|
||||
|
||||
llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate");
|
||||
let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");
|
||||
let funclet;
|
||||
let llbb;
|
||||
let mut bx;
|
||||
if base::wants_msvc_seh(self.cx.sess()) {
|
||||
// This is a basic block that we're aborting the program for,
|
||||
// notably in an `extern` function. These basic blocks are inserted
|
||||
// so that we assert that `extern` functions do indeed not panic,
|
||||
// and if they do we abort the process.
|
||||
//
|
||||
// On MSVC these are tricky though (where we're doing funclets). If
|
||||
// we were to do a cleanuppad (like below) the normal functions like
|
||||
// `longjmp` would trigger the abort logic, terminating the
|
||||
// program. Instead we insert the equivalent of `catch(...)` for C++
|
||||
// which magically doesn't trigger when `longjmp` files over this
|
||||
// frame.
|
||||
//
|
||||
// Lots more discussion can be found on #48251 but this codegen is
|
||||
// modeled after clang's for:
|
||||
//
|
||||
// try {
|
||||
// foo();
|
||||
// } catch (...) {
|
||||
// bar();
|
||||
// }
|
||||
//
|
||||
// which creates an IR snippet like
|
||||
//
|
||||
// cs_terminate:
|
||||
// %cs = catchswitch within none [%cp_terminate] unwind to caller
|
||||
// cp_terminate:
|
||||
// %cp = catchpad within %cs [null, i32 64, null]
|
||||
// ...
|
||||
|
||||
let mut cs_bx = Bx::build(self.cx, llbb);
|
||||
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
|
||||
llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate");
|
||||
let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");
|
||||
|
||||
// The "null" here is actually a RTTI type descriptor for the
|
||||
// C++ personality function, but `catch (...)` has no type so
|
||||
// it's null. The 64 here is actually a bitfield which
|
||||
// represents that this is a catch-all block.
|
||||
bx = Bx::build(self.cx, cp_llbb);
|
||||
let null =
|
||||
bx.const_null(bx.type_ptr_ext(bx.cx().data_layout().instruction_address_space));
|
||||
let sixty_four = bx.const_i32(64);
|
||||
funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null]));
|
||||
} else {
|
||||
llbb = Bx::append_block(self.cx, self.llfn, "terminate");
|
||||
bx = Bx::build(self.cx, llbb);
|
||||
let mut cs_bx = Bx::build(self.cx, llbb);
|
||||
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
|
||||
|
||||
let llpersonality = self.cx.eh_personality();
|
||||
bx.filter_landing_pad(llpersonality);
|
||||
// The "null" here is actually a RTTI type descriptor for the
|
||||
// C++ personality function, but `catch (...)` has no type so
|
||||
// it's null. The 64 here is actually a bitfield which
|
||||
// represents that this is a catch-all block.
|
||||
bx = Bx::build(self.cx, cp_llbb);
|
||||
let null =
|
||||
bx.const_null(bx.type_ptr_ext(bx.cx().data_layout().instruction_address_space));
|
||||
let sixty_four = bx.const_i32(64);
|
||||
funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null]));
|
||||
} else {
|
||||
llbb = Bx::append_block(self.cx, self.llfn, "terminate");
|
||||
bx = Bx::build(self.cx, llbb);
|
||||
|
||||
funclet = None;
|
||||
}
|
||||
let llpersonality = self.cx.eh_personality();
|
||||
bx.filter_landing_pad(llpersonality);
|
||||
|
||||
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
|
||||
funclet = None;
|
||||
}
|
||||
|
||||
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicCannotUnwind);
|
||||
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
||||
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
|
||||
|
||||
let llret = bx.call(fn_ty, None, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
|
||||
bx.do_not_inline(llret);
|
||||
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, reason.lang_item());
|
||||
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
|
||||
|
||||
bx.unreachable();
|
||||
let llret = bx.call(fn_ty, None, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
|
||||
bx.do_not_inline(llret);
|
||||
|
||||
self.terminate_block = Some(llbb);
|
||||
llbb
|
||||
})
|
||||
bx.unreachable();
|
||||
|
||||
self.terminate_block = Some((llbb, reason));
|
||||
llbb
|
||||
}
|
||||
|
||||
/// Get the backend `BasicBlock` for a MIR `BasicBlock`, either already
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
use crate::traits::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_session::config::DebugInfo;
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
|
|
@ -17,11 +19,19 @@ use super::{FunctionCx, LocalRef};
|
|||
|
||||
use std::ops::Range;
|
||||
|
||||
pub struct FunctionDebugContext<S, L> {
|
||||
pub struct FunctionDebugContext<'tcx, S, L> {
|
||||
/// Maps from source code to the corresponding debug info scope.
|
||||
pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
|
||||
|
||||
/// Maps from a given inlined function to its debug info declaration.
|
||||
pub inlined_function_scopes: FxHashMap<Instance<'tcx>, S>,
|
||||
|
||||
/// Maps from a lexical block (parent scope, line, column, file) to its debug info declaration.
|
||||
/// This is particularily useful if the parent scope is an inlined function.
|
||||
pub lexical_blocks: FxHashMap<(S, u32, u32, S), S>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum VariableKind {
|
||||
ArgumentVariable(usize /*index*/),
|
||||
LocalVariable,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use rustc_index::IndexVec;
|
|||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::mir::traversal;
|
||||
use rustc_middle::mir::UnwindTerminateReason;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
|
||||
use rustc_target::abi::call::{FnAbi, PassMode};
|
||||
|
|
@ -45,7 +46,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
|||
|
||||
mir: &'tcx mir::Body<'tcx>,
|
||||
|
||||
debug_context: Option<FunctionDebugContext<Bx::DIScope, Bx::DILocation>>,
|
||||
debug_context: Option<FunctionDebugContext<'tcx, Bx::DIScope, Bx::DILocation>>,
|
||||
|
||||
llfn: Bx::Function,
|
||||
|
||||
|
|
@ -83,8 +84,8 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
|||
/// Cached unreachable block
|
||||
unreachable_block: Option<Bx::BasicBlock>,
|
||||
|
||||
/// Cached terminate upon unwinding block
|
||||
terminate_block: Option<Bx::BasicBlock>,
|
||||
/// Cached terminate upon unwinding block and its reason
|
||||
terminate_block: Option<(Bx::BasicBlock, UnwindTerminateReason)>,
|
||||
|
||||
/// The location where each MIR arg/var/tmp/ret is stored. This is
|
||||
/// usually an `PlaceRef` representing an alloca, but not always:
|
||||
|
|
@ -174,7 +175,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
let mut start_bx = Bx::build(cx, start_llbb);
|
||||
|
||||
if mir.basic_blocks.iter().any(|bb| {
|
||||
bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate))
|
||||
bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate(_)))
|
||||
}) {
|
||||
start_bx.set_personality_fn(cx.eh_personality());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes {
|
|||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||
llfn: Self::Function,
|
||||
mir: &mir::Body<'tcx>,
|
||||
) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>>;
|
||||
) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>>;
|
||||
|
||||
// FIXME(eddyb) find a common convention for all of the debuginfo-related
|
||||
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
|
||||
|
|
|
|||
|
|
@ -756,6 +756,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
///
|
||||
/// If `target` is `UnwindAction::Unreachable`, that indicates the function does not allow
|
||||
/// unwinding, and doing so is UB.
|
||||
#[cold] // usually we have normal returns, not unwinding
|
||||
pub fn unwind_to_block(&mut self, target: mir::UnwindAction) -> InterpResult<'tcx> {
|
||||
self.frame_mut().loc = match target {
|
||||
mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
|
||||
|
|
@ -763,9 +764,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
mir::UnwindAction::Unreachable => {
|
||||
throw_ub_custom!(fluent::const_eval_unreachable_unwind);
|
||||
}
|
||||
mir::UnwindAction::Terminate => {
|
||||
mir::UnwindAction::Terminate(reason) => {
|
||||
self.frame_mut().loc = Right(self.frame_mut().body.span);
|
||||
M::unwind_terminate(self)?;
|
||||
M::unwind_terminate(self, reason)?;
|
||||
// This might have pushed a new stack frame, or it terminated execution.
|
||||
// Either way, `loc` will not be updated.
|
||||
return Ok(());
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use crate::const_eval::CheckAlignment;
|
|||
|
||||
use super::{
|
||||
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, InterpCx,
|
||||
InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar,
|
||||
InterpResult, MPlaceTy, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar,
|
||||
};
|
||||
|
||||
/// Data returned by Machine::stack_pop,
|
||||
|
|
@ -222,7 +222,10 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
|||
fn panic_nounwind(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: &str) -> InterpResult<'tcx>;
|
||||
|
||||
/// Called when unwinding reached a state where execution should be terminated.
|
||||
fn unwind_terminate(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>;
|
||||
fn unwind_terminate(
|
||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
reason: mir::UnwindTerminateReason,
|
||||
) -> InterpResult<'tcx>;
|
||||
|
||||
/// Called for all binary operations where the LHS has pointer type.
|
||||
///
|
||||
|
|
@ -462,6 +465,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
|||
|
||||
/// Called immediately after a stack frame got popped, but before jumping back to the caller.
|
||||
/// The `locals` have already been destroyed!
|
||||
#[inline(always)]
|
||||
fn after_stack_pop(
|
||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
_frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
|
||||
|
|
@ -471,6 +475,18 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
|||
assert!(!unwinding);
|
||||
Ok(StackPopJump::Normal)
|
||||
}
|
||||
|
||||
/// Called immediately after actual memory was allocated for a local
|
||||
/// but before the local's stack frame is updated to point to that memory.
|
||||
#[inline(always)]
|
||||
fn after_local_allocated(
|
||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||
_frame: usize,
|
||||
_local: mir::Local,
|
||||
_mplace: &MPlaceTy<'tcx, Self::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines
|
||||
|
|
@ -501,7 +517,10 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unwind_terminate(_ecx: &mut InterpCx<$mir, $tcx, Self>) -> InterpResult<$tcx> {
|
||||
fn unwind_terminate(
|
||||
_ecx: &mut InterpCx<$mir, $tcx, Self>,
|
||||
_reason: mir::UnwindTerminateReason,
|
||||
) -> InterpResult<$tcx> {
|
||||
unreachable!("unwinding cannot happen during compile-time evaluation")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -899,7 +899,7 @@ where
|
|||
if local_layout.is_unsized() {
|
||||
throw_unsup_format!("unsized locals are not supported");
|
||||
}
|
||||
let mplace = *self.allocate(local_layout, MemoryKind::Stack)?;
|
||||
let mplace = self.allocate(local_layout, MemoryKind::Stack)?;
|
||||
// Preserve old value. (As an optimization, we can skip this if it was uninit.)
|
||||
if !matches!(local_val, Immediate::Uninit) {
|
||||
// We don't have to validate as we can assume the local was already
|
||||
|
|
@ -909,15 +909,16 @@ where
|
|||
local_val,
|
||||
local_layout,
|
||||
local_layout.align.abi,
|
||||
mplace,
|
||||
*mplace,
|
||||
)?;
|
||||
}
|
||||
M::after_local_allocated(self, frame, local, &mplace)?;
|
||||
// Now we can call `access_mut` again, asserting it goes well, and actually
|
||||
// overwrite things. This points to the entire allocation, not just the part
|
||||
// the place refers to, i.e. we do this before we apply `offset`.
|
||||
*M::access_local_mut(self, frame, local).unwrap() =
|
||||
Operand::Indirect(mplace);
|
||||
mplace
|
||||
Operand::Indirect(*mplace);
|
||||
*mplace
|
||||
}
|
||||
&mut Operand::Indirect(mplace) => mplace, // this already was an indirect local
|
||||
};
|
||||
|
|
|
|||
|
|
@ -196,8 +196,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
UnwindTerminate => {
|
||||
M::unwind_terminate(self)?;
|
||||
UnwindTerminate(reason) => {
|
||||
M::unwind_terminate(self, reason)?;
|
||||
}
|
||||
|
||||
// When we encounter Resume, we've finished unwinding
|
||||
|
|
|
|||
|
|
@ -1037,7 +1037,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
self.check_op(ops::Generator(hir::GeneratorKind::Gen))
|
||||
}
|
||||
|
||||
TerminatorKind::UnwindTerminate => {
|
||||
TerminatorKind::UnwindTerminate(_) => {
|
||||
// Cleanup blocks are skipped for const checking (see `visit_basic_block_data`).
|
||||
span_bug!(self.span, "`Terminate` terminator outside of cleanup block")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
mir::TerminatorKind::UnwindTerminate
|
||||
mir::TerminatorKind::UnwindTerminate(_)
|
||||
| mir::TerminatorKind::Call { .. }
|
||||
| mir::TerminatorKind::Assert { .. }
|
||||
| mir::TerminatorKind::FalseEdge { .. }
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ use rustc_middle::mir::{
|
|||
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
|
||||
MirPass, MirPhase, NonDivergingIntrinsic, NullOp, Operand, Place, PlaceElem, PlaceRef,
|
||||
ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
|
||||
Terminator, TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents,
|
||||
START_BLOCK,
|
||||
Terminator, TerminatorKind, UnOp, UnwindAction, UnwindTerminateReason, VarDebugInfo,
|
||||
VarDebugInfoContents, START_BLOCK,
|
||||
};
|
||||
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_mir_dataflow::impls::MaybeStorageLive;
|
||||
|
|
@ -274,7 +274,16 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
|
|||
self.fail(location, "`UnwindAction::Continue` in no-unwind function");
|
||||
}
|
||||
}
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate => (),
|
||||
UnwindAction::Terminate(UnwindTerminateReason::InCleanup) => {
|
||||
if !is_cleanup {
|
||||
self.fail(
|
||||
location,
|
||||
"`UnwindAction::Terminate(InCleanup)` in a non-cleanup block",
|
||||
);
|
||||
}
|
||||
}
|
||||
// These are allowed everywhere.
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate(UnwindTerminateReason::Abi) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -501,7 +510,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
self.fail(location, "Cannot `UnwindResume` in a function that cannot unwind")
|
||||
}
|
||||
}
|
||||
TerminatorKind::UnwindTerminate => {
|
||||
TerminatorKind::UnwindTerminate(_) => {
|
||||
let bb = location.block;
|
||||
if !self.body.basic_blocks[bb].is_cleanup {
|
||||
self.fail(location, "Cannot `UnwindTerminate` from non-cleanup basic block")
|
||||
|
|
@ -1233,7 +1242,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
| TerminatorKind::InlineAsm { .. }
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn is_within_packed<'tcx, L>(
|
||||
pub fn is_within_packed<'tcx, L>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
local_decls: &L,
|
||||
place: Place<'tcx>,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ mod check_validity_requirement;
|
|||
mod compare_types;
|
||||
mod type_name;
|
||||
|
||||
pub use self::alignment::is_disaligned;
|
||||
pub use self::alignment::{is_disaligned, is_within_packed};
|
||||
pub use self::check_validity_requirement::check_validity_requirement;
|
||||
pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype};
|
||||
pub use self::type_name::type_name;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
#![allow(rustc::potential_query_instability)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![allow(internal_features)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
|||
|
|
@ -11,9 +11,14 @@ pub struct Mmap(Vec<u8>);
|
|||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl Mmap {
|
||||
/// # Safety
|
||||
///
|
||||
/// The given file must not be mutated (i.e., not written, not truncated, ...) until the mapping is closed.
|
||||
///
|
||||
/// However in practice most callers do not ensure this, so uses of this function are likely unsound.
|
||||
#[inline]
|
||||
pub unsafe fn map(file: File) -> io::Result<Self> {
|
||||
// Safety: this is in fact not safe.
|
||||
// Safety: the caller must ensure that this is safe.
|
||||
unsafe { memmap2::Mmap::map(&file).map(Mmap) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,26 @@
|
|||
use crate::fx::{FxHashMap, FxHasher};
|
||||
#[cfg(parallel_compiler)]
|
||||
use crate::sync::is_dyn_thread_safe;
|
||||
use crate::sync::{CacheAligned, Lock, LockGuard};
|
||||
use crate::sync::{is_dyn_thread_safe, CacheAligned};
|
||||
use crate::sync::{Lock, LockGuard};
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::hash_map::RawEntryMut;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
|
||||
#[cfg(parallel_compiler)]
|
||||
// 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700,
|
||||
// but this should be tested on higher core count CPUs. How the `Sharded` type gets used
|
||||
// may also affect the ideal number of shards.
|
||||
const SHARD_BITS: usize = 5;
|
||||
|
||||
#[cfg(not(parallel_compiler))]
|
||||
const SHARD_BITS: usize = 0;
|
||||
|
||||
pub const SHARDS: usize = 1 << SHARD_BITS;
|
||||
#[cfg(parallel_compiler)]
|
||||
const SHARDS: usize = 1 << SHARD_BITS;
|
||||
|
||||
/// An array of cache-line aligned inner locked structures with convenience methods.
|
||||
pub struct Sharded<T> {
|
||||
/// This mask is used to ensure that accesses are inbounds of `shards`.
|
||||
/// When dynamic thread safety is off, this field is set to 0 causing only
|
||||
/// a single shard to be used for greater cache efficiency.
|
||||
/// A single field is used when the compiler uses only one thread.
|
||||
pub enum Sharded<T> {
|
||||
Single(Lock<T>),
|
||||
#[cfg(parallel_compiler)]
|
||||
mask: usize,
|
||||
shards: [CacheAligned<Lock<T>>; SHARDS],
|
||||
Shards(Box<[CacheAligned<Lock<T>>; SHARDS]>),
|
||||
}
|
||||
|
||||
impl<T: Default> Default for Sharded<T> {
|
||||
|
|
@ -38,35 +33,24 @@ impl<T: Default> Default for Sharded<T> {
|
|||
impl<T> Sharded<T> {
|
||||
#[inline]
|
||||
pub fn new(mut value: impl FnMut() -> T) -> Self {
|
||||
Sharded {
|
||||
#[cfg(parallel_compiler)]
|
||||
mask: if is_dyn_thread_safe() { SHARDS - 1 } else { 0 },
|
||||
shards: [(); SHARDS].map(|()| CacheAligned(Lock::new(value()))),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn mask(&self) -> usize {
|
||||
#[cfg(parallel_compiler)]
|
||||
{
|
||||
if SHARDS == 1 { 0 } else { self.mask }
|
||||
if is_dyn_thread_safe() {
|
||||
return Sharded::Shards(Box::new(
|
||||
[(); SHARDS].map(|()| CacheAligned(Lock::new(value()))),
|
||||
));
|
||||
}
|
||||
#[cfg(not(parallel_compiler))]
|
||||
{
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn count(&self) -> usize {
|
||||
// `self.mask` is always one below the used shard count
|
||||
self.mask() + 1
|
||||
Sharded::Single(Lock::new(value()))
|
||||
}
|
||||
|
||||
/// The shard is selected by hashing `val` with `FxHasher`.
|
||||
#[inline]
|
||||
pub fn get_shard_by_value<K: Hash + ?Sized>(&self, val: &K) -> &Lock<T> {
|
||||
self.get_shard_by_hash(if SHARDS == 1 { 0 } else { make_hash(val) })
|
||||
pub fn get_shard_by_value<K: Hash + ?Sized>(&self, _val: &K) -> &Lock<T> {
|
||||
match self {
|
||||
Self::Single(single) => &single,
|
||||
#[cfg(parallel_compiler)]
|
||||
Self::Shards(..) => self.get_shard_by_hash(make_hash(_val)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -75,20 +59,44 @@ impl<T> Sharded<T> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_shard_by_index(&self, i: usize) -> &Lock<T> {
|
||||
// SAFETY: The index get ANDed with the mask, ensuring it is always inbounds.
|
||||
unsafe { &self.shards.get_unchecked(i & self.mask()).0 }
|
||||
pub fn get_shard_by_index(&self, _i: usize) -> &Lock<T> {
|
||||
match self {
|
||||
Self::Single(single) => &single,
|
||||
#[cfg(parallel_compiler)]
|
||||
Self::Shards(shards) => {
|
||||
// SAFETY: The index gets ANDed with the shard mask, ensuring it is always inbounds.
|
||||
unsafe { &shards.get_unchecked(_i & (SHARDS - 1)).0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lock_shards(&self) -> Vec<LockGuard<'_, T>> {
|
||||
(0..self.count()).map(|i| self.get_shard_by_index(i).lock()).collect()
|
||||
match self {
|
||||
Self::Single(single) => vec![single.lock()],
|
||||
#[cfg(parallel_compiler)]
|
||||
Self::Shards(shards) => shards.iter().map(|shard| shard.0.lock()).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_lock_shards(&self) -> Option<Vec<LockGuard<'_, T>>> {
|
||||
(0..self.count()).map(|i| self.get_shard_by_index(i).try_lock()).collect()
|
||||
match self {
|
||||
Self::Single(single) => Some(vec![single.try_lock()?]),
|
||||
#[cfg(parallel_compiler)]
|
||||
Self::Shards(shards) => shards.iter().map(|shard| shard.0.try_lock()).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn shards() -> usize {
|
||||
#[cfg(parallel_compiler)]
|
||||
if is_dyn_thread_safe() {
|
||||
return SHARDS;
|
||||
}
|
||||
|
||||
1
|
||||
}
|
||||
|
||||
pub type ShardedHashMap<K, V> = Sharded<FxHashMap<K, V>>;
|
||||
|
||||
impl<K: Eq, V> ShardedHashMap<K, V> {
|
||||
|
|
|
|||
|
|
@ -171,3 +171,9 @@ impl<T> Deref for WorkerLocal<T> {
|
|||
unsafe { &self.locals.get_unchecked(self.registry.id().verify()).0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Default for WorkerLocal<T> {
|
||||
fn default() -> Self {
|
||||
WorkerLocal::new(|_| T::default())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,12 +140,6 @@ pub const EXIT_FAILURE: i32 = 1;
|
|||
pub const DEFAULT_BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
|
||||
?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
|
||||
|
||||
const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["-Z", "-C", "--crate-type"];
|
||||
|
||||
const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename"];
|
||||
|
||||
const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &[&str] = &["incremental"];
|
||||
|
||||
pub fn abort_on_err<T>(result: Result<T, ErrorGuaranteed>, sess: &Session) -> T {
|
||||
match result {
|
||||
Err(..) => {
|
||||
|
|
@ -1250,47 +1244,6 @@ fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets a list of extra command-line flags provided by the user, as strings.
|
||||
///
|
||||
/// This function is used during ICEs to show more information useful for
|
||||
/// debugging, since some ICEs only happens with non-default compiler flags
|
||||
/// (and the users don't always report them).
|
||||
fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
|
||||
let mut args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).peekable();
|
||||
|
||||
let mut result = Vec::new();
|
||||
let mut excluded_cargo_defaults = false;
|
||||
while let Some(arg) = args.next() {
|
||||
if let Some(a) = ICE_REPORT_COMPILER_FLAGS.iter().find(|a| arg.starts_with(*a)) {
|
||||
let content = if arg.len() == a.len() {
|
||||
// A space-separated option, like `-C incremental=foo` or `--crate-type rlib`
|
||||
match args.next() {
|
||||
Some(arg) => arg.to_string(),
|
||||
None => continue,
|
||||
}
|
||||
} else if arg.get(a.len()..a.len() + 1) == Some("=") {
|
||||
// An equals option, like `--crate-type=rlib`
|
||||
arg[a.len() + 1..].to_string()
|
||||
} else {
|
||||
// A non-space option, like `-Cincremental=foo`
|
||||
arg[a.len()..].to_string()
|
||||
};
|
||||
let option = content.split_once('=').map(|s| s.0).unwrap_or(&content);
|
||||
if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| option == *exc) {
|
||||
excluded_cargo_defaults = true;
|
||||
} else {
|
||||
result.push(a.to_string());
|
||||
match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| option == **s) {
|
||||
Some(s) => result.push(format!("{s}=[REDACTED]")),
|
||||
None => result.push(content),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !result.is_empty() { Some((result, excluded_cargo_defaults)) } else { None }
|
||||
}
|
||||
|
||||
/// Runs a closure and catches unwinds triggered by fatal errors.
|
||||
///
|
||||
/// The compiler currently unwinds with a special sentinel value to abort
|
||||
|
|
@ -1449,7 +1402,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info:
|
|||
None
|
||||
};
|
||||
|
||||
if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
|
||||
if let Some((flags, excluded_cargo_defaults)) = rustc_session::utils::extra_compiler_flags() {
|
||||
handler.emit_note(session_diagnostics::IceFlags { flags: flags.join(" ") });
|
||||
if excluded_cargo_defaults {
|
||||
handler.emit_note(session_diagnostics::IceExcludeCargoDefaults);
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ trait Trait {
|
|||
type Bar;
|
||||
}
|
||||
|
||||
type Foo = Trait; // error: the value of the associated type `Bar` (from
|
||||
// the trait `Trait`) must be specified
|
||||
type Foo = dyn Trait; // error: the value of the associated type `Bar` (from
|
||||
// the trait `Trait`) must be specified
|
||||
```
|
||||
|
||||
Trait objects need to have all associated types specified. Please verify that
|
||||
|
|
@ -20,5 +20,5 @@ trait Trait {
|
|||
type Bar;
|
||||
}
|
||||
|
||||
type Foo = Trait<Bar=i32>; // ok!
|
||||
type Foo = dyn Trait<Bar=i32>; // ok!
|
||||
```
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#![feature(type_alias_impl_trait)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![allow(internal_features)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
#![feature(box_patterns)]
|
||||
#![feature(error_reporter)]
|
||||
#![allow(incomplete_features)]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![allow(internal_features)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
|
|
@ -197,8 +197,14 @@ impl CodeSuggestion {
|
|||
|
||||
use rustc_span::{CharPos, Pos};
|
||||
|
||||
/// Append to a buffer the remainder of the line of existing source code, and return the
|
||||
/// count of lines that have been added for accurate highlighting.
|
||||
/// Extracts a substring from the provided `line_opt` based on the specified low and high indices,
|
||||
/// appends it to the given buffer `buf`, and returns the count of newline characters in the substring
|
||||
/// for accurate highlighting.
|
||||
/// If `line_opt` is `None`, a newline character is appended to the buffer, and 0 is returned.
|
||||
///
|
||||
/// ## Returns
|
||||
///
|
||||
/// The count of newline characters in the extracted substring.
|
||||
fn push_trailing(
|
||||
buf: &mut String,
|
||||
line_opt: Option<&Cow<'_, str>>,
|
||||
|
|
@ -206,22 +212,30 @@ impl CodeSuggestion {
|
|||
hi_opt: Option<&Loc>,
|
||||
) -> usize {
|
||||
let mut line_count = 0;
|
||||
// Convert CharPos to Usize, as CharPose is character offset
|
||||
// Extract low index and high index
|
||||
let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
|
||||
if let Some(line) = line_opt {
|
||||
if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
|
||||
// Get high index while account for rare unicode and emoji with char_indices
|
||||
let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
|
||||
match hi_opt {
|
||||
// If high index exist, take string from low to high index
|
||||
Some(hi) if hi > lo => {
|
||||
// count how many '\n' exist
|
||||
line_count = line[lo..hi].matches('\n').count();
|
||||
buf.push_str(&line[lo..hi])
|
||||
}
|
||||
Some(_) => (),
|
||||
// If high index absence, take string from low index till end string.len
|
||||
None => {
|
||||
// count how many '\n' exist
|
||||
line_count = line[lo..].matches('\n').count();
|
||||
buf.push_str(&line[lo..])
|
||||
}
|
||||
}
|
||||
}
|
||||
// If high index is None
|
||||
if hi_opt.is_none() {
|
||||
buf.push('\n');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
#![feature(try_blocks)]
|
||||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![allow(internal_features)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ declare_features! (
|
|||
(active, arm_target_feature, "1.27.0", Some(44839), None),
|
||||
(active, avx512_target_feature, "1.27.0", Some(44839), None),
|
||||
(active, bpf_target_feature, "1.54.0", Some(44839), None),
|
||||
(active, csky_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None),
|
||||
(active, csky_target_feature, "1.73.0", Some(44839), None),
|
||||
(active, ermsb_target_feature, "1.49.0", Some(44839), None),
|
||||
(active, hexagon_target_feature, "1.27.0", Some(44839), None),
|
||||
(active, mips_target_feature, "1.27.0", Some(44839), None),
|
||||
|
|
@ -315,7 +315,7 @@ declare_features! (
|
|||
/// Allows `extern "ptx-*" fn()`.
|
||||
(active, abi_ptx, "1.15.0", Some(38788), None),
|
||||
/// Allows `extern "riscv-interrupt-m" fn()` and `extern "riscv-interrupt-s" fn()`.
|
||||
(active, abi_riscv_interrupt, "CURRENT_RUSTC_VERSION", Some(111889), None),
|
||||
(active, abi_riscv_interrupt, "1.73.0", Some(111889), None),
|
||||
/// Allows `extern "x86-interrupt" fn()`.
|
||||
(active, abi_x86_interrupt, "1.17.0", Some(40180), None),
|
||||
/// Allows additional const parameter types, such as `&'static str` or user defined types
|
||||
|
|
@ -341,7 +341,7 @@ declare_features! (
|
|||
/// Allows async functions to be declared, implemented, and used in traits.
|
||||
(active, async_fn_in_trait, "1.66.0", Some(91611), None),
|
||||
/// Allows `#[track_caller]` on async functions.
|
||||
(active, async_fn_track_caller, "CURRENT_RUSTC_VERSION", Some(110011), None),
|
||||
(active, async_fn_track_caller, "1.73.0", Some(110011), None),
|
||||
/// Allows builtin # foo() syntax
|
||||
(active, builtin_syntax, "1.71.0", Some(110680), None),
|
||||
/// Allows `c"foo"` literals.
|
||||
|
|
@ -353,7 +353,7 @@ declare_features! (
|
|||
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
|
||||
(active, cfg_overflow_checks, "1.71.0", Some(111466), None),
|
||||
/// Provides the relocation model information as cfg entry
|
||||
(active, cfg_relocation_model, "CURRENT_RUSTC_VERSION", Some(114929), None),
|
||||
(active, cfg_relocation_model, "1.73.0", Some(114929), None),
|
||||
/// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
|
||||
(active, cfg_sanitize, "1.41.0", Some(39699), None),
|
||||
/// Allows `cfg(target_abi = "...")`.
|
||||
|
|
@ -411,7 +411,7 @@ declare_features! (
|
|||
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
|
||||
(active, deprecated_suggestion, "1.61.0", Some(94785), None),
|
||||
/// Allows using the `#[diagnostic]` attribute tool namespace
|
||||
(active, diagnostic_namespace, "CURRENT_RUSTC_VERSION", Some(94785), None),
|
||||
(active, diagnostic_namespace, "1.73.0", Some(94785), None),
|
||||
/// Controls errors in trait implementations.
|
||||
(active, do_not_recommend, "1.67.0", Some(51992), None),
|
||||
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
|
||||
|
|
@ -456,7 +456,7 @@ declare_features! (
|
|||
/// Allows non-trivial generic constants which have to have wfness manually propagated to callers
|
||||
(incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
|
||||
/// Allows generic parameters and where-clauses on free & associated const items.
|
||||
(incomplete, generic_const_items, "CURRENT_RUSTC_VERSION", Some(113521), None),
|
||||
(incomplete, generic_const_items, "1.73.0", Some(113521), None),
|
||||
/// Allows using `..=X` as a patterns in slices.
|
||||
(active, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None),
|
||||
/// Allows `if let` guard in match arms.
|
||||
|
|
@ -584,6 +584,8 @@ declare_features! (
|
|||
(active, type_privacy_lints, "1.72.0", Some(48054), None),
|
||||
/// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
|
||||
(active, unix_sigpipe, "1.65.0", Some(97889), None),
|
||||
/// Allows unnamed fields of struct and union type
|
||||
(incomplete, unnamed_fields, "CURRENT_RUSTC_VERSION", Some(49804), None),
|
||||
/// Allows unsized fn parameters.
|
||||
(active, unsized_fn_params, "1.49.0", Some(48055), None),
|
||||
/// Allows unsized rvalues at arguments and parameters.
|
||||
|
|
|
|||
|
|
@ -238,6 +238,7 @@ language_item_table! {
|
|||
PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None;
|
||||
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
|
||||
PanicCannotUnwind, sym::panic_cannot_unwind, panic_cannot_unwind, Target::Fn, GenericRequirement::Exact(0);
|
||||
PanicInCleanup, sym::panic_in_cleanup, panic_in_cleanup, Target::Fn, GenericRequirement::Exact(0);
|
||||
/// libstd panic entry point. Necessary for const eval to be able to catch it
|
||||
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![allow(internal_features)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
|
|
|
|||
|
|
@ -597,7 +597,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
}
|
||||
}
|
||||
if !suggestions.is_empty() {
|
||||
suggestions.sort_by_key(|&(span, _)| span);
|
||||
// There are cases where one bound points to a span within another bound's span, like when
|
||||
// you have code like the following (#115019), so we skip providing a suggestion in those
|
||||
// cases to avoid having a malformed suggestion.
|
||||
//
|
||||
// pub struct Flatten<I> {
|
||||
// inner: <IntoIterator<Item: IntoIterator<Item: >>::IntoIterator as Item>::core,
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// | ^^^^^^^^^^^^^^^^^^^^^
|
||||
// | |
|
||||
// | associated types `Item`, `IntoIter` must be specified
|
||||
// associated types `Item`, `IntoIter` must be specified
|
||||
// }
|
||||
let overlaps = suggestions.windows(2).any(|pair| pair[0].0.overlaps(pair[1].0));
|
||||
if !suggestions.is_empty() && !overlaps {
|
||||
err.multipart_suggestion(
|
||||
format!("specify the associated type{}", pluralize!(types_count)),
|
||||
suggestions,
|
||||
|
|
|
|||
|
|
@ -342,9 +342,16 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
continue;
|
||||
};
|
||||
for obligation in obligations {
|
||||
debug!(?obligation);
|
||||
match obligation.predicate.kind().skip_binder() {
|
||||
// We need to register Projection oblgiations too, because we may end up with
|
||||
// an implied `X::Item: 'a`, which gets desugared into `X::Item = ?0`, `?0: 'a`.
|
||||
// If we only register the region outlives obligation, this leads to an unconstrained var.
|
||||
// See `implied_bounds_entailment_alias_var` test.
|
||||
ty::PredicateKind::Clause(
|
||||
ty::ClauseKind::RegionOutlives(..) | ty::ClauseKind::TypeOutlives(..),
|
||||
ty::ClauseKind::RegionOutlives(..)
|
||||
| ty::ClauseKind::TypeOutlives(..)
|
||||
| ty::ClauseKind::Projection(..),
|
||||
) => ocx.register_obligation(obligation),
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
|
||||
if wf_args_seen.insert(arg) {
|
||||
|
|
|
|||
|
|
@ -44,20 +44,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
false
|
||||
}
|
||||
|
||||
fn check_asm_operand_type(
|
||||
&self,
|
||||
idx: usize,
|
||||
reg: InlineAsmRegOrRegClass,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
is_input: bool,
|
||||
tied_input: Option<(&'tcx hir::Expr<'tcx>, Option<InlineAsmType>)>,
|
||||
target_features: &FxIndexSet<Symbol>,
|
||||
) -> Option<InlineAsmType> {
|
||||
let ty = (self.get_operand_ty)(expr);
|
||||
if ty.has_non_region_infer() {
|
||||
bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty);
|
||||
}
|
||||
fn get_asm_ty(&self, ty: Ty<'tcx>) -> Option<InlineAsmType> {
|
||||
let asm_ty_isize = match self.tcx.sess.target.pointer_width {
|
||||
16 => InlineAsmType::I16,
|
||||
32 => InlineAsmType::I32,
|
||||
|
|
@ -65,10 +52,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let asm_ty = match *ty.kind() {
|
||||
// `!` is allowed for input but not for output (issue #87802)
|
||||
ty::Never if is_input => return None,
|
||||
_ if ty.references_error() => return None,
|
||||
match *ty.kind() {
|
||||
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8),
|
||||
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16),
|
||||
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32),
|
||||
|
|
@ -99,7 +83,6 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
match ty.kind() {
|
||||
ty::Never | ty::Error(_) => return None,
|
||||
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::VecI8(size)),
|
||||
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => {
|
||||
Some(InlineAsmType::VecI16(size))
|
||||
|
|
@ -128,6 +111,38 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
}
|
||||
ty::Infer(_) => unreachable!(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_asm_operand_type(
|
||||
&self,
|
||||
idx: usize,
|
||||
reg: InlineAsmRegOrRegClass,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
is_input: bool,
|
||||
tied_input: Option<(&'tcx hir::Expr<'tcx>, Option<InlineAsmType>)>,
|
||||
target_features: &FxIndexSet<Symbol>,
|
||||
) -> Option<InlineAsmType> {
|
||||
let ty = (self.get_operand_ty)(expr);
|
||||
if ty.has_non_region_infer() {
|
||||
bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty);
|
||||
}
|
||||
|
||||
let asm_ty = match *ty.kind() {
|
||||
// `!` is allowed for input but not for output (issue #87802)
|
||||
ty::Never if is_input => return None,
|
||||
_ if ty.references_error() => return None,
|
||||
ty::Adt(adt, args) if Some(adt.did()) == self.tcx.lang_items().maybe_uninit() => {
|
||||
let fields = &adt.non_enum_variant().fields;
|
||||
let ty = fields[FieldIdx::from_u32(1)].ty(self.tcx, args);
|
||||
let ty::Adt(ty, args) = ty.kind() else { unreachable!() };
|
||||
assert!(ty.is_manually_drop());
|
||||
let fields = &ty.non_enum_variant().fields;
|
||||
let ty = fields[FieldIdx::from_u32(0)].ty(self.tcx, args);
|
||||
self.get_asm_ty(ty)
|
||||
}
|
||||
_ => self.get_asm_ty(ty),
|
||||
};
|
||||
let Some(asm_ty) = asm_ty else {
|
||||
let msg = format!("cannot use value of type `{ty}` for inline assembly");
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ fn default_body_is_unstable(
|
|||
&tcx.sess.parse_sess,
|
||||
feature,
|
||||
rustc_feature::GateIssue::Library(issue),
|
||||
false,
|
||||
);
|
||||
|
||||
err.emit();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::FnCtxt;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::{infer::type_variable::TypeVariableOriginKind, traits::ObligationCauseCode};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||
|
|
@ -133,15 +133,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
// Notably, we only point to params that are local to the
|
||||
// item we're checking, since those are the ones we are able
|
||||
// to look in the final `hir::PathSegment` for. Everything else
|
||||
// would require a deeper search into the `qpath` than I think
|
||||
// is worthwhile.
|
||||
if let Some(param_to_point_at) = param_to_point_at
|
||||
&& self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
|
||||
|
||||
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
return true;
|
||||
if self.point_at_path_if_possible(error, def_id, param, qpath) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
|
||||
|
|
@ -166,12 +165,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
{
|
||||
return true;
|
||||
}
|
||||
// Handle `Self` param specifically, since it's separated in
|
||||
// the method call representation
|
||||
if self_param_to_point_at.is_some() {
|
||||
error.obligation.cause.span = receiver
|
||||
.span
|
||||
.find_ancestor_in_same_ctxt(error.obligation.cause.span)
|
||||
.unwrap_or(receiver.span);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Struct(qpath, fields, ..) => {
|
||||
if let Res::Def(
|
||||
hir::def::DefKind::Struct | hir::def::DefKind::Variant,
|
||||
variant_def_id,
|
||||
) = self.typeck_results.borrow().qpath_res(qpath, hir_id)
|
||||
if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) =
|
||||
self.typeck_results.borrow().qpath_res(qpath, hir_id)
|
||||
{
|
||||
for param in
|
||||
[param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
|
||||
|
|
@ -193,10 +199,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
if let Some(param_to_point_at) = param_to_point_at
|
||||
&& self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
|
||||
|
||||
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
{
|
||||
return true;
|
||||
if self.point_at_path_if_possible(error, def_id, param, qpath) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -213,17 +223,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
qpath: &hir::QPath<'tcx>,
|
||||
) -> bool {
|
||||
match qpath {
|
||||
hir::QPath::Resolved(_, path) => {
|
||||
if let Some(segment) = path.segments.last()
|
||||
&& self.point_at_generic_if_possible(error, def_id, param, segment)
|
||||
hir::QPath::Resolved(self_ty, path) => {
|
||||
for segment in path.segments.iter().rev() {
|
||||
if let Res::Def(kind, def_id) = segment.res
|
||||
&& !matches!(kind, DefKind::Mod | DefKind::ForeignMod)
|
||||
&& self.point_at_generic_if_possible(error, def_id, param, segment)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Handle `Self` param specifically, since it's separated in
|
||||
// the path representation
|
||||
if let Some(self_ty) = self_ty
|
||||
&& let ty::GenericArgKind::Type(ty) = param.unpack()
|
||||
&& ty == self.tcx.types.self_param
|
||||
{
|
||||
error.obligation.cause.span = self_ty
|
||||
.span
|
||||
.find_ancestor_in_same_ctxt(error.obligation.cause.span)
|
||||
.unwrap_or(self_ty.span);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
hir::QPath::TypeRelative(_, segment) => {
|
||||
hir::QPath::TypeRelative(self_ty, segment) => {
|
||||
if self.point_at_generic_if_possible(error, def_id, param, segment) {
|
||||
return true;
|
||||
}
|
||||
// Handle `Self` param specifically, since it's separated in
|
||||
// the path representation
|
||||
if let ty::GenericArgKind::Type(ty) = param.unpack()
|
||||
&& ty == self.tcx.types.self_param
|
||||
{
|
||||
error.obligation.cause.span = self_ty
|
||||
.span
|
||||
.find_ancestor_in_same_ctxt(error.obligation.cause.span)
|
||||
.unwrap_or(self_ty.span);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -618,14 +654,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
let variant_def_id = match expr_struct_def_kind {
|
||||
hir::def::DefKind::Struct => {
|
||||
DefKind::Struct => {
|
||||
if in_ty_adt.did() != expr_struct_def_id {
|
||||
// FIXME: Deal with type aliases?
|
||||
return Err(expr);
|
||||
}
|
||||
expr_struct_def_id
|
||||
}
|
||||
hir::def::DefKind::Variant => {
|
||||
DefKind::Variant => {
|
||||
// If this is a variant, its parent is the type definition.
|
||||
if in_ty_adt.did() != self.tcx.parent(expr_struct_def_id) {
|
||||
// FIXME: Deal with type aliases?
|
||||
|
|
@ -727,14 +763,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
let variant_def_id = match expr_struct_def_kind {
|
||||
hir::def::DefKind::Ctor(hir::def::CtorOf::Struct, hir::def::CtorKind::Fn) => {
|
||||
DefKind::Ctor(hir::def::CtorOf::Struct, hir::def::CtorKind::Fn) => {
|
||||
if in_ty_adt.did() != self.tcx.parent(expr_ctor_def_id) {
|
||||
// FIXME: Deal with type aliases?
|
||||
return Err(expr);
|
||||
}
|
||||
self.tcx.parent(expr_ctor_def_id)
|
||||
}
|
||||
hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, hir::def::CtorKind::Fn) => {
|
||||
DefKind::Ctor(hir::def::CtorOf::Variant, hir::def::CtorKind::Fn) => {
|
||||
// For a typical enum like
|
||||
// `enum Blah<T> { Variant(T) }`
|
||||
// we get the following resolutions:
|
||||
|
|
|
|||
|
|
@ -436,6 +436,12 @@ fn fatally_break_rust(tcx: TyCtxt<'_>) {
|
|||
tcx.sess.cfg_version,
|
||||
config::host_triple(),
|
||||
));
|
||||
if let Some((flags, excluded_cargo_defaults)) = rustc_session::utils::extra_compiler_flags() {
|
||||
handler.note_without_error(format!("compiler flags: {}", flags.join(" ")));
|
||||
if excluded_cargo_defaults {
|
||||
handler.note_without_error("some of the compiler flags provided by cargo are hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn has_expected_num_generic_args(tcx: TyCtxt<'_>, trait_did: DefId, expected: usize) -> bool {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
test
|
||||
)
|
||||
)]
|
||||
#![cfg_attr(all(not(bootstrap), feature = "nightly"), allow(internal_features))]
|
||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub mod bit_set;
|
||||
|
|
@ -29,6 +29,18 @@ pub use {idx::Idx, slice::IndexSlice, vec::IndexVec};
|
|||
pub use rustc_macros::newtype_index;
|
||||
|
||||
/// Type size assertion. The first argument is a type and the second argument is its expected size.
|
||||
///
|
||||
/// <div class="warning">
|
||||
///
|
||||
/// Emitting hard errors from size assertions like this is generally not
|
||||
/// recommended, especially in libraries, because they can cause build failures if the layout
|
||||
/// algorithm or dependencies change. Here in rustc we control the toolchain and layout algorithm,
|
||||
/// so the former is not a problem. For the latter we have a lockfile as rustc is an application and
|
||||
/// precompiled library.
|
||||
///
|
||||
/// Short version: Don't copy this macro into your own code. Use a `#[test]` instead.
|
||||
///
|
||||
/// </div>
|
||||
#[macro_export]
|
||||
macro_rules! static_assert_size {
|
||||
($ty:ty, $size:expr) => {
|
||||
|
|
|
|||
|
|
@ -821,7 +821,7 @@ fn test_unstable_options_tracking_hash() {
|
|||
tracked!(profile_emit, Some(PathBuf::from("abc")));
|
||||
tracked!(profile_sample_use, Some(PathBuf::from("abc")));
|
||||
tracked!(profiler_runtime, "abc".to_string());
|
||||
tracked!(relax_elf_relocations, Some(true));
|
||||
tracked!(relax_elf_relocations, Some(false));
|
||||
tracked!(relro_level, Some(RelroLevel::Full));
|
||||
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
|
||||
tracked!(report_delayed_bugs, true);
|
||||
|
|
|
|||
|
|
@ -158,13 +158,15 @@ lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
|
|||
|
||||
lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
|
||||
|
||||
lint_check_name_removed = lint `{$lint_name}` has been removed: {$reason}
|
||||
|
||||
lint_check_name_renamed = lint `{$lint_name}` has been renamed to `{$replace}`
|
||||
|
||||
lint_check_name_unknown = unknown lint: `{$lint_name}`
|
||||
.help = did you mean: `{$suggestion}`
|
||||
|
||||
lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
|
||||
|
||||
lint_check_name_warning = {$msg}
|
||||
|
||||
lint_command_line_source = `forbid` lint level was set on command line
|
||||
|
||||
lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as identifiers, which look alike
|
||||
|
|
@ -323,6 +325,8 @@ lint_invalid_reference_casting_assign_to_ref = assigning to `&T` is undefined be
|
|||
lint_invalid_reference_casting_borrow_as_mut = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
|
||||
.label = casting happend here
|
||||
|
||||
lint_invalid_reference_casting_note_book = for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
|
||||
|
||||
lint_lintpass_by_hand = implementing `LintPass` by hand
|
||||
.help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
|
||||
|
||||
|
|
@ -482,8 +486,11 @@ lint_redundant_semicolons =
|
|||
*[false] this semicolon
|
||||
}
|
||||
|
||||
lint_renamed_or_removed_lint = {$msg}
|
||||
lint_removed_lint = lint `{$name}` has been removed: {$reason}
|
||||
|
||||
lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}`
|
||||
.suggestion = use the new name
|
||||
.help = use the new name `{$replace}`
|
||||
|
||||
lint_requested_level = requested on the command line with `{$level} {$lint_name}`
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
use self::TargetLint::*;
|
||||
|
||||
use crate::errors::{
|
||||
CheckNameDeprecated, CheckNameUnknown, CheckNameUnknownTool, CheckNameWarning, RequestedLevel,
|
||||
UnsupportedGroup,
|
||||
CheckNameDeprecated, CheckNameRemoved, CheckNameRenamed, CheckNameUnknown,
|
||||
CheckNameUnknownTool, RequestedLevel, UnsupportedGroup,
|
||||
};
|
||||
use crate::levels::LintLevelsBuilder;
|
||||
use crate::passes::{EarlyLintPassObject, LateLintPassObject};
|
||||
|
|
@ -124,9 +124,10 @@ pub enum CheckLintNameResult<'a> {
|
|||
NoLint(Option<Symbol>),
|
||||
/// The lint refers to a tool that has not been registered.
|
||||
NoTool,
|
||||
/// The lint is either renamed or removed. This is the warning
|
||||
/// message, and an optional new name (`None` if removed).
|
||||
Warning(String, Option<String>),
|
||||
/// The lint has been renamed to a new name.
|
||||
Renamed(String),
|
||||
/// The lint has been removed due to the given reason.
|
||||
Removed(String),
|
||||
/// The lint is from a tool. If the Option is None, then either
|
||||
/// the lint does not exist in the tool or the code was not
|
||||
/// compiled with the tool and therefore the lint was never
|
||||
|
|
@ -342,25 +343,32 @@ impl LintStore {
|
|||
sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
|
||||
return;
|
||||
}
|
||||
let lint_name = lint_name.to_string();
|
||||
match self.check_lint_name(lint_name_only, tool_name, registered_tools) {
|
||||
CheckLintNameResult::Warning(msg, _) => {
|
||||
sess.emit_warning(CheckNameWarning {
|
||||
msg,
|
||||
CheckLintNameResult::Renamed(replace) => {
|
||||
sess.emit_warning(CheckNameRenamed {
|
||||
lint_name,
|
||||
replace: &replace,
|
||||
sub: RequestedLevel { level, lint_name },
|
||||
});
|
||||
}
|
||||
CheckLintNameResult::Removed(reason) => {
|
||||
sess.emit_warning(CheckNameRemoved {
|
||||
lint_name,
|
||||
reason: &reason,
|
||||
sub: RequestedLevel { level, lint_name },
|
||||
});
|
||||
}
|
||||
CheckLintNameResult::NoLint(suggestion) => {
|
||||
sess.emit_err(CheckNameUnknown {
|
||||
lint_name: lint_name.clone(),
|
||||
lint_name,
|
||||
suggestion,
|
||||
sub: RequestedLevel { level, lint_name },
|
||||
});
|
||||
}
|
||||
CheckLintNameResult::Tool(Err((Some(_), new_name))) => {
|
||||
sess.emit_warning(CheckNameDeprecated {
|
||||
lint_name: lint_name.clone(),
|
||||
new_name,
|
||||
lint_name,
|
||||
new_name: &new_name,
|
||||
sub: RequestedLevel { level, lint_name },
|
||||
});
|
||||
}
|
||||
|
|
@ -445,14 +453,8 @@ impl LintStore {
|
|||
}
|
||||
}
|
||||
match self.by_name.get(&complete_name) {
|
||||
Some(Renamed(new_name, _)) => CheckLintNameResult::Warning(
|
||||
format!("lint `{complete_name}` has been renamed to `{new_name}`"),
|
||||
Some(new_name.to_owned()),
|
||||
),
|
||||
Some(Removed(reason)) => CheckLintNameResult::Warning(
|
||||
format!("lint `{complete_name}` has been removed: {reason}"),
|
||||
None,
|
||||
),
|
||||
Some(Renamed(new_name, _)) => CheckLintNameResult::Renamed(new_name.to_string()),
|
||||
Some(Removed(reason)) => CheckLintNameResult::Removed(reason.to_string()),
|
||||
None => match self.lint_groups.get(&*complete_name) {
|
||||
// If neither the lint, nor the lint group exists check if there is a `clippy::`
|
||||
// variant of this lint
|
||||
|
|
@ -966,6 +968,14 @@ pub trait LintContext: Sized {
|
|||
Applicability::MachineApplicable
|
||||
);
|
||||
}
|
||||
BuiltinLintDiagnostics::AssociatedConstElidedLifetime { elided, span } => {
|
||||
db.span_suggestion_verbose(
|
||||
if elided { span.shrink_to_hi() } else { span },
|
||||
"use the `'static` lifetime",
|
||||
if elided { "'static " } else { "'static" },
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
}
|
||||
}
|
||||
// Rewrap `db`, and pass control to the user.
|
||||
decorate(db)
|
||||
|
|
|
|||
|
|
@ -91,9 +91,9 @@ pub struct BuiltinEllipsisInclusiveRangePatterns {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(lint_requested_level)]
|
||||
pub struct RequestedLevel {
|
||||
pub struct RequestedLevel<'a> {
|
||||
pub level: Level,
|
||||
pub lint_name: String,
|
||||
pub lint_name: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
@ -102,13 +102,13 @@ pub struct UnsupportedGroup {
|
|||
pub lint_group: String,
|
||||
}
|
||||
|
||||
pub struct CheckNameUnknown {
|
||||
pub lint_name: String,
|
||||
pub struct CheckNameUnknown<'a> {
|
||||
pub lint_name: &'a str,
|
||||
pub suggestion: Option<Symbol>,
|
||||
pub sub: RequestedLevel,
|
||||
pub sub: RequestedLevel<'a>,
|
||||
}
|
||||
|
||||
impl IntoDiagnostic<'_> for CheckNameUnknown {
|
||||
impl IntoDiagnostic<'_> for CheckNameUnknown<'_> {
|
||||
fn into_diagnostic(
|
||||
self,
|
||||
handler: &Handler,
|
||||
|
|
@ -127,25 +127,35 @@ impl IntoDiagnostic<'_> for CheckNameUnknown {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(lint_check_name_unknown_tool, code = "E0602")]
|
||||
pub struct CheckNameUnknownTool {
|
||||
pub struct CheckNameUnknownTool<'a> {
|
||||
pub tool_name: Symbol,
|
||||
#[subdiagnostic]
|
||||
pub sub: RequestedLevel,
|
||||
pub sub: RequestedLevel<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(lint_check_name_warning)]
|
||||
pub struct CheckNameWarning {
|
||||
pub msg: String,
|
||||
#[diag(lint_check_name_renamed)]
|
||||
pub struct CheckNameRenamed<'a> {
|
||||
pub lint_name: &'a str,
|
||||
pub replace: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub sub: RequestedLevel,
|
||||
pub sub: RequestedLevel<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(lint_check_name_removed)]
|
||||
pub struct CheckNameRemoved<'a> {
|
||||
pub lint_name: &'a str,
|
||||
pub reason: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub sub: RequestedLevel<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(lint_check_name_deprecated)]
|
||||
pub struct CheckNameDeprecated {
|
||||
pub lint_name: String,
|
||||
pub new_name: String,
|
||||
pub struct CheckNameDeprecated<'a> {
|
||||
pub lint_name: &'a str,
|
||||
pub new_name: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub sub: RequestedLevel,
|
||||
pub sub: RequestedLevel<'a>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@ use crate::{
|
|||
fluent_generated as fluent,
|
||||
late::unerased_lint_store,
|
||||
lints::{
|
||||
DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAttributeLint,
|
||||
RenamedOrRemovedLint, RenamedOrRemovedLintSuggestion, UnknownLint, UnknownLintSuggestion,
|
||||
DeprecatedLintName, IgnoredUnlessCrateSpecified, OverruledAttributeLint, RemovedLint,
|
||||
RenamedLint, RenamedLintSuggestion, UnknownLint, UnknownLintSuggestion,
|
||||
},
|
||||
};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan};
|
||||
use rustc_feature::Features;
|
||||
use rustc_feature::{Features, GateIssue};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::HirId;
|
||||
|
|
@ -24,12 +24,14 @@ use rustc_middle::lint::{
|
|||
};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{RegisteredTools, TyCtxt};
|
||||
use rustc_session::lint::builtin::{RENAMED_AND_REMOVED_LINTS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES};
|
||||
use rustc_session::lint::{
|
||||
builtin::{self, FORBIDDEN_LINT_GROUPS, SINGLE_USE_LIFETIMES, UNFULFILLED_LINT_EXPECTATIONS},
|
||||
builtin::{
|
||||
self, FORBIDDEN_LINT_GROUPS, RENAMED_AND_REMOVED_LINTS, SINGLE_USE_LIFETIMES,
|
||||
UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES,
|
||||
},
|
||||
Level, Lint, LintExpectationId, LintId,
|
||||
};
|
||||
use rustc_session::parse::{add_feature_diagnostics, feature_err};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
|
@ -566,7 +568,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
continue;
|
||||
}
|
||||
|
||||
if self.check_gated_lint(id, DUMMY_SP) {
|
||||
if self.check_gated_lint(id, DUMMY_SP, true) {
|
||||
let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
|
||||
self.insert(id, (level, src));
|
||||
}
|
||||
|
|
@ -837,7 +839,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
reason,
|
||||
};
|
||||
for &id in *ids {
|
||||
if self.check_gated_lint(id, attr.span) {
|
||||
if self.check_gated_lint(id, attr.span, false) {
|
||||
self.insert_spec(id, (level, src));
|
||||
}
|
||||
}
|
||||
|
|
@ -854,7 +856,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
reason,
|
||||
};
|
||||
for &id in ids {
|
||||
if self.check_gated_lint(id, attr.span) {
|
||||
if self.check_gated_lint(id, attr.span, false) {
|
||||
self.insert_spec(id, (level, src));
|
||||
}
|
||||
}
|
||||
|
|
@ -913,18 +915,26 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
|
||||
_ if !self.warn_about_weird_lints => {}
|
||||
|
||||
CheckLintNameResult::Warning(msg, renamed) => {
|
||||
CheckLintNameResult::Renamed(new_name) => {
|
||||
let suggestion =
|
||||
renamed.as_ref().map(|replace| RenamedOrRemovedLintSuggestion {
|
||||
suggestion: sp,
|
||||
replace: replace.as_str(),
|
||||
});
|
||||
RenamedLintSuggestion { suggestion: sp, replace: new_name.as_str() };
|
||||
let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
|
||||
self.emit_spanned_lint(
|
||||
RENAMED_AND_REMOVED_LINTS,
|
||||
sp.into(),
|
||||
RenamedOrRemovedLint { msg, suggestion },
|
||||
RenamedLint { name: name.as_str(), suggestion },
|
||||
);
|
||||
}
|
||||
|
||||
CheckLintNameResult::Removed(reason) => {
|
||||
let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
|
||||
self.emit_spanned_lint(
|
||||
RENAMED_AND_REMOVED_LINTS,
|
||||
sp.into(),
|
||||
RemovedLint { name: name.as_str(), reason: reason.as_str() },
|
||||
);
|
||||
}
|
||||
|
||||
CheckLintNameResult::NoLint(suggestion) => {
|
||||
let name = if let Some(tool_ident) = tool_ident {
|
||||
format!("{}::{}", tool_ident.name, name)
|
||||
|
|
@ -943,7 +953,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
// If this lint was renamed, apply the new lint instead of ignoring the attribute.
|
||||
// This happens outside of the match because the new lint should be applied even if
|
||||
// we don't warn about the name change.
|
||||
if let CheckLintNameResult::Warning(_, Some(new_name)) = lint_result {
|
||||
if let CheckLintNameResult::Renamed(new_name) = lint_result {
|
||||
// Ignore any errors or warnings that happen because the new name is inaccurate
|
||||
// NOTE: `new_name` already includes the tool name, so we don't have to add it again.
|
||||
if let CheckLintNameResult::Ok(ids) =
|
||||
|
|
@ -955,7 +965,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
reason,
|
||||
};
|
||||
for &id in ids {
|
||||
if self.check_gated_lint(id, attr.span) {
|
||||
if self.check_gated_lint(id, attr.span, false) {
|
||||
self.insert_spec(id, (level, src));
|
||||
}
|
||||
}
|
||||
|
|
@ -1000,7 +1010,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
// FIXME only emit this once for each attribute, instead of repeating it 4 times for
|
||||
// pre-expansion lints, post-expansion lints, `shallow_lint_levels_on` and `lint_expectations`.
|
||||
#[track_caller]
|
||||
fn check_gated_lint(&self, lint_id: LintId, span: Span) -> bool {
|
||||
fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool {
|
||||
if let Some(feature) = lint_id.lint.feature_gate {
|
||||
if !self.features.enabled(feature) {
|
||||
let lint = builtin::UNKNOWN_LINTS;
|
||||
|
|
@ -1015,7 +1025,13 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
|lint| {
|
||||
lint.set_arg("name", lint_id.lint.name_lower());
|
||||
lint.note(fluent::lint_note);
|
||||
add_feature_diagnostics(lint, &self.sess.parse_sess, feature);
|
||||
rustc_session::parse::add_feature_diagnostics_for_issue(
|
||||
lint,
|
||||
&self.sess.parse_sess,
|
||||
feature,
|
||||
GateIssue::Language,
|
||||
lint_from_cli,
|
||||
);
|
||||
lint
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![allow(internal_features)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_middle;
|
||||
|
|
|
|||
|
|
@ -764,11 +764,13 @@ pub enum InvalidFromUtf8Diag {
|
|||
#[derive(LintDiagnostic)]
|
||||
pub enum InvalidReferenceCastingDiag {
|
||||
#[diag(lint_invalid_reference_casting_borrow_as_mut)]
|
||||
#[note(lint_invalid_reference_casting_note_book)]
|
||||
BorrowAsMut {
|
||||
#[label]
|
||||
orig_cast: Option<Span>,
|
||||
},
|
||||
#[diag(lint_invalid_reference_casting_assign_to_ref)]
|
||||
#[note(lint_invalid_reference_casting_note_book)]
|
||||
AssignToRef {
|
||||
#[label]
|
||||
orig_cast: Option<Span>,
|
||||
|
|
@ -1010,23 +1012,29 @@ pub struct DeprecatedLintName<'a> {
|
|||
pub replace: &'a str,
|
||||
}
|
||||
|
||||
// FIXME: Non-translatable msg
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_renamed_or_removed_lint)]
|
||||
pub struct RenamedOrRemovedLint<'a> {
|
||||
pub msg: &'a str,
|
||||
#[diag(lint_renamed_lint)]
|
||||
pub struct RenamedLint<'a> {
|
||||
pub name: &'a str,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: Option<RenamedOrRemovedLintSuggestion<'a>>,
|
||||
pub suggestion: RenamedLintSuggestion<'a>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(lint_suggestion, code = "{replace}", applicability = "machine-applicable")]
|
||||
pub struct RenamedOrRemovedLintSuggestion<'a> {
|
||||
pub struct RenamedLintSuggestion<'a> {
|
||||
#[primary_span]
|
||||
pub suggestion: Span,
|
||||
pub replace: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_removed_lint)]
|
||||
pub struct RemovedLint<'a> {
|
||||
pub name: &'a str,
|
||||
pub reason: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unknown_lint)]
|
||||
pub struct UnknownLint {
|
||||
|
|
|
|||
|
|
@ -56,20 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
|
|||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
// &mut <expr>
|
||||
let inner = if let ExprKind::AddrOf(_, Mutability::Mut, expr) = expr.kind {
|
||||
expr
|
||||
// <expr> = ...
|
||||
} else if let ExprKind::Assign(expr, _, _) = expr.kind {
|
||||
expr
|
||||
// <expr> += ...
|
||||
} else if let ExprKind::AssignOp(_, expr, _) = expr.kind {
|
||||
expr
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let ExprKind::Unary(UnOp::Deref, e) = &inner.kind else {
|
||||
let Some((is_assignment, e)) = is_operation_we_care_about(cx, expr) else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -86,15 +73,58 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
|
|||
cx.emit_spanned_lint(
|
||||
INVALID_REFERENCE_CASTING,
|
||||
expr.span,
|
||||
if matches!(expr.kind, ExprKind::AddrOf(..)) {
|
||||
InvalidReferenceCastingDiag::BorrowAsMut { orig_cast }
|
||||
} else {
|
||||
if is_assignment {
|
||||
InvalidReferenceCastingDiag::AssignToRef { orig_cast }
|
||||
} else {
|
||||
InvalidReferenceCastingDiag::BorrowAsMut { orig_cast }
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_operation_we_care_about<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
e: &'tcx Expr<'tcx>,
|
||||
) -> Option<(bool, &'tcx Expr<'tcx>)> {
|
||||
fn deref_assign_or_addr_of<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(bool, &'tcx Expr<'tcx>)> {
|
||||
// &mut <expr>
|
||||
let inner = if let ExprKind::AddrOf(_, Mutability::Mut, expr) = expr.kind {
|
||||
expr
|
||||
// <expr> = ...
|
||||
} else if let ExprKind::Assign(expr, _, _) = expr.kind {
|
||||
expr
|
||||
// <expr> += ...
|
||||
} else if let ExprKind::AssignOp(_, expr, _) = expr.kind {
|
||||
expr
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if let ExprKind::Unary(UnOp::Deref, e) = &inner.kind {
|
||||
Some((!matches!(expr.kind, ExprKind::AddrOf(..)), e))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn ptr_write<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
e: &'tcx Expr<'tcx>,
|
||||
) -> Option<(bool, &'tcx Expr<'tcx>)> {
|
||||
if let ExprKind::Call(path, [arg_ptr, _arg_val]) = e.kind
|
||||
&& let ExprKind::Path(ref qpath) = path.kind
|
||||
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
|
||||
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_write | sym::ptr_write_volatile | sym::ptr_write_unaligned))
|
||||
{
|
||||
Some((true, arg_ptr))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
deref_assign_or_addr_of(e).or_else(|| ptr_write(cx, e))
|
||||
}
|
||||
|
||||
fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
|
||||
let e = e.peel_blocks();
|
||||
|
||||
|
|
|
|||
|
|
@ -3376,6 +3376,7 @@ declare_lint_pass! {
|
|||
DEPRECATED_IN_FUTURE,
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||
DUPLICATE_MACRO_ATTRIBUTES,
|
||||
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
|
||||
ELIDED_LIFETIMES_IN_PATHS,
|
||||
EXPORTED_PRIVATE_DEPENDENCIES,
|
||||
FFI_UNWIND_CALLS,
|
||||
|
|
@ -4527,3 +4528,44 @@ declare_lint! {
|
|||
reference: "issue #114095 <https://github.com/rust-lang/rust/issues/114095>",
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `elided_lifetimes_in_associated_constant` lint detects elided lifetimes
|
||||
/// that were erroneously allowed in associated constants.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(elided_lifetimes_in_associated_constant)]
|
||||
///
|
||||
/// struct Foo;
|
||||
///
|
||||
/// impl Foo {
|
||||
/// const STR: &str = "hello, world";
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Previous version of Rust
|
||||
///
|
||||
/// Implicit static-in-const behavior was decided [against] for associated
|
||||
/// constants because of ambiguity. This, however, regressed and the compiler
|
||||
/// erroneously treats elided lifetimes in associated constants as lifetime
|
||||
/// parameters on the impl.
|
||||
///
|
||||
/// This is a [future-incompatible] lint to transition this to a
|
||||
/// hard error in the future.
|
||||
///
|
||||
/// [against]: https://github.com/rust-lang/rust/issues/38831
|
||||
/// [future-incompatible]: ../index.md#future-incompatible-lints
|
||||
pub ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
|
||||
Warn,
|
||||
"elided lifetimes cannot be used in associated constants in impls",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseError,
|
||||
reference: "issue #115010 <https://github.com/rust-lang/rust/issues/115010>",
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,9 @@ pub mod builtin;
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! pluralize {
|
||||
// Pluralize based on count (e.g., apples)
|
||||
($x:expr) => {
|
||||
if $x != 1 { "s" } else { "" }
|
||||
if $x == 1 { "" } else { "s" }
|
||||
};
|
||||
("has", $x:expr) => {
|
||||
if $x == 1 { "has" } else { "have" }
|
||||
|
|
@ -572,6 +573,10 @@ pub enum BuiltinLintDiagnostics {
|
|||
/// The span of the unnecessarily-qualified path to remove.
|
||||
removal_span: Span,
|
||||
},
|
||||
AssociatedConstElidedLifetime {
|
||||
elided: bool,
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
/// Lints that are buffered up early on in the `Session` before the
|
||||
|
|
|
|||
|
|
@ -203,7 +203,12 @@ LLVMRustWriteArchive(char *Dst, size_t NumMembers,
|
|||
}
|
||||
}
|
||||
|
||||
#if LLVM_VERSION_LT(18, 0)
|
||||
auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
|
||||
#else
|
||||
auto SymtabMode = WriteSymbtab ? SymtabWritingMode::NormalSymtab : SymtabWritingMode::NoSymtab;
|
||||
auto Result = writeArchive(Dst, Members, SymtabMode, Kind, true, false);
|
||||
#endif
|
||||
if (!Result)
|
||||
return LLVMRustResult::Success;
|
||||
LLVMRustSetLastError(toString(std::move(Result)).c_str());
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#![allow(rustc::default_hash_types)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![allow(internal_features)]
|
||||
#![recursion_limit = "128"]
|
||||
|
||||
use synstructure::decl_derive;
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@
|
|||
#![feature(macro_metavar_expr)]
|
||||
#![recursion_limit = "512"]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![allow(internal_features)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
|
|
|
|||
|
|
@ -1275,9 +1275,11 @@ impl<O> AssertKind<O> {
|
|||
matches!(self, OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..))
|
||||
}
|
||||
|
||||
/// Getting a description does not require `O` to be printable, and does not
|
||||
/// require allocation.
|
||||
/// The caller is expected to handle `BoundsCheck` and `MisalignedPointerDereference` separately.
|
||||
/// Get the message that is printed at runtime when this assertion fails.
|
||||
///
|
||||
/// The caller is expected to handle `BoundsCheck` and `MisalignedPointerDereference` by
|
||||
/// invoking the appropriate lang item (panic_bounds_check/panic_misaligned_pointer_dereference)
|
||||
/// instead of printing a static message.
|
||||
pub fn description(&self) -> &'static str {
|
||||
use AssertKind::*;
|
||||
match self {
|
||||
|
|
@ -1303,6 +1305,11 @@ impl<O> AssertKind<O> {
|
|||
}
|
||||
|
||||
/// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing.
|
||||
///
|
||||
/// Needs to be kept in sync with the run-time behavior (which is defined by
|
||||
/// `AssertKind::description` and the lang items mentioned in its docs).
|
||||
/// Note that we deliberately show more details here than we do at runtime, such as the actual
|
||||
/// numbers that overflowed -- it is much easier to do so here than at runtime.
|
||||
pub fn fmt_assert_args<W: Write>(&self, f: &mut W) -> fmt::Result
|
||||
where
|
||||
O: Debug,
|
||||
|
|
@ -1358,6 +1365,12 @@ impl<O> AssertKind<O> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Format the diagnostic message for use in a lint (e.g. when the assertion fails during const-eval).
|
||||
///
|
||||
/// Needs to be kept in sync with the run-time behavior (which is defined by
|
||||
/// `AssertKind::description` and the lang items mentioned in its docs).
|
||||
/// Note that we deliberately show more details here than we do at runtime, such as the actual
|
||||
/// numbers that overflowed -- it is much easier to do so here than at runtime.
|
||||
pub fn diagnostic_message(&self) -> DiagnosticMessage {
|
||||
use crate::fluent_generated::*;
|
||||
use AssertKind::*;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ pub struct MirPatch<'tcx> {
|
|||
resume_block: Option<BasicBlock>,
|
||||
// Only for unreachable in cleanup path.
|
||||
unreachable_cleanup_block: Option<BasicBlock>,
|
||||
terminate_block: Option<BasicBlock>,
|
||||
// Cached block for UnwindTerminate (with reason)
|
||||
terminate_block: Option<(BasicBlock, UnwindTerminateReason)>,
|
||||
body_span: Span,
|
||||
next_local: usize,
|
||||
}
|
||||
|
|
@ -35,13 +36,15 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
|
||||
for (bb, block) in body.basic_blocks.iter_enumerated() {
|
||||
// Check if we already have a resume block
|
||||
if let TerminatorKind::UnwindResume = block.terminator().kind && block.statements.is_empty() {
|
||||
if matches!(block.terminator().kind, TerminatorKind::UnwindResume)
|
||||
&& block.statements.is_empty()
|
||||
{
|
||||
result.resume_block = Some(bb);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if we already have an unreachable block
|
||||
if let TerminatorKind::Unreachable = block.terminator().kind
|
||||
if matches!(block.terminator().kind, TerminatorKind::Unreachable)
|
||||
&& block.statements.is_empty()
|
||||
&& block.is_cleanup
|
||||
{
|
||||
|
|
@ -50,8 +53,10 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
}
|
||||
|
||||
// Check if we already have a terminate block
|
||||
if let TerminatorKind::UnwindTerminate = block.terminator().kind && block.statements.is_empty() {
|
||||
result.terminate_block = Some(bb);
|
||||
if let TerminatorKind::UnwindTerminate(reason) = block.terminator().kind
|
||||
&& block.statements.is_empty()
|
||||
{
|
||||
result.terminate_block = Some((bb, reason));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -93,20 +98,20 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
bb
|
||||
}
|
||||
|
||||
pub fn terminate_block(&mut self) -> BasicBlock {
|
||||
if let Some(bb) = self.terminate_block {
|
||||
return bb;
|
||||
pub fn terminate_block(&mut self, reason: UnwindTerminateReason) -> BasicBlock {
|
||||
if let Some((cached_bb, cached_reason)) = self.terminate_block && reason == cached_reason {
|
||||
return cached_bb;
|
||||
}
|
||||
|
||||
let bb = self.new_block(BasicBlockData {
|
||||
statements: vec![],
|
||||
terminator: Some(Terminator {
|
||||
source_info: SourceInfo::outermost(self.body_span),
|
||||
kind: TerminatorKind::UnwindTerminate,
|
||||
kind: TerminatorKind::UnwindTerminate(reason),
|
||||
}),
|
||||
is_cleanup: true,
|
||||
});
|
||||
self.terminate_block = Some(bb);
|
||||
self.terminate_block = Some((bb, reason));
|
||||
bb
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -621,7 +621,7 @@ pub enum TerminatorKind<'tcx> {
|
|||
///
|
||||
/// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in
|
||||
/// cleanup blocks.
|
||||
UnwindTerminate,
|
||||
UnwindTerminate(UnwindTerminateReason),
|
||||
|
||||
/// Returns from the function.
|
||||
///
|
||||
|
|
@ -813,7 +813,7 @@ impl TerminatorKind<'_> {
|
|||
TerminatorKind::Goto { .. } => "Goto",
|
||||
TerminatorKind::SwitchInt { .. } => "SwitchInt",
|
||||
TerminatorKind::UnwindResume => "UnwindResume",
|
||||
TerminatorKind::UnwindTerminate => "UnwindTerminate",
|
||||
TerminatorKind::UnwindTerminate(_) => "UnwindTerminate",
|
||||
TerminatorKind::Return => "Return",
|
||||
TerminatorKind::Unreachable => "Unreachable",
|
||||
TerminatorKind::Drop { .. } => "Drop",
|
||||
|
|
@ -842,11 +842,22 @@ pub enum UnwindAction {
|
|||
/// Terminates the execution if unwind happens.
|
||||
///
|
||||
/// Depending on the platform and situation this may cause a non-unwindable panic or abort.
|
||||
Terminate,
|
||||
Terminate(UnwindTerminateReason),
|
||||
/// Cleanups to be done.
|
||||
Cleanup(BasicBlock),
|
||||
}
|
||||
|
||||
/// The reason we are terminating the process during unwinding.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub enum UnwindTerminateReason {
|
||||
/// Unwinding is just not possible given the ABI of this function.
|
||||
Abi,
|
||||
/// We were already cleaning up for an ongoing unwind, and a *second*, *nested* unwind was
|
||||
/// triggered by the drop glue.
|
||||
InCleanup,
|
||||
}
|
||||
|
||||
/// Information about an assertion failure.
|
||||
#[derive(Clone, Hash, HashStable, PartialEq, Debug)]
|
||||
#[derive(TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use rustc_hir::LangItem;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind, UnwindAction};
|
||||
|
|
@ -100,6 +101,40 @@ impl<'a> Iterator for SwitchTargetsIter<'a> {
|
|||
|
||||
impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
|
||||
|
||||
impl UnwindAction {
|
||||
fn cleanup_block(self) -> Option<BasicBlock> {
|
||||
match self {
|
||||
UnwindAction::Cleanup(bb) => Some(bb),
|
||||
UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UnwindTerminateReason {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
// Keep this in sync with the messages in `core/src/panicking.rs`.
|
||||
match self {
|
||||
UnwindTerminateReason::Abi => "panic in a function that cannot unwind",
|
||||
UnwindTerminateReason::InCleanup => "panic in a destructor during cleanup",
|
||||
}
|
||||
}
|
||||
|
||||
/// A short representation of this used for MIR printing.
|
||||
pub fn as_short_str(self) -> &'static str {
|
||||
match self {
|
||||
UnwindTerminateReason::Abi => "abi",
|
||||
UnwindTerminateReason::InCleanup => "cleanup",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lang_item(self) -> LangItem {
|
||||
match self {
|
||||
UnwindTerminateReason::Abi => LangItem::PanicCannotUnwind,
|
||||
UnwindTerminateReason::InCleanup => LangItem::PanicInCleanup,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Terminator<'tcx> {
|
||||
pub source_info: SourceInfo,
|
||||
|
|
@ -156,7 +191,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
Some(t).into_iter().chain((&[]).into_iter().copied())
|
||||
}
|
||||
UnwindResume
|
||||
| UnwindTerminate
|
||||
| UnwindTerminate(_)
|
||||
| GeneratorDrop
|
||||
| Return
|
||||
| Unreachable
|
||||
|
|
@ -198,7 +233,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
Some(t).into_iter().chain(&mut [])
|
||||
}
|
||||
UnwindResume
|
||||
| UnwindTerminate
|
||||
| UnwindTerminate(_)
|
||||
| GeneratorDrop
|
||||
| Return
|
||||
| Unreachable
|
||||
|
|
@ -215,7 +250,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
match *self {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::GeneratorDrop
|
||||
|
|
@ -234,7 +269,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
match *self {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::GeneratorDrop
|
||||
|
|
@ -271,18 +306,28 @@ impl<'tcx> Debug for TerminatorKind<'tcx> {
|
|||
let labels = self.fmt_successor_labels();
|
||||
assert_eq!(successor_count, labels.len());
|
||||
|
||||
let unwind = match self.unwind() {
|
||||
// Not needed or included in successors
|
||||
None | Some(UnwindAction::Cleanup(_)) => None,
|
||||
Some(UnwindAction::Continue) => Some("unwind continue"),
|
||||
Some(UnwindAction::Unreachable) => Some("unwind unreachable"),
|
||||
Some(UnwindAction::Terminate) => Some("unwind terminate"),
|
||||
// `Cleanup` is already included in successors
|
||||
let show_unwind = !matches!(self.unwind(), None | Some(UnwindAction::Cleanup(_)));
|
||||
let fmt_unwind = |fmt: &mut Formatter<'_>| -> fmt::Result {
|
||||
write!(fmt, "unwind ")?;
|
||||
match self.unwind() {
|
||||
// Not needed or included in successors
|
||||
None | Some(UnwindAction::Cleanup(_)) => unreachable!(),
|
||||
Some(UnwindAction::Continue) => write!(fmt, "continue"),
|
||||
Some(UnwindAction::Unreachable) => write!(fmt, "unreachable"),
|
||||
Some(UnwindAction::Terminate(reason)) => {
|
||||
write!(fmt, "terminate({})", reason.as_short_str())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match (successor_count, unwind) {
|
||||
(0, None) => Ok(()),
|
||||
(0, Some(unwind)) => write!(fmt, " -> {unwind}"),
|
||||
(1, None) => write!(fmt, " -> {:?}", self.successors().next().unwrap()),
|
||||
match (successor_count, show_unwind) {
|
||||
(0, false) => Ok(()),
|
||||
(0, true) => {
|
||||
write!(fmt, " -> ")?;
|
||||
fmt_unwind(fmt)
|
||||
}
|
||||
(1, false) => write!(fmt, " -> {:?}", self.successors().next().unwrap()),
|
||||
_ => {
|
||||
write!(fmt, " -> [")?;
|
||||
for (i, target) in self.successors().enumerate() {
|
||||
|
|
@ -291,8 +336,9 @@ impl<'tcx> Debug for TerminatorKind<'tcx> {
|
|||
}
|
||||
write!(fmt, "{}: {:?}", labels[i], target)?;
|
||||
}
|
||||
if let Some(unwind) = unwind {
|
||||
write!(fmt, ", {unwind}")?;
|
||||
if show_unwind {
|
||||
write!(fmt, ", ")?;
|
||||
fmt_unwind(fmt)?;
|
||||
}
|
||||
write!(fmt, "]")
|
||||
}
|
||||
|
|
@ -312,7 +358,9 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
Return => write!(fmt, "return"),
|
||||
GeneratorDrop => write!(fmt, "generator_drop"),
|
||||
UnwindResume => write!(fmt, "resume"),
|
||||
UnwindTerminate => write!(fmt, "abort"),
|
||||
UnwindTerminate(reason) => {
|
||||
write!(fmt, "abort({})", reason.as_short_str())
|
||||
}
|
||||
Yield { value, resume_arg, .. } => write!(fmt, "{resume_arg:?} = yield({value:?})"),
|
||||
Unreachable => write!(fmt, "unreachable"),
|
||||
Drop { place, .. } => write!(fmt, "drop({place:?})"),
|
||||
|
|
@ -391,7 +439,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
|
||||
use self::TerminatorKind::*;
|
||||
match *self {
|
||||
Return | UnwindResume | UnwindTerminate | Unreachable | GeneratorDrop => vec![],
|
||||
Return | UnwindResume | UnwindTerminate(_) | Unreachable | GeneratorDrop => vec![],
|
||||
Goto { .. } => vec!["".into()],
|
||||
SwitchInt { ref targets, .. } => targets
|
||||
.values
|
||||
|
|
@ -443,7 +491,8 @@ pub enum TerminatorEdges<'mir, 'tcx> {
|
|||
/// Special action for `Yield`, `Call` and `InlineAsm` terminators.
|
||||
AssignOnReturn {
|
||||
return_: Option<BasicBlock>,
|
||||
unwind: UnwindAction,
|
||||
/// The cleanup block, if it exists.
|
||||
cleanup: Option<BasicBlock>,
|
||||
place: CallReturnPlaces<'mir, 'tcx>,
|
||||
},
|
||||
/// Special edge for `SwitchInt`.
|
||||
|
|
@ -486,7 +535,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
|
||||
use TerminatorKind::*;
|
||||
match *self {
|
||||
Return | UnwindResume | UnwindTerminate | GeneratorDrop | Unreachable => {
|
||||
Return | UnwindResume | UnwindTerminate(_) | GeneratorDrop | Unreachable => {
|
||||
TerminatorEdges::None
|
||||
}
|
||||
|
||||
|
|
@ -496,7 +545,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
| Drop { target, unwind, place: _, replace: _ }
|
||||
| FalseUnwind { real_target: target, unwind } => match unwind {
|
||||
UnwindAction::Cleanup(unwind) => TerminatorEdges::Double(target, unwind),
|
||||
UnwindAction::Continue | UnwindAction::Terminate | UnwindAction::Unreachable => {
|
||||
UnwindAction::Continue | UnwindAction::Terminate(_) | UnwindAction::Unreachable => {
|
||||
TerminatorEdges::Single(target)
|
||||
}
|
||||
},
|
||||
|
|
@ -508,7 +557,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
Yield { resume: target, drop, resume_arg, value: _ } => {
|
||||
TerminatorEdges::AssignOnReturn {
|
||||
return_: Some(target),
|
||||
unwind: drop.map_or(UnwindAction::Terminate, UnwindAction::Cleanup),
|
||||
cleanup: drop,
|
||||
place: CallReturnPlaces::Yield(resume_arg),
|
||||
}
|
||||
}
|
||||
|
|
@ -516,7 +565,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
Call { unwind, destination, target, func: _, args: _, fn_span: _, call_source: _ } => {
|
||||
TerminatorEdges::AssignOnReturn {
|
||||
return_: target,
|
||||
unwind,
|
||||
cleanup: unwind.cleanup_block(),
|
||||
place: CallReturnPlaces::Call(destination),
|
||||
}
|
||||
}
|
||||
|
|
@ -530,7 +579,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
unwind,
|
||||
} => TerminatorEdges::AssignOnReturn {
|
||||
return_: destination,
|
||||
unwind,
|
||||
cleanup: unwind.cleanup_block(),
|
||||
place: CallReturnPlaces::InlineAsm(operands),
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ macro_rules! make_mir_visitor {
|
|||
match kind {
|
||||
TerminatorKind::Goto { .. } |
|
||||
TerminatorKind::UnwindResume |
|
||||
TerminatorKind::UnwindTerminate |
|
||||
TerminatorKind::UnwindTerminate(_) |
|
||||
TerminatorKind::GeneratorDrop |
|
||||
TerminatorKind::Unreachable |
|
||||
TerminatorKind::FalseEdge { .. } |
|
||||
|
|
|
|||
|
|
@ -2150,6 +2150,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
for attr in self.get_attrs(did, sym::repr) {
|
||||
for r in attr::parse_repr_attr(&self.sess, attr) {
|
||||
flags.insert(match r {
|
||||
attr::ReprRust => ReprFlags::empty(),
|
||||
attr::ReprC => ReprFlags::IS_C,
|
||||
attr::ReprPacked(pack) => {
|
||||
let pack = Align::from_bytes(pack as u64).unwrap();
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
|
|||
/// Construct the MIR for a given `DefId`.
|
||||
fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
|
||||
// Ensure unsafeck and abstract const building is ran before we steal the THIR.
|
||||
tcx.ensure_with_value().thir_check_unsafety(def);
|
||||
tcx.ensure_with_value()
|
||||
.thir_check_unsafety(tcx.typeck_root_def_id(def.to_def_id()).expect_local());
|
||||
tcx.ensure_with_value().thir_abstract_const(def);
|
||||
if let Err(e) = tcx.check_match(def) {
|
||||
return construct_error(tcx, def, e);
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ impl DropTree {
|
|||
let terminator = TerminatorKind::Drop {
|
||||
target: blocks[drop_data.1].unwrap(),
|
||||
// The caller will handle this if needed.
|
||||
unwind: UnwindAction::Terminate,
|
||||
unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
|
||||
place: drop_data.0.local.into(),
|
||||
replace: false,
|
||||
};
|
||||
|
|
@ -1507,7 +1507,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
|
|||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::SwitchInt { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Yield { .. }
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ impl<'mir, 'tcx, C: TerminatorClassifier<'tcx>> TriColorVisitor<BasicBlocks<'tcx
|
|||
|
||||
match self.body[bb].terminator().kind {
|
||||
// These terminators return control flow to the caller.
|
||||
TerminatorKind::UnwindTerminate
|
||||
TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::Return
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use crate::errors::*;
|
|||
|
||||
use rustc_arena::TypedArena;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::{
|
||||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
|
||||
|
|
@ -660,6 +661,17 @@ fn report_arm_reachability<'p, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_non_exhaustive_tys<'p, 'tcx>(
|
||||
pat: &DeconstructedPat<'p, 'tcx>,
|
||||
non_exhaustive_tys: &mut FxHashSet<Ty<'tcx>>,
|
||||
) {
|
||||
if matches!(pat.ctor(), Constructor::NonExhaustive) {
|
||||
non_exhaustive_tys.insert(pat.ty());
|
||||
}
|
||||
pat.iter_fields()
|
||||
.for_each(|field_pat| collect_non_exhaustive_tys(field_pat, non_exhaustive_tys))
|
||||
}
|
||||
|
||||
/// Report that a match is not exhaustive.
|
||||
fn non_exhaustive_match<'p, 'tcx>(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
|
|
@ -717,22 +729,27 @@ fn non_exhaustive_match<'p, 'tcx>(
|
|||
scrut_ty,
|
||||
if is_variant_list_non_exhaustive { ", which is marked as non-exhaustive" } else { "" }
|
||||
));
|
||||
if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize)
|
||||
&& !is_empty_match
|
||||
&& witnesses.len() == 1
|
||||
&& matches!(witnesses[0].ctor(), Constructor::NonExhaustive)
|
||||
{
|
||||
err.note(format!(
|
||||
"`{scrut_ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
|
||||
exhaustively",
|
||||
));
|
||||
if cx.tcx.sess.is_nightly_build() {
|
||||
err.help(format!(
|
||||
"add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
|
||||
enable precise `{scrut_ty}` matching",
|
||||
));
|
||||
|
||||
if !is_empty_match && witnesses.len() == 1 {
|
||||
let mut non_exhaustive_tys = FxHashSet::default();
|
||||
collect_non_exhaustive_tys(&witnesses[0], &mut non_exhaustive_tys);
|
||||
|
||||
for ty in non_exhaustive_tys {
|
||||
if ty == cx.tcx.types.usize || ty == cx.tcx.types.isize {
|
||||
err.note(format!(
|
||||
"`{ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
|
||||
exhaustively",
|
||||
));
|
||||
if cx.tcx.sess.is_nightly_build() {
|
||||
err.help(format!(
|
||||
"add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
|
||||
enable precise `{ty}` matching",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let ty::Ref(_, sub_ty, _) = scrut_ty.kind() {
|
||||
if !sub_ty.is_inhabited_from(cx.tcx, cx.module, cx.param_env) {
|
||||
err.note("references are always considered inhabited");
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ impl Unwind {
|
|||
fn into_action(self) -> UnwindAction {
|
||||
match self {
|
||||
Unwind::To(bb) => UnwindAction::Cleanup(bb),
|
||||
Unwind::InCleanup => UnwindAction::Terminate,
|
||||
Unwind::InCleanup => UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_middle::mir::{
|
||||
self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges, UnwindAction,
|
||||
self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges,
|
||||
};
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
|
|
@ -486,10 +486,10 @@ impl Direction for Forward {
|
|||
propagate(target, exit_state);
|
||||
propagate(unwind, exit_state);
|
||||
}
|
||||
TerminatorEdges::AssignOnReturn { return_, unwind, place } => {
|
||||
TerminatorEdges::AssignOnReturn { return_, cleanup, place } => {
|
||||
// This must be done *first*, otherwise the unwind path will see the assignments.
|
||||
if let UnwindAction::Cleanup(unwind) = unwind {
|
||||
propagate(unwind, exit_state);
|
||||
if let Some(cleanup) = cleanup {
|
||||
propagate(cleanup, exit_state);
|
||||
}
|
||||
if let Some(return_) = return_ {
|
||||
analysis.apply_call_return_effect(exit_state, bb, place);
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
TerminatorKind::UnwindTerminate
|
||||
TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::Call { .. }
|
||||
| TerminatorKind::FalseEdge { .. }
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
|
|||
|
||||
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
||||
// variants are added.
|
||||
TerminatorKind::UnwindTerminate
|
||||
TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::Drop { .. }
|
||||
| TerminatorKind::FalseEdge { .. }
|
||||
|
|
@ -328,7 +328,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
|
|||
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
||||
// variants are added.
|
||||
TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::Drop { .. }
|
||||
| TerminatorKind::FalseEdge { .. }
|
||||
|
|
|
|||
|
|
@ -371,7 +371,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
// need recording.
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Drop { .. } => {}
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ pub trait ValueAnalysis<'tcx> {
|
|||
}
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Assert { .. }
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
|
|||
|
||||
for id in calls_to_terminate {
|
||||
let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap();
|
||||
*cleanup = UnwindAction::Terminate;
|
||||
*cleanup = UnwindAction::Terminate(UnwindTerminateReason::Abi);
|
||||
}
|
||||
|
||||
for id in cleanups_to_remove {
|
||||
|
|
|
|||
|
|
@ -53,8 +53,10 @@ impl AddCallGuards {
|
|||
kind: TerminatorKind::Call { target: Some(ref mut destination), unwind, .. },
|
||||
source_info,
|
||||
}) if pred_count[*destination] > 1
|
||||
&& (matches!(unwind, UnwindAction::Cleanup(_) | UnwindAction::Terminate)
|
||||
|| self == &AllCallEdges) =>
|
||||
&& (matches!(
|
||||
unwind,
|
||||
UnwindAction::Cleanup(_) | UnwindAction::Terminate(_)
|
||||
) || self == &AllCallEdges) =>
|
||||
{
|
||||
// It's a critical edge, break it
|
||||
let call_guard = BasicBlockData {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
|
|||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::FalseEdge { .. }
|
||||
|
|
|
|||
|
|
@ -679,7 +679,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
|||
// None of these have Operands to const-propagate.
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Drop { .. }
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ impl CoverageGraph {
|
|||
|
||||
match term.kind {
|
||||
TerminatorKind::Return { .. }
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::SwitchInt { .. } => {
|
||||
// The `bb` has more than one _outgoing_ edge, or exits the function. Save the
|
||||
|
|
|
|||
|
|
@ -868,7 +868,7 @@ pub(super) fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Sp
|
|||
|
||||
// Retain spans from all other terminators
|
||||
TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::GeneratorDrop
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
//! will still not cause any further changes.
|
||||
//!
|
||||
|
||||
use crate::util::is_within_packed;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::*;
|
||||
|
|
@ -49,6 +50,11 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
|
|||
&& !place.is_indirect()
|
||||
&& !borrowed.contains(place.local)
|
||||
&& !state.contains(place.local)
|
||||
// If `place` is a projection of a disaligned field in a packed ADT,
|
||||
// the move may be codegened as a pointer to that field.
|
||||
// Using that disaligned pointer may trigger UB in the callee,
|
||||
// so do nothing.
|
||||
&& is_within_packed(tcx, body, place).is_none()
|
||||
{
|
||||
call_operands_to_move.push((bb, index));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -648,7 +648,7 @@ impl WriteInfo {
|
|||
}
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable { .. } => (),
|
||||
TerminatorKind::Drop { .. } => {
|
||||
|
|
|
|||
|
|
@ -362,8 +362,13 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
UnwindAction::Unreachable => {
|
||||
Unwind::To(self.patch.unreachable_cleanup_block())
|
||||
}
|
||||
UnwindAction::Terminate => {
|
||||
Unwind::To(self.patch.terminate_block())
|
||||
UnwindAction::Terminate(reason) => {
|
||||
debug_assert_ne!(
|
||||
reason,
|
||||
UnwindTerminateReason::InCleanup,
|
||||
"we are not in a cleanup block, InCleanup reason should be impossible"
|
||||
);
|
||||
Unwind::To(self.patch.terminate_block(reason))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -496,7 +501,8 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
if let TerminatorKind::Call {
|
||||
destination,
|
||||
target: Some(_),
|
||||
unwind: UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate,
|
||||
unwind:
|
||||
UnwindAction::Continue | UnwindAction::Unreachable | UnwindAction::Terminate(_),
|
||||
..
|
||||
} = data.terminator().kind
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1091,7 +1091,7 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
UnwindAction::Cleanup(tgt) => tgt,
|
||||
UnwindAction::Continue => elaborator.patch.resume_block(),
|
||||
UnwindAction::Unreachable => elaborator.patch.unreachable_cleanup_block(),
|
||||
UnwindAction::Terminate => elaborator.patch.terminate_block(),
|
||||
UnwindAction::Terminate(reason) => elaborator.patch.terminate_block(reason),
|
||||
})
|
||||
};
|
||||
elaborate_drop(
|
||||
|
|
@ -1239,7 +1239,7 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
|
|||
// These never unwind.
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::SwitchInt { .. }
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::GeneratorDrop
|
||||
|
|
@ -1759,7 +1759,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
|
|||
| TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::SwitchInt { .. }
|
||||
| TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Drop { .. }
|
||||
|
|
|
|||
|
|
@ -906,12 +906,12 @@ impl Integrator<'_, '_> {
|
|||
UnwindAction::Cleanup(_) | UnwindAction::Continue => {
|
||||
bug!("cleanup on cleanup block");
|
||||
}
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate => return unwind,
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate(_) => return unwind,
|
||||
}
|
||||
}
|
||||
|
||||
match unwind {
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate => unwind,
|
||||
UnwindAction::Unreachable | UnwindAction::Terminate(_) => unwind,
|
||||
UnwindAction::Cleanup(target) => UnwindAction::Cleanup(self.map_block(target)),
|
||||
// Add an unwind edge to the original call's cleanup block
|
||||
UnwindAction::Continue => self.cleanup_block,
|
||||
|
|
@ -1022,10 +1022,10 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
|
|||
UnwindAction::Cleanup(tgt) => TerminatorKind::Goto { target: tgt },
|
||||
UnwindAction::Continue => TerminatorKind::UnwindResume,
|
||||
UnwindAction::Unreachable => TerminatorKind::Unreachable,
|
||||
UnwindAction::Terminate => TerminatorKind::UnwindTerminate,
|
||||
UnwindAction::Terminate(reason) => TerminatorKind::UnwindTerminate(reason),
|
||||
};
|
||||
}
|
||||
TerminatorKind::UnwindTerminate => {}
|
||||
TerminatorKind::UnwindTerminate(_) => {}
|
||||
TerminatorKind::Unreachable => {}
|
||||
TerminatorKind::FalseEdge { ref mut real_target, ref mut imaginary_target } => {
|
||||
*real_target = self.map_block(*real_target);
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ impl RemoveNoopLandingPads {
|
|||
TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Call { .. }
|
||||
| TerminatorKind::Assert { .. }
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
|
|||
| TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::FalseUnwind { .. }
|
||||
| TerminatorKind::Yield { .. }
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::InlineAsm { .. }
|
||||
|
|
@ -166,7 +166,7 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
|
|||
}
|
||||
|
||||
TerminatorKind::UnwindResume
|
||||
| TerminatorKind::UnwindTerminate
|
||||
| TerminatorKind::UnwindTerminate(_)
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::GeneratorDrop
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue