From 0d300ac678cfc69724861c7c94c3daa3eb15fac1 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Fri, 13 Sep 2024 14:01:02 -0700 Subject: [PATCH 01/10] Update StableMIR doc to reflect current status We no longer use git subtree, and we have 2 different crates. --- compiler/stable_mir/README.md | 102 +++++----------------------------- 1 file changed, 14 insertions(+), 88 deletions(-) diff --git a/compiler/stable_mir/README.md b/compiler/stable_mir/README.md index 31dee955f491f..89f610e110e79 100644 --- a/compiler/stable_mir/README.md +++ b/compiler/stable_mir/README.md @@ -1,93 +1,25 @@ -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. - -## 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. +Our goal is to start publishing `stable_mir` into crates.io. +Until then, users will use this as any other rustc crate, via extern crate. ## 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: +implementation is done using 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 and +translation between stable and internal constructs. +- `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. -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 +36,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. From 57eacbba4017142aefddbe6aac246942fc195891 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Wed, 9 Oct 2024 10:19:34 -0700 Subject: [PATCH 02/10] Expand `ptr::fn_addr_eq()` documentation. * Describe more clearly what is (not) guaranteed, and de-emphasize the implementation details. * Explain what you *can* reliably use it for. --- library/core/src/ptr/mod.rs | 38 +++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 67f1b0cd16de4..a207f7e5b9aa7 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2164,13 +2164,36 @@ 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)); +/// ``` +/// +/// * 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 /// @@ -2182,6 +2205,9 @@ 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"] From 8e2ac498f4e8240c21f1e4ed9ed8c2370a5913f7 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Wed, 9 Oct 2024 12:42:01 -0700 Subject: [PATCH 03/10] Apply suggestions from code review Co-authored-by: Urgau <3616612+Urgau@users.noreply.github.com> --- library/core/src/ptr/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index a207f7e5b9aa7..5ee2419591dcf 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2166,10 +2166,12 @@ pub fn addr_eq(p: *const T, q: *const U) -> bool { /// /// 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 +/// +/// 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: /// @@ -2182,6 +2184,7 @@ pub fn addr_eq(p: *const T, q: *const U) -> bool { /// ``` /// /// * 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.) @@ -2207,7 +2210,6 @@ pub fn addr_eq(p: *const T, q: *const U) -> bool { /// ``` /// /// [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"] From 5280f152b0dad9faf33478a06c6a1cdf97b71ae4 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Wed, 9 Oct 2024 12:53:03 -0700 Subject: [PATCH 04/10] Add "not guaranteed to be equal" Co-authored-by: Urgau <3616612+Urgau@users.noreply.github.com> --- library/core/src/ptr/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 5ee2419591dcf..dfe28aa7756eb 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2180,7 +2180,7 @@ pub fn addr_eq(p: *const T, q: *const U) -> bool { /// 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)); +/// 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. From f1114babebd82125bdcf6dfc8013563f32585def Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 24 Oct 2024 16:12:31 -0700 Subject: [PATCH 05/10] Apply suggestions from code review Co-authored-by: Michael Goulet --- compiler/stable_mir/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/stable_mir/README.md b/compiler/stable_mir/README.md index 89f610e110e79..5e37369e93c6b 100644 --- a/compiler/stable_mir/README.md +++ b/compiler/stable_mir/README.md @@ -5,8 +5,8 @@ Until then, users will use this as any other rustc crate, via extern crate. ## Stable MIR Design -The stable-mir will follow a similar approach to proc-macro2. It’s -implementation is done using 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 calls to `rustc_smir` APIs and From aa2f9681dbf7fc4ffcf5d4ecaa99fd3741d2ee33 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Thu, 24 Oct 2024 16:19:55 -0700 Subject: [PATCH 06/10] Update README.md Clarify that the translation between unstable and stable items is currently done in the `rustc_smir` crate. --- compiler/stable_mir/README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/stable_mir/README.md b/compiler/stable_mir/README.md index 5e37369e93c6b..ab2546e377ae6 100644 --- a/compiler/stable_mir/README.md +++ b/compiler/stable_mir/README.md @@ -1,7 +1,11 @@ This crate is currently developed in-tree together with the compiler. Our goal is to start publishing `stable_mir` into crates.io. -Until then, users will use this as any other rustc crate, via extern crate. +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. + +See the StableMIR ["Getting Started"](https://rust-lang.github.io/project-stable-mir/getting-started.html) +guide for more information. ## Stable MIR Design @@ -9,12 +13,16 @@ 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 calls to `rustc_smir` APIs and -translation between stable and internal constructs. +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. + I.e., tools will depend on `stable_mir` crate, which will invoke the compiler using APIs defined in `rustc_smir`. From 3bad5014c92686bc0e9914b03eb00e4855e48d99 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 22 Oct 2024 00:00:50 +0000 Subject: [PATCH 07/10] Add support for ~const item bounds --- .../src/solve/assembly/mod.rs | 11 ++++ .../src/solve/effect_goals.rs | 51 ++++++++++++++++++- .../src/solve/normalizes_to/mod.rs | 8 +++ .../src/solve/trait_goals.rs | 8 +++ .../assoc-type-const-bound-usage-0.rs | 2 +- .../assoc-type-const-bound-usage-0.stderr | 15 ------ .../assoc-type-const-bound-usage-1.stderr | 28 +++++++--- .../assoc-type-const-bound-usage-fail-2.rs | 35 +++++++++++++ ...assoc-type-const-bound-usage-fail-2.stderr | 15 ++++++ .../assoc-type-const-bound-usage-fail.rs | 28 ++++++++++ .../assoc-type-const-bound-usage-fail.stderr | 15 ++++++ 11 files changed, 191 insertions(+), 25 deletions(-) delete mode 100644 tests/ui/traits/const-traits/assoc-type-const-bound-usage-0.stderr create mode 100644 tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs create mode 100644 tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.stderr create mode 100644 tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs create mode 100644 tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.stderr 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/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`. From 4923e856be61bfb8faac18eaf1f2b0d8e70ea3be Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 25 Oct 2024 13:06:57 +1100 Subject: [PATCH 08/10] coverage: Emit `llvm.instrprof.increment` using the normal helper method --- compiler/rustc_codegen_llvm/src/builder.rs | 26 ++----------------- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 - .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 11 -------- 3 files changed, 2 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index dbf5298d64ba3..8e718226a9a3f 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1165,6 +1165,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size); } + #[instrument(level = "debug", skip(self))] fn instrprof_increment( &mut self, fn_name: &'ll Value, @@ -1172,30 +1173,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { 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, - ); - } + self.call_intrinsic("llvm.instrprof.increment", &[fn_name, hash, num_counters, index]); } fn call( diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 50e6c1494a8d6..a52004bacd929 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1615,7 +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; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 910c27da95463..ed9db20593325 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1531,17 +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) From b3d65852c3addf4e8e6be96965ead86c2d4fb8be Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 25 Oct 2024 13:25:19 +1100 Subject: [PATCH 09/10] coverage: Emit MC/DC intrinsics using the normal helper method --- compiler/rustc_codegen_llvm/src/builder.rs | 55 +++---------------- compiler/rustc_codegen_llvm/src/context.rs | 4 ++ .../src/coverageinfo/mod.rs | 1 + compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 3 - .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 28 ---------- 5 files changed, 14 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 8e718226a9a3f..f4463e037c945 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1654,40 +1654,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, @@ -1695,39 +1676,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 a52004bacd929..10e55a4f7f659 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1615,9 +1615,6 @@ unsafe extern "C" { pub fn LLVMRustSetAllowReassoc(Instr: &Value); // Miscellaneous instructions - 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_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index ed9db20593325..cb75888abd76d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1531,34 +1531,6 @@ extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, ArrayRef(OpBundles))); } -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, From 8f075145200aef04b36f2e2239f09b796c6ac8b8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 25 Oct 2024 13:57:46 +1100 Subject: [PATCH 10/10] coverage: SSA doesn't need to know about `instrprof_increment` --- compiler/rustc_codegen_gcc/src/builder.rs | 10 -------- compiler/rustc_codegen_llvm/src/builder.rs | 23 ++++++++++--------- .../rustc_codegen_ssa/src/traits/builder.rs | 8 ------- 3 files changed, 12 insertions(+), 29 deletions(-) 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 f4463e037c945..8702532c36eee 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1165,17 +1165,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size); } - #[instrument(level = "debug", skip(self))] - 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]); - } - fn call( &mut self, llty: &'ll Type, @@ -1645,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 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,