Compare commits

...

43 Commits

Author SHA1 Message Date
bors
2f43fe4303 Auto merge of #155863 - jhpratt:rollup-6wWyVPM, r=jhpratt
Some checks failed
CI / Calculate job matrix (push) Has been cancelled
CI / ${{ matrix.full_name }} (push) Has been cancelled
CI / publish toolstate (push) Has been cancelled
Rollup of 3 pull requests

Successful merges:

 - rust-lang/rust#155772 (Check closure's constness validity in the constness query)
 - rust-lang/rust#155833 (CI: rfl: move job forward to Linux v7.0)
 - rust-lang/rust#155839 (Remove unnecessary requires_lto: false for eBPF)
2026-04-27 07:49:26 +00:00
Jacob Pratt
88cc0052ec Rollup merge of #155839 - bjorn3:remove_unnecessary_target_override, r=jieyouxu
Remove unnecessary requires_lto: false for eBPF

requires_lto is already false by default.
2026-04-27 03:48:44 -04:00
Jacob Pratt
d03a7c9bf6 Rollup merge of #155833 - ojeda:rfl, r=lqd
CI: rfl: move job forward to Linux v7.0

This version contains both of the workarounds we had, thus remove them as well.

r? @lqd @Kobzol
try-job: x86_64-rust-for-linux
@rustbot label A-rust-for-linux
@bors try
2026-04-27 03:48:44 -04:00
Jacob Pratt
6897624a46 Rollup merge of #155772 - oli-obk:const-closures-everywhere, r=fee1-dead
Check closure's constness validity in the constness query

fixes rust-lang/rust#155584

instead of checking during ast lowering, where it's not easily possible to obtain all the right information in time. While lowering an assoc item we don't know if the parent was a const trait or a const impl. Tracing this information is quite annoying, and complicates a lot of code, which checking here after the fact is trivial.
2026-04-27 03:48:43 -04:00
Oli Scherer
8e1c34f5cc Check closure's constness validity in the constness query
instead of during ast lowering, where it's not easily possible to obtain all the right information in time
2026-04-27 07:44:19 +02:00
Oli Scherer
2b2f28d0ea Add regression test 2026-04-27 07:43:46 +02:00
bors
4933094f25 Auto merge of #155851 - jhpratt:rollup-Jst4hhC, r=jhpratt
Some checks failed
Post merge analysis / analysis (push) Has been cancelled
GHCR image mirroring / DockerHub mirror (push) Has been cancelled
Bump dependencies in Cargo.lock / skip if S-waiting-on-bors (push) Has been cancelled
Bump dependencies in Cargo.lock / update dependencies (push) Has been cancelled
Bump dependencies in Cargo.lock / amend PR (push) Has been cancelled
Rollup of 12 pull requests

Successful merges:

 - rust-lang/rust#149624 (Fix requires_lto targets needing lto set in cargo)
 - rust-lang/rust#155317 (`std::io::Take`: Clarify & optimize `BorrowedBuf::set_init` usage.)
 - rust-lang/rust#155579 (Make Rcs and Arcs use pointer comparison for unsized types)
 - rust-lang/rust#155588 (Implement more traits for FRTs)
 - rust-lang/rust#155708 (Fix heap overflow in slice::join caused by misbehaving Borrow)
 - rust-lang/rust#155778 (Avoid Vec allocation in TyCtxt::mk_place_elem)
 - rust-lang/rust#151014 (std: sys: process: uefi: Add program searching)
 - rust-lang/rust#155682 (Add boxing suggestions for `impl Trait` return type mismatches)
 - rust-lang/rust#155770 (Avoid misleading closure return type note)
 - rust-lang/rust#155818 (Convert attribute `FinalizeFn` to fn pointer)
 - rust-lang/rust#155829 (rustc_attr_parsing: use a `try {}` in `or_malformed`)
 - rust-lang/rust#155835 (couple of `crate_name` cleanups)
2026-04-27 02:32:52 +00:00
Jacob Pratt
bd2d1a8443 Rollup merge of #155835 - jyn514:jyn/verify-ich-diagnostics, r=wesleywiser
couple of `crate_name` cleanups

Split out from https://github.com/rust-lang/rust/pull/153924; these changes should be uncontroversial.
2026-04-26 21:56:46 -04:00
Jacob Pratt
c0e4189058 Rollup merge of #155829 - scrabsha:push-kwlqypwmnpul, r=mejrs
rustc_attr_parsing: use a `try {}` in `or_malformed`
2026-04-26 21:56:45 -04:00
Jacob Pratt
3502ed31ec Rollup merge of #155818 - JonathanBrouwer:finalize-fn-ptr, r=mejrs
Convert attribute `FinalizeFn` to fn pointer
2026-04-26 21:56:44 -04:00
Jacob Pratt
78569d8d6a Rollup merge of #155770 - chenyukang:yukang-fix-155670-closure-return-note, r=wesleywiser
Avoid misleading closure return type note

Fixes rust-lang/rust#155670
2026-04-26 21:56:44 -04:00
Jacob Pratt
9562f3da2d Rollup merge of #155682 - Unique-Usman:ua/box-impl, r=mejrs
Add boxing suggestions for `impl Trait` return type mismatches

A sort of a follow up pr to this -> https://github.com/rust-lang/rust/pull/155546
2026-04-26 21:56:43 -04:00
Jacob Pratt
e3a6fa5082 Rollup merge of #151014 - Ayush1325:uefi-cmd-path, r=jhpratt,nicholasbishop
std: sys: process: uefi: Add program searching

- Follow UEFI Shell search flow to search for programs while launching.
- Tested using OVMF on QEMU.

@rustbot label +O-UEFI
2026-04-26 21:56:42 -04:00
Jacob Pratt
c20a92efd9 Rollup merge of #155778 - kevinheavey:perf-mk-place-elem-avoid-vec-alloc, r=cjgillot,JohnTitor
Avoid Vec allocation in TyCtxt::mk_place_elem

`mk_place_elem` appends a single `PlaceElem` to an existing (interned) projection. The current implementation copies the projection into a fresh `Vec`, pushes the new element, and re-interns the slice, which allocates on every call.

Feed the elements through `mk_place_elems_from_iter` so that `CollectAndApply`'s hand-unrolled stack fast path (up to 9 elements, in `rustc_type_ir::interner`) kicks in for the common case of short projections and the `Vec` allocation is skipped entirely. The behavior is identical for longer projections (the fast path falls back to a `Vec` internally).
2026-04-26 21:56:42 -04:00
Jacob Pratt
f4043f8c09 Rollup merge of #155708 - Manishearth:borrow-fix, r=Mark-Simulacrum
Fix heap overflow in slice::join caused by misbehaving Borrow

This code allocates a buffer using lengths calculated by calling `.borrow()` on some slices, and then copies them over after again calling `.borrow()`. There is no safety-reliable guarantee that these will return the same slices.

While this code calls `.borrow()` three times, only one of them is problematic: the others already use checked indexing.

I made the test a normal library test, but let me know if it should go elsewhere.

Bug discovered by Rust Foundation Security using AI. I'm just helping with the patch as a member of wg-security-response. We do not believe this bug needs embargo, it is a soundness fix for hard-to-trigger unsoundness.
2026-04-26 21:56:41 -04:00
Jacob Pratt
7695b849d4 Rollup merge of #155588 - BennoLossin:frt-traits, r=Mark-Simulacrum
Implement more traits for FRTs

From https://github.com/rust-lang/rust/pull/154927#discussion_r3068460955.

FRTs now implement the following traits: `Sized + Freeze + RefUnwindSafe + Send + Sync + Unpin + UnsafeUnpin + UnwindSafe + Copy + Debug + Default + Eq + Hash + Ord`.

Let me know if there is any trait missing.

I also removed the explicit  `Send` and `Sync` impls, since commit cb37ee2c87 ("make field representing types invariant over the base type") made the auto-trait impl work even if `T: !Send` or `T: !Sync`. Very happy to see unsafe impls get dropped :)

Note that I used the reflection feature (cc @oli-obk) to print the actual field names in the debug implementation. I think this is a cool way to use it, but if it isn't ready for that, I'm happy to change it to the alternative implementation I gave in the note comment (it's essentially Mark's suggestion but printing `T`'s name instead of `Self`'s).

Since this is a library change, I'll give this to Mark; feel free to also take a look/leave comments, Oli :)

r? @Mark-Simulacrum
2026-04-26 21:56:41 -04:00
Jacob Pratt
72cd5fba78 Rollup merge of #155579 - Gaming32:fix-154998, r=Mark-Simulacrum
Make Rcs and Arcs use pointer comparison for unsized types

`Rc` and `Arc`s have an `Eq` implementation that first attempt to compare the pointers as an optimization. This, however, was not extended to DSTs, which is what this PR fixes.

Fixes rust-lang/rust#154998.
2026-04-26 21:56:40 -04:00
Jacob Pratt
12a843a020 Rollup merge of #155317 - briansmith:b/take-opt, r=Mark-Simulacrum
`std::io::Take`: Clarify & optimize `BorrowedBuf::set_init` usage.

Don't initialize `buf` if it was already initialized. Clarify safety comments.

Move the `buf.advance()` call to make the initialization more like
calling `buf.ensure_init()`, then clarify how the code here is an
optimized variant of `ensure_init`.
2026-04-26 21:56:39 -04:00
Jacob Pratt
f8e3af446e Rollup merge of #149624 - Flakebi:fix-lto, r=bjorn3
Fix requires_lto targets needing lto set in cargo

Targets that set `requires_lto = true` were not actually using lto when compiling with cargo by default. They needed an extra `lto = true` in `Cargo.toml` to work.

Fix this by letting lto take precedence over the `embed_bitcode` flag when lto is required by a target.

If both these flags would be supplied by the user, an error is generated. However, this did not happen when lto was requested by the target instead of the user.

Fixes rust-lang/rust#148514
Tracking issue: rust-lang/rust#135024
2026-04-26 21:56:39 -04:00
Manish Goregaokar
da545d0856 Fix heap overflow in slice::join caused by misbehaving Borrow
* Fix heap overflow in slice join via inconsistent Borrow
* Update library/alloc/src/str.rs

Co-authored-by: Mark Rousskov <mark.simulacrum@gmail.com>
2026-04-26 23:20:32 +00:00
bjorn3
effe8b5235 Remove unnecessary requires_lto: false for eBPF
requires_lto is already false by default.
2026-04-26 21:07:25 +02:00
jyn
7151184b46 Add some debugging to rustc_session filename handling 2026-04-26 16:19:11 +00:00
jyn
d9e227e98a Fix broken logic in incremental_verify_ich_failed 2026-04-26 16:18:45 +00:00
Miguel Ojeda
1e6ba4f385 CI: rfl: move job forward to Linux v7.0
This version contains both of the workarounds we had, thus remove them
as well.

Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2026-04-26 17:49:24 +02:00
Sasha Pourcelot
a7330f4897 rustc_attr_parsing: use a try {} in or_malformed 2026-04-26 15:15:25 +00:00
Usman Akinyemi
a677828c48 Add boxing suggestions for return expressions in impl Trait functions
Signed-off-by: Usman Akinyemi <usmanakinyemi202@gmail.com>
2026-04-26 17:43:40 +05:30
Jonathan Brouwer
163aedc873 Convert attribute FinalizeFn to fn pointer 2026-04-26 13:09:50 +02:00
Usman Akinyemi
4fc64f4180 Add boxing suggestions for impl Trait return type mismatches
Signed-off-by: Usman Akinyemi <usmanakinyemi202@gmail.com>
2026-04-26 14:58:49 +05:30
Kevin Heavey
5cd9d929a9 Avoid Vec allocation in TyCtxt::mk_place_elem
`mk_place_elem` appends a single `PlaceElem` to an existing (interned)
projection. The current implementation copies the projection into a
fresh `Vec`, pushes the new element, and re-interns the slice, which
allocates on the heap on every call.

Feed the elements through `mk_place_elems_from_iter` so that
`CollectAndApply`'s hand-unrolled stack fast path (up to 9 elements,
in `rustc_type_ir::interner`) kicks in for the common case of short
projections and the `Vec` allocation is skipped entirely. The behavior
is identical for longer projections (the fast path falls back to a
`Vec` internally).
2026-04-25 15:05:59 +01:00
yukang
5e00484c38 Avoid misleading closure return type note 2026-04-25 16:27:05 +08:00
Brian Smith
3a0a14fd7c <Take as Read>::read_buf: Don't initialize buf if it was already initialized. 2026-04-22 11:38:04 -07:00
Brian Smith
c716ce5c2e <Take as Read>::read_buf: Clarify safety comments and naming. 2026-04-22 11:38:04 -07:00
Brian Smith
71076f2338 <Take as Read>::read_buf: Eliminate unneeded local variables.
Eliminate `cursor` and `ibuf` as named variables, as their presence
makes things more confusing.
2026-04-22 11:36:50 -07:00
Brian Smith
4abc28f570 <Take as Read>::read_buf: Clarify local variable name. 2026-04-22 11:34:05 -07:00
Benno Lossin
a041a76097 field representing types: add test for unsized types 2026-04-21 09:29:34 +02:00
Benno Lossin
ca700edee3 field representing types: test all implemented traits 2026-04-21 09:29:10 +02:00
Benno Lossin
104914e614 field representing types: implement Hash, Eq & Ord 2026-04-21 09:28:53 +02:00
Benno Lossin
f3719b1686 field representing types: implement Default 2026-04-21 09:27:55 +02:00
Benno Lossin
59f18c21b0 field representing types: implement Debug through reflection
Using the reflection experiment, we can print the actual names of the
field that an FRT is referring to. In case this breaks, there is an
alternative implementation in the note comment.
2026-04-21 09:22:28 +02:00
Benno Lossin
2c79213bc5 field representing types: remove explicit Send and Sync impls
Commit cb37ee2c87 ("make field representing types invariant over the
base type") made the auto-trait impl work even if `T: !Send` or `T:
!Sync` thus we can remove these explicit unsafe impls while FRTs still
implement `Send` and `Sync`.
2026-04-21 09:20:02 +02:00
Josiah Glosson
6f28cd5073 Make Rcs and Arcs use pointer comparison for unsized types 2026-04-20 21:48:58 -05:00
Ayush Singh
47bec22de1 std: sys: process: uefi: Add program searching
- Follow UEFI Shell search flow to search for programs while launching.
- Tested using OVMF on QEMU.

Signed-off-by: Ayush Singh <ayush@beagleboard.org>
2026-02-17 10:50:35 +05:30
Flakebi
842c087427 Fix requires_lto targets needing lto set in cargo
Targets that set `requires_lto = true` were not actually using lto when
compiling with cargo by default. They needed an extra `lto = true` in
`Cargo.toml` to work.

Fix this by letting lto take precedence over the `embed_bitcode` flag
when lto is required by a target.

If both these flags would be supplied by the user, an error is
generated. However, this did not happen when lto was requested by the
target instead of the user.
2025-12-29 21:56:52 +01:00
44 changed files with 625 additions and 111 deletions

View File

@@ -1052,7 +1052,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
binder: &ClosureBinder,
capture_clause: CaptureBy,
closure_id: NodeId,
mut constness: Const,
constness: Const,
movability: Movability,
decl: &FnDecl,
body: &Expr,
@@ -1062,18 +1062,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
let closure_def_id = self.local_def_id(closure_id);
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
if let Const::Yes(span) = constness {
if !self.is_in_const_context {
self.dcx().span_err(span, "cannot use `const` closures outside of const contexts");
constness = Const::No;
}
}
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
let mut coroutine_kind = find_attr!(attrs, Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable));
// FIXME(contracts): Support contracts on closures?
let body_id = this.lower_fn_body(decl, None, constness, |this| {
let body_id = this.lower_fn_body(decl, None, |this| {
this.coroutine_kind = coroutine_kind;
let e = this.lower_expr_mut(body);
coroutine_kind = this.coroutine_kind;

View File

@@ -1,5 +1,3 @@
use std::mem;
use rustc_abi::ExternAbi;
use rustc_ast::visit::AssocCtxt;
use rustc_ast::*;
@@ -378,7 +376,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
body.as_deref(),
attrs,
contract.as_deref(),
header.constness,
);
let itctx = ImplTraitContext::Universal;
@@ -1068,7 +1065,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
Some(body),
attrs,
contract.as_deref(),
sig.header.constness,
);
let (generics, sig) = self.lower_method_sig(
generics,
@@ -1262,7 +1258,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
body.as_deref(),
attrs,
contract.as_deref(),
sig.header.constness,
);
let (generics, sig) = self.lower_method_sig(
generics,
@@ -1391,13 +1386,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
f: impl FnOnce(&mut Self) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>),
) -> hir::BodyId {
let prev_coroutine_kind = self.coroutine_kind.take();
let prev_is_in_const_context = mem::take(&mut self.is_in_const_context);
let task_context = self.task_context.take();
let (parameters, result) = f(self);
let body_id = self.record_body(parameters, result);
self.task_context = task_context;
self.coroutine_kind = prev_coroutine_kind;
self.is_in_const_context = prev_is_in_const_context;
body_id
}
@@ -1416,13 +1409,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
decl: &FnDecl,
contract: Option<&FnContract>,
constness: Const,
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
) -> hir::BodyId {
self.lower_body(|this| {
if let Const::Yes(_) = constness {
this.is_in_const_context = true;
}
let params =
this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x)));
@@ -1440,9 +1429,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
decl: &FnDecl,
body: &Block,
contract: Option<&FnContract>,
constness: Const,
) -> hir::BodyId {
self.lower_fn_body(decl, contract, constness, |this| this.lower_block_expr(body))
self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body))
}
pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId {
@@ -1450,10 +1438,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
(
&[],
match expr {
Some(expr) => {
this.is_in_const_context = true;
this.lower_expr_mut(expr)
}
Some(expr) => this.lower_expr_mut(expr),
None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")),
},
)
@@ -1472,13 +1457,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
body: Option<&Block>,
attrs: &'hir [hir::Attribute],
contract: Option<&FnContract>,
constness: Const,
) -> hir::BodyId {
let Some(body) = body else {
// Functions without a body are an error, except if this is an intrinsic. For those we
// create a fake body so that the entire rest of the compiler doesn't have to deal with
// this as a special case.
return self.lower_fn_body(decl, contract, constness, |this| {
return self.lower_fn_body(decl, contract, |this| {
if find_attr!(attrs, RustcIntrinsic) || this.tcx.is_sdylib_interface_build() {
let span = this.lower_span(span);
let empty_block = hir::Block {
@@ -1503,7 +1487,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
};
let Some(coroutine_kind) = coroutine_kind else {
// Typical case: not a coroutine.
return self.lower_fn_body_block(decl, body, contract, constness);
return self.lower_fn_body_block(decl, body, contract);
};
// FIXME(contracts): Support contracts on async fn.
self.lower_body(|this| {

View File

@@ -124,7 +124,6 @@ struct LoweringContext<'a, 'hir> {
loop_scope: Option<HirId>,
is_in_loop_condition: bool,
is_in_dyn_type: bool,
is_in_const_context: bool,
current_hir_id_owner: hir::OwnerId,
item_local_id_counter: hir::ItemLocalId,
@@ -193,7 +192,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
loop_scope: None,
is_in_loop_condition: false,
is_in_dyn_type: false,
is_in_const_context: false,
coroutine_kind: None,
task_context: None,
current_item: None,

View File

@@ -236,9 +236,11 @@ fn parse_directive_items<'p, S: Stage>(
}}
macro or_malformed($($code:tt)*) {{
let Some(ret) = (||{
Some($($code)*)
})() else {
let Some(ret) = (
try {
$($code)*
}
) else {
malformed!()
};
ret

View File

@@ -84,8 +84,7 @@ pub(super) struct GroupTypeInnerAccept<S: Stage> {
pub(crate) type AcceptFn<S> =
Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>;
pub(crate) type FinalizeFn<S> =
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
pub(crate) type FinalizeFn<S> = fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>;
macro_rules! attribute_parsers {
(
@@ -131,10 +130,10 @@ macro_rules! attribute_parsers {
}),
safety: <$names as crate::attributes::AttributeParser<$stage>>::SAFETY,
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
finalizer: Box::new(|cx| {
finalizer: |cx| {
let state = STATE_OBJECT.take();
state.finalize(cx)
})
}
});
}
Entry::Occupied(_) => panic!("Attribute {path:?} has multiple accepters"),

View File

@@ -297,7 +297,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
let mut early_parsed_state = EarlyParsedState::default();
let mut finalizers: Vec<&FinalizeFn<S>> = Vec::with_capacity(attrs.len());
let mut finalizers: Vec<FinalizeFn<S>> = Vec::with_capacity(attrs.len());
for attr in attrs {
// If we're only looking for a single attribute, skip all the ones we don't care about.
@@ -413,7 +413,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
};
(accept.accept_fn)(&mut cx, &args);
finalizers.push(&accept.finalizer);
finalizers.push(accept.finalizer);
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
Self::check_target(&accept.allowed_targets, target, &mut cx);

View File

@@ -153,7 +153,7 @@ impl ModuleConfig {
// `#![no_builtins]` is assumed to not participate in LTO and
// instead goes on to generate object code.
EmitObj::Bitcode
} else if need_bitcode_in_object(tcx) {
} else if need_bitcode_in_object(tcx) || sess.target.requires_lto {
EmitObj::ObjectCode(BitcodeSection::Full)
} else {
EmitObj::ObjectCode(BitcodeSection::None)

View File

@@ -16,7 +16,13 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Constness {
// Foreign functions cannot be evaluated at compile-time.
Constness::NotConst
}
Node::Expr(e) if let ExprKind::Closure(c) = e.kind => c.constness,
Node::Expr(e) if let ExprKind::Closure(c) = e.kind => {
if let Constness::Const = c.constness && tcx.hir_body_const_context(tcx.local_parent(def_id)).is_none() {
tcx.dcx().span_err(tcx.def_span(def_id), "cannot use `const` closures outside of const contexts");
return Constness::NotConst;
}
c.constness
},
// FIXME(fee1-dead): extract this one out and rename this query to `fn_constness` so we don't need `is_const_fn` anymore.
Node::Item(i) if let ItemKind::Impl(impl_) = i.kind => impl_.constness,
Node::Item(Item { kind: ItemKind::Fn { sig, .. }, .. }) => sig.header.constness,

View File

@@ -2009,6 +2009,9 @@ impl<'tcx> CoerceMany<'tcx> {
// note in this case, since it would be incorrect.
&& let Some(fn_sig) = fcx.body_fn_sig()
&& fn_sig.output().is_ty_var()
&& fcx.ret_coercion.as_ref().is_some_and(|ret_coercion| {
fcx.resolve_vars_if_possible(ret_coercion.borrow().expected_ty()) == expected
})
{
err.span_note(sp, format!("return type inferred to be `{expected}` here"));
}

View File

@@ -7,6 +7,7 @@ use rustc_ast::util::parser::ExprPrecedence;
use rustc_data_structures::packed::Pu128;
use rustc_errors::{Applicability, Diag, MultiSpan, listify, msg};
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind,
@@ -26,13 +27,14 @@ use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::{ExpnKind, Ident, MacroKind, Span, Spanned, Symbol, sym};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::error_reporting::traits::DefIdOrName;
use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use tracing::{debug, instrument};
use super::FnCtxt;
use crate::errors;
use crate::errors::{self, SuggestBoxingForReturnImplTrait};
use crate::fn_ctxt::rustc_span::BytePos;
use crate::method::probe;
use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
@@ -963,6 +965,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
let trait_def_id = trait_ref.trait_ref.path.res.def_id();
if self.tcx.is_dyn_compatible(trait_def_id) {
err.subdiagnostic(SuggestBoxingForReturnImplTrait::ChangeReturnType {
start_sp: hir_ty.span.with_hi(hir_ty.span.lo() + BytePos(4)),
end_sp: hir_ty.span.shrink_to_hi(),
});
let body = self.tcx.hir_body_owned_by(fn_id);
let mut visitor = ReturnsVisitor::default();
visitor.visit_body(&body);
if !visitor.returns.is_empty() {
let starts: Vec<Span> = visitor
.returns
.iter()
.filter(|expr| expr.span.can_be_used_for_suggestions())
.map(|expr| expr.span.shrink_to_lo())
.collect();
let ends: Vec<Span> = visitor
.returns
.iter()
.filter(|expr| expr.span.can_be_used_for_suggestions())
.map(|expr| expr.span.shrink_to_hi())
.collect();
if !starts.is_empty() {
err.subdiagnostic(SuggestBoxingForReturnImplTrait::BoxReturnExpr {
starts,
ends,
});
}
}
}
self.try_suggest_return_impl_trait(err, expected, found, fn_id);
self.try_note_caller_chooses_ty_for_ty_param(err, expected, found);
return true;

View File

@@ -143,7 +143,7 @@ pub(crate) struct Reentrant;
#[note(
"an ideal reproduction consists of the code before and some patch that then triggers the bug when applied and compiled again"
)]
#[note("as a workaround, you can run {$run_cmd} to allow your project to compile")]
#[note("as a workaround, you can {$run_cmd} to allow your project to compile")]
pub(crate) struct IncrementCompilation {
pub run_cmd: String,
pub dep_node: String,

View File

@@ -319,17 +319,7 @@ impl<'tcx> TyCtxt<'tcx> {
BodyOwnerKind::Fn if self.is_constructor(def_id) => return None,
// Const closures use their parent's const context
BodyOwnerKind::Closure if self.is_const_fn(def_id) => {
return Some(
self.hir_body_const_context(self.local_parent(local_def_id)).unwrap_or_else(
|| {
assert!(
self.dcx().has_errors().is_some(),
"`const` closure with no enclosing const context",
);
ConstContext::ConstFn
},
),
);
return self.hir_body_const_context(self.local_parent(local_def_id));
}
BodyOwnerKind::Fn if self.is_const_fn(def_id) => ConstContext::ConstFn,
BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None,

View File

@@ -2416,10 +2416,10 @@ impl<'tcx> TyCtxt<'tcx> {
/// to build a full `Place` it's just a convenient way to grab a projection and modify it in
/// flight.
pub fn mk_place_elem(self, place: Place<'tcx>, elem: PlaceElem<'tcx>) -> Place<'tcx> {
let mut projection = place.projection.to_vec();
projection.push(elem);
Place { local: place.local, projection: self.mk_place_elems(&projection) }
Place {
local: place.local,
projection: self.mk_place_elems_from_iter(place.projection.iter().chain([elem])),
}
}
pub fn mk_poly_existential_predicates(

View File

@@ -1,6 +1,8 @@
use std::cell::Cell;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_session::utils::was_invoked_from_cargo;
use tracing::instrument;
use crate::dep_graph::{DepGraphData, SerializedDepNodeIndex};
@@ -66,10 +68,10 @@ fn incremental_verify_ich_failed<'tcx>(
if old_in_panic {
tcx.dcx().emit_err(crate::error::Reentrant);
} else {
let run_cmd = if let Some(crate_name) = &tcx.sess.opts.crate_name {
format!("`cargo clean -p {crate_name}` or `cargo clean`")
let run_cmd = if was_invoked_from_cargo() {
format!("run `cargo clean -p {}` or `cargo clean`", tcx.crate_name(LOCAL_CRATE))
} else {
"`cargo clean`".to_string()
"clean your build cache".to_owned()
};
let dep_node = tcx.dep_graph.data().unwrap().prev_node_of(prev_index);

View File

@@ -1205,6 +1205,7 @@ impl OutputFilenames {
}
pub fn interface_path(&self) -> PathBuf {
debug!("using crate_name={} for interface_path", self.crate_stem);
self.out_directory.join(format!("lib{}.rs", self.crate_stem))
}
@@ -1214,6 +1215,7 @@ impl OutputFilenames {
let extension = flavor.extension();
match flavor {
OutputType::Metadata => {
debug!("using crate_name={} for {extension}", self.crate_stem);
self.out_directory.join(format!("lib{}.{}", self.crate_stem, extension))
}
_ => self.with_directory_and_extension(&self.out_directory, extension),
@@ -1288,6 +1290,7 @@ impl OutputFilenames {
}
pub fn with_directory_and_extension(&self, directory: &Path, extension: &str) -> PathBuf {
debug!("using filestem={} for {extension}", self.filestem);
let mut path = directory.join(&self.filestem);
path.set_extension(extension);
path

View File

@@ -18,7 +18,6 @@ pub(crate) fn opts(endian: Endian) -> TargetOptions {
// BPF_PROG_LOAD and not all BPF libraries do that yet
merge_functions: MergeFunctions::Disabled,
obj_is_bitcode: true,
requires_lto: false,
singlethread: true,
// When targeting the `v3` cpu in llvm, 32-bit atomics are also supported.
// But making this value change based on the target cpu can be mostly confusing

View File

@@ -2615,7 +2615,7 @@ impl<T: ?Sized + PartialEq, A: Allocator> RcEqIdent<T, A> for Rc<T, A> {
#[rustc_unsafe_specialization_marker]
pub(crate) trait MarkerEq: PartialEq<Self> {}
impl<T: Eq> MarkerEq for T {}
impl<T: ?Sized + Eq> MarkerEq for T {}
/// We're doing this specialization here, and not as a more general optimization on `&T`, because it
/// would otherwise add a cost to all equality checks on refs. We assume that `Rc`s are used to
@@ -2628,12 +2628,12 @@ impl<T: Eq> MarkerEq for T {}
impl<T: ?Sized + MarkerEq, A: Allocator> RcEqIdent<T, A> for Rc<T, A> {
#[inline]
fn eq(&self, other: &Rc<T, A>) -> bool {
Rc::ptr_eq(self, other) || **self == **other
ptr::eq(self.ptr.as_ptr(), other.ptr.as_ptr()) || **self == **other
}
#[inline]
fn ne(&self, other: &Rc<T, A>) -> bool {
!Rc::ptr_eq(self, other) && **self != **other
!ptr::eq(self.ptr.as_ptr(), other.ptr.as_ptr()) && **self != **other
}
}

View File

@@ -126,6 +126,26 @@ macro_rules! copy_slice_and_advance {
// the bounds for String-join are S: Borrow<str> and for Vec-join Borrow<[T]>
// [T] and str both impl AsRef<[T]> for some T
// => s.borrow().as_ref() and we always have slices
//
// # Safety notes
//
// `Borrow` is a safe trait, and implementations are not required
// to be deterministic. An inconsistent `Borrow` implementation could return slices
// of different lengths on consecutive calls (e.g. by using interior mutability).
//
// This implementation calls `borrow()` multiple times:
// 1. To calculate `reserved_len`, all elements are borrowed once.
// 2. The first element is borrowed again when copied via `extend_from_slice`.
// 3. Subsequent elements are borrowed a second time when building the mapped iterator.
//
// Risks and Mitigations:
// - If the first element GROWS on the second borrow, the length subtraction underflows.
// We mitigate this by doing a `checked_sub` to panic rather than allowing an underflow
// that fabricates a huge destination slice.
// - If elements 2..N GROW on their second borrow, the target slice bounds set by `checked_sub`
// means that `split_at_mut` inside `copy_slice_and_advance!` will correctly panic.
// - If elements SHRINK on their second borrow, the spare space is never written, and the final
// length set via `set_len` masks trailing uninitialized bytes.
#[cfg(not(no_global_oom_handling))]
fn join_generic_copy<B, T, S>(slice: &[S], sep: &[T]) -> Vec<T>
where
@@ -161,19 +181,21 @@ where
unsafe {
let pos = result.len();
let target = result.spare_capacity_mut().get_unchecked_mut(..reserved_len - pos);
let target_len = reserved_len.checked_sub(pos).expect("inconsistent Borrow implementation");
let target = result.spare_capacity_mut().get_unchecked_mut(..target_len);
// Convert the separator and slices to slices of MaybeUninit
// to simplify implementation in specialize_for_lengths
// to simplify implementation in specialize_for_lengths.
let sep_uninit = core::slice::from_raw_parts(sep.as_ptr().cast(), sep.len());
let iter_uninit = iter.map(|it| {
let it = it.borrow().as_ref();
core::slice::from_raw_parts(it.as_ptr().cast(), it.len())
});
// copy separator and slices over without bounds checks
// generate loops with hardcoded offsets for small separators
// massive improvements possible (~ x2)
// copy separator and slices over without bounds checks.
// `specialize_for_lengths!` internally calls `s.borrow()`, but because it uses
// the bounds-checked `split_at_mut` any misbehaving implementation
// will not write out of bounds.
let remain = specialize_for_lengths!(sep_uninit, target, iter_uninit; 0, 1, 2, 3, 4);
// A weird borrow implementation may return different

View File

@@ -3549,12 +3549,12 @@ impl<T: ?Sized + PartialEq, A: Allocator> ArcEqIdent<T, A> for Arc<T, A> {
impl<T: ?Sized + crate::rc::MarkerEq, A: Allocator> ArcEqIdent<T, A> for Arc<T, A> {
#[inline]
fn eq(&self, other: &Arc<T, A>) -> bool {
Arc::ptr_eq(self, other) || **self == **other
ptr::eq(self.ptr.as_ptr(), other.ptr.as_ptr()) || **self == **other
}
#[inline]
fn ne(&self, other: &Arc<T, A>) -> bool {
!Arc::ptr_eq(self, other) && **self != **other
!ptr::eq(self.ptr.as_ptr(), other.ptr.as_ptr()) && **self != **other
}
}

View File

@@ -86,6 +86,34 @@ fn eq() {
assert_eq!(*x.0.borrow(), 0);
}
#[test]
fn eq_unsized() {
#[derive(Eq)]
struct TestEq<T: ?Sized>(RefCell<usize>, T);
impl<T: ?Sized> PartialEq for TestEq<T> {
fn eq(&self, other: &TestEq<T>) -> bool {
*self.0.borrow_mut() += 1;
*other.0.borrow_mut() += 1;
true
}
}
let x = Arc::<TestEq<[u8; 3]>>::new(TestEq(RefCell::new(0), [0, 1, 2])) as Arc<TestEq<[u8]>>;
assert!(x == x);
assert!(!(x != x));
assert_eq!(*x.0.borrow(), 0);
}
#[test]
fn eq_unsized_slice() {
let a: Arc<[()]> = Arc::new([(); 3]);
let ptr: *const () = Arc::into_raw(a.clone()).cast();
let b: Arc<[()]> = unsafe { Arc::from_raw(core::ptr::slice_from_raw_parts(ptr, 42)) };
assert!(a == a);
assert!(!(a != a));
assert!(a != b);
assert!(!(a == b));
}
// The test code below is identical to that in `rc.rs`.
// For better maintainability we therefore define this type alias.
type Rc<T, A = std::alloc::Global> = Arc<T, A>;

View File

@@ -87,6 +87,34 @@ fn eq() {
assert_eq!(*x.0.borrow(), 0);
}
#[test]
fn eq_unsized() {
#[derive(Eq)]
struct TestEq<T: ?Sized>(RefCell<usize>, T);
impl<T: ?Sized> PartialEq for TestEq<T> {
fn eq(&self, other: &TestEq<T>) -> bool {
*self.0.borrow_mut() += 1;
*other.0.borrow_mut() += 1;
true
}
}
let x = Rc::<TestEq<[u8; 3]>>::new(TestEq(RefCell::new(0), [0, 1, 2])) as Rc<TestEq<[u8]>>;
assert!(x == x);
assert!(!(x != x));
assert_eq!(*x.0.borrow(), 0);
}
#[test]
fn eq_unsized_slice() {
let a: Rc<[()]> = Rc::new([(); 3]);
let ptr: *const () = Rc::into_raw(a.clone()).cast();
let b: Rc<[()]> = unsafe { Rc::from_raw(core::ptr::slice_from_raw_parts(ptr, 42)) };
assert!(a == a);
assert!(!(a != a));
assert!(a != b);
assert!(!(a == b));
}
const SHARED_ITER_MAX: u16 = 100;
fn assert_trusted_len<I: TrustedLen>(_: &I) {}

View File

@@ -194,6 +194,25 @@ fn test_join_issue_80335() {
test_join!("0-0-0", arr, "-");
}
#[test]
#[should_panic(expected = "inconsistent Borrow implementation")]
fn test_join_inconsistent_borrow() {
use std::borrow::Borrow;
use std::cell::Cell;
struct E(Cell<u32>);
impl Borrow<str> for E {
fn borrow(&self) -> &str {
let count = self.0.get();
self.0.set(count + 1);
if count == 0 { "" } else { "longer string" }
}
}
let _s = [E(Cell::new(0)), E(Cell::new(0))].join("");
}
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_unsafe_slice() {

View File

@@ -1,11 +1,12 @@
//! Field Reflection
use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::marker::PhantomData;
/// Field Representing Type
#[unstable(feature = "field_representing_type_raw", issue = "none")]
#[lang = "field_representing_type"]
#[expect(missing_debug_implementations)]
#[fundamental]
pub struct FieldRepresentingType<T: ?Sized, const VARIANT: u32, const FIELD: u32> {
// We want this type to be invariant over `T`, because otherwise `field_of!(Struct<'short>,
@@ -14,16 +15,50 @@ pub struct FieldRepresentingType<T: ?Sized, const VARIANT: u32, const FIELD: u32
_phantom: PhantomData<fn(T) -> T>,
}
// SAFETY: `FieldRepresentingType` doesn't contain any `T`
unsafe impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Send
for FieldRepresentingType<T, VARIANT, FIELD>
{
}
// SAFETY: `FieldRepresentingType` doesn't contain any `T`
unsafe impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Sync
impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> fmt::Debug
for FieldRepresentingType<T, VARIANT, FIELD>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
enum Member {
Name(&'static str),
Index(u32),
}
impl fmt::Display for Member {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Name(name) => fmt::Display::fmt(name, f),
Self::Index(idx) => fmt::Display::fmt(idx, f),
}
}
}
let (variant, field) = const {
use crate::mem::type_info::{Type, TypeKind};
match Type::of::<T>().kind {
TypeKind::Struct(struct_) => {
(None, Member::Name(struct_.fields[FIELD as usize].name))
}
TypeKind::Tuple(_) => (None, Member::Index(FIELD)),
TypeKind::Enum(enum_) => {
let variant = &enum_.variants[VARIANT as usize];
(Some(variant.name), Member::Name(variant.fields[FIELD as usize].name))
}
TypeKind::Union(union) => (None, Member::Name(union.fields[FIELD as usize].name)),
_ => unreachable!(),
}
};
let type_name = const { crate::any::type_name::<T>() };
match variant {
Some(variant) => write!(f, "field_of!({type_name}, {variant}.{field})"),
None => write!(f, "field_of!({type_name}, {field})"),
}
// NOTE: if there are changes in the reflection work and the above no
// longer compiles, then the following debug impl could also work in
// the meantime:
// ```rust
// let type_name = const { type_name::<T>() };
// write!(f, "field_of!({type_name}, {VARIANT}.{FIELD})")
// ```
}
}
impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Copy
@@ -39,6 +74,51 @@ impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Clone
}
}
impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Default
for FieldRepresentingType<T, VARIANT, FIELD>
{
fn default() -> Self {
Self { _phantom: PhantomData::default() }
}
}
impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Hash
for FieldRepresentingType<T, VARIANT, FIELD>
{
fn hash<H: Hasher>(&self, state: &mut H) {
self._phantom.hash(state);
}
}
impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> PartialEq
for FieldRepresentingType<T, VARIANT, FIELD>
{
fn eq(&self, other: &Self) -> bool {
self._phantom == other._phantom
}
}
impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Eq
for FieldRepresentingType<T, VARIANT, FIELD>
{
}
impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> PartialOrd
for FieldRepresentingType<T, VARIANT, FIELD>
{
fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> {
self._phantom.partial_cmp(&other._phantom)
}
}
impl<T: ?Sized, const VARIANT: u32, const FIELD: u32> Ord
for FieldRepresentingType<T, VARIANT, FIELD>
{
fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
self._phantom.cmp(&other._phantom)
}
}
/// Expands to the field representing type of the given field.
///
/// The container type may be a tuple, `struct`, `union` or `enum`. In the case of an enum, the

View File

@@ -3098,9 +3098,7 @@ impl<T: Read> Read for Take<T> {
let is_init = buf.is_init();
// SAFETY: no uninit data is written to ibuf
let ibuf = unsafe { &mut buf.as_mut()[..limit] };
let mut sliced_buf: BorrowedBuf<'_> = ibuf.into();
let mut sliced_buf = BorrowedBuf::from(unsafe { &mut buf.as_mut()[..limit] });
if is_init {
// SAFETY: `sliced_buf` is a subslice of `buf`, so if `buf` was initialized then
@@ -3108,22 +3106,23 @@ impl<T: Read> Read for Take<T> {
unsafe { sliced_buf.set_init() };
}
let mut cursor = sliced_buf.unfilled();
let result = self.inner.read_buf(cursor.reborrow());
let result = self.inner.read_buf(sliced_buf.unfilled());
let should_init = cursor.is_init();
let did_init_up_to_limit = sliced_buf.is_init();
let filled = sliced_buf.len();
// cursor / sliced_buf / ibuf must drop here
// sliced_buf must drop here
// Avoid accidentally quadratic behaviour by initializing the whole
// cursor if only part of it was initialized.
if should_init {
// SAFETY: no uninit data is written
let uninit = unsafe { &mut buf.as_mut()[limit..] };
uninit.write_filled(0);
// SAFETY: all bytes that were not initialized by `T::read_buf`
// have just been written to.
if did_init_up_to_limit && !is_init {
// SAFETY: No uninit data will be written.
let unfilled_before_advance = unsafe { buf.as_mut() };
unfilled_before_advance[limit..].write_filled(0);
// SAFETY: `unfilled_before_advance[..limit]` was initialized by `T::read_buf`, and
// `unfilled_before_advance[limit..]` was just initialized.
unsafe { buf.set_init() };
}

View File

@@ -5,7 +5,7 @@ use crate::collections::BTreeMap;
pub use crate::ffi::OsString as EnvKey;
use crate::ffi::{OsStr, OsString};
use crate::num::{NonZero, NonZeroI32};
use crate::path::Path;
use crate::path::{Path, PathBuf};
use crate::process::StdioPipes;
use crate::sys::fs::File;
use crate::sys::io::error_string;
@@ -138,7 +138,9 @@ impl Command {
}
pub fn output(command: &mut Command) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let mut cmd = uefi_command_internal::Image::load_image(&command.prog)?;
let prog_path = resolve_program(&command.prog)
.ok_or(io::const_error!(io::ErrorKind::NotFound, "could not find the program."))?;
let mut cmd = uefi_command_internal::Image::load_image(prog_path.as_os_str())?;
// UEFI adds the bin name by default
if !command.args.is_empty() {
@@ -366,6 +368,36 @@ pub fn read_output(
match out.diverge() {}
}
// Search for programs similar to UEFI Shell defined in Section 3.6.1. It follows the following flow:
// 1. If program is already absolute path, just check if it exists.
// 2. For non-absolute path, search relative to current directory.
// 3. Search the path list sequentially.
//
// [UEFI Shell Specification](https://uefi.org/sites/default/files/resources/UEFI_Shell_2_2.pdf).
fn resolve_program<S: AsRef<OsStr> + ?Sized>(prog: &S) -> Option<PathBuf> {
let absolute_prog_path = crate::path::absolute(prog.as_ref()).ok()?;
match crate::fs::exists(&absolute_prog_path) {
Ok(true) => return Some(absolute_prog_path),
// If program path was already absolute and is not found, then stop.
Ok(false) if Path::new(prog.as_ref()).is_absolute() => return None,
_ => {}
}
// Search for the program in path.
if let Ok(path_var) = crate::env::var("path") {
for p in crate::env::split_paths(&path_var) {
let temp = p.join(prog.as_ref());
if let Ok(true) = crate::fs::exists(&temp) {
return Some(temp);
}
}
}
None
}
#[allow(dead_code)]
mod uefi_command_internal {
use r_efi::protocols::{loaded_image, simple_text_input, simple_text_output};

View File

@@ -2,9 +2,7 @@
set -euo pipefail
# https://github.com/rust-lang/rust/pull/151534
# https://github.com/rust-lang/rust/pull/149389
LINUX_VERSION=167ea5357eb7c3a39200627a36dfbfe249576192
LINUX_VERSION=v7.0
# Build rustc, rustdoc, cargo, clippy-driver and rustfmt
../x.py build --stage 2 library rustdoc clippy rustfmt

View File

@@ -59,11 +59,6 @@ Build the library as `cdylib`:
# Cargo.toml
[lib]
crate-type = ["cdylib"]
[profile.dev]
lto = true # LTO must be explicitly enabled for now
[profile.release]
lto = true
```
The target-cpu must be from the list [supported by LLVM] (or printed with `rustc --target amdgcn-amd-amdhsa --print target-cpus`).

View File

@@ -0,0 +1,8 @@
[package]
name = "amdgpu_lto"
version = "0.1.0"
edition = "2024"
[lib]
path = "lib.rs"
crate-type = ["cdylib"]

View File

@@ -0,0 +1,15 @@
#![feature(abi_gpu_kernel)]
#![no_std]
#[panic_handler]
fn panic_handler(_info: &core::panic::PanicInfo) -> ! {
loop {}
}
#[unsafe(no_mangle)]
fn foo(a: i32, b: i32) -> i32 {
a + b
}
#[unsafe(no_mangle)]
extern "gpu-kernel" fn kernel() {}

View File

@@ -0,0 +1,28 @@
// Check that compiling for the amdgpu target which needs LTO works with a default
// cargo configuration.
//@ needs-llvm-components: amdgpu
//@ needs-rust-lld
#![deny(warnings)]
use run_make_support::{cargo, path};
fn main() {
let target_dir = path("target");
cargo()
.args(&[
"build",
"--release",
"--lib",
"--manifest-path",
"Cargo.toml",
"-Zbuild-std=core",
"--target",
"amdgcn-amd-amdhsa",
])
.env("RUSTFLAGS", "-Ctarget-cpu=gfx900")
.env("CARGO_TARGET_DIR", &target_dir)
.run();
}

View File

@@ -0,0 +1,14 @@
struct SmolStr;
const _: fn() = || {
match Some(()) {
Some(()) => (),
None => return,
};
let _: String = {
SmolStr
//~^ ERROR mismatched types
};
};
fn main() {}

View File

@@ -0,0 +1,9 @@
error[E0308]: mismatched types
--> $DIR/closure-return-block-note-issue-155670.rs:9:9
|
LL | SmolStr
| ^^^^^^^ expected `String`, found `SmolStr`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.

View File

@@ -0,0 +1,25 @@
//@ check-pass
#![feature(const_closures, const_destruct, const_trait_impl)]
use std::marker::Destruct;
use std::num::NonZero;
const trait T {
fn a(&mut self, f: impl [const] Fn() + [const] Destruct);
fn b(&mut self);
}
struct S;
impl const T for S {
fn a(&mut self, f: impl [const] Fn() + [const] Destruct) {
f()
}
fn b(&mut self) {
self.a(const || {});
}
}
fn main() {}

View File

@@ -0,0 +1,27 @@
error[E0277]: the trait bound `field_of!(MyStruct, 0): std::field::Field` is not satisfied
--> $DIR/not-field-if-unsized.rs:17:20
|
LL | assert_field::<field_of!(MyStruct, 0)>();
| ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyStruct, 0)`
|
note: required by a bound in `assert_field`
--> $DIR/not-field-if-unsized.rs:12:20
|
LL | fn assert_field<F: Field>() {}
| ^^^^^ required by this bound in `assert_field`
error[E0277]: the trait bound `field_of!(MyStruct, 1): std::field::Field` is not satisfied
--> $DIR/not-field-if-unsized.rs:21:20
|
LL | assert_field::<field_of!(MyStruct, 1)>();
| ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyStruct, 1)`
|
note: required by a bound in `assert_field`
--> $DIR/not-field-if-unsized.rs:12:20
|
LL | fn assert_field<F: Field>() {}
| ^^^^^ required by this bound in `assert_field`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@@ -0,0 +1,27 @@
error[E0277]: the trait bound `field_of!(MyStruct, 0): std::field::Field` is not satisfied
--> $DIR/not-field-if-unsized.rs:17:20
|
LL | assert_field::<field_of!(MyStruct, 0)>();
| ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyStruct, 0)`
|
note: required by a bound in `assert_field`
--> $DIR/not-field-if-unsized.rs:12:20
|
LL | fn assert_field<F: Field>() {}
| ^^^^^ required by this bound in `assert_field`
error[E0277]: the trait bound `field_of!(MyStruct, 1): std::field::Field` is not satisfied
--> $DIR/not-field-if-unsized.rs:21:20
|
LL | assert_field::<field_of!(MyStruct, 1)>();
| ^^^^^^^^^^^^^^^^^^^^^^ the nightly-only, unstable trait `std::field::Field` is not implemented for `field_of!(MyStruct, 1)`
|
note: required by a bound in `assert_field`
--> $DIR/not-field-if-unsized.rs:12:20
|
LL | fn assert_field<F: Field>() {}
| ^^^^^ required by this bound in `assert_field`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@@ -0,0 +1,23 @@
//@ revisions: old next
//@ [next] compile-flags: -Znext-solver
#![expect(incomplete_features)]
#![feature(field_projections)]
use std::field::{Field, field_of};
pub trait Trait {}
pub struct MyStruct(usize, dyn Trait);
fn assert_field<F: Field>() {}
fn main() {
// FIXME(FRTs): this requires relaxing the `Base: ?Sized` bound in the
// `Field` trait & compiler changes.
assert_field::<field_of!(MyStruct, 0)>();
//~^ ERROR: the trait bound `field_of!(MyStruct, 0): std::field::Field` is not satisfied [E0277]
// FIXME(FRTs): improve this error message, point to the `dyn Trait` span.
assert_field::<field_of!(MyStruct, 1)>();
//~^ ERROR: the trait bound `field_of!(MyStruct, 1): std::field::Field` is not satisfied [E0277]
}

View File

@@ -1,13 +1,17 @@
//@ revisions: old next
//@ [next] compile-flags: -Znext-solver
//@ run-pass
#![feature(field_projections, freeze)]
#![feature(field_projections, freeze, unsafe_unpin)]
#![expect(incomplete_features, dead_code)]
use std::field::field_of;
use std::marker::{Freeze, Unpin};
use std::fmt::Debug;
use std::hash::Hash;
use std::marker::{Freeze, Unpin, UnsafeUnpin};
use std::panic::{RefUnwindSafe, UnwindSafe};
struct Struct {
field: u32,
tail: [u32],
}
union Union {
@@ -19,11 +23,37 @@ enum Enum {
Variant2(u32),
}
fn assert_traits<T: Send + Sync + Unpin + Copy + Clone + Sized + Freeze>() {}
type Tuple = ((), usize, String, dyn Debug);
fn assert_traits<
T: Sized
+ Freeze
+ RefUnwindSafe
+ Send
+ Sync
+ Unpin
+ UnsafeUnpin
+ UnwindSafe
+ Copy
+ Debug
+ Default
+ Eq
+ Hash
+ Ord,
>() {
}
fn main() {
assert_traits::<field_of!(Struct, field)>();
assert_traits::<field_of!(Struct, tail)>();
assert_traits::<field_of!(Union, field)>();
assert_traits::<field_of!(Enum, Variant1.field)>();
assert_traits::<field_of!(Enum, Variant2.0)>();
assert_traits::<field_of!(Tuple, 0)>();
assert_traits::<field_of!(Tuple, 1)>();
assert_traits::<field_of!(Tuple, 2)>();
assert_traits::<field_of!(Tuple, 3)>();
}

View File

@@ -21,6 +21,18 @@ LL | return A;
LL | }
LL | B
| ^ expected `A`, found `B`
|
help: you could change the return type to be a boxed trait object
|
LL - fn cat() -> impl DynCompatible {
LL + fn cat() -> Box<dyn DynCompatible> {
|
help: if you change the return type to expect trait objects, box the returned expressions
|
LL ~ return Box::new(A);
LL | }
LL ~ Box::new(B)
|
error: aborting due to 2 previous errors

View File

@@ -72,6 +72,17 @@ LL | }
LL | 1u32
| ^^^^ expected `i32`, found `u32`
|
help: you could change the return type to be a boxed trait object
|
LL - fn foo() -> impl std::fmt::Display {
LL + fn foo() -> Box<dyn std::fmt::Display> {
|
help: if you change the return type to expect trait objects, box the returned expressions
|
LL ~ return Box::new(0i32);
LL | }
LL ~ Box::new(1u32)
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL - 1u32
@@ -90,6 +101,17 @@ LL | } else {
LL | return 1u32;
| ^^^^ expected `i32`, found `u32`
|
help: you could change the return type to be a boxed trait object
|
LL - fn bar() -> impl std::fmt::Display {
LL + fn bar() -> Box<dyn std::fmt::Display> {
|
help: if you change the return type to expect trait objects, box the returned expressions
|
LL ~ return Box::new(0i32);
LL | } else {
LL ~ return Box::new(1u32);
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL - return 1u32;
@@ -108,6 +130,17 @@ LL | } else {
LL | 1u32
| ^^^^ expected `i32`, found `u32`
|
help: you could change the return type to be a boxed trait object
|
LL - fn baz() -> impl std::fmt::Display {
LL + fn baz() -> Box<dyn std::fmt::Display> {
|
help: if you change the return type to expect trait objects, box the returned expressions
|
LL ~ return Box::new(0i32);
LL | } else {
LL ~ Box::new(1u32)
|
help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
|
LL | }.try_into().unwrap()
@@ -153,6 +186,16 @@ LL | 0 => return 0i32,
LL | _ => 1u32,
| ^^^^ expected `i32`, found `u32`
|
help: you could change the return type to be a boxed trait object
|
LL - fn bat() -> impl std::fmt::Display {
LL + fn bat() -> Box<dyn std::fmt::Display> {
|
help: if you change the return type to expect trait objects, box the returned expressions
|
LL ~ 0 => return Box::new(0i32),
LL ~ _ => Box::new(1u32),
|
help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
|
LL | }.try_into().unwrap()
@@ -171,6 +214,17 @@ LL | | _ => 2u32,
LL | | }
| |_____^ expected `i32`, found `u32`
|
help: you could change the return type to be a boxed trait object
|
LL - fn can() -> impl std::fmt::Display {
LL + fn can() -> Box<dyn std::fmt::Display> {
|
help: if you change the return type to expect trait objects, box the returned expressions
|
LL ~ 0 => return Box::new(0i32),
LL ~ 1 => Box::new(1u32),
LL ~ _ => Box::new(2u32),
|
help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
|
LL | }.try_into().unwrap()
@@ -188,6 +242,18 @@ LL | return 0i32;
LL | 1u32
| ^^^^ expected `i32`, found `u32`
|
help: you could change the return type to be a boxed trait object
|
LL - fn cat() -> impl std::fmt::Display {
LL + fn cat() -> Box<dyn std::fmt::Display> {
|
help: if you change the return type to expect trait objects, box the returned expressions
|
LL ~ return Box::new(0i32);
LL | }
LL | _ => {
LL ~ Box::new(1u32)
|
help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
|
LL | }.try_into().unwrap()

View File

@@ -11,6 +11,7 @@ impl<T: Foo> Foo for &mut T {
const fn test() -> impl [const] Fn() {
//~^ ERROR functions in trait impls cannot be declared const
const move || {}
//~^ ERROR: cannot use `const` closures outside of const contexts
}
}

View File

@@ -14,6 +14,12 @@ help: ... and declare the impl to be const instead
LL | impl<T: Foo> const Foo for &mut T {
| +++++
error: aborting due to 1 previous error
error: cannot use `const` closures outside of const contexts
--> $DIR/const-closure-in-non-const-trait-impl-method.rs:13:9
|
LL | const move || {}
| ^^^^^^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0379`.

View File

@@ -6,6 +6,7 @@ trait Tr {
const fn test() {
//~^ ERROR functions in traits cannot be declared const
(const || {})()
//~^ ERROR cannot use `const` closures outside of const contexts
}
}

View File

@@ -7,6 +7,12 @@ LL | const fn test() {
| functions in traits cannot be const
| help: remove the `const`
error: aborting due to 1 previous error
error: cannot use `const` closures outside of const contexts
--> $DIR/const-closure-in-non-const-trait-method.rs:8:10
|
LL | (const || {})()
| ^^^^^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0379`.

View File

@@ -2,7 +2,7 @@ error: cannot use `const` closures outside of const contexts
--> $DIR/non-const-op-const-closure-non-const-outer.rs:14:6
|
LL | (const || { (()).foo() })();
| ^^^^^
| ^^^^^^^^
error: aborting due to 1 previous error