diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 8f7459c046946..99c31551d234d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1992,7 +1992,7 @@ impl<'hir> LoweringContext<'_, 'hir> { bounds: &[GenericBound], colon_span: Option, parent_span: Span, - rbp: RelaxedBoundPolicy<'_>, + rbp: RelaxedBoundPolicy, itctx: ImplTraitContext, origin: PredicateOrigin, ) -> Option> { @@ -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( diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c861b17c00c6f..a1bc9cc4b8e09 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -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), } @@ -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, @@ -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 { @@ -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 = @@ -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 @@ -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(); @@ -2272,7 +2265,7 @@ impl<'hir> LoweringContext<'_, 'hir> { return; } RelaxedBoundForbiddenReason::AssocTyBounds - | RelaxedBoundForbiddenReason::LateBoundVarsInScope => {} + | RelaxedBoundForbiddenReason::WhereBound => {} }; } } @@ -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)) @@ -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> { bounds.iter().map(move |bound| self.lower_param_bound(bound, rbp, itctx)) diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 1ad5c18f64293..73662bb4a28b2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -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. @@ -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. diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 8d56717be48aa..3ef8c6665e950 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -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; @@ -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, diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 6e63bf2d78fdc..cf5a722f0529e 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -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}; diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 640817a876eea..98b7bfe8b216e 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -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. @@ -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)). //! @@ -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 @@ -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)] @@ -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; diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 820400813f910..4d714fccc3f61 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -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. //! @@ -89,6 +94,12 @@ impl> Display for PathParser

{ } } +/// 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 { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 963f902b71fcb..a00d39eea12d3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -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, @@ -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."); @@ -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, + ), }) } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 718322a691f70..3f6010e55928d 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -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] = [ @@ -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 { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 1fde5866f5dca..919868b9005eb 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -318,6 +318,7 @@ pub(crate) enum AttributeKind { SanitizeRealtimeNonblocking = 47, SanitizeRealtimeBlocking = 48, Convergent = 49, + NoFree = 50, } /// LLVMIntPredicate diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index be9c562031698..4a92a3ed62e0e 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -395,92 +395,108 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // For coroutine-closures, we additionally must compute the // `coroutine_captures_by_ref_ty` type, which is used to generate the by-ref // version of the coroutine-closure's output coroutine. - if let UpvarArgs::CoroutineClosure(args) = args - && !args.references_error() - { - let closure_env_region: ty::Region<'_> = ty::Region::new_bound( - self.tcx, - ty::INNERMOST, - ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::ClosureEnv }, - ); - - let num_args = args - .as_coroutine_closure() - .coroutine_closure_sig() - .skip_binder() - .tupled_inputs_ty - .tuple_fields() - .len(); - let typeck_results = self.typeck_results.borrow(); + // + // If the args already reference an error, computing the by-ref upvar + // tuple may itself reach malformed types. We still equate the + // `coroutine_captures_by_ref_ty` inference variable to an error type + // so downstream consumers (e.g. `has_self_borrows`) can rely on it + // being resolved to either an `FnPtr` or `Error` rather than remaining + // an unconstrained inference variable. + if let UpvarArgs::CoroutineClosure(args) = args { + if let Some(guar) = args.error_reported().err() { + self.demand_eqtype( + span, + args.as_coroutine_closure().coroutine_captures_by_ref_ty(), + Ty::new_error(self.tcx, guar), + ); + } else { + let closure_env_region: ty::Region<'_> = ty::Region::new_bound( + self.tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::ZERO, + kind: ty::BoundRegionKind::ClosureEnv, + }, + ); - let tupled_upvars_ty_for_borrow = Ty::new_tup_from_iter( - self.tcx, - ty::analyze_coroutine_closure_captures( - typeck_results.closure_min_captures_flattened(closure_def_id), - typeck_results - .closure_min_captures_flattened( - self.tcx.coroutine_for_closure(closure_def_id).expect_local(), - ) - // Skip the captures that are just moving the closure's args - // into the coroutine. These are always by move, and we append - // those later in the `CoroutineClosureSignature` helper functions. - .skip(num_args), - |(_, parent_capture), (_, child_capture)| { - // This is subtle. See documentation on function. - let needs_ref = should_reborrow_from_env_of_parent_coroutine_closure( - parent_capture, - child_capture, - ); + let num_args = args + .as_coroutine_closure() + .coroutine_closure_sig() + .skip_binder() + .tupled_inputs_ty + .tuple_fields() + .len(); + let typeck_results = self.typeck_results.borrow(); - let upvar_ty = child_capture.place.ty(); - let capture = child_capture.info.capture_kind; - // Not all upvars are captured by ref, so use - // `apply_capture_kind_on_capture_ty` to ensure that we - // compute the right captured type. - apply_capture_kind_on_capture_ty( - self.tcx, - upvar_ty, - capture, - if needs_ref { - closure_env_region - } else { - self.tcx.lifetimes.re_erased - }, - ) - }, - ), - ); - let coroutine_captures_by_ref_ty = Ty::new_fn_ptr( - self.tcx, - ty::Binder::bind_with_vars( - self.tcx.mk_fn_sig_safe_rust_abi([], tupled_upvars_ty_for_borrow), - self.tcx.mk_bound_variable_kinds(&[ty::BoundVariableKind::Region( - ty::BoundRegionKind::ClosureEnv, - )]), - ), - ); - self.demand_eqtype( - span, - args.as_coroutine_closure().coroutine_captures_by_ref_ty(), - coroutine_captures_by_ref_ty, - ); + let tupled_upvars_ty_for_borrow = Ty::new_tup_from_iter( + self.tcx, + ty::analyze_coroutine_closure_captures( + typeck_results.closure_min_captures_flattened(closure_def_id), + typeck_results + .closure_min_captures_flattened( + self.tcx.coroutine_for_closure(closure_def_id).expect_local(), + ) + // Skip the captures that are just moving the closure's args + // into the coroutine. These are always by move, and we append + // those later in the `CoroutineClosureSignature` helper functions. + .skip(num_args), + |(_, parent_capture), (_, child_capture)| { + // This is subtle. See documentation on function. + let needs_ref = should_reborrow_from_env_of_parent_coroutine_closure( + parent_capture, + child_capture, + ); - // Additionally, we can now constrain the coroutine's kind type. - // - // We only do this if `infer_kind`, because if we have constrained - // the kind from closure signature inference, the kind inferred - // for the inner coroutine may actually be more restrictive. - if infer_kind { - let ty::Coroutine(_, coroutine_args) = - *self.typeck_results.borrow().expr_ty(body.value).kind() - else { - bug!(); - }; + let upvar_ty = child_capture.place.ty(); + let capture = child_capture.info.capture_kind; + // Not all upvars are captured by ref, so use + // `apply_capture_kind_on_capture_ty` to ensure that we + // compute the right captured type. + apply_capture_kind_on_capture_ty( + self.tcx, + upvar_ty, + capture, + if needs_ref { + closure_env_region + } else { + self.tcx.lifetimes.re_erased + }, + ) + }, + ), + ); + let coroutine_captures_by_ref_ty = Ty::new_fn_ptr( + self.tcx, + ty::Binder::bind_with_vars( + self.tcx.mk_fn_sig_safe_rust_abi([], tupled_upvars_ty_for_borrow), + self.tcx.mk_bound_variable_kinds(&[ty::BoundVariableKind::Region( + ty::BoundRegionKind::ClosureEnv, + )]), + ), + ); self.demand_eqtype( span, - coroutine_args.as_coroutine().kind_ty(), - Ty::from_coroutine_closure_kind(self.tcx, closure_kind), + args.as_coroutine_closure().coroutine_captures_by_ref_ty(), + coroutine_captures_by_ref_ty, ); + + // Additionally, we can now constrain the coroutine's kind type. + // + // We only do this if `infer_kind`, because if we have constrained + // the kind from closure signature inference, the kind inferred + // for the inner coroutine may actually be more restrictive. + if infer_kind { + let ty::Coroutine(_, coroutine_args) = + *self.typeck_results.borrow().expr_ty(body.value).kind() + else { + bug!(); + }; + self.demand_eqtype( + span, + coroutine_args.as_coroutine().kind_ty(), + Ty::from_coroutine_closure_kind(self.tcx, closure_kind), + ); + } } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index ce38ba8338338..a50b06e5120b2 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -388,6 +388,7 @@ enum class LLVMRustAttributeKind { SanitizeRealtimeNonblocking = 47, SanitizeRealtimeBlocking = 48, Convergent = 49, + NoFree = 50, }; static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) { @@ -486,6 +487,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) { return Attribute::SanitizeRealtimeBlocking; case LLVMRustAttributeKind::Convergent: return Attribute::Convergent; + case LLVMRustAttributeKind::NoFree: + return Attribute::NoFree; } report_fatal_error("bad LLVMRustAttributeKind"); } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8c5421d582df2..9dcf76ead4b75 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1687,16 +1687,20 @@ macro_rules! nop_lift { macro_rules! nop_list_lift { ($set:ident; $ty:ty => $lifted:ty) => { - impl<'a, 'tcx> Lift> for &'a List<$ty> { - type Lifted = &'tcx List<$lifted>; + nop_list_lift! { $set: List; $ty => $lifted } + }; + // Allows defining own list type + ($set:ident: $list:ident; $ty:ty => $lifted:ty) => { + impl<'a, 'tcx> Lift> for &'a $list<$ty> { + type Lifted = &'tcx $list<$lifted>; fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { // Assert that the set has the right type. if false { - let _x: &InternedSet<'tcx, List<$lifted>> = &tcx.interners.$set; + let _x: &InternedSet<'tcx, $list<$lifted>> = &tcx.interners.$set; } if self.is_empty() { - return List::empty(); + return $list::empty(); } assert!(tcx.interners.$set.contains_pointer_to(&InternedInSet(self))); // SAFETY: we just checked that `self` is interned and therefore is valid for the @@ -1718,10 +1722,15 @@ nop_lift! { layout; Layout<'a> => Layout<'tcx> } nop_lift! { valtree; ValTree<'a> => ValTree<'tcx> } nop_list_lift! { type_lists; Ty<'a> => Ty<'tcx> } +nop_list_lift! { clauses: ListWithCachedTypeInfo; Clause<'a> => Clause<'tcx> } nop_list_lift! { poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx> } nop_list_lift! { bound_variable_kinds; ty::BoundVariableKind<'a> => ty::BoundVariableKind<'tcx> } +nop_list_lift! { patterns; Pattern<'a> => Pattern<'tcx> } +nop_list_lift! { + outlives; ty::ArgOutlivesPredicate<'a> => ty::ArgOutlivesPredicate<'tcx> +} // This is the impl for `&'a GenericArgs<'a>`. nop_list_lift! { args; GenericArg<'a> => GenericArg<'tcx> } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 800683f43fe8c..682bec55b4a38 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1038,33 +1038,19 @@ where } ty::Ref(_, ty, mt) if offset.bytes() == 0 => { tcx.layout_of(typing_env.as_query_input(ty)).ok().map(|layout| { - let (size, kind); - match mt { + let kind = match mt { hir::Mutability::Not => { let frozen = optimize && ty.is_freeze(tcx, typing_env); - - // Non-frozen shared references are not necessarily dereferenceable for the entire duration of the function - // (see ) - // (if we had "dereferenceable on entry", we could support this) - size = if frozen { layout.size } else { Size::ZERO }; - - kind = PointerKind::SharedRef { frozen }; + PointerKind::SharedRef { frozen } } hir::Mutability::Mut => { let unpin = optimize && ty.is_unpin(tcx, typing_env) && ty.is_unsafe_unpin(tcx, typing_env); - - // Mutable references to potentially self-referential types are not - // necessarily dereferenceable for the entire duration of the function - // (see ) - // (if we had "dereferenceable on entry", we could support this) - size = if unpin { layout.size } else { Size::ZERO }; - - kind = PointerKind::MutableRef { unpin }; + PointerKind::MutableRef { unpin } } }; - PointeeInfo { safe: Some(kind), size, align: layout.align.abi } + PointeeInfo { safe: Some(kind), size: layout.size, align: layout.align.abi } }) } @@ -1080,12 +1066,7 @@ where && pointee.is_unsafe_unpin(tcx, typing_env), global: this.ty.is_box_global(tcx), }), - - // `Box` are not necessarily dereferenceable for the entire duration of the function as - // they can be deallocated at any time. - // (if we had "dereferenceable on entry", we could support this) - size: Size::ZERO, - + size: layout.size, align: layout.align.abi, }) } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 08a8491bab6c5..a92a407133e32 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -184,7 +184,6 @@ impl<'tcx> fmt::Debug for Region<'tcx> { // For things for which the type library provides traversal implementations // for all Interners, we only need to provide a Lift implementation. TrivialLiftImpls! { - (), bool, usize, u64, @@ -197,6 +196,7 @@ TrivialLiftImpls! { rustc_abi::Size, rustc_hir::Safety, rustc_middle::mir::ConstValue, + rustc_span::Symbol, rustc_type_ir::BoundConstness, rustc_type_ir::PredicatePolarity, // tidy-alphabetical-end @@ -269,6 +269,14 @@ TrivialTypeTraversalAndLiftImpls! { /////////////////////////////////////////////////////////////////////////// // Lift implementations +impl<'a, 'tcx> Lift> for ty::ParamEnv<'a> { + type Lifted = ty::ParamEnv<'tcx>; + + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { + ty::ParamEnv::new(tcx.lift(self.caller_bounds())) + } +} + impl<'tcx, T: Lift>> Lift> for Option { type Lifted = Option; fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 14fef2880ff68..44e52c9a7e976 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_macros::{Decodable, Encodable, StableHash}; use rustc_span::Symbol; -use crate::spec::{Arch, CfgAbi, RelocModel, Target}; +use crate::spec::{Arch, RelocModel, Target}; pub struct ModifierInfo { pub modifier: char, @@ -1001,7 +1001,7 @@ impl InlineAsmClobberAbi { _ => Err(&["C", "system", "efiapi"]), }, InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => match name { - "C" | "system" => Ok(if target.cfg_abi == CfgAbi::Spe { + "C" | "system" => Ok(if powerpc::is_spe(target) { InlineAsmClobberAbi::PowerPCSPE } else { InlineAsmClobberAbi::PowerPC diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs index a09b93c64e0e0..4f478fe8c257c 100644 --- a/compiler/rustc_target/src/asm/powerpc.rs +++ b/compiler/rustc_target/src/asm/powerpc.rs @@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_span::Symbol; use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; -use crate::spec::{CfgAbi, RelocModel, Target}; +use crate::spec::{CfgAbi, RelocModel, RustcAbi, Target}; def_reg_class! { PowerPC PowerPCInlineAsmRegClass { @@ -115,6 +115,10 @@ fn reserved_v20to31( } } +pub(crate) fn is_spe(target: &Target) -> bool { + target.rustc_abi == Some(RustcAbi::PowerPcSpe) +} + fn spe_acc_target_check( _arch: InlineAsmArch, _reloc_model: RelocModel, @@ -122,11 +126,7 @@ fn spe_acc_target_check( target: &Target, _is_clobber: bool, ) -> Result<(), &'static str> { - if target.cfg_abi == CfgAbi::Spe { - Ok(()) - } else { - Err("spe_acc is only available on spe targets") - } + if is_spe(target) { Ok(()) } else { Err("spe_acc is only available on spe targets") } } def_regs! { diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 3013d41eacaae..b3f7efb4d7cf7 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -123,6 +123,11 @@ mod attr_impl { const InReg = 1 << 6; const NoUndef = 1 << 7; const Writable = 1 << 8; + /// It is UB for this pointer or any pointer derived from it to be used for + /// deallocation (except for zero-sized deallocation) while the function is + /// executing. Only valid on arguments (including return values that are passed + /// indirectly as arguments). + const NoFree = 1 << 9; } } rustc_data_structures::external_bitflags_debug! { ArgAttribute } @@ -144,9 +149,8 @@ pub enum ArgExtension { pub struct ArgAttributes { pub regular: ArgAttribute, pub arg_ext: ArgExtension, - /// The minimum size of the pointee, guaranteed to be valid for the duration of the whole call - /// (corresponding to LLVM's dereferenceable_or_null attributes, i.e., it is okay for this to be - /// set on a null pointer, but all non-null pointers must be dereferenceable). + /// If the pointer is not null, the minimum dereferenceable size of the pointee, at the time of + /// function entry (for arguments) or function return (for return values). pub pointee_size: Size, /// The minimum alignment of the pointee, if any. pub pointee_align: Option, @@ -414,7 +418,8 @@ impl<'a, Ty> ArgAbi<'a, Ty> { .set(ArgAttribute::NoAlias) .set(ArgAttribute::CapturesAddress) .set(ArgAttribute::NonNull) - .set(ArgAttribute::NoUndef); + .set(ArgAttribute::NoUndef) + .set(ArgAttribute::NoFree); attrs.pointee_size = layout.size; attrs.pointee_align = Some(layout.align.abi); diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index fe854715da24a..72f1b51d19e9d 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -13,7 +13,7 @@ use rustc_span::DUMMY_SP; use smallvec::{SmallVec, smallvec}; use tracing::debug; -use crate::traits::{impossible_predicates, is_vtable_safe_method}; +use crate::traits::is_vtable_safe_method; #[derive(Clone, Debug)] pub enum VtblSegment<'tcx> { @@ -276,11 +276,7 @@ fn vtable_entries<'tcx>( // do not hold for this particular set of type parameters. // Note that this method could then never be called, so we // do not want to try and codegen it, in that case (see #23435). - let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, args); - if impossible_predicates( - tcx, - predicates.map(|(predicate, _)| predicate.skip_norm_wip()).collect(), - ) { + if tcx.instantiate_and_check_impossible_predicates((def_id, args)) { debug!("vtable_entries: predicates do not hold"); return VtblEntry::Vacant; } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 02739ef6a4135..e782557d126bf 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -356,13 +356,7 @@ fn arg_attrs_for_rust_scalar<'tcx>( Some(pointee.align.min(cx.tcx().sess.target.max_reliable_alignment())); } - // LLVM dereferenceable attribute has unclear semantics on the return type, - // they seem to be "dereferenceable until the end of the program", which is - // generally, not valid for references. See - // - if !is_return { - attrs.pointee_size = pointee.size; - }; + attrs.pointee_size = pointee.size; if let Some(kind) = pointee.safe { // The aliasing rules for `Box` are still not decided, but currently we emit @@ -407,6 +401,26 @@ fn arg_attrs_for_rust_scalar<'tcx>( } } + // NoFree is not valid on return values. If it were, it would mean something like + // "will not be freed until the end of the program", which is generally not valid for + // references. + let no_free = !is_return + && match kind { + // Non-frozen shared references are not necessarily dereferenceable for the + // entire duration of the function + // (see ). + PointerKind::SharedRef { frozen } => frozen, + // Mutable references to potentially self-referential types are not necessarily + // dereferenceable for the entire duration of the function + // (see ). + PointerKind::MutableRef { unpin } => unpin, + // Box may be deallocated during execution of the function. + PointerKind::Box { .. } => false, + }; + if no_free { + attrs.set(ArgAttribute::NoFree); + } + if matches!(kind, PointerKind::SharedRef { frozen: true }) && !is_return { attrs.set(ArgAttribute::ReadOnly); attrs.set(ArgAttribute::CapturesReadOnly); @@ -423,11 +437,18 @@ fn fn_abi_sanity_check<'tcx>( fn_abi: &FnAbi<'tcx, Ty<'tcx>>, spec_abi: ExternAbi, ) { + fn fn_arg_attrs_sanity_check(attrs: &ArgAttributes, is_ret: bool) { + if attrs.regular.contains(ArgAttribute::NoFree) { + assert!(!is_ret, "NoFree not valid on return values"); + } + } + fn fn_arg_sanity_check<'tcx>( cx: &LayoutCx<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, spec_abi: ExternAbi, arg: &ArgAbi<'tcx, Ty<'tcx>>, + is_ret: bool, ) { let tcx = cx.tcx(); @@ -452,7 +473,7 @@ fn fn_abi_sanity_check<'tcx>( PassMode::Ignore => { assert!(arg.layout.is_zst()); } - PassMode::Direct(_) => { + PassMode::Direct(attrs) => { // Here the Rust type is used to determine the actual ABI, so we have to be very // careful. Scalar/Vector is fine, since backends will generally use // `layout.backend_repr` and ignore everything else. We should just reject @@ -482,8 +503,9 @@ fn fn_abi_sanity_check<'tcx>( ); } } + fn_arg_attrs_sanity_check(attrs, is_ret); } - PassMode::Pair(_, _) => { + PassMode::Pair(attrs1, attrs2) => { // Similar to `Direct`, we need to make sure that backends use `layout.backend_repr` // and ignore the rest of the layout. assert!( @@ -491,19 +513,23 @@ fn fn_abi_sanity_check<'tcx>( "PassMode::Pair for type {}", arg.layout.ty ); + fn_arg_attrs_sanity_check(attrs1, is_ret); + fn_arg_attrs_sanity_check(attrs2, is_ret); } PassMode::Cast { .. } => { // `Cast` means "transmute to `CastType`"; that only makes sense for sized types. assert!(arg.layout.is_sized()); } - PassMode::Indirect { meta_attrs: None, .. } => { + PassMode::Indirect { meta_attrs: None, attrs, .. } => { // No metadata, must be sized. // Conceptually, unsized arguments must be copied around, which requires dynamically // determining their size, which we cannot do without metadata. Consult // t-opsem before removing this check. assert!(arg.layout.is_sized()); + // Indirect returns are arguments from an ABI perspective. + fn_arg_attrs_sanity_check(attrs, false); } - PassMode::Indirect { meta_attrs: Some(_), on_stack, .. } => { + PassMode::Indirect { meta_attrs: Some(meta_attrs), attrs, on_stack } => { // With metadata. Must be unsized and not on the stack. assert!(arg.layout.is_unsized() && !on_stack); // Also, must not be `extern` type. @@ -515,14 +541,17 @@ fn fn_abi_sanity_check<'tcx>( // t-opsem before removing this check. panic!("unsized arguments must not be `extern` types"); } + // Indirect returns are arguments from an ABI perspective. + fn_arg_attrs_sanity_check(attrs, false); + fn_arg_attrs_sanity_check(meta_attrs, false); } } } for arg in fn_abi.args.iter() { - fn_arg_sanity_check(cx, fn_abi, spec_abi, arg); + fn_arg_sanity_check(cx, fn_abi, spec_abi, arg, false); } - fn_arg_sanity_check(cx, fn_abi, spec_abi, &fn_abi.ret); + fn_arg_sanity_check(cx, fn_abi, spec_abi, &fn_abi.ret, true); } #[tracing::instrument( diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index de3e04626f823..dbd8beed2ed26 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -14,7 +14,6 @@ use tracing::instrument; use crate::data_structures::SsoHashSet; use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::inherent::*; -use crate::lift::Lift; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use crate::{self as ty, DebruijnIndex, Interner, UniverseIndex, Unnormalized}; @@ -27,7 +26,7 @@ use crate::{self as ty, DebruijnIndex, Interner, UniverseIndex, Unnormalized}; /// /// `Decodable` and `Encodable` are implemented for `Binder` using the `impl_binder_encode_decode!` macro. #[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner, T)] -#[derive(GenericTypeVisitable)] +#[derive(GenericTypeVisitable, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(StableHash_NoContext))] pub struct Binder { value: T, @@ -36,23 +35,6 @@ pub struct Binder { impl Eq for Binder {} -// FIXME: We manually derive `Lift` because the `derive(Lift_Generic)` doesn't -// understand how to turn `T` to `T::Lifted` in the output `type Lifted`. -impl Lift for Binder -where - T: Lift, - I::BoundVarKinds: Lift, -{ - type Lifted = Binder; - - fn lift_to_interner(self, cx: U) -> Self::Lifted { - Binder { - value: self.value.lift_to_interner(cx), - bound_vars: self.bound_vars.lift_to_interner(cx), - } - } -} - #[cfg(feature = "nightly")] macro_rules! impl_binder_encode_decode { ($($t:ty),+ $(,)?) => { @@ -966,12 +948,13 @@ pub enum BoundVarIndexKind { /// identified by both a universe, as well as a name residing within that universe. Distinct bound /// regions/types/consts within the same universe simply have an unknown relationship to one #[derive_where(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash; I: Interner, T)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic, GenericTypeVisitable)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, GenericTypeVisitable, Lift_Generic)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext) )] pub struct Placeholder { + #[lift(identity)] pub universe: UniverseIndex, pub bound: T, #[type_foldable(identity)] @@ -989,21 +972,6 @@ impl fmt::Debug for ty::Placeholder { } } -impl Lift for Placeholder -where - T: Lift, -{ - type Lifted = Placeholder; - - fn lift_to_interner(self, cx: U) -> Self::Lifted { - Placeholder { - universe: self.universe, - bound: self.bound.lift_to_interner(cx), - _tcx: PhantomData, - } - } -} - #[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)] #[derive(Lift_Generic, GenericTypeVisitable)] #[cfg_attr( @@ -1174,27 +1142,17 @@ impl PlaceholderRegion { } #[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)] -#[derive(GenericTypeVisitable)] +#[derive(GenericTypeVisitable, Lift_Generic)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext) )] pub struct BoundTy { + #[lift(identity)] pub var: ty::BoundVar, pub kind: BoundTyKind, } -impl Lift for BoundTy -where - BoundTyKind: Lift>, -{ - type Lifted = BoundTy; - - fn lift_to_interner(self, cx: U) -> Self::Lifted { - BoundTy { var: self.var, kind: self.kind.lift_to_interner(cx) } - } -} - impl fmt::Debug for ty::BoundTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.kind { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index a4737cf137b0c..f0bb4e75974ca 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -474,6 +474,52 @@ pub trait Interner: fn item_name(self, item_index: Self::DefId) -> Self::Symbol; } +macro_rules! declare_lift_into { + ($($assoc:ident),* $(,)?) => { + /// An interner whose associated types can be lifted into another interner `J`. + /// + /// These are associated type bounds rather than `where` clauses so a caller with + /// `I: LiftInto` can rely on the individual associated type `Lift` bounds being + /// implied. + pub trait LiftInto: Interner<$($assoc: crate::lift::Lift,)*> + where + J: Interner, + {} + + impl LiftInto for I + where + J: Interner, + I: Interner<$($assoc: crate::lift::Lift,)*>, + {} + }; +} + +declare_lift_into! { + BoundVarKinds, + Const, + DefId, + FreeConstAliasId, + FreeTyAliasId, + GenericArg, + GenericArgs, + InherentAssocConstId, + InherentAssocTyId, + OpaqueTyId, + ParamEnv, + PatList, + Region, + RegionAssumptions, + Symbol, + Term, + TraitAssocConstId, + TraitAssocTermId, + TraitAssocTyId, + TraitId, + Ty, + Tys, + UnevaluatedConstId, +} + /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` /// that produces `T` items. You could combine them with /// `f(&iter.collect::>())`, but this requires allocating memory for the diff --git a/compiler/rustc_type_ir/src/lift.rs b/compiler/rustc_type_ir/src/lift.rs index 739d3a8512329..f281825803e9e 100644 --- a/compiler/rustc_type_ir/src/lift.rs +++ b/compiler/rustc_type_ir/src/lift.rs @@ -19,3 +19,9 @@ pub trait Lift: std::fmt::Debug { type Lifted: std::fmt::Debug; fn lift_to_interner(self, cx: I) -> Self::Lifted; } + +impl Lift for () { + type Lifted = (); + + fn lift_to_interner(self, _: I) -> Self::Lifted {} +} diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 176c05a3fa54e..8de64762c30b5 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -9,7 +9,6 @@ use rustc_type_ir_macros::{ }; use crate::inherent::*; -use crate::lift::Lift; use crate::upcast::{Upcast, UpcastFrom}; use crate::visit::TypeVisitableExt as _; use crate::{self as ty, AliasTyKind, Interner, UnevaluatedConstKind}; @@ -17,7 +16,7 @@ use crate::{self as ty, AliasTyKind, Interner, UnevaluatedConstKind}; /// `A: 'region` #[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, A)] #[derive_where(Copy; I: Interner, A: Copy)] -#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] +#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", derive(Decodable_NoContext, Encodable_NoContext, StableHash_NoContext) @@ -26,20 +25,6 @@ pub struct OutlivesPredicate(pub A, pub I::Region); impl Eq for OutlivesPredicate {} -// FIXME: We manually derive `Lift` because the `derive(Lift_Generic)` doesn't -// understand how to turn `A` to `A::Lifted` in the output `type Lifted`. -impl Lift for OutlivesPredicate -where - A: Lift, - I::Region: Lift, -{ - type Lifted = OutlivesPredicate; - - fn lift_to_interner(self, cx: U) -> Self::Lifted { - OutlivesPredicate(self.0.lift_to_interner(cx), self.1.lift_to_interner(cx)) - } -} - /// `'a == 'b`. /// For the rationale behind having this instead of a pair of bidirectional /// `'a: 'b` and `'b: 'a`, see @@ -210,6 +195,7 @@ pub struct TraitPredicate { /// If polarity is Negative: we are proving that a negative impl of this trait /// exists. (Note that coherence also checks whether negative impls of supertraits /// exist via a series of predicates.) + #[lift(identity)] pub polarity: PredicatePolarity, } @@ -1036,6 +1022,7 @@ impl fmt::Debug for NormalizesTo { )] pub struct HostEffectPredicate { pub trait_ref: ty::TraitRef, + #[lift(identity)] pub constness: BoundConstness, } @@ -1081,6 +1068,7 @@ impl ty::Binder> { derive(Decodable_NoContext, Encodable_NoContext, StableHash_NoContext) )] pub struct SubtypePredicate { + #[lift(identity)] pub a_is_expected: bool, pub a: I::Ty, pub b: I::Ty, diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 6f3cea27cafdb..2014ec094524f 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -764,7 +764,7 @@ impl Eq for TypeAndMut {} /// Contains the packed non-type fields of a function signature. // FIXME(splat): add the splatted argument index as a u16 #[derive_where(Copy, Clone, PartialEq, Eq, Hash; I: Interner)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash_NoContext) @@ -772,6 +772,7 @@ impl Eq for TypeAndMut {} pub struct FnSigKind { /// Holds the c_variadic and safety bitflags, and 6 bits for the `ExternAbi` variant and unwind /// flag. + #[lift(identity)] #[type_visitable(ignore)] #[type_foldable(identity)] flags: u8, @@ -780,13 +781,6 @@ pub struct FnSigKind { _marker: PhantomData I>, } -impl crate::lift::Lift for FnSigKind { - type Lifted = FnSigKind; - fn lift_to_interner(self, _cx: J) -> Self::Lifted { - FnSigKind { flags: self.flags, _marker: PhantomData } - } -} - impl fmt::Debug for FnSigKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut f = f.debug_tuple("FnSigKind"); diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index 7ea8bd384e3cf..9d576c3deacee 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -10,13 +10,18 @@ decl_derive!( [TypeFoldable_Generic, attributes(type_foldable)] => type_foldable_derive ); decl_derive!( - [Lift_Generic] => lift_derive + [Lift_Generic, attributes(lift)] => lift_derive ); #[cfg(not(feature = "nightly"))] decl_derive!( [GenericTypeVisitable] => customizable_type_visitable_derive ); +struct LiftedTy { + ty: syn::Type, + generic_parameter_bounds: Vec, +} + fn has_ignore_attr(attrs: &[Attribute], name: &'static str, meta: &'static str) -> bool { let mut ignored = false; attrs.iter().for_each(|attr| { @@ -144,6 +149,18 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke ) } +/// `Lift_Generic` is specialised for structs/enums parameterised by an interner +/// `I: Interner`. It derives `Lift` by rewriting interner associated types +/// from `I::Assoc` to `J::Assoc`. The required associated type lift bounds are +/// supplied by `I: LiftInto`. +/// +/// Ordinary generic parameters still get explicit `Lift` bounds. Interner +/// independent fields must either implement `Lift` manually or use +/// `#[lift(identity)]`. +/// +/// `PhantomData` is a special case that occurs enough in the code base to be +/// handled here directly. We collect any generic bounds from the type then +/// produce another `PhantomData`. fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { if let syn::Data::Union(_) = s.ast().data { panic!("cannot derive on union") @@ -154,9 +171,12 @@ fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { } s.add_bounds(synstructure::AddBounds::None); - s.add_where_predicate(parse_quote! { I: Interner }); s.add_impl_generic(parse_quote! { J }); s.add_where_predicate(parse_quote! { J: Interner }); + s.add_where_predicate(parse_quote! { I: ::rustc_type_ir::LiftInto }); + + let generic_parameters = + s.ast().generics.type_params().map(|ty| ty.ident.clone()).collect::>(); let mut wc = vec![]; s.bind_with(|_| synstructure::BindStyle::Move); @@ -164,9 +184,28 @@ fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { let bindings = vi.bindings(); vi.construct(|field, index| { let ty = field.ty.clone(); - let lifted_ty = lift(ty.clone()); - wc.push(parse_quote! { #ty: ::rustc_type_ir::lift::Lift }); let bind = &bindings[index]; + // Allow field to be ignored from lift + if has_ignore_attr(&field.attrs, "lift", "identity") { + return bind.to_token_stream(); + } + + let lifted = lift(ty.clone(), &generic_parameters); + + // Field types involving ordinary generic parameters still need + // explicit bounds for those parameters, e.g. `Binder` needs + // `T: Lift` so its own derived `Lift` impl applies. Interner + // associated types are covered by `I: LiftInto`. + for param in lifted.generic_parameter_bounds { + wc.push(parse_quote! { #param: ::rustc_type_ir::lift::Lift }); + } + + if is_type_phantom(&ty) { + return quote! { + PhantomData + }; + } + quote! { #bind.lift_to_interner(interner) } @@ -179,7 +218,8 @@ fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { let (_, ty_generics, _) = s.ast().generics.split_for_impl(); let name = s.ast().ident.clone(); let self_ty: syn::Type = parse_quote! { #name #ty_generics }; - let lifted_ty = lift(self_ty); + let lifted = lift(self_ty, &generic_parameters); + let lifted_ty = lifted.ty; s.bound_impl( quote!(::rustc_type_ir::lift::Lift), @@ -196,24 +236,55 @@ fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { ) } -fn lift(mut ty: syn::Type) -> syn::Type { - struct ItoJ; - impl VisitMut for ItoJ { +fn get_first_path_segment(ty: &syn::Type) -> Option<&syn::PathSegment> { + if let syn::Type::Path(ty) = ty + && ty.path.segments.len() == 1 + { + ty.path.segments.first() + } else { + None + } +} + +/// Return if the type is `PhantomData` +fn is_type_phantom(ty: &syn::Type) -> bool { + get_first_path_segment(ty).is_some_and(|segment| segment.ident == "PhantomData") +} + +fn lift(mut ty: syn::Type, generic_parameters: &[syn::Ident]) -> LiftedTy { + struct ItoJ<'a> { + generic_parameters: &'a [syn::Ident], + generic_parameter_bounds: Vec, + } + + impl VisitMut for ItoJ<'_> { fn visit_type_path_mut(&mut self, i: &mut syn::TypePath) { if i.qself.is_none() { - if let Some(first) = i.path.segments.first_mut() - && first.ident == "I" - { - *first = parse_quote! { J }; + let segments_len = i.path.segments.len(); + if let Some(first) = i.path.segments.first_mut() { + // Turn paths from `I` into `J` + if first.ident == "I" { + *first = parse_quote! { J }; + } else if segments_len == 1 + && matches!(first.arguments, syn::PathArguments::None) + && self.generic_parameters.iter().any(|param| first.ident == *param) + { + let ident = first.ident.clone(); + if !self.generic_parameter_bounds.iter().any(|param| *param == ident) { + self.generic_parameter_bounds.push(ident.clone()); + } + + *i = parse_quote! { <#ident as ::rustc_type_ir::lift::Lift>::Lifted }; + return; + } } } syn::visit_mut::visit_type_path_mut(self, i); } } - - ItoJ.visit_type_mut(&mut ty); - - ty + let mut visitor = ItoJ { generic_parameters, generic_parameter_bounds: Vec::new() }; + visitor.visit_type_mut(&mut ty); + LiftedTy { ty, generic_parameter_bounds: visitor.generic_parameter_bounds } } #[cfg(not(feature = "nightly"))] diff --git a/tests/codegen-llvm/addr-of-mutate.rs b/tests/codegen-llvm/addr-of-mutate.rs index d1939391b25de..def73bf8190d7 100644 --- a/tests/codegen-llvm/addr-of-mutate.rs +++ b/tests/codegen-llvm/addr-of-mutate.rs @@ -5,7 +5,7 @@ // Test for the absence of `readonly` on the argument when it is mutated via `&raw const`. // See . -// CHECK: i8 @foo(ptr{{( dead_on_return)?}} noalias noundef align 1{{( captures\(address\))?}}{{( dead_on_return)?}} dereferenceable(128) %x) +// CHECK: i8 @foo(ptr{{( dead_on_return)?}} noalias nofree noundef align 1{{( captures\(address\))?}}{{( dead_on_return)?}} dereferenceable(128) %x) #[no_mangle] pub fn foo(x: [u8; 128]) -> u8 { let ptr = core::ptr::addr_of!(x).cast_mut(); @@ -15,7 +15,7 @@ pub fn foo(x: [u8; 128]) -> u8 { x[0] } -// CHECK: i1 @second(ptr{{( dead_on_return)?}} noalias noundef align {{[0-9]+}}{{( captures\(address\))?}}{{( dead_on_return)?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) +// CHECK: i1 @second(ptr{{( dead_on_return)?}} noalias nofree noundef align {{[0-9]+}}{{( captures\(address\))?}}{{( dead_on_return)?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) #[no_mangle] pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut(); @@ -24,7 +24,7 @@ pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { } // If going through a deref (and there are no other mutating accesses), then `readonly` is fine. -// CHECK: i1 @third(ptr{{( dead_on_return)?}} noalias noundef readonly align {{[0-9]+}}{{( captures\(none\))?}}{{( dead_on_return)?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) +// CHECK: i1 @third(ptr{{( dead_on_return)?}} noalias nofree noundef readonly align {{[0-9]+}}{{( captures\(none\))?}}{{( dead_on_return)?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) #[no_mangle] pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut(); diff --git a/tests/codegen-llvm/drop-in-place-noalias.rs b/tests/codegen-llvm/drop-in-place-noalias.rs index bff2f52781f23..86e0caa1b287d 100644 --- a/tests/codegen-llvm/drop-in-place-noalias.rs +++ b/tests/codegen-llvm/drop-in-place-noalias.rs @@ -7,7 +7,7 @@ use std::marker::PhantomPinned; -// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructUnpin{{.*}}(ptr noalias noundef align 4 dereferenceable(12) %{{.+}}) +// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructUnpin{{.*}}(ptr noalias nofree noundef align 4 dereferenceable(12) %{{.+}}) // CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructNotUnpin{{.*}}(ptr noundef nonnull align 4 %{{.+}}) diff --git a/tests/codegen-llvm/function-arguments.rs b/tests/codegen-llvm/function-arguments.rs index 6eab9a58b47ad..0832778a6ed93 100644 --- a/tests/codegen-llvm/function-arguments.rs +++ b/tests/codegen-llvm/function-arguments.rs @@ -80,7 +80,7 @@ pub fn option_nonzero_int(x: Option>) -> Option> { x } -// CHECK: @readonly_borrow(ptr noalias noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(4) %_1) +// CHECK: @readonly_borrow(ptr noalias nofree noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(4) %_1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn readonly_borrow(_: &i32) {} @@ -91,12 +91,12 @@ pub fn readonly_borrow_ret() -> &'static i32 { loop {} } -// CHECK: @static_borrow(ptr noalias noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(4) %_1) +// CHECK: @static_borrow(ptr noalias nofree noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(4) %_1) // static borrow may be captured #[no_mangle] pub fn static_borrow(_: &'static i32) {} -// CHECK: @named_borrow(ptr noalias noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(4) %_1) +// CHECK: @named_borrow(ptr noalias nofree noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(4) %_1) // borrow with named lifetime may be captured #[no_mangle] pub fn named_borrow<'r>(_: &'r i32) {} @@ -106,12 +106,12 @@ pub fn named_borrow<'r>(_: &'r i32) {} #[no_mangle] pub fn unsafe_borrow(_: &UnsafeInner) {} -// CHECK: @mutable_unsafe_borrow(ptr noalias noundef align 2 dereferenceable(2) %_1) +// CHECK: @mutable_unsafe_borrow(ptr noalias nofree noundef align 2 dereferenceable(2) %_1) // ... unless this is a mutable borrow, those never alias #[no_mangle] pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {} -// CHECK: @mutable_borrow(ptr noalias noundef align 4 dereferenceable(4) %_1) +// CHECK: @mutable_borrow(ptr noalias nofree noundef align 4 dereferenceable(4) %_1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn mutable_borrow(_: &mut i32) {} @@ -129,25 +129,25 @@ pub fn mutable_borrow_ret() -> &'static mut i32 { // . pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {} -// CHECK: @notunpin_borrow(ptr noalias noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(4) %_1) +// CHECK: @notunpin_borrow(ptr noalias nofree noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(4) %_1) // But `&NotUnpin` behaves perfectly normal. #[no_mangle] pub fn notunpin_borrow(_: &NotUnpin) {} -// CHECK: @indirect_struct(ptr{{( dead_on_return)?}} noalias noundef readonly align 4{{( captures\(none\))?}}{{( dead_on_return)?}} dereferenceable(32) %_1) +// CHECK: @indirect_struct(ptr{{( dead_on_return)?}} noalias nofree noundef readonly align 4{{( captures\(none\))?}}{{( dead_on_return)?}} dereferenceable(32) %_1) #[no_mangle] pub fn indirect_struct(_: S) {} -// CHECK: @borrowed_struct(ptr noalias noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(32) %_1) +// CHECK: @borrowed_struct(ptr noalias nofree noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable(32) %_1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn borrowed_struct(_: &S) {} -// CHECK: @option_borrow(ptr noalias noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable_or_null(4) %_x) +// CHECK: @option_borrow(ptr noalias nofree noundef readonly align 4{{( captures\(address, read_provenance\))?}} dereferenceable_or_null(4) %_x) #[no_mangle] pub fn option_borrow(_x: Option<&i32>) {} -// CHECK: @option_borrow_mut(ptr noalias noundef align 4 dereferenceable_or_null(4) %_x) +// CHECK: @option_borrow_mut(ptr noalias nofree noundef align 4 dereferenceable_or_null(4) %_x) #[no_mangle] pub fn option_borrow_mut(_x: Option<&mut i32>) {} @@ -170,7 +170,7 @@ pub fn _box(x: Box) -> Box { // With a custom allocator, it should *not* have `noalias`. (See // for why.) The second argument is the allocator, // which is a reference here that still carries `noalias` as usual. -// CHECK: @_box_custom(ptr noundef nonnull align 4 %x.0, ptr noalias noundef nonnull readonly{{( captures\(address, read_provenance\))?}} %x.1) +// CHECK: @_box_custom(ptr noundef nonnull align 4 %x.0, ptr noalias nofree noundef nonnull readonly{{( captures\(address, read_provenance\))?}} %x.1) #[no_mangle] pub fn _box_custom(x: Box) { drop(x) @@ -182,7 +182,7 @@ pub fn notunpin_box(x: Box) -> Box { x } -// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias noundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(none\))?}} dereferenceable(32){{( %_0)?}}) +// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias nofree noundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(none\))?}} dereferenceable(32){{( %_0)?}}) #[no_mangle] pub fn struct_return() -> S { S { _field: [0, 0, 0, 0, 0, 0, 0, 0] } @@ -194,14 +194,14 @@ pub fn struct_return() -> S { pub fn helper(_: usize) {} // CHECK: @slice( -// CHECK-SAME: ptr noalias noundef nonnull readonly{{( captures\(address, read_provenance\))?}} %_1.0, +// CHECK-SAME: ptr noalias nofree noundef nonnull readonly{{( captures\(address, read_provenance\))?}} %_1.0, // CHECK-SAME: [[USIZE]] noundef range({{i32 0, -2147483648|i64 0, -9223372036854775808}}) %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn slice(_: &[u8]) {} // CHECK: @mutable_slice( -// CHECK-SAME: ptr noalias noundef nonnull %_1.0, +// CHECK-SAME: ptr noalias nofree noundef nonnull %_1.0, // CHECK-SAME: [[USIZE]] noundef range({{i32 0, -2147483648|i64 0, -9223372036854775808}}) %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] @@ -219,13 +219,13 @@ pub fn unsafe_slice(_: &[UnsafeInner]) {} pub fn raw_slice(_: *const [u8]) {} // CHECK: @str( -// CHECK-SAME: ptr noalias noundef nonnull readonly{{( captures\(address, read_provenance\))?}} %_1.0, +// CHECK-SAME: ptr noalias nofree noundef nonnull readonly{{( captures\(address, read_provenance\))?}} %_1.0, // CHECK-SAME: [[USIZE]] noundef range({{i32 0, -2147483648|i64 0, -9223372036854775808}}) %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn str(_: &[u8]) {} -// CHECK: @trait_borrow(ptr noundef nonnull %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) +// CHECK: @trait_borrow(ptr noundef nonnull %_1.0, {{.+}} noalias nofree noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) // FIXME #25759 This should also have `nocapture` #[no_mangle] pub fn trait_borrow(_: &dyn Drop) {} @@ -238,31 +238,31 @@ pub fn option_trait_borrow(x: Option<&dyn Drop>) {} #[no_mangle] pub fn option_trait_borrow_mut(x: Option<&mut dyn Drop>) {} -// CHECK: @trait_raw(ptr noundef %_1.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) +// CHECK: @trait_raw(ptr noundef %_1.0, {{.+}} noalias nofree noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1) #[no_mangle] pub fn trait_raw(_: *const dyn Drop) {} // Ensure that `Box` gets `noalias` when the right traits are present, but removing *either* `Unpin` // or `UnsafeUnpin` is enough to lose the attribute. -// CHECK: @trait_box(ptr noalias noundef nonnull{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) +// CHECK: @trait_box(ptr noalias noundef nonnull{{( %0)?}}, {{.+}} noalias nofree noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) #[no_mangle] pub fn trait_box(_: Box) {} -// CHECK: @trait_box_pin1(ptr noundef nonnull{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) +// CHECK: @trait_box_pin1(ptr noundef nonnull{{( %0)?}}, {{.+}} noalias nofree noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) #[no_mangle] pub fn trait_box_pin1(_: Box) {} -// CHECK: @trait_box_pin2(ptr noundef nonnull{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) +// CHECK: @trait_box_pin2(ptr noundef nonnull{{( %0)?}}, {{.+}} noalias nofree noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}}) #[no_mangle] pub fn trait_box_pin2(_: Box) {} // Same for mutable references (with a non-zero minimal size so that we also see the // `dereferenceable` disappear). -// CHECK: @trait_mutref(ptr noalias noundef align 4 dereferenceable(4){{( %_1.0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %_1.1)?}}) +// CHECK: @trait_mutref(ptr noalias nofree noundef align 4 dereferenceable(4){{( %_1.0)?}}, {{.+}} noalias nofree noundef readonly align {{.*}} dereferenceable({{.*}}){{( %_1.1)?}}) #[no_mangle] pub fn trait_mutref(_: &mut (i32, dyn Drop + Unpin + UnsafeUnpin)) {} -// CHECK: @trait_mutref_pin1(ptr noundef nonnull align 4{{( %_1.0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %_1.1)?}}) +// CHECK: @trait_mutref_pin1(ptr noundef nonnull align 4{{( %_1.0)?}}, {{.+}} noalias nofree noundef readonly align {{.*}} dereferenceable({{.*}}){{( %_1.1)?}}) #[no_mangle] pub fn trait_mutref_pin1(_: &mut (i32, dyn Drop + Unpin)) {} -// CHECK: @trait_mutref_pin2(ptr noundef nonnull align 4{{( %_1.0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %_1.1)?}}) +// CHECK: @trait_mutref_pin2(ptr noundef nonnull align 4{{( %_1.0)?}}, {{.+}} noalias nofree noundef readonly align {{.*}} dereferenceable({{.*}}){{( %_1.1)?}}) #[no_mangle] pub fn trait_mutref_pin2(_: &mut (i32, dyn Drop + UnsafeUnpin)) {} @@ -275,7 +275,7 @@ pub fn trait_option( } // CHECK: { ptr, [[USIZE]] } @return_slice( -// CHECK-SAME: ptr noalias noundef nonnull readonly align 2{{( captures\(address, read_provenance\))?}} %x.0, +// CHECK-SAME: ptr noalias nofree noundef nonnull readonly align 2{{( captures\(address, read_provenance\))?}} %x.0, // CHECK-SAME: [[USIZE]] noundef range({{i32 0, 1073741824|i64 0, 4611686018427387904}}) %x.1) #[no_mangle] pub fn return_slice(x: &[u16]) -> &[u16] { diff --git a/tests/codegen-llvm/llvm-writable.rs b/tests/codegen-llvm/llvm-writable.rs index ea245fc3a6e7a..0c72fb8a1dd9f 100644 --- a/tests/codegen-llvm/llvm-writable.rs +++ b/tests/codegen-llvm/llvm-writable.rs @@ -4,15 +4,15 @@ #![crate_type = "lib"] #![feature(rustc_attrs, unsafe_pinned)] -// CHECK: @mutable_borrow(ptr noalias noundef writable align 4 dereferenceable(4) %_1) +// CHECK: @mutable_borrow(ptr noalias nofree noundef writable align 4 dereferenceable(4) %_1) #[no_mangle] pub fn mutable_borrow(_: &mut i32) {} -// CHECK: @mutable_unsafe_borrow(ptr noalias noundef writable align 2 dereferenceable(2) %_1) +// CHECK: @mutable_unsafe_borrow(ptr noalias nofree noundef writable align 2 dereferenceable(2) %_1) #[no_mangle] pub fn mutable_unsafe_borrow(_: &mut std::cell::UnsafeCell) {} -// CHECK: @option_borrow_mut(ptr noalias noundef writable align 4 dereferenceable_or_null(4) %_1) +// CHECK: @option_borrow_mut(ptr noalias nofree noundef writable align 4 dereferenceable_or_null(4) %_1) #[no_mangle] pub fn option_borrow_mut(_: Option<&mut i32>) {} @@ -24,7 +24,7 @@ pub fn box_moved(_: Box) {} #[no_mangle] pub fn unsafe_pinned_borrow_mut(_: &mut std::pin::UnsafePinned) {} -// CHECK: @mutable_borrow_no_writable(ptr noalias noundef align 4 dereferenceable(4) %_1) +// CHECK: @mutable_borrow_no_writable(ptr noalias nofree noundef align 4 dereferenceable(4) %_1) #[no_mangle] #[rustc_no_writable] pub fn mutable_borrow_no_writable(_: &mut i32) {} diff --git a/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs b/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs index 4c61224ac6d8f..68f1267c2a444 100644 --- a/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs +++ b/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs @@ -256,11 +256,11 @@ pub struct IntDoubleInt { c: i32, } -// CHECK: define void @f_int_double_int_s_arg(ptr{{( dead_on_return)?}} noalias noundef align 8{{( captures\(address\))?}}{{( dead_on_return)?}} dereferenceable(24) %a) +// CHECK: define void @f_int_double_int_s_arg(ptr{{( dead_on_return)?}} noalias nofree noundef align 8{{( captures\(address\))?}}{{( dead_on_return)?}} dereferenceable(24) %a) #[no_mangle] pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} -// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias noundef{{( writable)?}} sret([24 x i8]) align 8{{( captures\(address\))?}} dereferenceable(24) %_0) +// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias nofree noundef{{( writable)?}} sret([24 x i8]) align 8{{( captures\(address\))?}} dereferenceable(24) %_0) #[no_mangle] pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt { IntDoubleInt { a: 1, b: 2., c: 3 } diff --git a/tests/codegen-llvm/packed.rs b/tests/codegen-llvm/packed.rs index 6f62719282eac..84e2b0897c09c 100644 --- a/tests/codegen-llvm/packed.rs +++ b/tests/codegen-llvm/packed.rs @@ -52,7 +52,7 @@ pub struct BigPacked2 { #[no_mangle] pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 { // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca [32 x i8] - // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} noundef sret{{.*}} dereferenceable(32) [[ALLOCA]]) + // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} nofree noundef sret{{.*}} dereferenceable(32) [[ALLOCA]]) // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false) // check that calls whose destination is a field of a packed struct // go through an alloca rather than calling the function with an @@ -64,7 +64,7 @@ pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 { #[no_mangle] pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 { // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca [32 x i8] - // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} noundef sret{{.*}} dereferenceable(32) [[ALLOCA]]) + // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} nofree noundef sret{{.*}} dereferenceable(32) [[ALLOCA]]) // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false) // check that calls whose destination is a field of a packed struct // go through an alloca rather than calling the function with an diff --git a/tests/codegen-llvm/slice-iter-nonnull.rs b/tests/codegen-llvm/slice-iter-nonnull.rs index 6b8416662314f..8ef313f2d6715 100644 --- a/tests/codegen-llvm/slice-iter-nonnull.rs +++ b/tests/codegen-llvm/slice-iter-nonnull.rs @@ -51,7 +51,7 @@ pub fn slice_iter_next_back<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&' // attribute is there, and confirms adding the assume back doesn't do anything. // CHECK-LABEL: @slice_iter_new -// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef range({{.+}}) %slice.1) +// CHECK-SAME: (ptr noalias nofree noundef nonnull {{.+}} %slice.0, {{.+}} noundef range({{.+}}) %slice.1) #[no_mangle] pub fn slice_iter_new(slice: &[u32]) -> std::slice::Iter<'_, u32> { // CHECK-NOT: slice @@ -66,7 +66,7 @@ pub fn slice_iter_new(slice: &[u32]) -> std::slice::Iter<'_, u32> { } // CHECK-LABEL: @slice_iter_mut_new -// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef range({{.+}}) %slice.1) +// CHECK-SAME: (ptr noalias nofree noundef nonnull {{.+}} %slice.0, {{.+}} noundef range({{.+}}) %slice.1) #[no_mangle] pub fn slice_iter_mut_new(slice: &mut [u32]) -> std::slice::IterMut<'_, u32> { // CHECK-NOT: slice diff --git a/tests/crashes/137190-2.rs b/tests/crashes/137190-2.rs deleted file mode 100644 index 0c68b5aa4a518..0000000000000 --- a/tests/crashes/137190-2.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ known-bug: #137190 -trait Supertrait { - fn method(&self) {} -} - -trait Trait

: Supertrait<()> {} - -impl

Trait

for () {} - -const fn upcast

(x: &dyn Trait

) -> &dyn Supertrait<()> { - x -} - -const fn foo() -> &'static dyn Supertrait<()> { - upcast::<()>(&()) -} - -const _: &'static dyn Supertrait<()> = foo(); diff --git a/tests/crashes/137190-3.rs b/tests/crashes/137190-3.rs deleted file mode 100644 index 88ae88e11bcdb..0000000000000 --- a/tests/crashes/137190-3.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #137190 -trait Supertrait { - fn method(&self) {} -} - -trait Trait: Supertrait {} - -impl Trait for () {} - -const _: &dyn Supertrait = &() as &dyn Trait as &dyn Supertrait; diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr index f297aa984dd2e..edea2d5772280 100644 --- a/tests/ui/abi/c-zst.powerpc-linux.stderr +++ b/tests/ui/abi/c-zst.powerpc-linux.stderr @@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some( diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr index f297aa984dd2e..edea2d5772280 100644 --- a/tests/ui/abi/c-zst.s390x-linux.stderr +++ b/tests/ui/abi/c-zst.s390x-linux.stderr @@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some( diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr index f297aa984dd2e..edea2d5772280 100644 --- a/tests/ui/abi/c-zst.sparc64-linux.stderr +++ b/tests/ui/abi/c-zst.sparc64-linux.stderr @@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some( diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr index f297aa984dd2e..edea2d5772280 100644 --- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr +++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr @@ -27,7 +27,7 @@ error: fn_abi_of(pass_zst) = FnAbi { }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some( diff --git a/tests/ui/abi/debug.generic.stderr b/tests/ui/abi/debug.generic.stderr index b154c3fa201e5..125150f2c2e3f 100644 --- a/tests/ui/abi/debug.generic.stderr +++ b/tests/ui/abi/debug.generic.stderr @@ -487,7 +487,7 @@ error: ABIs are not compatible }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(32 bytes), pointee_align: Some( @@ -560,7 +560,7 @@ error: ABIs are not compatible }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(128 bytes), pointee_align: Some( @@ -966,7 +966,7 @@ error: fn_abi_of(assoc_test) = FnAbi { }, mode: Direct( ArgAttributes { - regular: CapturesReadOnly | NoAlias | NonNull | ReadOnly | NoUndef, + regular: CapturesReadOnly | NoAlias | NonNull | ReadOnly | NoUndef | NoFree, arg_ext: None, pointee_size: Size(2 bytes), pointee_align: Some( diff --git a/tests/ui/abi/debug.loongarch64.stderr b/tests/ui/abi/debug.loongarch64.stderr index 68bcd736e47ce..5f05174c12760 100644 --- a/tests/ui/abi/debug.loongarch64.stderr +++ b/tests/ui/abi/debug.loongarch64.stderr @@ -487,7 +487,7 @@ error: ABIs are not compatible }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(32 bytes), pointee_align: Some( @@ -560,7 +560,7 @@ error: ABIs are not compatible }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(128 bytes), pointee_align: Some( @@ -966,7 +966,7 @@ error: fn_abi_of(assoc_test) = FnAbi { }, mode: Direct( ArgAttributes { - regular: CapturesReadOnly | NoAlias | NonNull | ReadOnly | NoUndef, + regular: CapturesReadOnly | NoAlias | NonNull | ReadOnly | NoUndef | NoFree, arg_ext: None, pointee_size: Size(2 bytes), pointee_align: Some( diff --git a/tests/ui/abi/debug.riscv64.stderr b/tests/ui/abi/debug.riscv64.stderr index 68bcd736e47ce..5f05174c12760 100644 --- a/tests/ui/abi/debug.riscv64.stderr +++ b/tests/ui/abi/debug.riscv64.stderr @@ -487,7 +487,7 @@ error: ABIs are not compatible }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(32 bytes), pointee_align: Some( @@ -560,7 +560,7 @@ error: ABIs are not compatible }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(128 bytes), pointee_align: Some( @@ -966,7 +966,7 @@ error: fn_abi_of(assoc_test) = FnAbi { }, mode: Direct( ArgAttributes { - regular: CapturesReadOnly | NoAlias | NonNull | ReadOnly | NoUndef, + regular: CapturesReadOnly | NoAlias | NonNull | ReadOnly | NoUndef | NoFree, arg_ext: None, pointee_size: Size(2 bytes), pointee_align: Some( diff --git a/tests/ui/abi/pass-indirectly-attr.stderr b/tests/ui/abi/pass-indirectly-attr.stderr index 226d880d7945d..320840c8149f5 100644 --- a/tests/ui/abi/pass-indirectly-attr.stderr +++ b/tests/ui/abi/pass-indirectly-attr.stderr @@ -40,7 +40,7 @@ error: fn_abi_of(extern_c) = FnAbi { }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(1 bytes), pointee_align: Some( diff --git a/tests/ui/async-await/async-closures/cast-as-infer-self-borrows.rs b/tests/ui/async-await/async-closures/cast-as-infer-self-borrows.rs new file mode 100644 index 0000000000000..a172aaf93acd0 --- /dev/null +++ b/tests/ui/async-await/async-closures/cast-as-infer-self-borrows.rs @@ -0,0 +1,10 @@ +//@ edition:2021 + +// Regression test for #155999. + +fn needs_fn_mut(x: impl FnMut() -> T) { + needs_fn_mut(async || x as _) + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/async-await/async-closures/cast-as-infer-self-borrows.stderr b/tests/ui/async-await/async-closures/cast-as-infer-self-borrows.stderr new file mode 100644 index 0000000000000..9dbf29f92abe9 --- /dev/null +++ b/tests/ui/async-await/async-closures/cast-as-infer-self-borrows.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/cast-as-infer-self-borrows.rs:6:32 + | +LL | needs_fn_mut(async || x as _) + | ^ cannot infer type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/async-await/async-closures/not-lending.stderr b/tests/ui/async-await/async-closures/not-lending.stderr index f0028129caa02..fb941502d3646 100644 --- a/tests/ui/async-await/async-closures/not-lending.stderr +++ b/tests/ui/async-await/async-closures/not-lending.stderr @@ -7,7 +7,7 @@ LL | let x = async move || -> &String { &s }; | | return type of async closure `{async closure body@$DIR/not-lending.rs:12:42: 12:48}` contains a lifetime `'2` | lifetime `'1` represents this closure's body | - = note: closure implements `Fn`, so references to captured variables can't escape the closure + = note: closure implements `AsyncFn`, so references to captured variables can't escape the closure error: lifetime may not live long enough --> $DIR/not-lending.rs:16:31 @@ -18,7 +18,7 @@ LL | let x = async move || { &s }; | | return type of async closure `{async closure body@$DIR/not-lending.rs:16:31: 16:37}` contains a lifetime `'2` | lifetime `'1` represents this closure's body | - = note: closure implements `Fn`, so references to captured variables can't escape the closure + = note: closure implements `AsyncFn`, so references to captured variables can't escape the closure error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr index e1f268116fc54..c479adfa56d7e 100644 --- a/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr +++ b/tests/ui/async-await/issue-74072-lifetime-name-annotations.stderr @@ -39,7 +39,7 @@ LL | | y LL | | })() | |_____^ returning this value requires that `'1` must outlive `'2` | - = note: closure implements `FnMut`, so references to captured variables can't escape the closure + = note: closure implements `AsyncFnMut`, so references to captured variables can't escape the closure error[E0716]: temporary value dropped while borrowed --> $DIR/issue-74072-lifetime-name-annotations.rs:13:5 @@ -88,7 +88,7 @@ LL | | y LL | | })() | |_____^ returning this value requires that `'1` must outlive `'2` | - = note: closure implements `FnMut`, so references to captured variables can't escape the closure + = note: closure implements `AsyncFnMut`, so references to captured variables can't escape the closure error[E0716]: temporary value dropped while borrowed --> $DIR/issue-74072-lifetime-name-annotations.rs:23:5 diff --git a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr index 584416f58f861..45edd7bc0e0ee 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr @@ -27,7 +27,7 @@ error: fn_abi_of(take_va_list) = FnAbi { }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(32 bytes), pointee_align: Some( diff --git a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr index b5e0e8589af16..1e203b93e66b3 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr @@ -27,7 +27,7 @@ error: fn_abi_of(take_va_list) = FnAbi { }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(24 bytes), pointee_align: Some( @@ -105,7 +105,7 @@ error: fn_abi_of(take_va_list_sysv64) = FnAbi { }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(24 bytes), pointee_align: Some( @@ -185,7 +185,7 @@ error: fn_abi_of(take_va_list_win64) = FnAbi { }, mode: Indirect { attrs: ArgAttributes { - regular: CapturesAddress | NoAlias | NonNull | NoUndef, + regular: CapturesAddress | NoAlias | NonNull | NoUndef | NoFree, arg_ext: None, pointee_size: Size(24 bytes), pointee_align: Some( diff --git a/tests/crashes/135470.rs b/tests/ui/coercion/vtable-impossible-predicates-async.rs similarity index 79% rename from tests/crashes/135470.rs rename to tests/ui/coercion/vtable-impossible-predicates-async.rs index efa017b5457cf..fe6aa9843fc61 100644 --- a/tests/crashes/135470.rs +++ b/tests/ui/coercion/vtable-impossible-predicates-async.rs @@ -1,4 +1,8 @@ -//@ known-bug: #135470 +// Regression test for #135470. +// Verify that we don't ICE when building vtable entries +// for a blanket impl involving async and impossible predicates. + +//@ check-pass //@ compile-flags: -Copt-level=0 //@ edition: 2021 diff --git a/tests/ui/coercion/vtable-unsatisfied-supertrait-generics.rs b/tests/ui/coercion/vtable-unsatisfied-supertrait-generics.rs new file mode 100644 index 0000000000000..41e603fc0a0a3 --- /dev/null +++ b/tests/ui/coercion/vtable-unsatisfied-supertrait-generics.rs @@ -0,0 +1,25 @@ +// Regression test for #137190. +// Variant of vtable-unsatisfied-supertrait.rs with generic traits. +// Verify that we don't ICE when building vtable entries +// for a generic trait whose supertrait is not implemented. + +//@ compile-flags: --crate-type lib + +trait Supertrait { + fn method(&self) {} +} + +trait Trait

: Supertrait<()> {} + +impl

Trait

for () {} +//~^ ERROR the trait bound `(): Supertrait<()>` is not satisfied + +const fn upcast

(x: &dyn Trait

) -> &dyn Supertrait<()> { + x +} + +const fn foo() -> &'static dyn Supertrait<()> { + upcast::<()>(&()) +} + +const _: &'static dyn Supertrait<()> = foo(); diff --git a/tests/ui/coercion/vtable-unsatisfied-supertrait-generics.stderr b/tests/ui/coercion/vtable-unsatisfied-supertrait-generics.stderr new file mode 100644 index 0000000000000..a485d2d539534 --- /dev/null +++ b/tests/ui/coercion/vtable-unsatisfied-supertrait-generics.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `(): Supertrait<()>` is not satisfied + --> $DIR/vtable-unsatisfied-supertrait-generics.rs:14:22 + | +LL | impl

Trait

for () {} + | ^^ the trait `Supertrait<()>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/vtable-unsatisfied-supertrait-generics.rs:8:1 + | +LL | trait Supertrait { + | ^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `Trait` + --> $DIR/vtable-unsatisfied-supertrait-generics.rs:12:17 + | +LL | trait Trait

: Supertrait<()> {} + | ^^^^^^^^^^^^^^ required by this bound in `Trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/coercion/vtable-unsatisfied-supertrait.rs b/tests/ui/coercion/vtable-unsatisfied-supertrait.rs new file mode 100644 index 0000000000000..26a83d2fb0661 --- /dev/null +++ b/tests/ui/coercion/vtable-unsatisfied-supertrait.rs @@ -0,0 +1,16 @@ +// Regression test for #137190. +// Verify that we don't ICE when building vtable entries +// for a trait whose supertrait is not implemented. + +//@ compile-flags: --crate-type lib + +trait Supertrait { + fn method(&self) {} +} + +trait Trait: Supertrait {} + +impl Trait for () {} +//~^ ERROR the trait bound `(): Supertrait` is not satisfied + +const _: &dyn Supertrait = &() as &dyn Trait as &dyn Supertrait; diff --git a/tests/ui/coercion/vtable-unsatisfied-supertrait.stderr b/tests/ui/coercion/vtable-unsatisfied-supertrait.stderr new file mode 100644 index 0000000000000..7df2c95c7facc --- /dev/null +++ b/tests/ui/coercion/vtable-unsatisfied-supertrait.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `(): Supertrait` is not satisfied + --> $DIR/vtable-unsatisfied-supertrait.rs:13:16 + | +LL | impl Trait for () {} + | ^^ the trait `Supertrait` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/vtable-unsatisfied-supertrait.rs:7:1 + | +LL | trait Supertrait { + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `Trait` + --> $DIR/vtable-unsatisfied-supertrait.rs:11:14 + | +LL | trait Trait: Supertrait {} + | ^^^^^^^^^^ required by this bound in `Trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.