Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
5e53d92
fix
bb1yd Jun 28, 2026
a0b3416
add safety section for mem::zeroed
hxuhack Apr 1, 2026
b78c8ac
Provide a `supertrait_def_ids()` function in rustc_type_ir's interner
ChayimFriedman2 Aug 21, 2026
940498d
fix const_item_mutation lint to use needs_drop instead of has_dtor
Rachit2323 Aug 24, 2026
98a157a
Add test for the fn item uniqueness note with late bound lifetimes
zakrad Aug 31, 2026
21228c2
Do not suppress the fn item uniqueness note for late bound lifetimes
zakrad Aug 31, 2026
ac0e9fa
First pass at windows::fs::FileExt.seek_read_exact()
json420 Sep 16, 2026
88af4fd
First pass at windows::fs::FileExt.seek_write_all()
json420 Sep 16, 2026
535fa77
Fix function signature in seek_read_exact(), duh
json420 Sep 16, 2026
5c56219
First pass at tests for .seek_read_exact(), seek_write_all()
json420 Sep 16, 2026
6df2dd9
Whitespace fix
json420 Sep 16, 2026
482f884
Use hypothetical seek_read_exact_seek_write_all feature also for .see…
json420 Sep 16, 2026
165e755
Tracking issues 162868
json420 Sep 16, 2026
fafa1ee
Oops, fix seek_write_all() doc example, was using write_all_at() still
json420 Sep 17, 2026
d179246
Add mocked test for windows FileExt trait
json420 Sep 17, 2026
c0785e4
Spelling fixes
json420 Sep 17, 2026
2adb748
Expand test for windows FileExt trait to include almost all scenarios
json420 Sep 17, 2026
1ee8475
Split three tests out of file_test_windows_fileext_trait()
json420 Sep 18, 2026
c9c5a06
Remove old versions of those 3 tests
json420 Sep 18, 2026
66a3b72
Split remaining file_test_windows_fileext_trait() into case 4, 5
json420 Sep 18, 2026
71f10b4
More test cleanup, always test expected_offset where possible
json420 Sep 18, 2026
e9aaeef
Test read first for consistency
json420 Sep 18, 2026
c2218a7
Use same doctsring examples as seek_read(), seek_write()
json420 Sep 18, 2026
6ac2b72
Missing period
json420 Sep 18, 2026
ee766dc
post GH comment on types nominations
lqd Sep 18, 2026
75b444d
Constify `impl FromStr for NonZero<T>`
sorairolake Sep 6, 2026
c30f2a4
Use `end_point` for trailing brace in `let...else` diagnostics
lapla-cogito Sep 19, 2026
1b3f10d
add Dir::try_clone
RalfJung Sep 19, 2026
bbdd298
Oops: actually call _exact(), _all() methods in case 2, 3
json420 Sep 19, 2026
6524ec5
Remove incorrect parse error recovery code that mistakes `as` casts f…
fmease Sep 12, 2026
c095a72
add test
inkreasing Sep 18, 2026
fe96227
recover true and false as bool type
inkreasing Sep 18, 2026
8026b7b
bless tests
inkreasing Sep 18, 2026
e224f8f
Further simplify `parse_assoc_op_cast`
fmease Sep 12, 2026
8a0a23d
Trigger "C array" parse error recovery in far fewer cases
fmease Sep 12, 2026
d80ee2c
Add missing seek_read_exact_seek_write_all feature flags in doc examples
json420 Sep 19, 2026
656f710
Rollup merge of #158515 - bb1yd:let-else-detect-invisible-delimiter, …
jhpratt Sep 19, 2026
76d9a0b
Rollup merge of #160097 - Rachit2323:const-mutation-needs-drop, r=jac…
jhpratt Sep 19, 2026
8c3d95b
Rollup merge of #161435 - ChayimFriedman2:supertraits-query, r=jackh726
jhpratt Sep 19, 2026
5092b0f
Rollup merge of #161894 - zakrad:fix-fn-item-note-late-bound-145558, …
jhpratt Sep 19, 2026
f897da9
Rollup merge of #162990 - lqd:types-magic, r=Mark-Simulacrum
jhpratt Sep 19, 2026
f07549e
Rollup merge of #154665 - safer-rust:fix-doc, r=Mark-Simulacrum
jhpratt Sep 19, 2026
aede7a3
Rollup merge of #162700 - fmease:rm-dead-ascr-recov, r=fee1-dead
jhpratt Sep 19, 2026
ff7646b
Rollup merge of #162705 - fmease:fix-c-array-diag, r=JonathanBrouwer
jhpratt Sep 19, 2026
f4e5ed9
Rollup merge of #162875 - json420:seek_read_exact, r=clarfonthey
jhpratt Sep 19, 2026
8f1d38e
Rollup merge of #162988 - inkreasing:attempt2-fix-162947, r=chenyukang
jhpratt Sep 19, 2026
71748b1
Rollup merge of #162995 - sorairolake:const-nonzero-from-str, r=jhpratt
jhpratt Sep 19, 2026
5b0448e
Rollup merge of #163006 - lapla-cogito:letelse_fullwidthbrace, r=folk…
jhpratt Sep 19, 2026
07ca6e3
Rollup merge of #163007 - RalfJung:dirfd-clone, r=ChrisDenton
jhpratt Sep 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/context/impl_interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.impl_super_outlives(impl_def_id)
}

fn supertrait_def_ids(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> {
rustc_type_ir::elaborate::supertrait_def_ids(self, trait_def_id)
}

fn impl_is_const(self, def_id: DefId) -> bool {
debug_assert_matches!(self.def_kind(def_id), DefKind::Impl { of_trait: true });
self.is_conditionally_const(def_id)
Expand Down
40 changes: 25 additions & 15 deletions compiler/rustc_mir_transform/src/check_const_item_mutation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use rustc_hir::HirId;
use rustc_lint_defs::builtin::CONST_ITEM_MUTATION;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_span::Span;
use rustc_span::def_id::DefId;

Expand Down Expand Up @@ -35,8 +35,9 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
fn is_const_item_without_destructor(&self, local: Local) -> Option<DefId> {
let def_id = self.is_const_item(local)?;

// We avoid linting mutation of a const item if the const's type has a
// Drop impl. The Drop logic observes the mutation which was performed.
// We avoid linting mutation of a const item if the const's type needs
// drop. Any drop logic (including that of fields) may observe the
// mutation which was performed.
//
// pub struct Log { msg: &'static str }
// pub const LOG: Log = Log { msg: "" };
Expand All @@ -46,21 +47,30 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
//
// LOG.msg = "wow"; // prints "wow"
//
// Likewise, if a field of the const type has its own Drop impl, that
// drop logic may also observe the mutation:
//
// struct Inner { val: u32 }
// impl Drop for Inner { fn drop(&mut self) { println!("{}", self.val); } }
// struct Outer { inner: Inner }
// const O: Outer = Outer { inner: Inner { val: 0 } };
//
// O.inner.val = 42; // Inner::drop prints "42"
//
// FIXME(https://github.com/rust-lang/rust/issues/77425):
// Drop this exception once there is a stable attribute to suppress the
// const item mutation lint for a single specific const only. Something
// equivalent to:
//
// #[const_mutation_allowed]
// pub const LOG: Log = Log { msg: "" };
// FIXME: this should not be checking for `Drop` impls,
// but whether it or any field has a Drop impl (`needs_drop`)
// as fields' Drop impls may make this observable, too.
match self.tcx.type_of(def_id).skip_binder().ty_adt_def().map(|adt| adt.has_dtor(self.tcx))
{
Some(true) => None,
Some(false) | None => Some(def_id),
// const item mutation lint for a single specific const only.
let ty = self.tcx.type_of(def_id).instantiate_identity().skip_norm_wip();
// `needs_drop` is overly conservative for types that contain type
// parameters (e.g. `Self` in a trait associated const): it always
// returns `true` because the parameter *might* implement Drop, even
// when the concrete type at the call site does not. In that case we
// cannot suppress the lint, so fall through and warn.
if ty.has_param() {
return Some(def_id);
}
let typing_env = ty::TypingEnv::non_body_analysis(self.tcx, def_id);
if ty.needs_drop(self.tcx, typing_env) { None } else { Some(def_id) }
}

/// If we should lint on this usage, return the [`HirId`], source [`Span`]
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1096,7 +1096,8 @@ where
.auto_traits()
.into_iter()
.chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
elaborate::supertrait_def_ids(self.cx(), principal_def_id)
self.cx()
.supertrait_def_ids(principal_def_id)
.filter(|def_id| self.cx().trait_is_auto(*def_id))
}))
.collect();
Expand Down
153 changes: 35 additions & 118 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,7 @@ impl<'a> Parser<'a> {
let (rhs, span) = finish_parsing_bin_op(self)?;
self.mk_expr(span, ExprKind::Assign(lhs, rhs, op.span))
}
AssocOp::Cast => {
self.parse_assoc_op_cast(lhs, lhs_span, op.span, ExprKind::Cast)?
}
AssocOp::Cast => self.parse_assoc_op_cast(lhs, lhs_span, op.span)?,
AssocOp::Range(limits) => self.parse_expr_range(min_prec, lhs, limits, op.span)?,
};

Expand Down Expand Up @@ -555,17 +553,17 @@ impl<'a> Parser<'a> {
lhs: Box<Expr>,
lhs_span: Span,
op_span: Span,
expr_kind: fn(Box<Expr>, Box<Ty>) -> ExprKind,
) -> PResult<'a, Box<Expr>> {
let mk_expr = |this: &mut Self, lhs: Box<Expr>, rhs: Box<Ty>| {
this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span), expr_kind(lhs, rhs))
let mk_expr = |this: &mut Self, rhs: Box<Ty>| {
let span = this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span);
this.mk_expr(span, ExprKind::Cast(lhs, rhs))
};

// Save the state of the parser before parsing type normally, in case there is a
// LessThan comparison after this cast.
let parser_snapshot_before_type = self.clone();
let cast_expr = match self.parse_as_cast_ty() {
Ok(rhs) => mk_expr(self, lhs, rhs),
Ok(rhs) => mk_expr(self, rhs),
Err(type_err) => {
if !self.may_recover() {
return Err(type_err);
Expand All @@ -576,46 +574,11 @@ impl<'a> Parser<'a> {
// `usize < y` as a type with generic arguments.
let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);

// Check for typo of `'a: loop { break 'a }` with a missing `'`.
match (&lhs.kind, &self.token.kind) {
(
// `foo: `
ExprKind::Path(None, ast::Path { segments, .. }),
token::Ident(kw::For | kw::Loop | kw::While, IdentIsRaw::No),
) if let [segment] = segments.as_slice() => {
let snapshot = self.create_snapshot_for_diagnostic();
let label = Label {
ident: Ident::from_str_and_span(
&format!("'{}", segment.ident),
segment.ident.span,
),
};
match self.parse_expr_labeled(label, false) {
Ok(expr) => {
type_err.cancel();
self.dcx().emit_err(crate::diagnostics::MalformedLoopLabel {
span: label.ident.span,
suggestion: label.ident.span.shrink_to_lo(),
});
return Ok(expr);
}
Err(err) => {
err.cancel();
self.restore_snapshot(snapshot);
}
}
}
_ => {}
}

match self.parse_path(PathStyle::Expr) {
Ok(path) => {
let span_after_type = parser_snapshot_after_type.token.span;
let expr = mk_expr(
self,
lhs,
self.mk_ty(path.span, TyKind::Path(None, path.clone())),
);
let expr =
mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path.clone())));

let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);
match self.token.kind {
Expand Down Expand Up @@ -674,48 +637,38 @@ impl<'a> Parser<'a> {
// written `((&x) as T)[0]`.

let span = cast_expr.span;

let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?;

// Check if an illegal postfix operator has been added after the cast.
// If the resulting expression is not a cast, it is an illegal postfix operator.
if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) {
let msg = format!(
"cast cannot be followed by {}",
match with_postfix.kind {
ExprKind::Index(..) => "indexing",
ExprKind::Try(_) => "`?`",
ExprKind::Field(_, _) => "a field access",
ExprKind::MethodCall(_) => "a method call",
ExprKind::Call(_, _) => "a function call",
ExprKind::Await(_, _) => "`.await`",
ExprKind::Use(_, _) => "`.use`",
ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`",
ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
ExprKind::Err(_) => return Ok(with_postfix),
_ => unreachable!(
"did not expect {:?} as an illegal postfix operator following cast",
with_postfix.kind
),
}
);
let mut err = self.dcx().struct_span_err(span, msg);

let suggest_parens = |err: &mut Diag<'_>| {
let suggestions = vec![
(span.shrink_to_lo(), "(".to_string()),
(span.shrink_to_hi(), ")".to_string()),
];
err.multipart_suggestion(
let kind = match with_postfix.kind {
ExprKind::Index(..) => "indexing",
ExprKind::Try(_) => "`?`",
ExprKind::Field(_, _) => "a field access",
ExprKind::MethodCall(_) => "a method call",
ExprKind::Call(_, _) => "a function call",
ExprKind::Await(_, _) => "`.await`",
ExprKind::Use(_, _) => "`.use`",
ExprKind::Yield(YieldKind::Postfix(_)) => "`.yield`",
ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match",
ExprKind::Err(_) => return Ok(with_postfix),
_ => unreachable!(
"did not expect {:?} as an illegal postfix operator following cast",
with_postfix.kind
),
};
self.dcx()
.struct_span_err(span, format!("cast cannot be followed by {kind}"))
.with_multipart_suggestion(
"try surrounding the expression in parentheses",
suggestions,
vec![
(span.shrink_to_lo(), "(".to_string()),
(span.shrink_to_hi(), ")".to_string()),
],
Applicability::MachineApplicable,
);
};

suggest_parens(&mut err);

err.emit();
)
.emit();
};
Ok(with_postfix)
}
Expand Down Expand Up @@ -1401,6 +1354,9 @@ impl<'a> Parser<'a> {
if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {
return Ok(expr);
}
if let Some(arr) = this.recover_from_c_array(lo) {
return Ok(arr);
}
this.parse_expr_block(None, lo, BlockCheckMode::Default)
} else if this.check(exp!(Or)) || this.check(exp!(OrOr)) {
this.parse_expr_closure().map_err(|mut err| {
Expand Down Expand Up @@ -2227,39 +2183,6 @@ impl<'a> Parser<'a> {
}
}

fn is_array_like_block(&mut self) -> bool {
self.token.kind == TokenKind::OpenBrace
&& self
.look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_)))
&& self.look_ahead(2, |t| t == &token::Comma)
&& self.look_ahead(3, |t| t.can_begin_expr())
}

/// Emits a suggestion if it looks like the user meant an array but
/// accidentally used braces, causing the code to be interpreted as a block
/// expression.
fn maybe_suggest_brackets_instead_of_braces(&mut self, lo: Span) -> Option<Box<Expr>> {
let mut snapshot = self.create_snapshot_for_diagnostic();
match snapshot.parse_expr_array_or_repeat(exp!(CloseBrace)) {
Ok(arr) => {
let guar = self.dcx().emit_err(crate::diagnostics::ArrayBracketsInsteadOfBraces {
span: arr.span,
sub: crate::diagnostics::ArrayBracketsInsteadOfBracesSugg {
left: lo,
right: snapshot.prev_token.span,
},
});

self.restore_snapshot(snapshot);
Some(self.mk_expr_err(arr.span, guar))
}
Err(e) => {
e.cancel();
None
}
}
}

fn suggest_missing_semicolon_before_array(
&self,
prev_span: Span,
Expand Down Expand Up @@ -2309,12 +2232,6 @@ impl<'a> Parser<'a> {
lo: Span,
blk_mode: BlockCheckMode,
) -> PResult<'a, Box<Expr>> {
if self.may_recover() && self.is_array_like_block() {
if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo) {
return Ok(arr);
}
}

if self.token.is_metavar_block() {
self.dcx().emit_err(crate::diagnostics::InvalidBlockMacroSegment {
span: self.token.span,
Expand Down
34 changes: 33 additions & 1 deletion compiler/rustc_parse/src/parser/expr/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use rustc_ast::{BinOpKind, Expr, ExprKind, token};
use rustc_errors::{Applicability, Diag, PResult};
use rustc_span::{Span, Spanned, respan, sym};

use crate::diagnostics;
use crate::parser::Parser;
use crate::{diagnostics, exp};

impl<'a> Parser<'a> {
/// Recover from alphabetic logic operators `and` and `or` as found in e.g., Python and PHP.
Expand Down Expand Up @@ -216,6 +216,38 @@ impl<'a> Parser<'a> {
}
err
}

/// Recover from array expressions as found in C like `{0, 1, 2, 3}`.
pub(super) fn recover_from_c_array(&mut self, lo: Span) -> Option<Box<Expr>> {
if !self.may_recover()
|| self.token.kind != token::OpenBrace
|| self.look_ahead(1, |t| !matches!(t.kind, token::Literal(_)))
|| self.look_ahead(2, |t| t != &token::Comma)
|| self.look_ahead(3, |t| !t.can_begin_expr())
{
return None;
}

let mut snapshot = self.create_snapshot_for_diagnostic();
match snapshot.parse_expr_array_or_repeat(exp!(CloseBrace)) {
Ok(arr) => {
let guar = self.dcx().emit_err(diagnostics::ArrayBracketsInsteadOfBraces {
span: arr.span,
sub: diagnostics::ArrayBracketsInsteadOfBracesSugg {
left: lo,
right: snapshot.prev_token.span,
},
});

self.restore_snapshot(snapshot);
Some(self.mk_expr_err(arr.span, guar))
}
Err(e) => {
e.cancel();
None
}
}
}
}

#[derive(Copy, Clone)]
Expand Down
Loading
Loading