Skip to content

Commit 5c54be3

Browse files
committed
Auto merge of rust-lang#100195 - matthiaskrgr:rollup-ovzyyb0, r=matthiaskrgr
Rollup of 4 pull requests Successful merges: - rust-lang#100094 (Detect type mismatch due to loop that might never iterate) - rust-lang#100132 (Use (actually) dummy place for let-else divergence) - rust-lang#100167 (Recover `require`, `include` instead of `use` in item) - rust-lang#100193 (Remove more Clean trait implementations) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 76b0484 + 811b036 commit 5c54be3

File tree

12 files changed

+182
-53
lines changed

12 files changed

+182
-53
lines changed

compiler/rustc_mir_build/src/build/matches/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2334,7 +2334,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
23342334
// This place is not really used because this destination place
23352335
// should never be used to take values at the end of the failure
23362336
// block.
2337-
let dummy_place = Place { local: RETURN_PLACE, projection: ty::List::empty() };
2337+
let dummy_place = self.temp(self.tcx.types.never, else_block.span);
23382338
let failure_block;
23392339
unpack!(
23402340
failure_block = self.ast_block(

compiler/rustc_parse/src/parser/item.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,10 @@ impl<'a> Parser<'a> {
271271
// MACRO_RULES ITEM
272272
self.parse_item_macro_rules(vis, has_bang)?
273273
} else if self.isnt_macro_invocation()
274-
&& (self.token.is_ident_named(sym::import) || self.token.is_ident_named(sym::using))
274+
&& (self.token.is_ident_named(sym::import)
275+
|| self.token.is_ident_named(sym::using)
276+
|| self.token.is_ident_named(sym::include)
277+
|| self.token.is_ident_named(sym::require))
275278
{
276279
return self.recover_import_as_use();
277280
} else if self.isnt_macro_invocation() && vis.kind.is_pub() {

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1170,6 +1170,7 @@ symbols! {
11701170
repr_packed,
11711171
repr_simd,
11721172
repr_transparent,
1173+
require,
11731174
residual,
11741175
result,
11751176
rhs,

compiler/rustc_typeck/src/check/coercion.rs

+48-1
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@
3838
use crate::astconv::AstConv;
3939
use crate::check::FnCtxt;
4040
use rustc_errors::{
41-
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
41+
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
4242
};
4343
use rustc_hir as hir;
4444
use rustc_hir::def_id::DefId;
45+
use rustc_hir::intravisit::{self, Visitor};
46+
use rustc_hir::Expr;
4547
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
4648
use rustc_infer::infer::{Coercion, InferOk, InferResult};
4749
use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};
@@ -87,6 +89,19 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> {
8789

8890
type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>;
8991

92+
struct CollectRetsVisitor<'tcx> {
93+
ret_exprs: Vec<&'tcx hir::Expr<'tcx>>,
94+
}
95+
96+
impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> {
97+
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
98+
if let hir::ExprKind::Ret(_) = expr.kind {
99+
self.ret_exprs.push(expr);
100+
}
101+
intravisit::walk_expr(self, expr);
102+
}
103+
}
104+
90105
/// Coercing a mutable reference to an immutable works, while
91106
/// coercing `&T` to `&mut T` should be forbidden.
92107
fn coerce_mutbls<'tcx>(
@@ -1481,6 +1496,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
14811496

14821497
let mut err;
14831498
let mut unsized_return = false;
1499+
let mut visitor = CollectRetsVisitor { ret_exprs: vec![] };
14841500
match *cause.code() {
14851501
ObligationCauseCode::ReturnNoExpression => {
14861502
err = struct_span_err!(
@@ -1506,6 +1522,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
15061522
if !fcx.tcx.features().unsized_locals {
15071523
unsized_return = self.is_return_ty_unsized(fcx, blk_id);
15081524
}
1525+
if let Some(expression) = expression
1526+
&& let hir::ExprKind::Loop(loop_blk, ..) = expression.kind {
1527+
intravisit::walk_block(& mut visitor, loop_blk);
1528+
}
15091529
}
15101530
ObligationCauseCode::ReturnValue(id) => {
15111531
err = self.report_return_mismatched_types(
@@ -1551,12 +1571,39 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
15511571
);
15521572
}
15531573

1574+
if visitor.ret_exprs.len() > 0 && let Some(expr) = expression {
1575+
self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs);
1576+
}
15541577
err.emit_unless(unsized_return);
15551578

15561579
self.final_ty = Some(fcx.tcx.ty_error());
15571580
}
15581581
}
15591582
}
1583+
fn note_unreachable_loop_return<'a>(
1584+
&self,
1585+
err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>,
1586+
expr: &hir::Expr<'tcx>,
1587+
ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>,
1588+
) {
1589+
let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;};
1590+
let mut span: MultiSpan = vec![loop_span].into();
1591+
span.push_span_label(loop_span, "this might have zero elements to iterate on".to_string());
1592+
for ret_expr in ret_exprs {
1593+
span.push_span_label(
1594+
ret_expr.span,
1595+
"if the loop doesn't execute, this value would never get returned".to_string(),
1596+
);
1597+
}
1598+
err.span_note(
1599+
span,
1600+
"the function expects a value to always be returned, but loops might run zero times",
1601+
);
1602+
err.help(
1603+
"return a value for the case when the loop has zero elements to iterate on, or \
1604+
consider changing the return type to account for that possibility",
1605+
);
1606+
}
15601607

15611608
fn report_return_mismatched_types<'a>(
15621609
&self,

src/librustdoc/clean/mod.rs

+42-48
Original file line numberDiff line numberDiff line change
@@ -126,40 +126,40 @@ impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
126126
}
127127
}
128128

129-
impl<'tcx> Clean<'tcx, Option<GenericBound>> for hir::GenericBound<'tcx> {
130-
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<GenericBound> {
131-
Some(match *self {
132-
hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
133-
hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
134-
let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
135-
136-
let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder();
137-
138-
let generic_args = generic_args.clean(cx);
139-
let GenericArgs::AngleBracketed { bindings, .. } = generic_args
140-
else {
141-
bug!("clean: parenthesized `GenericBound::LangItemTrait`");
142-
};
129+
fn clean_generic_bound<'tcx>(
130+
bound: &hir::GenericBound<'tcx>,
131+
cx: &mut DocContext<'tcx>,
132+
) -> Option<GenericBound> {
133+
Some(match *bound {
134+
hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
135+
hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
136+
let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
137+
138+
let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder();
139+
140+
let generic_args = generic_args.clean(cx);
141+
let GenericArgs::AngleBracketed { bindings, .. } = generic_args
142+
else {
143+
bug!("clean: parenthesized `GenericBound::LangItemTrait`");
144+
};
143145

144-
let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
145-
GenericBound::TraitBound(
146-
PolyTrait { trait_, generic_params: vec![] },
147-
hir::TraitBoundModifier::None,
148-
)
146+
let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
147+
GenericBound::TraitBound(
148+
PolyTrait { trait_, generic_params: vec![] },
149+
hir::TraitBoundModifier::None,
150+
)
151+
}
152+
hir::GenericBound::Trait(ref t, modifier) => {
153+
// `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
154+
if modifier == hir::TraitBoundModifier::MaybeConst
155+
&& cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap())
156+
{
157+
return None;
149158
}
150-
hir::GenericBound::Trait(ref t, modifier) => {
151-
// `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
152-
if modifier == hir::TraitBoundModifier::MaybeConst
153-
&& cx.tcx.lang_items().destruct_trait()
154-
== Some(t.trait_ref.trait_def_id().unwrap())
155-
{
156-
return None;
157-
}
158159

159-
GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier)
160-
}
161-
})
162-
}
160+
GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier)
161+
}
162+
})
163163
}
164164

165165
pub(crate) fn clean_trait_ref_with_bindings<'tcx>(
@@ -207,12 +207,6 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
207207
)
208208
}
209209

210-
impl<'tcx> Clean<'tcx, GenericBound> for ty::PolyTraitRef<'tcx> {
211-
fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericBound {
212-
clean_poly_trait_ref_with_bindings(cx, *self, &[])
213-
}
214-
}
215-
216210
fn clean_lifetime<'tcx>(lifetime: hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
217211
let def = cx.tcx.named_region(lifetime.hir_id);
218212
if let Some(
@@ -294,14 +288,14 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> {
294288
.collect();
295289
WherePredicate::BoundPredicate {
296290
ty: clean_ty(wbp.bounded_ty, cx),
297-
bounds: wbp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
291+
bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
298292
bound_params,
299293
}
300294
}
301295

302296
hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
303297
lifetime: clean_lifetime(wrp.lifetime, cx),
304-
bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
298+
bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
305299
},
306300

307301
hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
@@ -349,7 +343,7 @@ fn clean_poly_trait_predicate<'tcx>(
349343
let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref);
350344
Some(WherePredicate::BoundPredicate {
351345
ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
352-
bounds: vec![poly_trait_ref.clean(cx)],
346+
bounds: vec![clean_poly_trait_ref_with_bindings(cx, poly_trait_ref, &[])],
353347
bound_params: Vec::new(),
354348
})
355349
}
@@ -531,7 +525,7 @@ fn clean_generic_param<'tcx>(
531525
.bounds_for_param(did)
532526
.filter(|bp| bp.origin != PredicateOrigin::WhereClause)
533527
.flat_map(|bp| bp.bounds)
534-
.filter_map(|x| x.clean(cx))
528+
.filter_map(|x| clean_generic_bound(x, cx))
535529
.collect()
536530
} else {
537531
Vec::new()
@@ -1041,7 +1035,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
10411035
}
10421036
hir::TraitItemKind::Type(bounds, Some(default)) => {
10431037
let generics = enter_impl_trait(cx, |cx| trait_item.generics.clean(cx));
1044-
let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
1038+
let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
10451039
let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
10461040
AssocTypeItem(
10471041
Box::new(Typedef {
@@ -1054,7 +1048,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
10541048
}
10551049
hir::TraitItemKind::Type(bounds, None) => {
10561050
let generics = enter_impl_trait(cx, |cx| trait_item.generics.clean(cx));
1057-
let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
1051+
let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
10581052
TyAssocTypeItem(Box::new(generics), bounds)
10591053
}
10601054
};
@@ -1507,7 +1501,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
15071501
TyKind::OpaqueDef(item_id, _) => {
15081502
let item = cx.tcx.hir().item(item_id);
15091503
if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
1510-
ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect())
1504+
ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
15111505
} else {
15121506
unreachable!()
15131507
}
@@ -1911,7 +1905,7 @@ fn clean_maybe_renamed_item<'tcx>(
19111905
kind: ConstantKind::Local { body: body_id, def_id },
19121906
}),
19131907
ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
1914-
bounds: ty.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
1908+
bounds: ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
19151909
generics: ty.generics.clean(cx),
19161910
}),
19171911
ItemKind::TyAlias(hir_ty, generics) => {
@@ -1929,7 +1923,7 @@ fn clean_maybe_renamed_item<'tcx>(
19291923
}),
19301924
ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias {
19311925
generics: generics.clean(cx),
1932-
bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
1926+
bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
19331927
}),
19341928
ItemKind::Union(ref variant_data, generics) => UnionItem(Union {
19351929
generics: generics.clean(cx),
@@ -1961,7 +1955,7 @@ fn clean_maybe_renamed_item<'tcx>(
19611955
def_id,
19621956
items,
19631957
generics: generics.clean(cx),
1964-
bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
1958+
bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
19651959
})
19661960
}
19671961
ItemKind::ExternCrate(orig_name) => {
@@ -2241,7 +2235,7 @@ fn clean_type_binding<'tcx>(
22412235
TypeBindingKind::Equality { term: clean_hir_term(term, cx) }
22422236
}
22432237
hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint {
2244-
bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
2238+
bounds: bounds.iter().filter_map(|b| clean_generic_bound(b, cx)).collect(),
22452239
},
22462240
},
22472241
}

src/test/ui/did_you_mean/use_instead_of_import.fixed

+8
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,18 @@ use std::{
66
rc::Rc,
77
};
88

9+
use std::time::Duration;
10+
//~^ ERROR expected item, found `require`
11+
12+
use std::time::Instant;
13+
//~^ ERROR expected item, found `include`
14+
915
pub use std::io;
1016
//~^ ERROR expected item, found `using`
1117

1218
fn main() {
1319
let x = Rc::new(1);
1420
let _ = write!(io::stdout(), "{:?}", x);
21+
let _ = Duration::new(5, 0);
22+
let _ = Instant::now();
1523
}

src/test/ui/did_you_mean/use_instead_of_import.rs

+8
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,18 @@ import std::{
66
rc::Rc,
77
};
88

9+
require std::time::Duration;
10+
//~^ ERROR expected item, found `require`
11+
12+
include std::time::Instant;
13+
//~^ ERROR expected item, found `include`
14+
915
pub using std::io;
1016
//~^ ERROR expected item, found `using`
1117

1218
fn main() {
1319
let x = Rc::new(1);
1420
let _ = write!(io::stdout(), "{:?}", x);
21+
let _ = Duration::new(5, 0);
22+
let _ = Instant::now();
1523
}

src/test/ui/did_you_mean/use_instead_of_import.stderr

+14-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,23 @@ error: expected item, found `import`
44
LL | import std::{
55
| ^^^^^^ help: items are imported using the `use` keyword
66

7+
error: expected item, found `require`
8+
--> $DIR/use_instead_of_import.rs:9:1
9+
|
10+
LL | require std::time::Duration;
11+
| ^^^^^^^ help: items are imported using the `use` keyword
12+
13+
error: expected item, found `include`
14+
--> $DIR/use_instead_of_import.rs:12:1
15+
|
16+
LL | include std::time::Instant;
17+
| ^^^^^^^ help: items are imported using the `use` keyword
18+
719
error: expected item, found `using`
8-
--> $DIR/use_instead_of_import.rs:9:5
20+
--> $DIR/use_instead_of_import.rs:15:5
921
|
1022
LL | pub using std::io;
1123
| ^^^^^ help: items are imported using the `use` keyword
1224

13-
error: aborting due to 2 previous errors
25+
error: aborting due to 4 previous errors
1426

src/test/ui/for-loop-while/break-while-condition.stderr

+8
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ LL | | }
3131
|
3232
= note: expected type `!`
3333
found unit type `()`
34+
note: the function expects a value to always be returned, but loops might run zero times
35+
--> $DIR/break-while-condition.rs:24:13
36+
|
37+
LL | while false {
38+
| ^^^^^^^^^^^ this might have zero elements to iterate on
39+
LL | return
40+
| ------ if the loop doesn't execute, this value would never get returned
41+
= help: return a value for the case when the loop has zero elements to iterate on, or consider changing the return type to account for that possibility
3442

3543
error: aborting due to 3 previous errors
3644

src/test/ui/let-else/issue-100103.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// edition:2021
2+
// check-pass
3+
4+
#![feature(try_blocks)]
5+
#![feature(let_else)]
6+
7+
fn main() {
8+
let _: Result<i32, i32> = try {
9+
let Some(x) = Some(0) else {
10+
Err(1)?
11+
};
12+
13+
x
14+
};
15+
}

0 commit comments

Comments
 (0)