Skip to content

Taint the type of ill-formed (unsized) statics #144226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 27, 2025
Merged
Show file tree
Hide file tree
Changes from 5 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
1 change: 0 additions & 1 deletion compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
DefKind::Static { .. } => {
check_static_inhabited(tcx, def_id);
check_static_linkage(tcx, def_id);
res = res.and(wfcheck::check_static_item(tcx, def_id));
}
DefKind::Const => res = res.and(wfcheck::check_const_item(tcx, def_id)),
_ => unreachable!(),
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1180,12 +1180,12 @@ fn check_item_fn(
}

#[instrument(level = "debug", skip(tcx))]
pub(super) fn check_static_item(
tcx: TyCtxt<'_>,
pub(crate) fn check_static_item<'tcx>(
tcx: TyCtxt<'tcx>,
item_id: LocalDefId,
ty: Ty<'tcx>,
) -> Result<(), ErrorGuaranteed> {
enter_wf_checking_ctxt(tcx, item_id, |wfcx| {
let ty = tcx.type_of(item_id).instantiate_identity();
let span = tcx.ty_span(item_id);
let item_ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);

Expand Down
19 changes: 17 additions & 2 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use rustc_middle::{bug, span_bug};
use rustc_span::{DUMMY_SP, Ident, Span};

use super::{HirPlaceholderCollector, ItemCtxt, bad_placeholder};
use crate::check::wfcheck::check_static_item;
use crate::errors::TypeofReservedKeywordUsed;
use crate::hir_ty_lowering::HirTyLowerer;

Expand Down Expand Up @@ -217,7 +218,13 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
"static variable",
)
} else {
icx.lower_ty(ty)
let ty = icx.lower_ty(ty);
// MIR relies on references to statics being scalars.
// Verify that here to avoid ill-formed MIR.
match check_static_item(tcx, def_id, ty) {
Ok(()) => ty,
Err(guar) => Ty::new_error(tcx, guar),
}
}
}
ItemKind::Const(ident, _, ty, body_id) => {
Expand Down Expand Up @@ -275,7 +282,15 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
}
ForeignItemKind::Static(t, _, _) => icx.lower_ty(t),
ForeignItemKind::Static(ty, _, _) => {
let ty = icx.lower_ty(ty);
// MIR relies on references to statics being scalars.
// Verify that here to avoid ill-formed MIR.
match check_static_item(tcx, def_id, ty) {
Ok(()) => ty,
Err(guar) => Ty::new_error(tcx, guar),
}
}
ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()),
},

Expand Down
9 changes: 0 additions & 9 deletions tests/crashes/121176.rs

This file was deleted.

10 changes: 0 additions & 10 deletions tests/crashes/129109.rs

This file was deleted.

9 changes: 0 additions & 9 deletions tests/crashes/130970.rs

This file was deleted.

9 changes: 0 additions & 9 deletions tests/crashes/131347.rs

This file was deleted.

4 changes: 0 additions & 4 deletions tests/ui/consts/const-unsized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,10 @@ const CONST_FOO: str = *"foo";

static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
//~^ ERROR the size for values of type
//~| ERROR cannot move out of a shared reference

static STATIC_BAR: str = *"bar";
//~^ ERROR the size for values of type
//~| ERROR cannot move out of a shared reference

fn main() {
println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR);
//~^ ERROR: cannot move a value of type `str`
//~| ERROR: cannot move a value of type `dyn Debug + Sync`
}
32 changes: 4 additions & 28 deletions tests/ui/consts/const-unsized.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
= note: statics and constants must have a statically known size

error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/const-unsized.rs:15:1
--> $DIR/const-unsized.rs:14:1
|
LL | static STATIC_BAR: str = *"bar";
| ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
Expand All @@ -46,31 +46,7 @@ error[E0507]: cannot move out of a shared reference
LL | const CONST_FOO: str = *"foo";
| ^^^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait

error[E0507]: cannot move out of a shared reference
--> $DIR/const-unsized.rs:11:37
|
LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `dyn Debug + Sync`, which does not implement the `Copy` trait

error[E0507]: cannot move out of a shared reference
--> $DIR/const-unsized.rs:15:26
|
LL | static STATIC_BAR: str = *"bar";
| ^^^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait

error[E0161]: cannot move a value of type `dyn Debug + Sync`
--> $DIR/const-unsized.rs:20:38
|
LL | println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR);
| ^^^^^^^ the size of `dyn Debug + Sync` cannot be statically determined

error[E0161]: cannot move a value of type `str`
--> $DIR/const-unsized.rs:20:48
|
LL | println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR);
| ^^^^^^^^^ the size of `str` cannot be statically determined

error: aborting due to 10 previous errors
error: aborting due to 6 previous errors

Some errors have detailed explanations: E0161, E0277, E0507.
For more information about an error, try `rustc --explain E0161`.
Some errors have detailed explanations: E0277, E0507.
For more information about an error, try `rustc --explain E0277`.
3 changes: 3 additions & 0 deletions tests/ui/coroutine/layout-error.rs
Copy link
Member

Choose a reason for hiding this comment

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

@oli-obk is it okay for this to cycle-error? Having the type of a static depend on its value does seem quite cursed.^^

Copy link
Contributor

Choose a reason for hiding this comment

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

Is a static's type meaningfully different from a function's return type? Because it's not about its evaluated value, but just how opaque types work.

I don't think this use case is particularly unusual and expect people will want to be using TAITs like this.

Copy link
Member

Choose a reason for hiding this comment

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

Is a static's type meaningfully different from a function's return type?

Hm... not really, the problem is just that the constraint on the type cannot be so easily expressed as a trait query. For return types it's T: Sized, but for static types it's... T: Pointee<Metadata = ()> or so?

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ impl<F: Future> Task<F> {
}

pub type F = impl Future;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
pub type F = impl Future;
pub type F = impl Future + Sync;

Needing an extra annotation for an opaque type in a static item seems fine to me


#[define_opaque(F)]
fn foo()
where
Expand All @@ -31,5 +32,7 @@ where

// Check that statics are inhabited computes they layout.
static POOL: Task<F> = Task::new();
//~^ ERROR cycle detected when computing type of `POOL`
//~| ERROR cycle detected when computing type of `POOL`

fn main() {}
94 changes: 91 additions & 3 deletions tests/ui/coroutine/layout-error.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,97 @@
error[E0425]: cannot find value `Foo` in this scope
--> $DIR/layout-error.rs:26:17
--> $DIR/layout-error.rs:27:17
|
LL | let a = Foo;
| ^^^ not found in this scope

error: aborting due to 1 previous error
error[E0391]: cycle detected when computing type of `POOL`
--> $DIR/layout-error.rs:34:14
|
LL | static POOL: Task<F> = Task::new();
| ^^^^^^^
|
= note: ...which requires evaluating trait selection obligation `Task<F>: core::marker::Sync`...
note: ...which requires computing type of opaque `F::{opaque#0}`...
--> $DIR/layout-error.rs:19:14
|
LL | pub type F = impl Future;
| ^^^^^^^^^^^
note: ...which requires borrow-checking `foo`...
--> $DIR/layout-error.rs:22:1
|
LL | / fn foo()
LL | | where
LL | | F:,
| |_______^
note: ...which requires promoting constants in MIR for `foo`...
--> $DIR/layout-error.rs:22:1
|
LL | / fn foo()
LL | | where
LL | | F:,
| |_______^
note: ...which requires checking if `foo` contains FFI-unwind calls...
--> $DIR/layout-error.rs:22:1
|
LL | / fn foo()
LL | | where
LL | | F:,
| |_______^
note: ...which requires building MIR for `foo`...
--> $DIR/layout-error.rs:22:1
|
LL | / fn foo()
LL | | where
LL | | F:,
| |_______^
note: ...which requires match-checking `foo`...
--> $DIR/layout-error.rs:22:1
|
LL | / fn foo()
LL | | where
LL | | F:,
| |_______^
note: ...which requires type-checking `foo`...
--> $DIR/layout-error.rs:22:1
|
LL | / fn foo()
LL | | where
LL | | F:,
| |_______^
= note: ...which again requires computing type of `POOL`, completing the cycle
note: cycle used when checking that `POOL` is well-formed
--> $DIR/layout-error.rs:34:1
|
LL | static POOL: Task<F> = Task::new();
| ^^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

error[E0391]: cycle detected when computing type of `POOL`
--> $DIR/layout-error.rs:34:14
|
LL | static POOL: Task<F> = Task::new();
| ^^^^^^^
|
= note: ...which requires evaluating trait selection obligation `Task<F>: core::marker::Sync`...
note: ...which requires computing type of opaque `F::{opaque#0}`...
--> $DIR/layout-error.rs:19:14
|
LL | pub type F = impl Future;
| ^^^^^^^^^^^
note: ...which requires computing the opaque types defined by `POOL`...
--> $DIR/layout-error.rs:34:1
|
LL | static POOL: Task<F> = Task::new();
| ^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires computing type of `POOL`, completing the cycle
note: cycle used when checking that `POOL` is well-formed
--> $DIR/layout-error.rs:34:1
|
LL | static POOL: Task<F> = Task::new();
| ^^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0425`.
Some errors have detailed explanations: E0391, E0425.
For more information about an error, try `rustc --explain E0391`.
2 changes: 1 addition & 1 deletion tests/ui/coroutine/metadata-sufficient-for-layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
// Regression test for #80998.
//
//@ aux-build:metadata-sufficient-for-layout.rs
//@ check-pass

#![feature(type_alias_impl_trait, rustc_attrs)]
#![feature(coroutine_trait)]
Expand All @@ -23,5 +22,6 @@ mod helper {

// Static queries the layout of the coroutine.
static A: Option<helper::F> = None;
//~^ ERROR cycle detected when computing type of `A`
Copy link
Contributor

Choose a reason for hiding this comment

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

Similarly here. Open an issue that this cycle diagnostic should propose adding the bound to the opaque. We'll fix that for TAITs but that shouldn't stop your PR


fn main() {}
38 changes: 38 additions & 0 deletions tests/ui/coroutine/metadata-sufficient-for-layout.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
error[E0391]: cycle detected when computing type of `A`
--> $DIR/metadata-sufficient-for-layout.rs:24:11
|
LL | static A: Option<helper::F> = None;
| ^^^^^^^^^^^^^^^^^
|
= note: ...which requires evaluating trait selection obligation `core::option::Option<helper::F>: core::marker::Sync`...
note: ...which requires computing type of opaque `helper::F::{opaque#0}`...
--> $DIR/metadata-sufficient-for-layout.rs:15:18
|
LL | pub type F = impl Coroutine<(), Yield = (), Return = ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires borrow-checking `helper::f`...
--> $DIR/metadata-sufficient-for-layout.rs:18:5
|
LL | fn f() -> F {
| ^^^^^^^^^^^
note: ...which requires computing type of opaque `helper::F::{opaque#0}` via HIR typeck...
--> $DIR/metadata-sufficient-for-layout.rs:15:18
|
LL | pub type F = impl Coroutine<(), Yield = (), Return = ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires computing the opaque types defined by `A`...
--> $DIR/metadata-sufficient-for-layout.rs:24:1
|
LL | static A: Option<helper::F> = None;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires computing type of `A`, completing the cycle
note: cycle used when checking that `A` is well-formed
--> $DIR/metadata-sufficient-for-layout.rs:24:1
|
LL | static A: Option<helper::F> = None;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0391`.
1 change: 0 additions & 1 deletion tests/ui/dyn-compatibility/taint-const-eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@ trait Qux {

static FOO: &(dyn Qux + Sync) = "desc";
//~^ ERROR the trait `Qux` is not dyn compatible
//~| ERROR the trait `Qux` is not dyn compatible

fn main() {}
26 changes: 1 addition & 25 deletions tests/ui/dyn-compatibility/taint-const-eval.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,6 @@ help: alternatively, consider constraining `bar` so it does not apply to trait o
LL | fn bar() where Self: Sized;
| +++++++++++++++++

error[E0038]: the trait `Qux` is not dyn compatible
--> $DIR/taint-const-eval.rs:7:15
|
LL | static FOO: &(dyn Qux + Sync) = "desc";
| ^^^^^^^^^^^^^^ `Qux` is not dyn compatible
|
note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $DIR/taint-const-eval.rs:4:8
|
LL | trait Qux {
| --- this trait is not dyn compatible...
LL | fn bar();
| ^^^ ...because associated function `bar` has no `self` parameter
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider turning `bar` into a method by giving it a `&self` argument
|
LL | fn bar(&self);
| +++++
help: alternatively, consider constraining `bar` so it does not apply to trait objects
|
LL | fn bar() where Self: Sized;
| +++++++++++++++++

error: aborting due to 2 previous errors
error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0038`.
1 change: 0 additions & 1 deletion tests/ui/extern/issue-36122-accessing-externed-dst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ fn main() {
static symbol: [usize]; //~ ERROR: the size for values of type
}
println!("{}", symbol[0]);
//~^ ERROR: extern static is unsafe
}
13 changes: 2 additions & 11 deletions tests/ui/extern/issue-36122-accessing-externed-dst.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,6 @@ LL | static symbol: [usize];
= help: the trait `Sized` is not implemented for `[usize]`
= note: statics and constants must have a statically known size

error[E0133]: use of extern static is unsafe and requires unsafe function or block
--> $DIR/issue-36122-accessing-externed-dst.rs:5:20
|
LL | println!("{}", symbol[0]);
| ^^^^^^ use of extern static
|
= note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior

error: aborting due to 2 previous errors
error: aborting due to 1 previous error

Some errors have detailed explanations: E0133, E0277.
For more information about an error, try `rustc --explain E0133`.
For more information about this error, try `rustc --explain E0277`.
Loading
Loading