Skip to content

Commit fa70b89

Browse files
committed
Auto merge of rust-lang#97356 - Dylan-DPC:rollup-bhceawj, r=Dylan-DPC
Rollup of 4 pull requests Successful merges: - rust-lang#97288 (Lifetime variance fixes for rustdoc) - rust-lang#97298 (Parse expression after `else` as a condition if followed by `{`) - rust-lang#97308 (Stabilize `cell_filter_map`) - rust-lang#97321 (explain how to turn integers into fn ptrs) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
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

+4-4
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

+57-5
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

+2-6
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

+3
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

+26
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

+26
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

+1-1
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);

0 commit comments

Comments
 (0)