diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 457380685093f..7c52cba096b40 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1725,16 +1725,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn fptosi_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { self.fptoint_sat(true, val, dest_ty) } - - fn instrprof_increment( - &mut self, - _fn_name: RValue<'gcc>, - _hash: RValue<'gcc>, - _num_counters: RValue<'gcc>, - _index: RValue<'gcc>, - ) { - unimplemented!(); - } } impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index dbf5298d64ba3..8702532c36eee 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1165,39 +1165,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size); } - fn instrprof_increment( - &mut self, - fn_name: &'ll Value, - hash: &'ll Value, - num_counters: &'ll Value, - index: &'ll Value, - ) { - debug!( - "instrprof_increment() with args ({:?}, {:?}, {:?}, {:?})", - fn_name, hash, num_counters, index - ); - - let llfn = unsafe { llvm::LLVMRustGetInstrProfIncrementIntrinsic(self.cx().llmod) }; - let llty = self.cx.type_func( - &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_i32()], - self.cx.type_void(), - ); - let args = &[fn_name, hash, num_counters, index]; - let args = self.check_call("call", llty, llfn, args); - - unsafe { - let _ = llvm::LLVMRustBuildCall( - self.llbuilder, - llty, - llfn, - args.as_ptr() as *const &llvm::Value, - args.len() as c_uint, - [].as_ptr(), - 0 as c_uint, - ); - } - } - fn call( &mut self, llty: &'ll Type, @@ -1667,6 +1634,18 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { kcfi_bundle } + /// Emits a call to `llvm.instrprof.increment`. Used by coverage instrumentation. + #[instrument(level = "debug", skip(self))] + pub(crate) fn instrprof_increment( + &mut self, + fn_name: &'ll Value, + hash: &'ll Value, + num_counters: &'ll Value, + index: &'ll Value, + ) { + self.call_intrinsic("llvm.instrprof.increment", &[fn_name, hash, num_counters, index]); + } + /// Emits a call to `llvm.instrprof.mcdc.parameters`. /// /// This doesn't produce any code directly, but is used as input by @@ -1676,40 +1655,21 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { /// /// [`CodeGenPGO::emitMCDCParameters`]: /// https://github.com/rust-lang/llvm-project/blob/5399a24/clang/lib/CodeGen/CodeGenPGO.cpp#L1124 + #[instrument(level = "debug", skip(self))] pub(crate) fn mcdc_parameters( &mut self, fn_name: &'ll Value, hash: &'ll Value, bitmap_bits: &'ll Value, ) { - debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bits); - assert!( crate::llvm_util::get_version() >= (19, 0, 0), "MCDC intrinsics require LLVM 19 or later" ); - - let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCParametersIntrinsic(self.cx().llmod) }; - let llty = self.cx.type_func( - &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32()], - self.cx.type_void(), - ); - let args = &[fn_name, hash, bitmap_bits]; - let args = self.check_call("call", llty, llfn, args); - - unsafe { - let _ = llvm::LLVMRustBuildCall( - self.llbuilder, - llty, - llfn, - args.as_ptr() as *const &llvm::Value, - args.len() as c_uint, - [].as_ptr(), - 0 as c_uint, - ); - } + self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[fn_name, hash, bitmap_bits]); } + #[instrument(level = "debug", skip(self))] pub(crate) fn mcdc_tvbitmap_update( &mut self, fn_name: &'ll Value, @@ -1717,39 +1677,21 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { bitmap_index: &'ll Value, mcdc_temp: &'ll Value, ) { - debug!( - "mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?})", - fn_name, hash, bitmap_index, mcdc_temp - ); assert!( crate::llvm_util::get_version() >= (19, 0, 0), "MCDC intrinsics require LLVM 19 or later" ); - - let llfn = - unsafe { llvm::LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(self.cx().llmod) }; - let llty = self.cx.type_func( - &[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_ptr()], - self.cx.type_void(), - ); let args = &[fn_name, hash, bitmap_index, mcdc_temp]; - let args = self.check_call("call", llty, llfn, args); - unsafe { - let _ = llvm::LLVMRustBuildCall( - self.llbuilder, - llty, - llfn, - args.as_ptr() as *const &llvm::Value, - args.len() as c_uint, - [].as_ptr(), - 0 as c_uint, - ); - } + self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", args); + } + + #[instrument(level = "debug", skip(self))] + pub(crate) fn mcdc_condbitmap_reset(&mut self, mcdc_temp: &'ll Value) { self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi); } + #[instrument(level = "debug", skip(self))] pub(crate) fn mcdc_condbitmap_update(&mut self, cond_index: &'ll Value, mcdc_temp: &'ll Value) { - debug!("mcdc_condbitmap_update() with args ({:?}, {:?})", cond_index, mcdc_temp); assert!( crate::llvm_util::get_version() >= (19, 0, 0), "MCDC intrinsics require LLVM 19 or later" diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 2f830d6f941e7..fb845c0087b1f 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1099,6 +1099,10 @@ impl<'ll> CodegenCx<'ll, '_> { if self.sess().instrument_coverage() { ifn!("llvm.instrprof.increment", fn(ptr, t_i64, t_i32, t_i32) -> void); + if crate::llvm_util::get_version() >= (19, 0, 0) { + ifn!("llvm.instrprof.mcdc.parameters", fn(ptr, t_i64, t_i32) -> void); + ifn!("llvm.instrprof.mcdc.tvbitmap.update", fn(ptr, t_i64, t_i32, ptr) -> void); + } } ifn!("llvm.type.test", fn(ptr, t_metadata) -> i1); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index b2956945911b1..36b1747f2fdc8 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -208,6 +208,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { let hash = bx.const_u64(function_coverage_info.function_source_hash); let bitmap_index = bx.const_u32(bitmap_idx); bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap); + bx.mcdc_condbitmap_reset(cond_bitmap); } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 50e6c1494a8d6..10e55a4f7f659 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1615,10 +1615,6 @@ unsafe extern "C" { pub fn LLVMRustSetAllowReassoc(Instr: &Value); // Miscellaneous instructions - pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &Value; - pub fn LLVMRustGetInstrProfMCDCParametersIntrinsic(M: &Module) -> &Value; - pub fn LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(M: &Module) -> &Value; - pub fn LLVMRustBuildCall<'a>( B: &Builder<'a>, Ty: &'a Type, diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index c0c1085e949e2..50a5171414695 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -437,14 +437,6 @@ pub trait BuilderMethods<'a, 'tcx>: /// Called for `StorageDead` fn lifetime_end(&mut self, ptr: Self::Value, size: Size); - fn instrprof_increment( - &mut self, - fn_name: Self::Value, - hash: Self::Value, - num_counters: Self::Value, - index: Self::Value, - ); - fn call( &mut self, llty: Self::Type, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 910c27da95463..cb75888abd76d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1531,45 +1531,6 @@ extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, ArrayRef(OpBundles))); } -extern "C" LLVMValueRef -LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) { -#if LLVM_VERSION_GE(20, 0) - return wrap(llvm::Intrinsic::getOrInsertDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_increment)); -#else - return wrap(llvm::Intrinsic::getDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_increment)); -#endif -} - -extern "C" LLVMValueRef -LLVMRustGetInstrProfMCDCParametersIntrinsic(LLVMModuleRef M) { -#if LLVM_VERSION_LT(19, 0) - report_fatal_error("LLVM 19.0 is required for mcdc intrinsic functions"); -#endif -#if LLVM_VERSION_GE(20, 0) - return wrap(llvm::Intrinsic::getOrInsertDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_mcdc_parameters)); -#else - return wrap(llvm::Intrinsic::getDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_mcdc_parameters)); -#endif -} - -extern "C" LLVMValueRef -LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(LLVMModuleRef M) { -#if LLVM_VERSION_LT(19, 0) - report_fatal_error("LLVM 19.0 is required for mcdc intrinsic functions"); -#endif -#if LLVM_VERSION_GE(20, 0) - return wrap(llvm::Intrinsic::getOrInsertDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update)); -#else - return wrap(llvm::Intrinsic::getDeclaration( - unwrap(M), llvm::Intrinsic::instrprof_mcdc_tvbitmap_update)); -#endif -} - extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, LLVMValueRef Src, unsigned SrcAlign, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 5e604a5d74f58..f6a5f20a639ec 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -100,6 +100,15 @@ where }) } + /// Assemble additional assumptions for an alias that are not included + /// in the item bounds of the alias. For now, this is limited to the + /// `implied_const_bounds` for an associated type. + fn consider_additional_alias_assumptions( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + alias_ty: ty::AliasTy, + ) -> Vec>; + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, @@ -594,6 +603,8 @@ where )); } + candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty)); + if kind != ty::Projection { return; } diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 62b4bb0004cad..8d57ad8f2551b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -3,7 +3,7 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; -use rustc_type_ir::{self as ty, Interner}; +use rustc_type_ir::{self as ty, Interner, elaborate}; use tracing::instrument; use super::assembly::Candidate; @@ -70,6 +70,55 @@ where } } + /// Register additional assumptions for aliases corresponding to `~const` item bounds. + /// + /// Unlike item bounds, they are not simply implied by the well-formedness of the alias. + /// Instead, they only hold if the const conditons on the alias also hold. This is why + /// we also register the const conditions of the alias after matching the goal against + /// the assumption. + fn consider_additional_alias_assumptions( + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + alias_ty: ty::AliasTy, + ) -> Vec> { + let cx = ecx.cx(); + let mut candidates = vec![]; + + // FIXME(effects): We elaborate here because the implied const bounds + // aren't necessarily elaborated. We probably should prefix this query + // with `explicit_`... + for clause in elaborate::elaborate( + cx, + cx.implied_const_bounds(alias_ty.def_id) + .iter_instantiated(cx, alias_ty.args) + .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.host)), + ) { + candidates.extend(Self::probe_and_match_goal_against_assumption( + ecx, + CandidateSource::AliasBound, + goal, + clause, + |ecx| { + // Const conditions must hold for the implied const bound to hold. + ecx.add_goals( + GoalSource::Misc, + cx.const_conditions(alias_ty.def_id) + .iter_instantiated(cx, alias_ty.args) + .map(|trait_ref| { + goal.with( + cx, + trait_ref.to_host_effect_clause(cx, goal.predicate.host), + ) + }), + ); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + }, + )); + } + + candidates + } + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index c98fd85355142..7287cdf74bf45 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -193,6 +193,14 @@ where } } + fn consider_additional_alias_assumptions( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + _alias_ty: ty::AliasTy, + ) -> Vec> { + vec![] + } + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal>, diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 6b26f960286f6..08cc89d950e22 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -39,6 +39,14 @@ where self.def_id() } + fn consider_additional_alias_assumptions( + _ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, + _alias_ty: ty::AliasTy, + ) -> Vec> { + vec![] + } + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal>, diff --git a/compiler/stable_mir/README.md b/compiler/stable_mir/README.md index 31dee955f491f..ab2546e377ae6 100644 --- a/compiler/stable_mir/README.md +++ b/compiler/stable_mir/README.md @@ -1,93 +1,33 @@ -This crate is regularly synced with its mirror in the rustc repo at `compiler/rustc_smir`. +This crate is currently developed in-tree together with the compiler. -We use `git subtree` for this to preserve commits and allow the rustc repo to -edit these crates without having to touch this repo. This keeps the crates compiling -while allowing us to independently work on them here. The effort of keeping them in -sync is pushed entirely onto us, without affecting rustc workflows negatively. -This may change in the future, but changes to policy should only be done via a -compiler team MCP. +Our goal is to start publishing `stable_mir` into crates.io. +Until then, users will use this as any other rustc crate, by installing +the rustup component `rustc-dev`, and declaring `stable-mir` as an external crate. -## Instructions for working on this crate locally - -Since the crate is the same in the rustc repo and here, the dependencies on rustc_* crates -will only either work here or there, but never in both places at the same time. Thus we use -optional dependencies on the rustc_* crates, requiring local development to use - -``` -cargo build --no-default-features -Zavoid-dev-deps -``` - -in order to compile successfully. - -## Instructions for syncing - -### Updating this repository - -In the rustc repo, execute - -``` -git subtree push --prefix=compiler/rustc_smir url_to_your_fork_of_project_stable_mir some_feature_branch -``` - -and then open a PR of your `some_feature_branch` against https://github.com/rust-lang/project-stable-mir - -### Updating the rustc library - -First we need to bump our stack limit, as the rustc repo otherwise quickly hits that: - -``` -ulimit -s 60000 -``` - -#### Maximum function recursion depth (1000) reached - -Then we need to disable `dash` as the default shell for sh scripts, as otherwise we run into a -hard limit of a recursion depth of 1000: - -``` -sudo dpkg-reconfigure dash -``` - -and then select `No` to disable dash. - - -#### Patching your `git worktree` - -The regular git worktree does not scale to repos of the size of the rustc repo. -So download the `git-subtree.sh` from https://github.com/gitgitgadget/git/pull/493/files and run - -``` -sudo cp --backup /path/to/patched/git-subtree.sh /usr/lib/git-core/git-subtree -sudo chmod --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree -sudo chown --reference=/usr/lib/git-core/git-subtree~ /usr/lib/git-core/git-subtree -``` - -#### Actually doing a sync - -In the rustc repo, execute - -``` -git subtree pull --prefix=compiler/rustc_smir https://github.com/rust-lang/project-stable-mir smir -``` - -Note: only ever sync to rustc from the project-stable-mir's `smir` branch. Do not sync with your own forks. - -Then open a PR against rustc just like a regular PR. +See the StableMIR ["Getting Started"](https://rust-lang.github.io/project-stable-mir/getting-started.html) +guide for more information. ## Stable MIR Design -The stable-mir will follow a similar approach to proc-macro2. It’s -implementation will eventually be broken down into two main crates: +The stable-mir will follow a similar approach to proc-macro2. Its +implementation is split between two main crates: - `stable_mir`: Public crate, to be published on crates.io, which will contain -the stable data structure as well as proxy APIs to make calls to the -compiler. -- `rustc_smir`: The compiler crate that will translate from internal MIR to -SMIR. This crate will also implement APIs that will be invoked by -stable-mir to query the compiler for more information. +the stable data structure as well as calls to `rustc_smir` APIs. The +translation between stable and internal constructs will also be done in this crate, +however, this is currently implemented in the `rustc_smir` crate.[^translation]. +- `rustc_smir`: This crate implements the public APIs to the compiler. +It is responsible for gathering all the information requested, and providing +the data in its unstable form. + +[^translation]: This is currently implemented in the `rustc_smir` crate, +but we are working to change that. -This will help tools to communicate with the rust compiler via stable APIs. Tools will depend on -`stable_mir` crate, which will invoke the compiler using APIs defined in `rustc_smir`. I.e.: +I.e., +tools will depend on `stable_mir` crate, +which will invoke the compiler using APIs defined in `rustc_smir`. + +I.e.: ``` ┌──────────────────────────────────┐ ┌──────────────────────────────────┐ @@ -104,9 +44,3 @@ This will help tools to communicate with the rust compiler via stable APIs. Tool More details can be found here: https://hackmd.io/XhnYHKKuR6-LChhobvlT-g?view - -For now, the code for these two crates are in separate modules of this crate. -The modules have the same name for simplicity. We also have a third module, -`rustc_internal` which will expose APIs and definitions that allow users to -gather information from internal MIR constructs that haven't been exposed in -the `stable_mir` module. diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index ea185f0fbe586..03cab232742ab 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2107,13 +2107,39 @@ pub fn addr_eq(p: *const T, q: *const U) -> bool { /// Compares the *addresses* of the two function pointers for equality. /// -/// Function pointers comparisons can have surprising results since -/// they are never guaranteed to be unique and could vary between different -/// code generation units. Furthermore, different functions could have the -/// same address after being merged together. +/// This is the same as `f == g`, but using this function makes clear that the potentially +/// surprising semantics of function pointer comparison are involved. +/// +/// There are **very few guarantees** about how functions are compiled and they have no intrinsic +/// “identity”; in particular, this comparison: +/// +/// * May return `true` unexpectedly, in cases where functions are equivalent. +/// +/// For example, the following program is likely (but not guaranteed) to print `(true, true)` +/// when compiled with optimization: +/// +/// ``` +/// # #![feature(ptr_fn_addr_eq)] +/// let f: fn(i32) -> i32 = |x| x; +/// let g: fn(i32) -> i32 = |x| x + 0; // different closure, different body +/// let h: fn(u32) -> u32 = |x| x + 0; // different signature too +/// dbg!(std::ptr::fn_addr_eq(f, g), std::ptr::fn_addr_eq(f, h)); // not guaranteed to be equal +/// ``` +/// +/// * May return `false` in any case. +/// +/// This is particularly likely with generic functions but may happen with any function. +/// (From an implementation perspective, this is possible because functions may sometimes be +/// processed more than once by the compiler, resulting in duplicate machine code.) +/// +/// Despite these false positives and false negatives, this comparison can still be useful. +/// Specifically, if +/// +/// * `T` is the same type as `U`, `T` is a [subtype] of `U`, or `U` is a [subtype] of `T`, and +/// * `ptr::fn_addr_eq(f, g)` returns true, +/// +/// then calling `f` and calling `g` will be equivalent. /// -/// This is the same as `f == g` but using this function makes clear -/// that you are aware of these potentially surprising semantics. /// /// # Examples /// @@ -2125,6 +2151,8 @@ pub fn addr_eq(p: *const T, q: *const U) -> bool { /// fn b() { println!("b"); } /// assert!(!ptr::fn_addr_eq(a as fn(), b as fn())); /// ``` +/// +/// [subtype]: https://doc.rust-lang.org/reference/subtyping.html #[unstable(feature = "ptr_fn_addr_eq", issue = "129322")] #[inline(always)] #[must_use = "function pointer comparison produces a value"] diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs index 5a54e8eec91f2..bbf8891790516 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.rs @@ -1,5 +1,5 @@ //@ compile-flags: -Znext-solver -//@ known-bug: unknown +//@ check-pass #![allow(incomplete_features)] #![feature(const_trait_impl, effects)] diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.stderr deleted file mode 100644 index 35069a5a52fc3..0000000000000 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0271]: type mismatch resolving `::Assoc == T` - --> $DIR/assoc-type-const-bound-usage-0.rs:14:5 - | -LL | T::Assoc::func() - | ^^^^^^^^^^^^^^^^ types differ - -error[E0271]: type mismatch resolving `::Assoc == T` - --> $DIR/assoc-type-const-bound-usage-0.rs:18:5 - | -LL | ::Assoc::func() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr index ed9182c733423..b8768bd5541c9 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-1.stderr @@ -6,18 +6,30 @@ LL | #![feature(const_trait_impl, effects, generic_const_exprs)] | = help: remove one of these features -error[E0271]: type mismatch resolving `::Assoc == T` - --> $DIR/assoc-type-const-bound-usage-1.rs:15:44 +error[E0284]: type annotations needed: cannot normalize `unqualified::{constant#0}` + --> $DIR/assoc-type-const-bound-usage-1.rs:15:37 | LL | fn unqualified() -> Type<{ T::Assoc::func() }> { - | ^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `unqualified::{constant#0}` -error[E0271]: type mismatch resolving `::Assoc == T` - --> $DIR/assoc-type-const-bound-usage-1.rs:19:42 +error[E0284]: type annotations needed: cannot normalize `qualified::{constant#0}` + --> $DIR/assoc-type-const-bound-usage-1.rs:19:35 | LL | fn qualified() -> Type<{ ::Assoc::func() }> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `qualified::{constant#0}` -error: aborting due to 3 previous errors +error[E0284]: type annotations needed: cannot normalize `unqualified::{constant#0}` + --> $DIR/assoc-type-const-bound-usage-1.rs:16:5 + | +LL | Type + | ^^^^ cannot normalize `unqualified::{constant#0}` + +error[E0284]: type annotations needed: cannot normalize `qualified::{constant#0}` + --> $DIR/assoc-type-const-bound-usage-1.rs:20:5 + | +LL | Type + | ^^^^ cannot normalize `qualified::{constant#0}` + +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs new file mode 100644 index 0000000000000..5e873082781be --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs @@ -0,0 +1,35 @@ +//@ compile-flags: -Znext-solver + +// Check that `~const` item bounds only hold if the where clauses on the +// associated type are also const. +// i.e. check that we validate the const conditions for the associated type +// when considering one of implied const bounds. + +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] + +#[const_trait] +trait Trait { + type Assoc: ~const Trait + where + U: ~const Other; + + fn func(); +} + +#[const_trait] +trait Other {} + +const fn fails() { + T::Assoc::::func(); + //~^ ERROR the trait bound `::Assoc: ~const Trait` is not satisfied + ::Assoc::::func(); + //~^ ERROR the trait bound `::Assoc: ~const Trait` is not satisfied +} + +const fn works() { + T::Assoc::::func(); + ::Assoc::::func(); +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr new file mode 100644 index 0000000000000..1f6532c7a570e --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `::Assoc: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail-2.rs:24:5 + | +LL | T::Assoc::::func(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `::Assoc: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail-2.rs:26:5 + | +LL | ::Assoc::::func(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs new file mode 100644 index 0000000000000..73b3d142f7c84 --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Znext-solver + +// Check that `~const` item bounds only hold if the parent trait is `~const`. +// i.e. check that we validate the const conditions for the associated type +// when considering one of implied const bounds. + +#![allow(incomplete_features)] +#![feature(const_trait_impl, effects)] + +#[const_trait] +trait Trait { + type Assoc: ~const Trait; + fn func(); +} + +const fn unqualified() { + T::Assoc::func(); + //~^ ERROR the trait bound `T: ~const Trait` is not satisfied + ::Assoc::func(); + //~^ ERROR the trait bound `T: ~const Trait` is not satisfied +} + +const fn works() { + T::Assoc::func(); + ::Assoc::func(); +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr new file mode 100644 index 0000000000000..fb08e74eb7f41 --- /dev/null +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `T: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail.rs:17:5 + | +LL | T::Assoc::func(); + | ^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `T: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail.rs:19:5 + | +LL | ::Assoc::func(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.