Skip to content

Commit 01ad0ad

Browse files
committed
Auto merge of #94787 - matthiaskrgr:rollup-yyou15f, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #91804 (Make some `Clone` impls `const`) - #92541 (Mention intent of `From` trait in its docs) - #93057 (Add Iterator::collect_into) - #94739 (Suggest `if let`/`let_else` for refutable pat in `let`) - #94754 (Warn users about `||` in let chain expressions) - #94763 (Add documentation about lifetimes to thread::scope.) - #94768 (Ignore `close_read_wakes_up` test on SGX platform) - #94772 (Add miri to the well known conditional compilation names and values) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 85ce7fd + 94f5f1f commit 01ad0ad

36 files changed

+527
-173
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

+65-39
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ struct AstValidator<'a> {
6464
/// certain positions.
6565
is_assoc_ty_bound_banned: bool,
6666

67-
/// Used to allow `let` expressions in certain syntactic locations.
68-
is_let_allowed: bool,
67+
/// See [ForbiddenLetReason]
68+
forbidden_let_reason: Option<ForbiddenLetReason>,
6969

7070
lint_buffer: &'a mut LintBuffer,
7171
}
@@ -103,20 +103,28 @@ impl<'a> AstValidator<'a> {
103103
self.is_tilde_const_allowed = old;
104104
}
105105

106-
fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) {
107-
let old = mem::replace(&mut self.is_let_allowed, allowed);
106+
fn with_let_management(
107+
&mut self,
108+
forbidden_let_reason: Option<ForbiddenLetReason>,
109+
f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
110+
) {
111+
let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
108112
f(self, old);
109-
self.is_let_allowed = old;
113+
self.forbidden_let_reason = old;
110114
}
111115

112116
/// Emits an error banning the `let` expression provided in the given location.
113-
fn ban_let_expr(&self, expr: &'a Expr) {
117+
fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
114118
let sess = &self.session;
115119
if sess.opts.unstable_features.is_nightly_build() {
116-
sess.struct_span_err(expr.span, "`let` expressions are not supported here")
117-
.note("only supported directly in conditions of `if`- and `while`-expressions")
118-
.note("as well as when nested within `&&` and parentheses in those conditions")
119-
.emit();
120+
let err = "`let` expressions are not supported here";
121+
let mut diag = sess.struct_span_err(expr.span, err);
122+
diag.note("only supported directly in conditions of `if` and `while` expressions");
123+
diag.note("as well as when nested within `&&` and parentheses in those conditions");
124+
if let ForbiddenLetReason::ForbiddenWithOr(span) = forbidden_let_reason {
125+
diag.span_note(span, "`||` operators are not allowed in let chain expressions");
126+
}
127+
diag.emit();
120128
} else {
121129
sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
122130
.note("variable declaration using `let` is a statement")
@@ -988,39 +996,48 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
988996
}
989997

990998
fn visit_expr(&mut self, expr: &'a Expr) {
991-
self.with_let_allowed(false, |this, let_allowed| match &expr.kind {
992-
ExprKind::If(cond, then, opt_else) => {
993-
this.visit_block(then);
994-
walk_list!(this, visit_expr, opt_else);
995-
this.with_let_allowed(true, |this, _| this.visit_expr(cond));
996-
return;
997-
}
998-
ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
999-
ExprKind::Match(expr, arms) => {
1000-
this.visit_expr(expr);
1001-
for arm in arms {
1002-
this.visit_expr(&arm.body);
1003-
this.visit_pat(&arm.pat);
1004-
walk_list!(this, visit_attribute, &arm.attrs);
1005-
if let Some(ref guard) = arm.guard {
1006-
if let ExprKind::Let(_, ref expr, _) = guard.kind {
1007-
this.with_let_allowed(true, |this, _| this.visit_expr(expr));
999+
self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
1000+
match &expr.kind {
1001+
ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
1002+
let forbidden_let_reason = Some(ForbiddenLetReason::ForbiddenWithOr(*span));
1003+
this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(lhs));
1004+
this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(rhs));
1005+
}
1006+
ExprKind::If(cond, then, opt_else) => {
1007+
this.visit_block(then);
1008+
walk_list!(this, visit_expr, opt_else);
1009+
this.with_let_management(None, |this, _| this.visit_expr(cond));
1010+
return;
1011+
}
1012+
ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
1013+
this.ban_let_expr(expr, elem);
1014+
},
1015+
ExprKind::Match(scrutinee, arms) => {
1016+
this.visit_expr(scrutinee);
1017+
for arm in arms {
1018+
this.visit_expr(&arm.body);
1019+
this.visit_pat(&arm.pat);
1020+
walk_list!(this, visit_attribute, &arm.attrs);
1021+
if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
1022+
this.with_let_management(None, |this, _| {
1023+
this.visit_expr(guard_expr)
1024+
});
10081025
return;
10091026
}
10101027
}
10111028
}
1029+
ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
1030+
this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
1031+
return;
1032+
}
1033+
ExprKind::While(cond, then, opt_label) => {
1034+
walk_list!(this, visit_label, opt_label);
1035+
this.visit_block(then);
1036+
this.with_let_management(None, |this, _| this.visit_expr(cond));
1037+
return;
1038+
}
1039+
_ => visit::walk_expr(this, expr),
10121040
}
1013-
ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
1014-
this.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
1015-
return;
1016-
}
1017-
ExprKind::While(cond, then, opt_label) => {
1018-
walk_list!(this, visit_label, opt_label);
1019-
this.visit_block(then);
1020-
this.with_let_allowed(true, |this, _| this.visit_expr(cond));
1021-
return;
1022-
}
1023-
_ => visit::walk_expr(this, expr),
10241041
});
10251042
}
10261043

@@ -1772,10 +1789,19 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
17721789
is_tilde_const_allowed: false,
17731790
is_impl_trait_banned: false,
17741791
is_assoc_ty_bound_banned: false,
1775-
is_let_allowed: false,
1792+
forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
17761793
lint_buffer: lints,
17771794
};
17781795
visit::walk_crate(&mut validator, krate);
17791796

17801797
validator.has_proc_macro_decls
17811798
}
1799+
1800+
/// Used to forbid `let` expressions in certain syntactic locations.
1801+
#[derive(Clone, Copy)]
1802+
enum ForbiddenLetReason {
1803+
/// A let chain with the `||` operator
1804+
ForbiddenWithOr(Span),
1805+
/// `let` is not valid and the source environment is not important
1806+
GenericForbidden,
1807+
}

compiler/rustc_ast_passes/src/lib.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
//!
55
//! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
66
7-
#![feature(iter_is_partitioned)]
7+
#![allow(rustc::potential_query_instability)]
88
#![feature(box_patterns)]
9+
#![feature(if_let_guard)]
10+
#![feature(iter_is_partitioned)]
11+
#![feature(let_chains)]
912
#![feature(let_else)]
1013
#![recursion_limit = "256"]
11-
#![allow(rustc::potential_query_instability)]
1214

1315
pub mod ast_validation;
1416
pub mod feature_gate;

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+79-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use super::{PatCtxt, PatternError};
77
use rustc_arena::TypedArena;
88
use rustc_ast::Mutability;
99
use rustc_errors::{
10-
error_code, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
10+
error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
11+
ErrorGuaranteed,
1112
};
1213
use rustc_hir as hir;
1314
use rustc_hir::def::*;
@@ -20,7 +21,7 @@ use rustc_session::lint::builtin::{
2021
};
2122
use rustc_session::Session;
2223
use rustc_span::source_map::Spanned;
23-
use rustc_span::{DesugaringKind, ExpnKind, MultiSpan, Span};
24+
use rustc_span::{BytePos, DesugaringKind, ExpnKind, MultiSpan, Span};
2425

2526
crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
2627
let body_id = match def_id.as_local() {
@@ -241,6 +242,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
241242
}
242243

243244
let joined_patterns = joined_uncovered_patterns(&cx, &witnesses);
245+
246+
let mut bindings = vec![];
247+
244248
let mut err = struct_span_err!(
245249
self.tcx.sess,
246250
pat.span,
@@ -257,6 +261,16 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
257261
false
258262
}
259263
_ => {
264+
pat.walk(&mut |pat: &hir::Pat<'_>| {
265+
match pat.kind {
266+
hir::PatKind::Binding(_, _, ident, _) => {
267+
bindings.push(ident);
268+
}
269+
_ => {}
270+
}
271+
true
272+
});
273+
260274
err.span_label(pat.span, pattern_not_covered_label(&witnesses, &joined_patterns));
261275
true
262276
}
@@ -267,13 +281,71 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
267281
"`let` bindings require an \"irrefutable pattern\", like a `struct` or \
268282
an `enum` with only one variant",
269283
);
270-
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
271-
err.span_suggestion(
272-
span,
273-
"you might want to use `if let` to ignore the variant that isn't matched",
274-
format!("if {} {{ /* */ }}", &snippet[..snippet.len() - 1]),
284+
if self.tcx.sess.source_map().span_to_snippet(span).is_ok() {
285+
let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1));
286+
let start_span = span.shrink_to_lo();
287+
let end_span = semi_span.shrink_to_lo();
288+
err.multipart_suggestion(
289+
&format!(
290+
"you might want to use `if let` to ignore the variant{} that {} matched",
291+
pluralize!(witnesses.len()),
292+
match witnesses.len() {
293+
1 => "isn't",
294+
_ => "aren't",
295+
},
296+
),
297+
vec![
298+
match &bindings[..] {
299+
[] => (start_span, "if ".to_string()),
300+
[binding] => (start_span, format!("let {} = if ", binding)),
301+
bindings => (
302+
start_span,
303+
format!(
304+
"let ({}) = if ",
305+
bindings
306+
.iter()
307+
.map(|ident| ident.to_string())
308+
.collect::<Vec<_>>()
309+
.join(", ")
310+
),
311+
),
312+
},
313+
match &bindings[..] {
314+
[] => (semi_span, " { todo!() }".to_string()),
315+
[binding] => {
316+
(end_span, format!(" {{ {} }} else {{ todo!() }}", binding))
317+
}
318+
bindings => (
319+
end_span,
320+
format!(
321+
" {{ ({}) }} else {{ todo!() }}",
322+
bindings
323+
.iter()
324+
.map(|ident| ident.to_string())
325+
.collect::<Vec<_>>()
326+
.join(", ")
327+
),
328+
),
329+
},
330+
],
275331
Applicability::HasPlaceholders,
276332
);
333+
if !bindings.is_empty() && cx.tcx.sess.is_nightly_build() {
334+
err.span_suggestion_verbose(
335+
semi_span.shrink_to_lo(),
336+
&format!(
337+
"alternatively, on nightly, you might want to use \
338+
`#![feature(let_else)]` to handle the variant{} that {} matched",
339+
pluralize!(witnesses.len()),
340+
match witnesses.len() {
341+
1 => "isn't",
342+
_ => "aren't",
343+
},
344+
),
345+
" else { todo!() }".to_string(),
346+
Applicability::HasPlaceholders,
347+
);
348+
}
277349
}
278350
err.note(
279351
"for more information, visit \

compiler/rustc_session/src/config.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,7 @@ impl CrateCheckConfig {
10721072
// NOTE: This should be kept in sync with `default_configuration` and
10731073
// `fill_well_known_values`
10741074
const WELL_KNOWN_NAMES: &[Symbol] = &[
1075+
// rustc
10751076
sym::unix,
10761077
sym::windows,
10771078
sym::target_os,
@@ -1091,9 +1092,12 @@ impl CrateCheckConfig {
10911092
sym::debug_assertions,
10921093
sym::proc_macro,
10931094
sym::test,
1095+
sym::feature,
1096+
// rustdoc
10941097
sym::doc,
10951098
sym::doctest,
1096-
sym::feature,
1099+
// miri
1100+
sym::miri,
10971101
];
10981102

10991103
// We only insert well-known names if `names()` was activated
@@ -1128,13 +1132,14 @@ impl CrateCheckConfig {
11281132

11291133
// No-values
11301134
for name in [
1135+
sym::doc,
1136+
sym::miri,
11311137
sym::unix,
1132-
sym::windows,
1133-
sym::debug_assertions,
1134-
sym::proc_macro,
11351138
sym::test,
1136-
sym::doc,
11371139
sym::doctest,
1140+
sym::windows,
1141+
sym::proc_macro,
1142+
sym::debug_assertions,
11381143
sym::target_thread_local,
11391144
] {
11401145
self.values_valid.entry(name).or_default();

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,7 @@ symbols! {
891891
minnumf32,
892892
minnumf64,
893893
mips_target_feature,
894+
miri,
894895
misc,
895896
mmx_reg,
896897
modifiers,

library/core/src/clone.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,11 @@ pub trait Clone: Sized {
127127
/// allocations.
128128
#[inline]
129129
#[stable(feature = "rust1", since = "1.0.0")]
130-
fn clone_from(&mut self, source: &Self) {
130+
#[default_method_body_is_const]
131+
fn clone_from(&mut self, source: &Self)
132+
where
133+
Self: ~const Drop,
134+
{
131135
*self = source.clone()
132136
}
133137
}
@@ -178,7 +182,8 @@ mod impls {
178182
($($t:ty)*) => {
179183
$(
180184
#[stable(feature = "rust1", since = "1.0.0")]
181-
impl Clone for $t {
185+
#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
186+
impl const Clone for $t {
182187
#[inline]
183188
fn clone(&self) -> Self {
184189
*self
@@ -196,23 +201,26 @@ mod impls {
196201
}
197202

198203
#[unstable(feature = "never_type", issue = "35121")]
199-
impl Clone for ! {
204+
#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
205+
impl const Clone for ! {
200206
#[inline]
201207
fn clone(&self) -> Self {
202208
*self
203209
}
204210
}
205211

206212
#[stable(feature = "rust1", since = "1.0.0")]
207-
impl<T: ?Sized> Clone for *const T {
213+
#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
214+
impl<T: ?Sized> const Clone for *const T {
208215
#[inline]
209216
fn clone(&self) -> Self {
210217
*self
211218
}
212219
}
213220

214221
#[stable(feature = "rust1", since = "1.0.0")]
215-
impl<T: ?Sized> Clone for *mut T {
222+
#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
223+
impl<T: ?Sized> const Clone for *mut T {
216224
#[inline]
217225
fn clone(&self) -> Self {
218226
*self
@@ -221,7 +229,8 @@ mod impls {
221229

222230
/// Shared references can be cloned, but mutable references *cannot*!
223231
#[stable(feature = "rust1", since = "1.0.0")]
224-
impl<T: ?Sized> Clone for &T {
232+
#[rustc_const_unstable(feature = "const_clone", issue = "91805")]
233+
impl<T: ?Sized> const Clone for &T {
225234
#[inline]
226235
#[rustc_diagnostic_item = "noop_method_clone"]
227236
fn clone(&self) -> Self {

0 commit comments

Comments
 (0)