Skip to content

Commit fa70b89

Browse files
committedMay 24, 2022
Auto merge of #97356 - Dylan-DPC:rollup-bhceawj, r=Dylan-DPC
Rollup of 4 pull requests Successful merges: - #97288 (Lifetime variance fixes for rustdoc) - #97298 (Parse expression after `else` as a condition if followed by `{`) - #97308 (Stabilize `cell_filter_map`) - #97321 (explain how to turn integers into fn ptrs) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
·
1.88.01.63.0
2 parents ee9726c + 4bd4018 commit fa70b89

File tree

11 files changed

+370
-165
lines changed

11 files changed

+370
-165
lines changed
 

‎compiler/rustc_hir/src/hir.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -343,12 +343,12 @@ pub struct GenericArgs<'hir> {
343343
pub span_ext: Span,
344344
}
345345

346-
impl GenericArgs<'_> {
346+
impl<'hir> GenericArgs<'hir> {
347347
pub const fn none() -> Self {
348348
Self { args: &[], bindings: &[], parenthesized: false, span_ext: DUMMY_SP }
349349
}
350350

351-
pub fn inputs(&self) -> &[Ty<'_>] {
351+
pub fn inputs(&self) -> &[Ty<'hir>] {
352352
if self.parenthesized {
353353
for arg in self.args {
354354
match arg {
@@ -549,7 +549,7 @@ impl<'hir> Generics<'hir> {
549549
&NOPE
550550
}
551551

552-
pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'_>> {
552+
pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'hir>> {
553553
for param in self.params {
554554
if name == param.name.ident().name {
555555
return Some(param);
@@ -608,7 +608,7 @@ impl<'hir> Generics<'hir> {
608608
pub fn bounds_for_param(
609609
&self,
610610
param_def_id: LocalDefId,
611-
) -> impl Iterator<Item = &WhereBoundPredicate<'_>> {
611+
) -> impl Iterator<Item = &WhereBoundPredicate<'hir>> {
612612
self.predicates.iter().filter_map(move |pred| match pred {
613613
WherePredicate::BoundPredicate(bp) if bp.is_param_bound(param_def_id.to_def_id()) => {
614614
Some(bp)

‎compiler/rustc_parse/src/parser/expr.rs

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2010,6 +2010,12 @@ impl<'a> Parser<'a> {
20102010
Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs))
20112011
}
20122012

2013+
/// Parse a block which takes no attributes and has no label
2014+
fn parse_simple_block(&mut self) -> PResult<'a, P<Expr>> {
2015+
let blk = self.parse_block()?;
2016+
Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()))
2017+
}
2018+
20132019
/// Recover on an explicitly quantified closure expression, e.g., `for<'a> |x: &'a u8| *x + 1`.
20142020
fn recover_quantified_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
20152021
let lo = self.token.span;
@@ -2157,14 +2163,22 @@ impl<'a> Parser<'a> {
21572163
let lo = self.prev_token.span;
21582164
let cond = self.parse_cond_expr()?;
21592165

2166+
self.parse_if_after_cond(attrs, lo, cond)
2167+
}
2168+
2169+
fn parse_if_after_cond(
2170+
&mut self,
2171+
attrs: AttrVec,
2172+
lo: Span,
2173+
cond: P<Expr>,
2174+
) -> PResult<'a, P<Expr>> {
21602175
let missing_then_block_binop_span = || {
21612176
match cond.kind {
21622177
ExprKind::Binary(Spanned { span: binop_span, .. }, _, ref right)
21632178
if let ExprKind::Block(..) = right.kind => Some(binop_span),
21642179
_ => None
21652180
}
21662181
};
2167-
21682182
// Verify that the parsed `if` condition makes sense as a condition. If it is a block, then
21692183
// verify that the last statement is either an implicit return (no `;`) or an explicit
21702184
// return. This won't catch blocks with an explicit `return`, but that would be caught by
@@ -2256,15 +2270,53 @@ impl<'a> Parser<'a> {
22562270

22572271
/// Parses an `else { ... }` expression (`else` token already eaten).
22582272
fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
2259-
let ctx_span = self.prev_token.span; // `else`
2273+
let else_span = self.prev_token.span; // `else`
22602274
let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
22612275
let expr = if self.eat_keyword(kw::If) {
22622276
self.parse_if_expr(AttrVec::new())?
2277+
} else if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) {
2278+
self.parse_simple_block()?
22632279
} else {
2264-
let blk = self.parse_block()?;
2265-
self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new())
2280+
let snapshot = self.create_snapshot_for_diagnostic();
2281+
let first_tok = super::token_descr(&self.token);
2282+
let first_tok_span = self.token.span;
2283+
match self.parse_expr() {
2284+
Ok(cond)
2285+
// If it's not a free-standing expression, and is followed by a block,
2286+
// then it's very likely the condition to an `else if`.
2287+
if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
2288+
&& classify::expr_requires_semi_to_be_stmt(&cond) =>
2289+
{
2290+
self.struct_span_err(first_tok_span, format!("expected `{{`, found {first_tok}"))
2291+
.span_label(else_span, "expected an `if` or a block after this `else`")
2292+
.span_suggestion(
2293+
cond.span.shrink_to_lo(),
2294+
"add an `if` if this is the condition to an chained `if` statement after the `else`",
2295+
"if ".to_string(),
2296+
Applicability::MaybeIncorrect,
2297+
).multipart_suggestion(
2298+
"... otherwise, place this expression inside of a block if it is not an `if` condition",
2299+
vec![
2300+
(cond.span.shrink_to_lo(), "{ ".to_string()),
2301+
(cond.span.shrink_to_hi(), " }".to_string()),
2302+
],
2303+
Applicability::MaybeIncorrect,
2304+
)
2305+
.emit();
2306+
self.parse_if_after_cond(AttrVec::new(), cond.span.shrink_to_lo(), cond)?
2307+
}
2308+
Err(e) => {
2309+
e.cancel();
2310+
self.restore_snapshot(snapshot);
2311+
self.parse_simple_block()?
2312+
},
2313+
Ok(_) => {
2314+
self.restore_snapshot(snapshot);
2315+
self.parse_simple_block()?
2316+
},
2317+
}
22662318
};
2267-
self.error_on_if_block_attrs(ctx_span, true, expr.span, &attrs);
2319+
self.error_on_if_block_attrs(else_span, true, expr.span, &attrs);
22682320
Ok(expr)
22692321
}
22702322

‎library/core/src/cell.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,16 +1390,14 @@ impl<'b, T: ?Sized> Ref<'b, T> {
13901390
/// # Examples
13911391
///
13921392
/// ```
1393-
/// #![feature(cell_filter_map)]
1394-
///
13951393
/// use std::cell::{RefCell, Ref};
13961394
///
13971395
/// let c = RefCell::new(vec![1, 2, 3]);
13981396
/// let b1: Ref<Vec<u32>> = c.borrow();
13991397
/// let b2: Result<Ref<u32>, _> = Ref::filter_map(b1, |v| v.get(1));
14001398
/// assert_eq!(*b2.unwrap(), 2);
14011399
/// ```
1402-
#[unstable(feature = "cell_filter_map", reason = "recently added", issue = "81061")]
1400+
#[stable(feature = "cell_filter_map", since = "1.63.0")]
14031401
#[inline]
14041402
pub fn filter_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Result<Ref<'b, U>, Self>
14051403
where
@@ -1538,8 +1536,6 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
15381536
/// # Examples
15391537
///
15401538
/// ```
1541-
/// #![feature(cell_filter_map)]
1542-
///
15431539
/// use std::cell::{RefCell, RefMut};
15441540
///
15451541
/// let c = RefCell::new(vec![1, 2, 3]);
@@ -1555,7 +1551,7 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
15551551
///
15561552
/// assert_eq!(*c.borrow(), vec![1, 4, 3]);
15571553
/// ```
1558-
#[unstable(feature = "cell_filter_map", reason = "recently added", issue = "81061")]
1554+
#[stable(feature = "cell_filter_map", since = "1.63.0")]
15591555
#[inline]
15601556
pub fn filter_map<U: ?Sized, F>(mut orig: RefMut<'b, T>, f: F) -> Result<RefMut<'b, U>, Self>
15611557
where

‎library/core/src/intrinsics.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,9 @@ extern "rust-intrinsic" {
930930
/// fn foo() -> i32 {
931931
/// 0
932932
/// }
933+
/// // Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer.
934+
/// // This avoids an integer-to-pointer `transmute`, which can be problematic.
935+
/// // Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine.
933936
/// let pointer = foo as *const ();
934937
/// let function = unsafe {
935938
/// std::mem::transmute::<*const (), fn() -> i32>(pointer)

‎library/core/src/primitive_docs.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,32 @@ mod prim_ref {}
13511351
/// is a reference to the function-specific ZST. `&bar` is basically never what you
13521352
/// want when `bar` is a function.
13531353
///
1354+
/// ### Casting to and from integers
1355+
///
1356+
/// You cast function pointers directly to integers:
1357+
///
1358+
/// ```rust
1359+
/// let fnptr: fn(i32) -> i32 = |x| x+2;
1360+
/// let fnptr_addr = fnptr as usize;
1361+
/// ```
1362+
///
1363+
/// However, a direct cast back is not possible. You need to use `transmute`:
1364+
///
1365+
/// ```rust
1366+
/// # let fnptr: fn(i32) -> i32 = |x| x+2;
1367+
/// # let fnptr_addr = fnptr as usize;
1368+
/// let fnptr = fnptr_addr as *const ();
1369+
/// let fnptr: fn(i32) -> i32 = unsafe { std::mem::transmute(fnptr) };
1370+
/// assert_eq!(fnptr(40), 42);
1371+
/// ```
1372+
///
1373+
/// Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer.
1374+
/// This avoids an integer-to-pointer `transmute`, which can be problematic.
1375+
/// Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine.
1376+
///
1377+
/// Note that all of this is not portable to platforms where function pointers and data pointers
1378+
/// have different sizes.
1379+
///
13541380
/// ### Traits
13551381
///
13561382
/// Function pointers implement the following traits:

‎library/std/src/primitive_docs.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,32 @@ mod prim_ref {}
13511351
/// is a reference to the function-specific ZST. `&bar` is basically never what you
13521352
/// want when `bar` is a function.
13531353
///
1354+
/// ### Casting to and from integers
1355+
///
1356+
/// You cast function pointers directly to integers:
1357+
///
1358+
/// ```rust
1359+
/// let fnptr: fn(i32) -> i32 = |x| x+2;
1360+
/// let fnptr_addr = fnptr as usize;
1361+
/// ```
1362+
///
1363+
/// However, a direct cast back is not possible. You need to use `transmute`:
1364+
///
1365+
/// ```rust
1366+
/// # let fnptr: fn(i32) -> i32 = |x| x+2;
1367+
/// # let fnptr_addr = fnptr as usize;
1368+
/// let fnptr = fnptr_addr as *const ();
1369+
/// let fnptr: fn(i32) -> i32 = unsafe { std::mem::transmute(fnptr) };
1370+
/// assert_eq!(fnptr(40), 42);
1371+
/// ```
1372+
///
1373+
/// Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer.
1374+
/// This avoids an integer-to-pointer `transmute`, which can be problematic.
1375+
/// Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine.
1376+
///
1377+
/// Note that all of this is not portable to platforms where function pointers and data pointers
1378+
/// have different sizes.
1379+
///
13541380
/// ### Traits
13551381
///
13561382
/// Function pointers implement the following traits:

‎src/librustdoc/clean/inline.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
218218
}
219219
}
220220

221-
fn build_external_function(cx: &mut DocContext<'_>, did: DefId) -> clean::Function {
221+
fn build_external_function<'tcx>(cx: &mut DocContext<'tcx>, did: DefId) -> clean::Function {
222222
let sig = cx.tcx.fn_sig(did);
223223

224224
let predicates = cx.tcx.predicates_of(did);

‎src/librustdoc/clean/mod.rs

Lines changed: 150 additions & 138 deletions
Large diffs are not rendered by default.

‎src/librustdoc/clean/utils.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
7575
Crate { module, primitives, external_traits: cx.external_traits.clone() }
7676
}
7777

78-
pub(crate) fn substs_to_args(
79-
cx: &mut DocContext<'_>,
80-
substs: &[ty::subst::GenericArg<'_>],
78+
pub(crate) fn substs_to_args<'tcx>(
79+
cx: &mut DocContext<'tcx>,
80+
substs: &[ty::subst::GenericArg<'tcx>],
8181
mut skip_first: bool,
8282
) -> Vec<GenericArg> {
8383
let mut ret_val =
@@ -99,12 +99,12 @@ pub(crate) fn substs_to_args(
9999
ret_val
100100
}
101101

102-
fn external_generic_args(
103-
cx: &mut DocContext<'_>,
102+
fn external_generic_args<'tcx>(
103+
cx: &mut DocContext<'tcx>,
104104
did: DefId,
105105
has_self: bool,
106106
bindings: Vec<TypeBinding>,
107-
substs: SubstsRef<'_>,
107+
substs: SubstsRef<'tcx>,
108108
) -> GenericArgs {
109109
let args = substs_to_args(cx, &substs, has_self);
110110

@@ -127,12 +127,12 @@ fn external_generic_args(
127127
}
128128
}
129129

130-
pub(super) fn external_path(
131-
cx: &mut DocContext<'_>,
130+
pub(super) fn external_path<'tcx>(
131+
cx: &mut DocContext<'tcx>,
132132
did: DefId,
133133
has_self: bool,
134134
bindings: Vec<TypeBinding>,
135-
substs: SubstsRef<'_>,
135+
substs: SubstsRef<'tcx>,
136136
) -> Path {
137137
let def_kind = cx.tcx.def_kind(did);
138138
let name = cx.tcx.item_name(did);
@@ -439,9 +439,9 @@ pub(crate) fn resolve_use_source(cx: &mut DocContext<'_>, path: Path) -> ImportS
439439
}
440440
}
441441

442-
pub(crate) fn enter_impl_trait<F, R>(cx: &mut DocContext<'_>, f: F) -> R
442+
pub(crate) fn enter_impl_trait<'tcx, F, R>(cx: &mut DocContext<'tcx>, f: F) -> R
443443
where
444-
F: FnOnce(&mut DocContext<'_>) -> R,
444+
F: FnOnce(&mut DocContext<'tcx>) -> R,
445445
{
446446
let old_bounds = mem::take(&mut cx.impl_trait_bounds);
447447
let r = f(cx);

‎src/test/ui/parser/else-no-if.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
fn foo() {
2+
if true {
3+
} else false {
4+
//~^ ERROR expected `{`, found keyword `false`
5+
}
6+
}
7+
8+
fn foo2() {
9+
if true {
10+
} else falsy() {
11+
//~^ ERROR expected `{`, found `falsy`
12+
}
13+
}
14+
15+
fn foo3() {
16+
if true {
17+
} else falsy();
18+
//~^ ERROR expected `{`, found `falsy`
19+
}
20+
21+
fn foo4() {
22+
if true {
23+
} else loop{}
24+
//~^ ERROR expected `{`, found keyword `loop`
25+
{}
26+
}
27+
28+
fn falsy() -> bool {
29+
false
30+
}
31+
32+
fn main() {}

‎src/test/ui/parser/else-no-if.stderr

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
error: expected `{`, found keyword `false`
2+
--> $DIR/else-no-if.rs:3:12
3+
|
4+
LL | } else false {
5+
| ---- ^^^^^
6+
| |
7+
| expected an `if` or a block after this `else`
8+
|
9+
help: add an `if` if this is the condition to an chained `if` statement after the `else`
10+
|
11+
LL | } else if false {
12+
| ++
13+
help: ... otherwise, place this expression inside of a block if it is not an `if` condition
14+
|
15+
LL | } else { false } {
16+
| + +
17+
18+
error: expected `{`, found `falsy`
19+
--> $DIR/else-no-if.rs:10:12
20+
|
21+
LL | } else falsy() {
22+
| ---- ^^^^^
23+
| |
24+
| expected an `if` or a block after this `else`
25+
|
26+
help: add an `if` if this is the condition to an chained `if` statement after the `else`
27+
|
28+
LL | } else if falsy() {
29+
| ++
30+
help: ... otherwise, place this expression inside of a block if it is not an `if` condition
31+
|
32+
LL | } else { falsy() } {
33+
| + +
34+
35+
error: expected `{`, found `falsy`
36+
--> $DIR/else-no-if.rs:17:12
37+
|
38+
LL | } else falsy();
39+
| ^^^^^ expected `{`
40+
|
41+
help: try placing this code inside a block
42+
|
43+
LL | } else { falsy() };
44+
| + +
45+
46+
error: expected `{`, found keyword `loop`
47+
--> $DIR/else-no-if.rs:23:12
48+
|
49+
LL | } else loop{}
50+
| ^^^^ expected `{`
51+
|
52+
help: try placing this code inside a block
53+
|
54+
LL | } else { loop{} }
55+
| + +
56+
57+
error: aborting due to 4 previous errors
58+

0 commit comments

Comments
 (0)
Please sign in to comment.