Skip to content

Commit

Permalink
Auto merge of #97356 - Dylan-DPC:rollup-bhceawj, r=Dylan-DPC
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed May 24, 2022
2 parents ee9726c + 4bd4018 commit fa70b89
Show file tree
Hide file tree
Showing 11 changed files with 370 additions and 165 deletions.
8 changes: 4 additions & 4 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,12 +343,12 @@ pub struct GenericArgs<'hir> {
pub span_ext: Span,
}

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

pub fn inputs(&self) -> &[Ty<'_>] {
pub fn inputs(&self) -> &[Ty<'hir>] {
if self.parenthesized {
for arg in self.args {
match arg {
Expand Down Expand Up @@ -549,7 +549,7 @@ impl<'hir> Generics<'hir> {
&NOPE
}

pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'_>> {
pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'hir>> {
for param in self.params {
if name == param.name.ident().name {
return Some(param);
Expand Down Expand Up @@ -608,7 +608,7 @@ impl<'hir> Generics<'hir> {
pub fn bounds_for_param(
&self,
param_def_id: LocalDefId,
) -> impl Iterator<Item = &WhereBoundPredicate<'_>> {
) -> impl Iterator<Item = &WhereBoundPredicate<'hir>> {
self.predicates.iter().filter_map(move |pred| match pred {
WherePredicate::BoundPredicate(bp) if bp.is_param_bound(param_def_id.to_def_id()) => {
Some(bp)
Expand Down
62 changes: 57 additions & 5 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2010,6 +2010,12 @@ impl<'a> Parser<'a> {
Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs))
}

/// Parse a block which takes no attributes and has no label
fn parse_simple_block(&mut self) -> PResult<'a, P<Expr>> {
let blk = self.parse_block()?;
Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()))
}

/// Recover on an explicitly quantified closure expression, e.g., `for<'a> |x: &'a u8| *x + 1`.
fn recover_quantified_closure_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
Expand Down Expand Up @@ -2157,14 +2163,22 @@ impl<'a> Parser<'a> {
let lo = self.prev_token.span;
let cond = self.parse_cond_expr()?;

self.parse_if_after_cond(attrs, lo, cond)
}

fn parse_if_after_cond(
&mut self,
attrs: AttrVec,
lo: Span,
cond: P<Expr>,
) -> PResult<'a, P<Expr>> {
let missing_then_block_binop_span = || {
match cond.kind {
ExprKind::Binary(Spanned { span: binop_span, .. }, _, ref right)
if let ExprKind::Block(..) = right.kind => Some(binop_span),
_ => None
}
};

// Verify that the parsed `if` condition makes sense as a condition. If it is a block, then
// verify that the last statement is either an implicit return (no `;`) or an explicit
// return. This won't catch blocks with an explicit `return`, but that would be caught by
Expand Down Expand Up @@ -2256,15 +2270,53 @@ impl<'a> Parser<'a> {

/// Parses an `else { ... }` expression (`else` token already eaten).
fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
let ctx_span = self.prev_token.span; // `else`
let else_span = self.prev_token.span; // `else`
let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
let expr = if self.eat_keyword(kw::If) {
self.parse_if_expr(AttrVec::new())?
} else if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) {
self.parse_simple_block()?
} else {
let blk = self.parse_block()?;
self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new())
let snapshot = self.create_snapshot_for_diagnostic();
let first_tok = super::token_descr(&self.token);
let first_tok_span = self.token.span;
match self.parse_expr() {
Ok(cond)
// If it's not a free-standing expression, and is followed by a block,
// then it's very likely the condition to an `else if`.
if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
&& classify::expr_requires_semi_to_be_stmt(&cond) =>
{
self.struct_span_err(first_tok_span, format!("expected `{{`, found {first_tok}"))
.span_label(else_span, "expected an `if` or a block after this `else`")
.span_suggestion(
cond.span.shrink_to_lo(),
"add an `if` if this is the condition to an chained `if` statement after the `else`",
"if ".to_string(),
Applicability::MaybeIncorrect,
).multipart_suggestion(
"... otherwise, place this expression inside of a block if it is not an `if` condition",
vec![
(cond.span.shrink_to_lo(), "{ ".to_string()),
(cond.span.shrink_to_hi(), " }".to_string()),
],
Applicability::MaybeIncorrect,
)
.emit();
self.parse_if_after_cond(AttrVec::new(), cond.span.shrink_to_lo(), cond)?
}
Err(e) => {
e.cancel();
self.restore_snapshot(snapshot);
self.parse_simple_block()?
},
Ok(_) => {
self.restore_snapshot(snapshot);
self.parse_simple_block()?
},
}
};
self.error_on_if_block_attrs(ctx_span, true, expr.span, &attrs);
self.error_on_if_block_attrs(else_span, true, expr.span, &attrs);
Ok(expr)
}

Expand Down
8 changes: 2 additions & 6 deletions library/core/src/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1390,16 +1390,14 @@ impl<'b, T: ?Sized> Ref<'b, T> {
/// # Examples
///
/// ```
/// #![feature(cell_filter_map)]
///
/// use std::cell::{RefCell, Ref};
///
/// let c = RefCell::new(vec![1, 2, 3]);
/// let b1: Ref<Vec<u32>> = c.borrow();
/// let b2: Result<Ref<u32>, _> = Ref::filter_map(b1, |v| v.get(1));
/// assert_eq!(*b2.unwrap(), 2);
/// ```
#[unstable(feature = "cell_filter_map", reason = "recently added", issue = "81061")]
#[stable(feature = "cell_filter_map", since = "1.63.0")]
#[inline]
pub fn filter_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Result<Ref<'b, U>, Self>
where
Expand Down Expand Up @@ -1538,8 +1536,6 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
/// # Examples
///
/// ```
/// #![feature(cell_filter_map)]
///
/// use std::cell::{RefCell, RefMut};
///
/// let c = RefCell::new(vec![1, 2, 3]);
Expand All @@ -1555,7 +1551,7 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
///
/// assert_eq!(*c.borrow(), vec![1, 4, 3]);
/// ```
#[unstable(feature = "cell_filter_map", reason = "recently added", issue = "81061")]
#[stable(feature = "cell_filter_map", since = "1.63.0")]
#[inline]
pub fn filter_map<U: ?Sized, F>(mut orig: RefMut<'b, T>, f: F) -> Result<RefMut<'b, U>, Self>
where
Expand Down
3 changes: 3 additions & 0 deletions library/core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,9 @@ extern "rust-intrinsic" {
/// fn foo() -> i32 {
/// 0
/// }
/// // Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer.
/// // This avoids an integer-to-pointer `transmute`, which can be problematic.
/// // Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine.
/// let pointer = foo as *const ();
/// let function = unsafe {
/// std::mem::transmute::<*const (), fn() -> i32>(pointer)
Expand Down
26 changes: 26 additions & 0 deletions library/core/src/primitive_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1351,6 +1351,32 @@ mod prim_ref {}
/// is a reference to the function-specific ZST. `&bar` is basically never what you
/// want when `bar` is a function.
///
/// ### Casting to and from integers
///
/// You cast function pointers directly to integers:
///
/// ```rust
/// let fnptr: fn(i32) -> i32 = |x| x+2;
/// let fnptr_addr = fnptr as usize;
/// ```
///
/// However, a direct cast back is not possible. You need to use `transmute`:
///
/// ```rust
/// # let fnptr: fn(i32) -> i32 = |x| x+2;
/// # let fnptr_addr = fnptr as usize;
/// let fnptr = fnptr_addr as *const ();
/// let fnptr: fn(i32) -> i32 = unsafe { std::mem::transmute(fnptr) };
/// assert_eq!(fnptr(40), 42);
/// ```
///
/// Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer.
/// This avoids an integer-to-pointer `transmute`, which can be problematic.
/// Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine.
///
/// Note that all of this is not portable to platforms where function pointers and data pointers
/// have different sizes.
///
/// ### Traits
///
/// Function pointers implement the following traits:
Expand Down
26 changes: 26 additions & 0 deletions library/std/src/primitive_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1351,6 +1351,32 @@ mod prim_ref {}
/// is a reference to the function-specific ZST. `&bar` is basically never what you
/// want when `bar` is a function.
///
/// ### Casting to and from integers
///
/// You cast function pointers directly to integers:
///
/// ```rust
/// let fnptr: fn(i32) -> i32 = |x| x+2;
/// let fnptr_addr = fnptr as usize;
/// ```
///
/// However, a direct cast back is not possible. You need to use `transmute`:
///
/// ```rust
/// # let fnptr: fn(i32) -> i32 = |x| x+2;
/// # let fnptr_addr = fnptr as usize;
/// let fnptr = fnptr_addr as *const ();
/// let fnptr: fn(i32) -> i32 = unsafe { std::mem::transmute(fnptr) };
/// assert_eq!(fnptr(40), 42);
/// ```
///
/// Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer.
/// This avoids an integer-to-pointer `transmute`, which can be problematic.
/// Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine.
///
/// Note that all of this is not portable to platforms where function pointers and data pointers
/// have different sizes.
///
/// ### Traits
///
/// Function pointers implement the following traits:
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
}
}

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

let predicates = cx.tcx.predicates_of(did);
Expand Down
Loading

0 comments on commit fa70b89

Please sign in to comment.