Skip to content

Commit

Permalink
Auto merge of #134039 - matthiaskrgr:rollup-ix8kdg1, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 7 pull requests

Successful merges:

 - #133424 (Parse guard patterns)
 - #133733 ( compiletest: show the difference between the normalized output and the actual output for lines which didn't match)
 - #133993 (Fix: typo in E0751 error explanation)
 - #134013 (Adds new intrinsic declaration)
 - #134020 (Remove unnecessary `int_type_width_signed` function)
 - #134024 (Advent of `tests/ui` (misc cleanups and improvements) [2/N])
 - #134038 (deps: Update psm)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Dec 8, 2024
2 parents 4d669fb + 5b133fe commit df5b8e3
Show file tree
Hide file tree
Showing 52 changed files with 739 additions and 301 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2815,9 +2815,9 @@ dependencies = [

[[package]]
name = "psm"
version = "0.1.23"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205"
checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810"
dependencies = [
"cc",
]
Expand Down
11 changes: 8 additions & 3 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,9 +627,11 @@ impl Pat {
| PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)),

// Trivial wrappers over inner patterns.
PatKind::Box(s) | PatKind::Deref(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => {
s.walk(it)
}
PatKind::Box(s)
| PatKind::Deref(s)
| PatKind::Ref(s, _)
| PatKind::Paren(s)
| PatKind::Guard(s, _) => s.walk(it),

// These patterns do not contain subpatterns, skip.
PatKind::Wild
Expand Down Expand Up @@ -839,6 +841,9 @@ pub enum PatKind {
// A never pattern `!`.
Never,

/// A guard pattern (e.g., `x if guard(x)`).
Guard(P<Pat>, P<Expr>),

/// Parentheses in patterns used for grouping (i.e., `(PAT)`).
Paren(P<Pat>),

Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1525,6 +1525,10 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
visit_opt(e2, |e| vis.visit_expr(e));
vis.visit_span(span);
}
PatKind::Guard(p, e) => {
vis.visit_pat(p);
vis.visit_expr(e);
}
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
visit_thin_vec(elems, |elem| vis.visit_pat(elem))
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,10 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
visit_opt!(visitor, visit_expr, lower_bound);
visit_opt!(visitor, visit_expr, upper_bound);
}
PatKind::Guard(subpattern, guard_condition) => {
try_visit!(visitor.visit_pat(subpattern));
try_visit!(visitor.visit_expr(guard_condition));
}
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
PatKind::Err(_guar) => {}
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_ast_lowering/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_range_end(end, e2.is_some()),
);
}
// FIXME(guard_patterns): lower pattern guards to HIR
PatKind::Guard(inner, _) => pattern = inner,
PatKind::Slice(pats) => break self.lower_pat_slice(pats),
PatKind::Rest => {
// If we reach here the `..` pattern is not semantically allowed.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
gate_all!(explicit_tail_calls, "`become` expression is experimental");
gate_all!(generic_const_items, "generic const items are experimental");
gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards");
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
gate_all!(postfix_match, "postfix match is experimental");
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1709,6 +1709,14 @@ impl<'a> State<'a> {
self.print_expr(e, FixupContext::default());
}
}
PatKind::Guard(subpat, condition) => {
self.popen();
self.print_pat(subpat);
self.space();
self.word_space("if");
self.print_expr(condition, FixupContext::default());
self.pclose();
}
PatKind::Slice(elts) => {
self.word("[");
self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
Expand Down
166 changes: 75 additions & 91 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,84 +352,84 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
| sym::saturating_add
| sym::saturating_sub => {
let ty = arg_tys[0];
match int_type_width_signed(ty, self) {
Some((width, signed)) => match name {
sym::ctlz | sym::cttz => {
let y = self.const_bool(false);
let ret = self.call_intrinsic(&format!("llvm.{name}.i{width}"), &[
args[0].immediate(),
y,
]);

self.intcast(ret, llret_ty, false)
}
sym::ctlz_nonzero => {
let y = self.const_bool(true);
let llvm_name = &format!("llvm.ctlz.i{width}");
let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
self.intcast(ret, llret_ty, false)
}
sym::cttz_nonzero => {
let y = self.const_bool(true);
let llvm_name = &format!("llvm.cttz.i{width}");
let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
self.intcast(ret, llret_ty, false)
}
sym::ctpop => {
let ret = self.call_intrinsic(&format!("llvm.ctpop.i{width}"), &[args
[0]
.immediate()]);
self.intcast(ret, llret_ty, false)
}
sym::bswap => {
if width == 8 {
args[0].immediate() // byte swap a u8/i8 is just a no-op
} else {
self.call_intrinsic(&format!("llvm.bswap.i{width}"), &[
args[0].immediate()
])
}
}
sym::bitreverse => self
.call_intrinsic(&format!("llvm.bitreverse.i{width}"), &[
if !ty.is_integral() {
tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
span,
name,
ty,
});
return Ok(());
}
let (size, signed) = ty.int_size_and_signed(self.tcx);
let width = size.bits();
match name {
sym::ctlz | sym::cttz => {
let y = self.const_bool(false);
let ret = self.call_intrinsic(&format!("llvm.{name}.i{width}"), &[
args[0].immediate(),
y,
]);

self.intcast(ret, llret_ty, false)
}
sym::ctlz_nonzero => {
let y = self.const_bool(true);
let llvm_name = &format!("llvm.ctlz.i{width}");
let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
self.intcast(ret, llret_ty, false)
}
sym::cttz_nonzero => {
let y = self.const_bool(true);
let llvm_name = &format!("llvm.cttz.i{width}");
let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
self.intcast(ret, llret_ty, false)
}
sym::ctpop => {
let ret = self.call_intrinsic(&format!("llvm.ctpop.i{width}"), &[
args[0].immediate()
]);
self.intcast(ret, llret_ty, false)
}
sym::bswap => {
if width == 8 {
args[0].immediate() // byte swap a u8/i8 is just a no-op
} else {
self.call_intrinsic(&format!("llvm.bswap.i{width}"), &[
args[0].immediate()
]),
sym::rotate_left | sym::rotate_right => {
let is_left = name == sym::rotate_left;
let val = args[0].immediate();
let raw_shift = args[1].immediate();
// rotate = funnel shift with first two args the same
let llvm_name =
&format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width);

// llvm expects shift to be the same type as the values, but rust
// always uses `u32`.
let raw_shift = self.intcast(raw_shift, self.val_ty(val), false);

self.call_intrinsic(llvm_name, &[val, val, raw_shift])
])
}
sym::saturating_add | sym::saturating_sub => {
let is_add = name == sym::saturating_add;
let lhs = args[0].immediate();
let rhs = args[1].immediate();
let llvm_name = &format!(
"llvm.{}{}.sat.i{}",
if signed { 's' } else { 'u' },
if is_add { "add" } else { "sub" },
width
);
self.call_intrinsic(llvm_name, &[lhs, rhs])
}
_ => bug!(),
},
None => {
tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
span,
name,
ty,
});
return Ok(());
}
sym::bitreverse => self
.call_intrinsic(&format!("llvm.bitreverse.i{width}"), &[
args[0].immediate()
]),
sym::rotate_left | sym::rotate_right => {
let is_left = name == sym::rotate_left;
let val = args[0].immediate();
let raw_shift = args[1].immediate();
// rotate = funnel shift with first two args the same
let llvm_name =
&format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width);

// llvm expects shift to be the same type as the values, but rust
// always uses `u32`.
let raw_shift = self.intcast(raw_shift, self.val_ty(val), false);

self.call_intrinsic(llvm_name, &[val, val, raw_shift])
}
sym::saturating_add | sym::saturating_sub => {
let is_add = name == sym::saturating_add;
let lhs = args[0].immediate();
let rhs = args[1].immediate();
let llvm_name = &format!(
"llvm.{}{}.sat.i{}",
if signed { 's' } else { 'u' },
if is_add { "add" } else { "sub" },
width
);
self.call_intrinsic(llvm_name, &[lhs, rhs])
}
_ => bug!(),
}
}

Expand Down Expand Up @@ -2531,19 +2531,3 @@ fn generic_simd_intrinsic<'ll, 'tcx>(

span_bug!(span, "unknown SIMD intrinsic");
}

// Returns the width of an int Ty, and if it's signed or not
// Returns None if the type is not an integer
// FIXME: there’s multiple of this functions, investigate using some of the already existing
// stuffs.
fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> {
match ty.kind() {
ty::Int(t) => {
Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), true))
}
ty::Uint(t) => {
Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), false))
}
_ => None,
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/error_codes/E0751.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ impl !MyTrait for i32 { } // error!
```

Negative implementations are a promise that the trait will never be implemented
for the given types. Therefore, both cannot exists at the same time.
for the given types. Therefore, both cannot exist at the same time.
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,7 @@ pub fn parse_ast_fragment<'a>(
}
}
AstFragmentKind::Ty => AstFragment::Ty(this.parse_ty()?),
AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat_allow_top_alt(
AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat_allow_top_guard(
None,
RecoverComma::No,
RecoverColon::Yes,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,8 @@ declare_features! (
(incomplete, generic_const_items, "1.73.0", Some(113521)),
/// Allows registering static items globally, possibly across crates, to iterate over at runtime.
(unstable, global_registration, "1.80.0", Some(125119)),
/// Allows using guards in patterns.
(incomplete, guard_patterns, "CURRENT_RUSTC_VERSION", Some(129967)),
/// Allows using `..=X` as a patterns in slices.
(unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)),
/// Allows `if let` guard in match arms.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1235,7 +1235,7 @@ impl EarlyLintPass for UnusedParens {
self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
},
// Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
Ident(.., Some(p)) | Box(p) | Deref(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
Ident(.., Some(p)) | Box(p) | Deref(p) | Guard(p, _) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
// Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
// Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
Expand Down
58 changes: 26 additions & 32 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2631,7 +2631,7 @@ impl<'a> Parser<'a> {
};
self.bump(); // Eat `let` token
let lo = self.prev_token.span;
let pat = self.parse_pat_allow_top_alt(
let pat = self.parse_pat_no_top_guard(
None,
RecoverComma::Yes,
RecoverColon::Yes,
Expand Down Expand Up @@ -2778,7 +2778,7 @@ impl<'a> Parser<'a> {
};
// Try to parse the pattern `for ($PAT) in $EXPR`.
let pat = match (
self.parse_pat_allow_top_alt(
self.parse_pat_allow_top_guard(
None,
RecoverComma::Yes,
RecoverColon::Yes,
Expand Down Expand Up @@ -3241,7 +3241,7 @@ impl<'a> Parser<'a> {
// then we should recover.
let mut snapshot = this.create_snapshot_for_diagnostic();
let pattern_follows = snapshot
.parse_pat_allow_top_alt(
.parse_pat_no_top_guard(
None,
RecoverComma::Yes,
RecoverColon::Yes,
Expand Down Expand Up @@ -3315,43 +3315,37 @@ impl<'a> Parser<'a> {

fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Expr>>)> {
if self.token == token::OpenDelim(Delimiter::Parenthesis) {
// Detect and recover from `($pat if $cond) => $arm`.
let left = self.token.span;
match self.parse_pat_allow_top_alt(
let pat = self.parse_pat_no_top_guard(
None,
RecoverComma::Yes,
RecoverColon::Yes,
CommaRecoveryMode::EitherTupleOrPipe,
) {
Ok(pat) => Ok((pat, self.parse_match_arm_guard()?)),
Err(err)
if let prev_sp = self.prev_token.span
&& let true = self.eat_keyword(kw::If) =>
{
// We know for certain we've found `($pat if` so far.
let mut cond = match self.parse_match_guard_condition() {
Ok(cond) => cond,
Err(cond_err) => {
cond_err.cancel();
return Err(err);
}
};
err.cancel();
CondChecker::new(self).visit_expr(&mut cond);
self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis)]);
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
let right = self.prev_token.span;
self.dcx().emit_err(errors::ParenthesesInMatchPat {
span: vec![left, right],
sugg: errors::ParenthesesInMatchPatSugg { left, right },
});
Ok((self.mk_pat(left.to(prev_sp), ast::PatKind::Wild), Some(cond)))
}
Err(err) => Err(err),
)?;
if let ast::PatKind::Paren(subpat) = &pat.kind
&& let ast::PatKind::Guard(..) = &subpat.kind
{
// Detect and recover from `($pat if $cond) => $arm`.
// FIXME(guard_patterns): convert this to a normal guard instead
let span = pat.span;
let ast::PatKind::Paren(subpat) = pat.into_inner().kind else { unreachable!() };
let ast::PatKind::Guard(_, mut cond) = subpat.into_inner().kind else {
unreachable!()
};
self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
CondChecker::new(self).visit_expr(&mut cond);
let right = self.prev_token.span;
self.dcx().emit_err(errors::ParenthesesInMatchPat {
span: vec![left, right],
sugg: errors::ParenthesesInMatchPatSugg { left, right },
});
Ok((self.mk_pat(span, ast::PatKind::Wild), Some(cond)))
} else {
Ok((pat, self.parse_match_arm_guard()?))
}
} else {
// Regular parser flow:
let pat = self.parse_pat_allow_top_alt(
let pat = self.parse_pat_no_top_guard(
None,
RecoverComma::Yes,
RecoverColon::Yes,
Expand Down
Loading

0 comments on commit df5b8e3

Please sign in to comment.