Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
786777f
Fix an ICE in the vtable iteration for a trait reference in const eva…
jakubadamw Feb 7, 2026
3541645
Move tests from tests/crashes to tests/ui now that they don't ICE
jakubadamw Feb 7, 2026
f8618d0
Report AsyncFn traits in async closure lifetime note
InvalidPathException May 12, 2026
b6422f7
Equate captures-by-ref ty to an error type when args reference errors
swjng May 7, 2026
bb5f1c8
`Lift_Generic` can lift generic parameters
Jamesbarford May 26, 2026
2837932
Add comment explaining why we need a `Lift` bound for all fields
Jamesbarford May 26, 2026
91a328f
Can lift structs with a field of `PhantomData`
Jamesbarford May 27, 2026
82c1c87
Eagerly decide whether relaxed bounds are allowed or not
oli-obk Jun 2, 2026
876d5f3
Rename and document a relaxed bound reason
oli-obk Jun 2, 2026
a55c892
Simplify generic Lift bounds
Jamesbarford Jun 3, 2026
57da2f6
Add documentation comment for `lift_derive`, move `PhantomData` check…
Jamesbarford Jun 4, 2026
cb09a42
Emit nofree attribute
nikic May 7, 2026
8832c42
Refactor/expand rustc_attr_parsing docs
mejrs Jun 4, 2026
d4e6f26
rustc_target: Use rustc_abi instead of cfg_abi to detect powerpcspe
taiki-e Jun 4, 2026
3ac83ce
Rollup merge of #156281 - nikic:nofree, r=RalfJung
JonathanBrouwer Jun 4, 2026
eb0d42d
Rollup merge of #157305 - oli-obk:relaxed-bounds-maybe, r=fmease
JonathanBrouwer Jun 4, 2026
14dd286
Rollup merge of #148713 - InvalidPathException:master, r=lcnr
JonathanBrouwer Jun 4, 2026
b97c8ef
Rollup merge of #156266 - swjng:fix/async-closure-coroutine-captures-…
JonathanBrouwer Jun 4, 2026
730bc39
Rollup merge of #156417 - jakubadamw:issue-137190-reapplied, r=lcnr
JonathanBrouwer Jun 4, 2026
3503a9c
Rollup merge of #156956 - Jamesbarford:feat/extend-lift-generic-capab…
JonathanBrouwer Jun 4, 2026
7ff0bb8
Rollup merge of #157140 - taiki-e:powerpcspe-asm, r=RalfJung
JonathanBrouwer Jun 4, 2026
b5058b6
Rollup merge of #157423 - mejrs:rustc_attr_parsing-docs, r=JonathanBr…
JonathanBrouwer Jun 4, 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
13 changes: 9 additions & 4 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1992,7 +1992,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
bounds: &[GenericBound],
colon_span: Option<Span>,
parent_span: Span,
rbp: RelaxedBoundPolicy<'_>,
rbp: RelaxedBoundPolicy,
itctx: ImplTraitContext,
origin: PredicateOrigin,
) -> Option<hir::WherePredicate<'hir>> {
Expand Down Expand Up @@ -2067,10 +2067,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
bounded_ty,
bounds,
}) => {
let rbp = if bound_generic_params.is_empty() {
RelaxedBoundPolicy::AllowedIfOnTyParam(bounded_ty.id, params)
let rbp = if bound_generic_params.is_empty()
&& let Some(res) =
self.get_partial_res(bounded_ty.id).and_then(|r| r.full_res())
&& let Res::Def(DefKind::TyParam, def_id) = res
&& params.iter().any(|p| def_id == self.local_def_id(p.id).to_def_id())
{
RelaxedBoundPolicy::Allowed
} else {
RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::LateBoundVarsInScope)
RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::WhereBound)
};
hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate {
bound_generic_params: self.lower_generic_params(
Expand Down
27 changes: 10 additions & 17 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,8 @@ impl<'tcx> ResolverAstLowering<'tcx> {
/// Relaxed bounds should only be allowed in places where we later
/// (namely during HIR ty lowering) perform *sized elaboration*.
#[derive(Clone, Copy, Debug)]
enum RelaxedBoundPolicy<'a> {
enum RelaxedBoundPolicy {
Allowed,
AllowedIfOnTyParam(NodeId, &'a [ast::GenericParam]),
Forbidden(RelaxedBoundForbiddenReason),
}

Expand All @@ -325,7 +324,9 @@ enum RelaxedBoundForbiddenReason {
SuperTrait,
TraitAlias,
AssocTyBounds,
LateBoundVarsInScope,
/// We do not allow where bounds doing relaxed bounds,
/// except if it's for generic parameters of the current item.
WhereBound,
}

/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
Expand Down Expand Up @@ -1950,7 +1951,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_param_bound(
&mut self,
tpb: &GenericBound,
rbp: RelaxedBoundPolicy<'_>,
rbp: RelaxedBoundPolicy,
itctx: ImplTraitContext,
) -> hir::GenericBound<'hir> {
match tpb {
Expand Down Expand Up @@ -2188,7 +2189,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_poly_trait_ref(
&mut self,
PolyTraitRef { bound_generic_params, modifiers, trait_ref, span, parens: _ }: &PolyTraitRef,
rbp: RelaxedBoundPolicy<'_>,
rbp: RelaxedBoundPolicy,
itctx: ImplTraitContext,
) -> hir::PolyTraitRef<'hir> {
let bound_generic_params =
Expand All @@ -2212,7 +2213,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&self,
trait_ref: hir::TraitRef<'_>,
span: Span,
rbp: RelaxedBoundPolicy<'_>,
rbp: RelaxedBoundPolicy,
) {
// Even though feature `more_maybe_bounds` enables the user to relax all default bounds
// other than `Sized` in a lot more positions (thereby bypassing the given policy), we don't
Expand All @@ -2225,14 +2226,6 @@ impl<'hir> LoweringContext<'_, 'hir> {

match rbp {
RelaxedBoundPolicy::Allowed => return,
RelaxedBoundPolicy::AllowedIfOnTyParam(id, params) => {
if let Some(res) = self.get_partial_res(id).and_then(|r| r.full_res())
&& let Res::Def(DefKind::TyParam, def_id) = res
&& params.iter().any(|p| def_id == self.local_def_id(p.id).to_def_id())
{
return;
}
}
RelaxedBoundPolicy::Forbidden(reason) => {
let gate = |context, subject| {
let extended = self.tcx.features().more_maybe_bounds();
Expand Down Expand Up @@ -2272,7 +2265,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
return;
}
RelaxedBoundForbiddenReason::AssocTyBounds
| RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
| RelaxedBoundForbiddenReason::WhereBound => {}
};
}
}
Expand All @@ -2294,7 +2287,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_param_bounds(
&mut self,
bounds: &[GenericBound],
rbp: RelaxedBoundPolicy<'_>,
rbp: RelaxedBoundPolicy,
itctx: ImplTraitContext,
) -> hir::GenericBounds<'hir> {
self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, rbp, itctx))
Expand All @@ -2303,7 +2296,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_param_bounds_mut(
&mut self,
bounds: &[GenericBound],
rbp: RelaxedBoundPolicy<'_>,
rbp: RelaxedBoundPolicy,
itctx: ImplTraitContext,
) -> impl Iterator<Item = hir::GenericBound<'hir>> {
bounds.iter().map(move |bound| self.lower_param_bound(bound, rbp, itctx))
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_attr_parsing/src/attributes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Traits for parsing attributes.
//!
//! This module defines traits for attribute parsers, little state machines that recognize and parse
//! attributes out of a longer list of attributes. The main trait is called [`AttributeParser`].
//! You can find more docs about [`AttributeParser`]s on the trait itself.
Expand All @@ -7,9 +9,11 @@
//! Specifically, you might not care about managing the state of your [`AttributeParser`]
//! state machine yourself. In this case you can choose to implement:
//!
//! - [`SingleAttributeParser`](crate::attributes::SingleAttributeParser): makes it easy to implement an attribute which should error if it
//! - [`NoArgsAttributeParser`]: used for implementing an attribute that appears only once and
//! accepts no arguments
//! - [`SingleAttributeParser`]: makes it easy to implement an attribute which should error if it
//! appears more than once in a list of attributes
//! - [`CombineAttributeParser`](crate::attributes::CombineAttributeParser): makes it easy to implement an attribute which should combine the
//! - [`CombineAttributeParser`]: makes it easy to implement an attribute which should combine the
//! contents of attributes, if an attribute appear multiple times in a list
//!
//! Attributes should be added to `crate::context::ATTRIBUTE_PARSERS` to be parsed.
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! Context given to attribute parsers when parsing.
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
Expand Down Expand Up @@ -846,6 +847,9 @@ impl ShouldEmit {
}
}

/// The interface for issuing argument parsing related diagnostics.
///
/// It can be obtained through the [`adcx`](AcceptContext::adcx) method on [`AcceptContext`].
pub(crate) struct AttributeDiagnosticContext<'a, 'f, 'sess> {
ctx: &'a mut AcceptContext<'f, 'sess>,
custom_suggestions: Vec<Suggestion>,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! API for other crates to parse attributes themselves.
use std::convert::identity;
#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicBool, Ordering};
Expand Down
30 changes: 11 additions & 19 deletions compiler/rustc_attr_parsing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
//!
//! ## Architecture
//! This crate is part of a series of crates and modules that handle attribute processing.
//! - [rustc_hir::attrs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/index.html): Defines the data structures that store parsed attributes
//! - [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html): This crate, handles the parsing of attributes
//! - (planned) rustc_attr_validation: Will handle attribute validation, logic currently handled in `rustc_passes`
//! - [`rustc_hir::attrs`]: Defines the data structures that store parsed attributes
//! - `rustc_attr_parsing`: This crate, handles the parsing of attributes
//! - [`rustc_passes::check_attr`] handles attribute validation that cannot be done in this crate
//!
//! The separation between data structures and parsing follows the principle of separation of concerns.
//! Data structures (`rustc_hir::attrs`) define what attributes look like after parsing.
Expand All @@ -13,7 +13,7 @@
//! the parsing logic, making the codebase more modular and maintainable.
//!
//! ## Background
//! Previously, the compiler had a single attribute definition (`ast::Attribute`) with parsing and
//! Previously, the compiler had a single attribute definition ([`ast::Attribute`]) with parsing and
//! validation scattered throughout the codebase. This was reorganized for better maintainability
//! (see [#131229](https://github.com/rust-lang/rust/issues/131229)).
//!
Expand Down Expand Up @@ -61,7 +61,7 @@
//! `#[stable(...)]` and `#[unstable()]` cannot occur together, and both semantically define
//! a "stability" of an item. So, the stability attribute has an
//! [`AttributeParser`](attributes::AttributeParser) that recognizes both the `#[stable()]`
//! and `#[unstable()]` syntactic attributes, and at the end produce a single
//! and `#[unstable()]` syntactic attributes, and at the end produces a single
//! [`AttributeKind::Stability`](rustc_hir::attrs::AttributeKind::Stability).
//!
//! When multiple instances of the same attribute are allowed, they're combined into a single
Expand All @@ -82,6 +82,9 @@
//! However, sometimes an attributes' parsed form is needed before the HIR is constructed.
//! This is referred to as "early" attribute parsing,
//! and is performed using the `parse_limited_*` family of functions on `AttributeParser`.
//!
//! [`ast::Attribute`]: rustc_ast::ast::Attribute
//! [`rustc_passes::check_attr`]: ../rustc_passes/check_attr/index.html

// tidy-alphabetical-start
#![feature(decl_macro)]
Expand All @@ -91,24 +94,13 @@
// tidy-alphabetical-end

#[macro_use]
/// All the individual attribute parsers for each of rustc's built-in attributes.
mod attributes;

/// All the important types given to attribute parsers when parsing
pub(crate) mod context;

/// Code that other crates interact with, to actually parse a list (or sometimes single)
/// attribute.
mod interface;

/// Despite this entire module called attribute parsing and the term being a little overloaded,
/// in this module the code lives that actually breaks up tokenstreams into semantic pieces of attributes,
/// like lists or name-value pairs.
pub mod parser;

mod check_cfg;
mod context;
mod early_parsed;
mod errors;
mod interface;
pub mod parser;
mod safety;
mod session_diagnostics;
mod stability;
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_attr_parsing/src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
//! Parsing of attribute arguments.
//!
//! Depending on the attribute parser, an [`ArgParser`] can be used to parse the arguments given to
//! an attribute. See its documentation for more information.
//!
//! This is in essence an (improved) duplicate of `rustc_ast/attr/mod.rs`.
//! That module is intended to be deleted in its entirety.
//!
Expand Down Expand Up @@ -89,6 +94,12 @@ impl<P: Borrow<Path>> Display for PathParser<P> {
}
}

/// Used for parsing attribute arguments.
///
/// See also [`AttributeDiagnosticContext`], which is the preferred interface for issuing argument
/// parsing related diagnostics.
///
/// [`AttributeDiagnosticContext`]: crate::context::AttributeDiagnosticContext
#[derive(Debug)]
#[must_use]
pub enum ArgParser {
Expand Down
41 changes: 23 additions & 18 deletions compiler/rustc_borrowck/src/diagnostics/region_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,12 @@ impl RegionName {
| RegionNameSource::NamedEarlyParamRegion(span) => {
diag.span_label(*span, format!("lifetime `{self}` defined here"));
}
RegionNameSource::SynthesizedFreeEnvRegion(span, note) => {
RegionNameSource::SynthesizedFreeEnvRegion(span, closure_trait) => {
diag.span_label(*span, format!("lifetime `{self}` represents this closure's body"));
diag.note(*note);
diag.note(format!(
"closure implements `{closure_trait}`, so references to captured variables \
can't escape the closure"
));
}
RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::CannotMatchHirTy(
span,
Expand Down Expand Up @@ -326,9 +329,15 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
ty::LateParamRegionKind::ClosureEnv => {
let def_ty = self.regioncx.universal_regions().defining_ty;

let closure_kind = match def_ty {
DefiningTy::Closure(_, args) => args.as_closure().kind(),
DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().kind(),
let (is_lending_coroutine_closure, closure_kind) = match def_ty {
DefiningTy::Closure(_, args) => (false, args.as_closure().kind()),
DefiningTy::CoroutineClosure(_, args) => {
let args = args.as_coroutine_closure();
(
!args.tupled_upvars_ty().is_ty_var() && args.has_self_borrows(),
args.kind(),
)
}
_ => {
// Can't have BrEnv in functions, constants or coroutines.
bug!("BrEnv outside of closure.");
Expand All @@ -340,23 +349,19 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
bug!("Closure is not defined by a closure expr");
};
let region_name = self.synthesize_region_name();
let note = match closure_kind {
ty::ClosureKind::Fn => {
"closure implements `Fn`, so references to captured variables \
can't escape the closure"
}
ty::ClosureKind::FnMut => {
"closure implements `FnMut`, so references to captured variables \
can't escape the closure"
}
ty::ClosureKind::FnOnce => {
bug!("BrEnv in a `FnOnce` closure");
}
let closure_trait = match (is_lending_coroutine_closure, closure_kind) {
(false, kind) => kind.as_str(),
(true, ty::ClosureKind::Fn) => "AsyncFn",
(true, ty::ClosureKind::FnMut) => "AsyncFnMut",
(true, ty::ClosureKind::FnOnce) => "AsyncFnOnce",
};

Some(RegionName {
name: region_name,
source: RegionNameSource::SynthesizedFreeEnvRegion(fn_decl_span, note),
source: RegionNameSource::SynthesizedFreeEnvRegion(
fn_decl_span,
closure_trait,
),
})
}

Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_codegen_llvm/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@ trait ArgAttributesExt {
const ABI_AFFECTING_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 1] =
[(ArgAttribute::InReg, llvm::AttributeKind::InReg)];

const OPTIMIZATION_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 5] = [
const OPTIMIZATION_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 6] = [
(ArgAttribute::NoAlias, llvm::AttributeKind::NoAlias),
(ArgAttribute::NonNull, llvm::AttributeKind::NonNull),
(ArgAttribute::ReadOnly, llvm::AttributeKind::ReadOnly),
(ArgAttribute::NoUndef, llvm::AttributeKind::NoUndef),
(ArgAttribute::Writable, llvm::AttributeKind::Writable),
// Our internal NoFree attribute still allows deallocation of zero-size allocations. However,
// these don't render any bytes non-dereferenceable, so it's still fine to apply LLVM NoFree
// for them.
(ArgAttribute::NoFree, llvm::AttributeKind::NoFree),
];

const CAPTURES_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 3] = [
Expand Down Expand Up @@ -75,7 +79,9 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'
// Only apply remaining attributes when optimizing
if cx.sess().opts.optimize != config::OptLevel::No {
let deref = this.pointee_size.bytes();
if deref != 0 {
// dereferenceable in LLVM currently implies nofree, so only emit dereferenceable if nofree
// is also set.
if deref != 0 && regular.contains(ArgAttribute::NoFree) {
if regular.contains(ArgAttribute::NonNull) {
attrs.push(llvm::CreateDereferenceableAttr(cx.llcx, deref));
} else {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ pub(crate) enum AttributeKind {
SanitizeRealtimeNonblocking = 47,
SanitizeRealtimeBlocking = 48,
Convergent = 49,
NoFree = 50,
}

/// LLVMIntPredicate
Expand Down
Loading
Loading