Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1069,13 +1069,25 @@ where
else {
return Err(NoSolution.into());
};
let def_id = goal.predicate.alias.expect_projection_ty_def_id();
let ty = match ecx.cx().as_projection_lang_item(def_id) {
Some(SolverProjectionLangItem::FieldBase) => base,
Some(SolverProjectionLangItem::FieldType) => ty,
_ => panic!("unexpected associated type {:?} in `Field`", goal.predicate),
};
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
let ty = match goal.predicate.alias.kind {
ty::AliasTermKind::ProjectionTy { def_id } => {
match ecx.cx().as_projection_lang_item(def_id) {
Some(SolverProjectionLangItem::FieldBase) => base,
Some(SolverProjectionLangItem::FieldType) => ty,
_ => panic!("unexpected associated type {:?} in `Field`", goal.predicate),
}
}
ty::AliasTermKind::ProjectionConst { .. } => {
return ecx.evaluate_const_and_instantiate_projection_term(

@lcnr lcnr Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, unsure about this 🤔

what is the builtin constant we're evaluating here? also, given this is builtin, should we not match on the lang item here to deal with changes to this trait?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's OFFSET on Field. Its default body in core calls the field_offset intrinsic with Self. The evaluator goes through builtin instance resolution, which selects that body, and the intrinsic computes the offset from the layout.

I used the existing evaluator because it already handles generic constants and unresolved inference. The part I'd change is the catch-all ProjectionConst arm. It accepts any associated constant on Field, so the code relies on OFFSET being the only one.

I think matching the field_offset lang item here is cleaner. It makes the supported constant explicit, and adding another constant to the trait would require us to decide how to handle it. I'd keep the evaluator and extend the solver's lang-item lookup to support const projections. Does that match what you had in mind?

goal.param_env,
goal.predicate.alias,
goal.predicate.term,
goal.predicate.alias.expect_ct(),
);
}
kind => panic!("expected projection, found {kind:?}"),
};
ecx.instantiate_normalizes_to_term(goal, ty.into())?;
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Request MIR so normalization runs even though the crate has feature errors.
//@ compile-flags: -Znext-solver --emit=mir

#![feature(gca_const_items)]
//~^ ERROR `gca_const_items` requires `gca_min_const_items` to be enabled
#![allow(incomplete_features)]

use std::field::{field_of, Field};
//~^ ERROR use of unstable library feature `field_projections`
//~| ERROR use of unstable library feature `field_projections`

struct Struct {
b: i64,
}

fn project_ref() {
<field_of!(Struct, b)>::OFFSET;
//~^ ERROR use of unstable library feature `field_projections`
//~| ERROR use of unstable library feature `field_projections`
}
//~^ ERROR `main` function not found
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
error[E0658]: use of unstable library feature `field_projections`
--> $DIR/offset-missing-features-issue-162338.rs:17:6
|
LL | <field_of!(Struct, b)>::OFFSET;
| ^^^^^^^^
|
= note: see issue #145383 <https://github.com/rust-lang/rust/issues/145383> for more information
= help: add `#![feature(field_projections)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: `gca_const_items` requires `gca_min_const_items` to be enabled
--> $DIR/offset-missing-features-issue-162338.rs:4:12
|
LL | #![feature(gca_const_items)]
| ^^^^^^^^^^^^^^^
|
= help: enable all of these features

error[E0601]: `main` function not found in crate `offset_missing_features_issue_162338`
--> $DIR/offset-missing-features-issue-162338.rs:20:2
|
LL | }
| ^ consider adding a `main` function to `$DIR/offset-missing-features-issue-162338.rs`

error[E0658]: use of unstable library feature `field_projections`
--> $DIR/offset-missing-features-issue-162338.rs:8:18
|
LL | use std::field::{field_of, Field};
| ^^^^^^^^
|
= note: see issue #145383 <https://github.com/rust-lang/rust/issues/145383> for more information
= help: add `#![feature(field_projections)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: use of unstable library feature `field_projections`
--> $DIR/offset-missing-features-issue-162338.rs:8:28
|
LL | use std::field::{field_of, Field};
| ^^^^^
|
= note: see issue #145383 <https://github.com/rust-lang/rust/issues/145383> for more information
= help: add `#![feature(field_projections)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: use of unstable library feature `field_projections`
--> $DIR/offset-missing-features-issue-162338.rs:17:5
|
LL | <field_of!(Struct, b)>::OFFSET;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #145383 <https://github.com/rust-lang/rust/issues/145383> for more information
= help: add `#![feature(field_projections)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: aborting due to 6 previous errors

Some errors have detailed explanations: E0601, E0658.
For more information about an error, try `rustc --explain E0601`.
16 changes: 15 additions & 1 deletion tests/ui/field_representing_types/offset.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
//@ revisions: old next
//@ revisions: old next gca_const_items
//@ ignore-compare-mode-next-solver (explicit revisions)
//@ [next] compile-flags: -Znext-solver
//@ [gca_const_items] compile-flags: -Znext-solver
//@ run-pass
#![expect(incomplete_features)]
#![feature(field_projections)]
#![cfg_attr(gca_const_items, feature(gca_const_items, gca_min_const_items))]

use std::field::{Field, field_of};
use std::mem::offset_of;
Expand Down Expand Up @@ -32,9 +34,21 @@ fn project_ref<'a, T, F: Field<Base = T>>(r: &'a T) -> &'a F::Type {
unsafe { &*ptr::from_ref(r).byte_add(F::OFFSET).cast() }
}

#[repr(C)]
struct Generic<T> {
a: u8,
b: T,
}

fn generic_offset<T>() -> usize {
<field_of!(Generic<T>, b)>::OFFSET
}

fn main() {
assert_eq!(<field_of!(Struct, a)>::OFFSET, offset_of!(Struct, a));
assert_eq!(<field_of!(Struct, b)>::OFFSET, offset_of!(Struct, b));
assert_eq!(generic_offset::<u8>(), offset_of!(Generic<u8>, b));
assert_eq!(generic_offset::<u64>(), offset_of!(Generic<u64>, b));

let _: field_of!(Union, a);
let _: field_of!(Union, b);
Expand Down
Loading