/// Allows associated types in inherent impls.
(active, inherent_associated_types, "1.52.0", Some(8995), None),
+ // Allows setting the threshold for the `large_assignments` lint.
+ (active, large_assignments, "1.52.0", Some(83518), None),
+
/// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries.
(active, c_unwind, "1.52.0", Some(74990), None),
const_eval_limit, CrateLevel, template!(NameValueStr: "N"), const_eval_limit,
experimental!(const_eval_limit)
),
+ gated!(
+ move_size_limit, CrateLevel, template!(NameValueStr: "N"), large_assignments,
+ experimental!(move_size_limit)
+ ),
// Entry point:
ungated!(main, Normal, template!(Word)),
/// This lint will trigger on all sites of large moves and thus allow the
/// user to resolve them in code.
pub LARGE_ASSIGNMENTS,
- Allow,
+ Warn,
"detects large moves or copies",
}
-//! Registering limits, recursion_limit, type_length_limit and const_eval_limit
+//! Registering limits:
+//! * recursion_limit,
+//! * move_size_limit,
+//! * type_length_limit, and
+//! * const_eval_limit
//!
//! There are various parts of the compiler that must impose arbitrary limits
//! on how deeply they recurse to prevent stack overflow. Users can override
use crate::bug;
use rustc_ast as ast;
use rustc_data_structures::sync::OnceCell;
-use rustc_session::{Limit, Session};
+use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
use std::num::IntErrorKind;
pub fn update_limits(sess: &Session, krate: &ast::Crate) {
update_limit(sess, krate, &sess.recursion_limit, sym::recursion_limit, 128);
+ update_limit(sess, krate, &sess.move_size_limit, sym::move_size_limit, 0);
update_limit(sess, krate, &sess.type_length_limit, sym::type_length_limit, 1048576);
update_limit(sess, krate, &sess.const_eval_limit, sym::const_eval_limit, 1_000_000);
}
fn update_limit(
sess: &Session,
krate: &ast::Crate,
- limit: &OnceCell<Limit>,
+ limit: &OnceCell<impl From<usize> + std::fmt::Debug>,
name: Symbol,
default: usize,
) {
if let Some(s) = attr.value_str() {
match s.as_str().parse() {
Ok(n) => {
- limit.set(Limit::new(n)).unwrap();
+ limit.set(From::from(n)).unwrap();
return;
}
Err(e) => {
}
}
}
- limit.set(Limit::new(default)).unwrap();
+ limit.set(From::from(default)).unwrap();
}
fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
self.super_operand(operand, location);
+ let limit = self.tcx.sess.move_size_limit();
+ if limit == 0 {
+ return;
+ }
+ let limit = Size::from_bytes(limit);
let ty = operand.ty(self.body, self.tcx);
let ty = self.monomorphize(ty);
let layout = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty));
if let Ok(layout) = layout {
- if layout.size > Size::from_bytes(1000) {
+ if layout.size > limit {
debug!(?layout);
let source_info = self.body.source_info(location);
debug!(?source_info);
}
}
+impl From<usize> for Limit {
+ fn from(value: usize) -> Self {
+ Self::new(value)
+ }
+}
+
impl fmt::Display for Limit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
/// operations such as auto-dereference and monomorphization.
pub recursion_limit: OnceCell<Limit>,
+ /// The size at which the `large_assignments` lint starts
+ /// being emitted.
+ pub move_size_limit: OnceCell<usize>,
+
/// The maximum length of types during monomorphization.
pub type_length_limit: OnceCell<Limit>,
self.recursion_limit.get().copied().unwrap()
}
+ #[inline]
+ pub fn move_size_limit(&self) -> usize {
+ self.move_size_limit.get().copied().unwrap()
+ }
+
#[inline]
pub fn type_length_limit(&self) -> Limit {
self.type_length_limit.get().copied().unwrap()
features: OnceCell::new(),
lint_store: OnceCell::new(),
recursion_limit: OnceCell::new(),
+ move_size_limit: OnceCell::new(),
type_length_limit: OnceCell::new(),
const_eval_limit: OnceCell::new(),
incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
label_break_value,
lang,
lang_items,
+ large_assignments,
lateout,
lazy_normalization_consts,
le,
more_struct_aliases,
movbe_target_feature,
move_ref_pattern,
+ move_size_limit,
mul,
mul_assign,
mul_with_overflow,
#![deny(large_assignments)]
+#![feature(large_assignments)]
+#![move_size_limit = "1000"]
// build-fail
// edition:2018
error: moving 10024 bytes
- --> $DIR/large_moves.rs:7:13
+ --> $DIR/large_moves.rs:9:13
|
LL | let x = async {
| _____________^
| ^^^^^^^^^^^^^^^^^
error: moving 10024 bytes
- --> $DIR/large_moves.rs:13:14
+ --> $DIR/large_moves.rs:15:14
|
LL | let z = (x, 42);
| ^ value moved from here
error: moving 10024 bytes
- --> $DIR/large_moves.rs:13:13
+ --> $DIR/large_moves.rs:15:13
|
LL | let z = (x, 42);
| ^^^^^^^ value moved from here
error: moving 10024 bytes
- --> $DIR/large_moves.rs:15:13
+ --> $DIR/large_moves.rs:17:13
|
LL | let a = z.0;
| ^^^ value moved from here
--- /dev/null
+// check that `move_size_limit is feature-gated
+
+#![move_size_limit = "42"] //~ ERROR the `#[move_size_limit]` attribute is an experimental feature
+
+fn main() {}
--- /dev/null
+error[E0658]: the `#[move_size_limit]` attribute is an experimental feature
+ --> $DIR/feature-gate-large-assignments.rs:3:1
+ |
+LL | #![move_size_limit = "42"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #83518 <https://github.com/rust-lang/rust/issues/83518> for more information
+ = help: add `#![feature(large_assignments)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.