Compare commits

..

41 commits

Author SHA1 Message Date
bors
c043085801 Auto merge of #152785 - Zalathar:rollup-UGtEsqh, r=Zalathar
Rollup of 20 pull requests

Successful merges:

 - rust-lang/rust#145399 (Unify wording of resolve error)
 - rust-lang/rust#150473 (tail calls: fix copying non-scalar arguments to callee)
 - rust-lang/rust#152637 (Add a note about elided lifetime)
 - rust-lang/rust#152729 (compiler: Don't mark `SingleUseConsts` MIR pass as "required for soundness")
 - rust-lang/rust#152751 (Rename dep node "fingerprints" to distinguish key and value hashes)
 - rust-lang/rust#152753 (remove the explicit error for old `rental` versions)
 - rust-lang/rust#152758 (Remove ShallowInitBox.)
 - rust-lang/rust#151530 (Fix invalid `mut T` suggestion for `&mut T` in missing lifetime error)
 - rust-lang/rust#152179 (Add documentation note about signed overflow direction)
 - rust-lang/rust#152474 (Implement opt-bisect-limit for MIR)
 - rust-lang/rust#152509 (tests/ui/test-attrs: add annotations for reference rules)
 - rust-lang/rust#152672 (std: use libc version of `_NSGetArgc`/`_NSGetArgv`)
 - rust-lang/rust#152711 (resolve: Disable an assert that no longer holds)
 - rust-lang/rust#152725 (Rework explanation of CLI lint level flags)
 - rust-lang/rust#152732 (add regression test for 147958)
 - rust-lang/rust#152745 (Fix ICE in `suggest_param_env_shadowing` with incompatible args)
 - rust-lang/rust#152749 (make `rustc_allow_const_fn_unstable` an actual `rustc_attrs` attribute)
 - rust-lang/rust#152756 (Miri: recursive validity: also recurse into Boxes)
 - rust-lang/rust#152770 (carryless_mul: mention the base)
 - rust-lang/rust#152778 (Update tracking issue number for final_associated_functions)
2026-02-18 11:12:36 +00:00
Stuart Cook
8a2c6ea409
Rollup merge of #152778 - mu001999-contrib:fix/final-method, r=fmease
Update tracking issue number for final_associated_functions

From https://github.com/rust-lang/rust/pull/151783#discussion_r2816929026
2026-02-18 17:29:51 +11:00
Stuart Cook
c7db84b0a3
Rollup merge of #152770 - RalfJung:carryless-mul-base, r=scottmcm
carryless_mul: mention the base

Arithmetic operations do not typically care about the base that is used to represent numbers, but this one does. Mentioning that makes it easier to understand the operation, I think.

Cc @folkertdev
2026-02-18 17:29:50 +11:00
Stuart Cook
123611f208
Rollup merge of #152756 - RalfJung:miri-recursive-box, r=Kivooeo
Miri: recursive validity: also recurse into Boxes

Now that https://github.com/rust-lang/rust/issues/97270 is fixed, the recursive validity mode for Miri can recuse into Boxes without exploding everywhere.
2026-02-18 17:29:50 +11:00
Stuart Cook
e53dd52e16
Rollup merge of #152749 - cyrgani:rustc-allow-const, r=jdonszelmann
make `rustc_allow_const_fn_unstable` an actual `rustc_attrs` attribute

It is already named like one, but used to have its own feature gate, which this PR now removes in favor of just using `#![feature(rustc_attrs)]`.

Most of the diff is just the line number changes in `malformed-attrs.stderr`.
2026-02-18 17:29:49 +11:00
Stuart Cook
e8327b0a79
Rollup merge of #152745 - TaKO8Ki:fix-ice-suggest-param-env-shadowing-incompatible-args, r=Kivooeo
Fix ICE in `suggest_param_env_shadowing` with incompatible args

Fixes rust-lang/rust#152684
2026-02-18 17:29:49 +11:00
Stuart Cook
77e29b25d0
Rollup merge of #152732 - Kivooeo:add-regression-test-1, r=TaKO8Ki
add regression test for 147958

fixes rust-lang/rust#147958
2026-02-18 17:29:48 +11:00
Stuart Cook
f7d5a6467d
Rollup merge of #152725 - ehuss:lint-level-cli, r=jieyouxu
Rework explanation of CLI lint level flags

I think the previous wording as either wrong or confusing. I would consider the CLI flags at a *lower* ranking, since source attributes are able to override the CLI flag.
2026-02-18 17:29:48 +11:00
Stuart Cook
8f3bbc1f5a
Rollup merge of #152711 - petrochenkov:globass, r=Kivooeo
resolve: Disable an assert that no longer holds

Fixes https://github.com/rust-lang/rust/issues/152606
Fixes https://github.com/rust-lang/rust/issues/152595
2026-02-18 17:29:47 +11:00
Stuart Cook
9a82b6700a
Rollup merge of #152672 - joboet:apple_args_libc, r=jhpratt
std: use libc version of `_NSGetArgc`/`_NSGetArgv`

These were added to libc in https://github.com/rust-lang/libc/pull/3702.
2026-02-18 17:29:47 +11:00
Stuart Cook
9ac3dcd7c9
Rollup merge of #152509 - DanielEScherzer:test-references-tests, r=ehuss
tests/ui/test-attrs: add annotations for reference rules
2026-02-18 17:29:46 +11:00
Stuart Cook
544462ad8b
Rollup merge of #152474 - sgasho:opt-bisect-limit-mir, r=saethlin
Implement opt-bisect-limit for MIR

closes: rust-lang/rust#150910

Enable bisecting MIR optimization passes to enhance debuggability.

discussions on zulip: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/MIR.20dump.20the.20pass.20names/with/573219207

### Check it works
#### Sample code
```rust
fn abs(num: isize) -> usize {
    if num < 0 { -num as usize } else { num as usize }
}

fn main() {
    println!("{}", abs(-10));
}
```

#### Output

```shell
rustc +mir -Zmir-opt-bisect-limit=30 src/main.rs
BISECT: running pass (1) CheckAlignment on main[89d5]::main
BISECT: running pass (2) CheckNull on main[89d5]::main
BISECT: running pass (3) CheckEnums on main[89d5]::main
BISECT: running pass (4) LowerSliceLenCalls on main[89d5]::main
BISECT: running pass (5) InstSimplify-before-inline on main[89d5]::main
BISECT: running pass (6) ForceInline on main[89d5]::main
BISECT: running pass (7) RemoveStorageMarkers on main[89d5]::main
BISECT: running pass (8) RemoveZsts on main[89d5]::main
BISECT: running pass (9) RemoveUnneededDrops on main[89d5]::main
BISECT: running pass (10) UnreachableEnumBranching on main[89d5]::main
BISECT: running pass (11) SimplifyCfg-after-unreachable-enum-branching on main[89d5]::main
BISECT: running pass (12) InstSimplify-after-simplifycfg on main[89d5]::main
BISECT: running pass (13) SimplifyConstCondition-after-inst-simplify on main[89d5]::main
BISECT: running pass (14) SimplifyLocals-before-const-prop on main[89d5]::main
BISECT: running pass (15) SimplifyLocals-after-value-numbering on main[89d5]::main
BISECT: running pass (16) MatchBranchSimplification on main[89d5]::main
BISECT: running pass (17) SingleUseConsts on main[89d5]::main
BISECT: running pass (18) SimplifyConstCondition-after-const-prop on main[89d5]::main
BISECT: running pass (19) SimplifyConstCondition-final on main[89d5]::main
BISECT: running pass (20) RemoveNoopLandingPads on main[89d5]::main
BISECT: running pass (21) SimplifyCfg-final on main[89d5]::main
BISECT: running pass (22) CopyProp on main[89d5]::main
BISECT: running pass (23) SimplifyLocals-final on main[89d5]::main
BISECT: running pass (24) AddCallGuards on main[89d5]::main
BISECT: running pass (25) PreCodegen on main[89d5]::main
BISECT: running pass (26) CheckAlignment on main[89d5]::abs
BISECT: running pass (27) CheckNull on main[89d5]::abs
BISECT: running pass (28) CheckEnums on main[89d5]::abs
BISECT: running pass (29) LowerSliceLenCalls on main[89d5]::abs
BISECT: running pass (30) InstSimplify-before-inline on main[89d5]::abs
BISECT: NOT running pass (31) ForceInline on main[89d5]::abs
BISECT: NOT running pass (32) RemoveStorageMarkers on main[89d5]::abs
BISECT: NOT running pass (33) RemoveZsts on main[89d5]::abs
BISECT: NOT running pass (34) RemoveUnneededDrops on main[89d5]::abs
BISECT: NOT running pass (35) UnreachableEnumBranching on main[89d5]::abs
BISECT: NOT running pass (36) SimplifyCfg-after-unreachable-enum-branching on main[89d5]::abs
BISECT: NOT running pass (37) InstSimplify-after-simplifycfg on main[89d5]::abs
BISECT: NOT running pass (38) SimplifyConstCondition-after-inst-simplify on main[89d5]::abs
BISECT: NOT running pass (39) SimplifyLocals-before-const-prop on main[89d5]::abs
BISECT: NOT running pass (40) SimplifyLocals-after-value-numbering on main[89d5]::abs
BISECT: NOT running pass (41) MatchBranchSimplification on main[89d5]::abs
BISECT: NOT running pass (42) SingleUseConsts on main[89d5]::abs
BISECT: NOT running pass (43) SimplifyConstCondition-after-const-prop on main[89d5]::abs
BISECT: NOT running pass (44) SimplifyConstCondition-final on main[89d5]::abs
BISECT: NOT running pass (45) RemoveNoopLandingPads on main[89d5]::abs
BISECT: NOT running pass (46) SimplifyCfg-final on main[89d5]::abs
BISECT: NOT running pass (47) CopyProp on main[89d5]::abs
BISECT: NOT running pass (48) SimplifyLocals-final on main[89d5]::abs
BISECT: NOT running pass (49) AddCallGuards on main[89d5]::abs
BISECT: NOT running pass (50) PreCodegen on main[89d5]::abs
```

r? @saethlin
2026-02-18 17:29:46 +11:00
Stuart Cook
ae196c772d
Rollup merge of #152179 - nickkuk:overflow-direction-note, r=jhpratt
Add documentation note about signed overflow direction

In https://github.com/rust-lang/rust/issues/151989#issuecomment-3845282666 I noticed that signed overflow direction can be determined by returned wrapped value. It is not very obvious (especially, assuming additional `carry: bool` summand), but it is important if we want to add new leading (signed) limb to big integer in this case.

Examples for small summands `x, y: i8` with result extension:

| x     | y    | overflow | result as (u8, i8) |
| ----  | ---- | -------- | ------------------ |
| -1    | -128 | true     | (127, -1)          |
| 0     | -1   | false    | (255, -1)          |
| 2     | 2    | false    | (4, 0)             |
| 127   | 1    | true     | (128, 0)           |

Here is general proof.

1. Set $s=2^{N-1}$ and let's say `iN::carrying_add(x, y, c)` returns `(result, true)` then

$$
\mathrm{result}=\begin{cases}
x + y + c + 2s,& x + y + c \le -s-1,\\
x+y+c-2s,& x+y+c\ge s.
\end{cases}
$$

First case is overflowing below `iN::MIN` and we have

$$
\mathrm{result}\ge -s-s+0+2s =0;\qquad
\mathrm{result}=x + y + c + 2s\le -s-1+2s = s - 1,
$$

so we obtain $[0; s-1]$ which is exactly range of non-negative `iN`.

Second case is overflowing above `iN::MAX` and

$$
\mathrm{result}=x+y+c-2s\ge s-2s =-s;\qquad
\mathrm{result}\le s-1 + s-1+1-2s = -1,
$$

that is, $[-s,-1]$ which is exactly range of negative `iN`.

2. Now suppose that `iN::borrowing_sub(x,y,b)` returns `(result, true)` then

$$
\mathrm{result}=\begin{cases}
x - y - b + 2s,& x - y - b \le -s-1,\\
x - y - b - 2s,& x - y - b\ge s.
\end{cases}
$$

First case is overflowing below `iN::MIN` and we have

$$
\mathrm{result}\ge -s-(s-1)-1+2s =0;\qquad
\mathrm{result}=x - y - b + 2s\le -s-1+2s = s - 1.
$$

Second case is overflowing above `iN::MAX` and

$$
\mathrm{result}=x-y-b-2s\ge s-2s =-s;\qquad
\mathrm{result}\le s-1 - (-s) - 0 - 2s = -1.
$$
2026-02-18 17:29:45 +11:00
Stuart Cook
a544b5df98
Rollup merge of #151530 - reddevilmidzy:e0106, r=fee1-dead
Fix invalid `mut T` suggestion for `&mut T` in missing lifetime error

close: rust-lang/rust#150077

When suggesting to return an owned value instead of a borrowed one, the diagnostic was only removing `&` instead of `&mut `, resulting in invalid syntax like `mut T`. This PR fixes the span calculation to properly cover the entire `&mut ` prefix.
2026-02-18 17:29:45 +11:00
Stuart Cook
d5e9f9d67b
Rollup merge of #152758 - cjgillot:noinit-box, r=RalfJung
Remove ShallowInitBox.

All uses of this were removed by https://github.com/rust-lang/rust/pull/148190
Split from https://github.com/rust-lang/rust/pull/147862

r? @RalfJung
2026-02-18 17:29:44 +11:00
Stuart Cook
64087bc8ec
Rollup merge of #152753 - cyrgani:remove-hack, r=petrochenkov
remove the explicit error for old `rental` versions

This was converted to a hard error 20 months ago (in rust-lang/rust#125596). This seems like enough time for anyone still using it to notice, so remove the note entirely now.
In comparison, the explicit note for the more impactful `time` breakage was already removed after 6 months (rust-lang/rust#129343).

Closes rust-lang/rust#73933.
Closes rust-lang/rust#83125.

r? @petrochenkov
2026-02-18 17:29:43 +11:00
Stuart Cook
7312ac389f
Rollup merge of #152751 - Zalathar:fingerprint, r=nnethercote
Rename dep node "fingerprints" to distinguish key and value hashes

In the query system's dependency graph, each node is associated with two *fingerprints*: one that is typically a hash of the query key, and one that is typically a hash of the query's return value when called with that key.

Unfortunately, many identifiers and comments fail to clearly distinguish between these two kinds of fingerprint, which have very different roles in dependency tracking. This is a frequent source of confusion.

This PR therefore tries to establish a clear distinction between:

- **Key fingerprints** that help to uniquely identify a node (along with its `DepKind`), and are typically a hash of the query key
- **Value fingerprints** that help to determine whether a node can be marked green (despite having red dependencies), and are typically a hash of the query value

There should be no change to compiler behaviour.

r? nnethercote (or compiler)
2026-02-18 17:29:43 +11:00
Stuart Cook
dbc2193d37
Rollup merge of #152729 - Enselic:single_use_consts-not-required, r=cjgillot
compiler: Don't mark `SingleUseConsts` MIR pass as "required for soundness"

I don't think this MIR pass is required for soundness. The reasons are:
* Something like it was not enabled by default before PR rust-lang/rust#107404 which was the precursor to `SingleUseConsts` (see rust-lang/rust#125910 for the switch).
* By following the advice from https://github.com/rust-lang/rust/pull/128657#discussion_r1705114015 we can conclude it is not required for soundness since it has only ever run on MIR opt level > 0.
* Its [`MirPass::can_be_overridden()`](0ee7d96253/compiler/rustc_mir_transform/src/pass_manager.rs (L98-L102)) is unchanged and thus returns `true`, indicating that it is not a required MIR pass.
* PR CI pass in rust-lang/rust#151426 which stops enabling it by default in non-optimized builds.

As shown in the updated test `tests/mir-opt/optimize_none.rs`, `#[optimize(none)]` functions become even less optimized, as expected and desired.

Unblocks https://github.com/rust-lang/rust/pull/151426.
2026-02-18 17:29:43 +11:00
Stuart Cook
9e38745532
Rollup merge of #152637 - JohnTitor:issue-65866, r=estebank
Add a note about elided lifetime

Fixes rust-lang/rust#65866
r? @estebank
2026-02-18 17:29:42 +11:00
Stuart Cook
b1c72fbb72
Rollup merge of #150473 - RalfJung:interpret-tail-call, r=WaffleLapkin
tail calls: fix copying non-scalar arguments to callee

Alternative to https://github.com/rust-lang/rust/pull/144933: when invoking a tail call with a non-scalar argument, we need to delay freeing the caller's local variables until after the callee is initialized, so that we can copy things from the caller to the callee.

Fixes https://github.com/rust-lang/rust/issues/144820... but as the FIXMEs in the code show, it's not clear to me whether these are the right semantics.
r? @WaffleLapkin
2026-02-18 17:29:42 +11:00
Stuart Cook
efbc8957a6
Rollup merge of #145399 - estebank:resolve-error-wording-2, r=petrochenkov
Unify wording of resolve error

Remove "failed to resolve" from the main error message and use the same format we use in other resolution errors "cannot find `name`":

```
error[E0433]: cannot find `nonexistent` in `existent`
  --> $DIR/custom_attr_multisegment_error.rs:5:13
   |
LL | #[existent::nonexistent]
   |             ^^^^^^^^^^^ could not find `nonexistent` in `existent`
```

The intent behind this is to end up with all resolve errors eventually be on the form of

```
error[ECODE]: cannot find `{NAME}` in {SCOPE}
  --> $DIR/file.rs:5:13
   |
LL | #[existent::nonexistent]
   |             ^^^^^^^^^^^ {SPECIFIC LABEL}
```

A category of errors that is interest are those that involve keywords. For example:

```
error[E0433]: cannot find `Self` in this scope
  --> $DIR/issue-97194.rs:2:35
   |
LL |     fn bget(&self, index: [usize; Self::DIM]) -> bool {
   |                                   ^^^^ `Self` is only available in impls, traits, and type definitions
```
and

```
error[E0433]: cannot find `super` in this scope
  --> $DIR/keyword-super.rs:2:9
   |
LL |     let super: isize;
   |         ^^^^^ there are too many leading `super` keywords
```

For these the label provides the actual help, while the message is less informative beyond telling you "couldn't find `name`".

This is an off-shoot of https://github.com/rust-lang/rust/pull/126810 and https://github.com/rust-lang/rust/pull/128086, a subset of the intended changes there with review comments applied.

r? @petrochenkov
2026-02-18 17:29:41 +11:00
Zalathar
b015d5712a Rename DepNodeKey::recover to try_recover_key 2026-02-18 17:20:32 +11:00
Zalathar
9eaedddb7f Rename dep node "fingerprints" to distinguish key and value hashes 2026-02-18 17:20:32 +11:00
mu001999
d2580fdd58 Update tracking issue number for final_associated_functions 2026-02-18 10:35:02 +08:00
Daniel Scherzer
6e65aba9a3
tests/ui/test-attrs: add annotations for reference rules 2026-02-17 17:38:48 -08:00
Ralf Jung
ad5108eaad tail calls: fix copying non-scalar arguments to callee 2026-02-17 22:17:58 +01:00
Ralf Jung
626de862a5 carryless_mul: mention the base 2026-02-17 21:57:52 +01:00
cyrgani
83ef5059d6 make rustc_allow_const_fn_unstable an actual rustc_attrs attribute 2026-02-17 20:16:29 +00:00
cyrgani
195b849ea7 remove the explicit error for old rental versions 2026-02-17 20:11:01 +00:00
Ralf Jung
f5421609d6 Miri: recursive validity: also recurse into Boxes 2026-02-17 15:13:58 +01:00
sgasho
28c8d71544 Implement opt-bisect-limit for mir 2026-02-17 21:26:39 +09:00
Camille Gillot
6d4b1b38e7 Remove ShallowInitBox. 2026-02-17 11:25:50 +00:00
reddevilmidzy
e0d9d470df Fix invalid mut T suggestion for &mut T in missing lifetime error
* Find ref prefix span for owned suggestions
* Improve missing lifetime suggestions for `&mut str`
2026-02-17 10:18:08 +00:00
Takayuki Maeda
cbfa215893 fix ICE in suggest_param_env_shadowing with incompatible args
remove comments
2026-02-17 16:48:57 +09:00
Martin Nordholts
52b19f7dda compiler: Don't mark SingleUseConsts MIR pass as "required for soundness"
Because:
* Something like it did not exist before PR 107404
* That it is not run our mir-opt-level 0 indicates that it is not
  required for soundness
* Its `MirPass::can_be_overridden()` is unchanged and thus returns true,
  indicating that it is not a required MIR pass.
* No test fails in PR 151426 that stops enabling by default in non-optimized builds

As can be seen from the updated test `tests/mir-opt/optimize_none.rs`,
this means that `#[optimize(none)]` functions become even less
optimized. As expected and as desired.
2026-02-17 06:22:39 +01:00
Kivooeo
e8b0e6b990 add regression test 2026-02-16 22:39:22 +00:00
Eric Huss
3099121bb5 Rework explanation of CLI lint level flags
I think the previous wording as either wrong or confusing. I would
consider the CLI flags at a *lower* ranking, since source attributes are
able to override the CLI flag.
2026-02-16 10:47:35 -08:00
Vadim Petrochenkov
b541f1b198 resolve: Disable an assert that no longer holds 2026-02-16 16:07:08 +03:00
joboet
bd523647a4
std: use libc version of _NSGetArgc/_NSGetArgv 2026-02-15 17:06:36 +01:00
Yuki Okushi
71dff62449 Add a note about elided lifetime 2026-02-15 11:32:46 +09:00
Nikolai Kuklin
689e8c2099
Add documentation note about signed overflow direction 2026-02-05 16:34:54 +01:00
116 changed files with 1217 additions and 847 deletions

View file

@ -1544,8 +1544,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
Rvalue::Use(operand) Rvalue::Use(operand)
| Rvalue::Repeat(operand, _) | Rvalue::Repeat(operand, _)
| Rvalue::UnaryOp(_ /*un_op*/, operand) | Rvalue::UnaryOp(_ /*un_op*/, operand)
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) | Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) => {
| Rvalue::ShallowInitBox(operand, _ /*ty*/) => {
self.consume_operand(location, (operand, span), state) self.consume_operand(location, (operand, span), state)
} }

View file

@ -297,8 +297,9 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
Rvalue::Use(operand) Rvalue::Use(operand)
| Rvalue::Repeat(operand, _) | Rvalue::Repeat(operand, _)
| Rvalue::UnaryOp(_ /*un_op*/, operand) | Rvalue::UnaryOp(_ /*un_op*/, operand)
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) | Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) => {
| Rvalue::ShallowInitBox(operand, _ /*ty*/) => self.consume_operand(location, operand), self.consume_operand(location, operand)
}
&Rvalue::Discriminant(place) => { &Rvalue::Discriminant(place) => {
self.access_place( self.access_place(

View file

@ -1004,17 +1004,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
} }
} }
Rvalue::ShallowInitBox(_operand, ty) => {
let trait_ref =
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, span), [*ty]);
self.prove_trait_ref(
trait_ref,
location.to_locations(),
ConstraintCategory::SizedBound,
);
}
Rvalue::Cast(cast_kind, op, ty) => { Rvalue::Cast(cast_kind, op, ty) => {
match *cast_kind { match *cast_kind {
CastKind::PointerCoercion( CastKind::PointerCoercion(
@ -2231,7 +2220,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
| Rvalue::Ref(..) | Rvalue::Ref(..)
| Rvalue::RawPtr(..) | Rvalue::RawPtr(..)
| Rvalue::Cast(..) | Rvalue::Cast(..)
| Rvalue::ShallowInitBox(..)
| Rvalue::BinaryOp(..) | Rvalue::BinaryOp(..)
| Rvalue::CopyForDeref(..) | Rvalue::CopyForDeref(..)
| Rvalue::UnaryOp(..) | Rvalue::UnaryOp(..)

View file

@ -902,7 +902,6 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt:
lval.write_cvalue_transmute(fx, operand); lval.write_cvalue_transmute(fx, operand);
} }
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"), Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"),
Rvalue::ShallowInitBox(..) => bug!("`ShallowInitBox` in codegen"),
} }
} }
StatementKind::StorageLive(_) StatementKind::StorageLive(_)

View file

@ -710,7 +710,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
OperandRef { val: operand.val, layout, move_annotation: None } OperandRef { val: operand.val, layout, move_annotation: None }
} }
mir::Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"), mir::Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"),
mir::Rvalue::ShallowInitBox(..) => bug!("`ShallowInitBox` in codegen"),
} }
} }

View file

@ -646,8 +646,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
Rvalue::Cast(_, _, _) => {} Rvalue::Cast(_, _, _) => {}
Rvalue::ShallowInitBox(_, _) => {}
Rvalue::UnaryOp(op, operand) => { Rvalue::UnaryOp(op, operand) => {
let ty = operand.ty(self.body, self.tcx); let ty = operand.ty(self.body, self.tcx);
match op { match op {

View file

@ -237,8 +237,7 @@ where
Rvalue::Use(operand) Rvalue::Use(operand)
| Rvalue::Repeat(operand, _) | Rvalue::Repeat(operand, _)
| Rvalue::UnaryOp(_, operand) | Rvalue::UnaryOp(_, operand)
| Rvalue::Cast(_, operand, _) | Rvalue::Cast(_, operand, _) => in_operand::<Q, _>(cx, in_local, operand),
| Rvalue::ShallowInitBox(operand, _) => in_operand::<Q, _>(cx, in_local, operand),
Rvalue::BinaryOp(_, box (lhs, rhs)) => { Rvalue::BinaryOp(_, box (lhs, rhs)) => {
in_operand::<Q, _>(cx, in_local, lhs) || in_operand::<Q, _>(cx, in_local, rhs) in_operand::<Q, _>(cx, in_local, lhs) || in_operand::<Q, _>(cx, in_local, rhs)

View file

@ -192,7 +192,6 @@ where
} }
mir::Rvalue::Cast(..) mir::Rvalue::Cast(..)
| mir::Rvalue::ShallowInitBox(..)
| mir::Rvalue::Use(..) | mir::Rvalue::Use(..)
| mir::Rvalue::CopyForDeref(..) | mir::Rvalue::CopyForDeref(..)
| mir::Rvalue::ThreadLocalRef(..) | mir::Rvalue::ThreadLocalRef(..)

View file

@ -236,7 +236,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
if self.tcx.is_lang_item(def_id, LangItem::PanicDisplay) if self.tcx.is_lang_item(def_id, LangItem::PanicDisplay)
|| self.tcx.is_lang_item(def_id, LangItem::BeginPanic) || self.tcx.is_lang_item(def_id, LangItem::BeginPanic)
{ {
let args = self.copy_fn_args(args); let args = Self::copy_fn_args(args);
// &str or &&str // &str or &&str
assert!(args.len() == 1); assert!(args.len() == 1);

View file

@ -19,8 +19,8 @@ use tracing::{info, instrument, trace};
use super::{ use super::{
CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy,
Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, StackPopInfo, interp_ok, Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, interp_ok, throw_ub,
throw_ub, throw_ub_custom, throw_ub_custom,
}; };
use crate::enter_trace_span; use crate::enter_trace_span;
use crate::interpret::EnteredTraceSpan; use crate::interpret::EnteredTraceSpan;
@ -43,25 +43,22 @@ impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> {
FnArg::InPlace(mplace) => &mplace.layout, FnArg::InPlace(mplace) => &mplace.layout,
} }
} }
}
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the /// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
/// original memory occurs. /// original memory occurs.
pub fn copy_fn_arg(&self, arg: &FnArg<'tcx, M::Provenance>) -> OpTy<'tcx, M::Provenance> { pub fn copy_fn_arg(&self) -> OpTy<'tcx, Prov> {
match arg { match self {
FnArg::Copy(op) => op.clone(), FnArg::Copy(op) => op.clone(),
FnArg::InPlace(mplace) => mplace.clone().into(), FnArg::InPlace(mplace) => mplace.clone().into(),
} }
} }
}
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// Make a copy of the given fn_args. Any `InPlace` are degenerated to copies, no protection of the /// Make a copy of the given fn_args. Any `InPlace` are degenerated to copies, no protection of the
/// original memory occurs. /// original memory occurs.
pub fn copy_fn_args( pub fn copy_fn_args(args: &[FnArg<'tcx, M::Provenance>]) -> Vec<OpTy<'tcx, M::Provenance>> {
&self, args.iter().map(|fn_arg| fn_arg.copy_fn_arg()).collect()
args: &[FnArg<'tcx, M::Provenance>],
) -> Vec<OpTy<'tcx, M::Provenance>> {
args.iter().map(|fn_arg| self.copy_fn_arg(fn_arg)).collect()
} }
/// Helper function for argument untupling. /// Helper function for argument untupling.
@ -319,7 +316,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// We work with a copy of the argument for now; if this is in-place argument passing, we // We work with a copy of the argument for now; if this is in-place argument passing, we
// will later protect the source it comes from. This means the callee cannot observe if we // will later protect the source it comes from. This means the callee cannot observe if we
// did in-place of by-copy argument passing, except for pointer equality tests. // did in-place of by-copy argument passing, except for pointer equality tests.
let caller_arg_copy = self.copy_fn_arg(caller_arg); let caller_arg_copy = caller_arg.copy_fn_arg();
if !already_live { if !already_live {
let local = callee_arg.as_local().unwrap(); let local = callee_arg.as_local().unwrap();
let meta = caller_arg_copy.meta(); let meta = caller_arg_copy.meta();
@ -616,7 +613,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
if let Some(fallback) = M::call_intrinsic( if let Some(fallback) = M::call_intrinsic(
self, self,
instance, instance,
&self.copy_fn_args(args), &Self::copy_fn_args(args),
destination, destination,
target, target,
unwind, unwind,
@ -703,7 +700,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// An `InPlace` does nothing here, we keep the original receiver intact. We can't // An `InPlace` does nothing here, we keep the original receiver intact. We can't
// really pass the argument in-place anyway, and we are constructing a new // really pass the argument in-place anyway, and we are constructing a new
// `Immediate` receiver. // `Immediate` receiver.
let mut receiver = self.copy_fn_arg(&args[0]); let mut receiver = args[0].copy_fn_arg();
let receiver_place = loop { let receiver_place = loop {
match receiver.layout.ty.kind() { match receiver.layout.ty.kind() {
ty::Ref(..) | ty::RawPtr(..) => { ty::Ref(..) | ty::RawPtr(..) => {
@ -824,41 +821,50 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
with_caller_location: bool, with_caller_location: bool,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
trace!("init_fn_tail_call: {:#?}", fn_val); trace!("init_fn_tail_call: {:#?}", fn_val);
// This is the "canonical" implementation of tails calls, // This is the "canonical" implementation of tails calls,
// a pop of the current stack frame, followed by a normal call // a pop of the current stack frame, followed by a normal call
// which pushes a new stack frame, with the return address from // which pushes a new stack frame, with the return address from
// the popped stack frame. // the popped stack frame.
// //
// Note that we are using `pop_stack_frame_raw` and not `return_from_current_stack_frame`, // Note that we cannot use `return_from_current_stack_frame`,
// as the latter "executes" the goto to the return block, but we don't want to, // as that "executes" the goto to the return block, but we don't want to,
// only the tail called function should return to the current return block. // only the tail called function should return to the current return block.
let StackPopInfo { return_action, return_cont, return_place } =
self.pop_stack_frame_raw(false, |_this, _return_place| {
// This function's return value is just discarded, the tail-callee will fill in the return place instead.
interp_ok(())
})?;
assert_eq!(return_action, ReturnAction::Normal); // The arguments need to all be copied since the current stack frame will be removed
// before the callee even starts executing.
// Take the "stack pop cleanup" info, and use that to initiate the next call. // FIXME(explicit_tail_calls,#144855): does this match what codegen does?
let ReturnContinuation::Goto { ret, unwind } = return_cont else { let args = args.iter().map(|fn_arg| FnArg::Copy(fn_arg.copy_fn_arg())).collect::<Vec<_>>();
bug!("can't tailcall as root"); // Remove the frame from the stack.
let frame = self.pop_stack_frame_raw()?;
// Remember where this frame would have returned to.
let ReturnContinuation::Goto { ret, unwind } = frame.return_cont() else {
bug!("can't tailcall as root of the stack");
}; };
// There's no return value to deal with! Instead, we forward the old return place
// to the new function.
// FIXME(explicit_tail_calls): // FIXME(explicit_tail_calls):
// we should check if both caller&callee can/n't unwind, // we should check if both caller&callee can/n't unwind,
// see <https://github.com/rust-lang/rust/pull/113128#issuecomment-1614979803> // see <https://github.com/rust-lang/rust/pull/113128#issuecomment-1614979803>
// Now push the new stack frame.
self.init_fn_call( self.init_fn_call(
fn_val, fn_val,
(caller_abi, caller_fn_abi), (caller_abi, caller_fn_abi),
args, &*args,
with_caller_location, with_caller_location,
&return_place, frame.return_place(),
ret, ret,
unwind, unwind,
) )?;
// Finally, clear the local variables. Has to be done after pushing to support
// non-scalar arguments.
// FIXME(explicit_tail_calls,#144855): revisit this once codegen supports indirect
// arguments, to ensure the semantics are compatible.
let return_action = self.cleanup_stack_frame(/* unwinding */ false, frame)?;
assert_eq!(return_action, ReturnAction::Normal);
interp_ok(())
} }
pub(super) fn init_drop_in_place_call( pub(super) fn init_drop_in_place_call(
@ -953,14 +959,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// local's value out. // local's value out.
let return_op = let return_op =
self.local_to_op(mir::RETURN_PLACE, None).expect("return place should always be live"); self.local_to_op(mir::RETURN_PLACE, None).expect("return place should always be live");
// Do the actual pop + copy. // Remove the frame from the stack.
let stack_pop_info = self.pop_stack_frame_raw(unwinding, |this, return_place| { let frame = self.pop_stack_frame_raw()?;
this.copy_op_allow_transmute(&return_op, return_place)?; // Copy the return value and remember the return continuation.
trace!("return value: {:?}", this.dump_place(return_place)); if !unwinding {
interp_ok(()) self.copy_op_allow_transmute(&return_op, frame.return_place())?;
})?; trace!("return value: {:?}", self.dump_place(frame.return_place()));
}
match stack_pop_info.return_action { let return_cont = frame.return_cont();
// Finish popping the stack frame.
let return_action = self.cleanup_stack_frame(unwinding, frame)?;
// Jump to the next block.
match return_action {
ReturnAction::Normal => {} ReturnAction::Normal => {}
ReturnAction::NoJump => { ReturnAction::NoJump => {
// The hook already did everything. // The hook already did everything.
@ -978,7 +988,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Normal return, figure out where to jump. // Normal return, figure out where to jump.
if unwinding { if unwinding {
// Follow the unwind edge. // Follow the unwind edge.
match stack_pop_info.return_cont { match return_cont {
ReturnContinuation::Goto { unwind, .. } => { ReturnContinuation::Goto { unwind, .. } => {
// This must be the very last thing that happens, since it can in fact push a new stack frame. // This must be the very last thing that happens, since it can in fact push a new stack frame.
self.unwind_to_block(unwind) self.unwind_to_block(unwind)
@ -989,7 +999,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
} }
} else { } else {
// Follow the normal return edge. // Follow the normal return edge.
match stack_pop_info.return_cont { match return_cont {
ReturnContinuation::Goto { ret, .. } => self.return_to_block(ret), ReturnContinuation::Goto { ret, .. } => self.return_to_block(ret),
ReturnContinuation::Stop { .. } => { ReturnContinuation::Stop { .. } => {
assert!( assert!(

View file

@ -36,7 +36,7 @@ pub use self::operand::{ImmTy, Immediate, OpTy};
pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable}; pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable};
use self::place::{MemPlace, Place}; use self::place::{MemPlace, Place};
pub use self::projection::{OffsetMode, Projectable}; pub use self::projection::{OffsetMode, Projectable};
pub use self::stack::{Frame, FrameInfo, LocalState, ReturnContinuation, StackPopInfo}; pub use self::stack::{Frame, FrameInfo, LocalState, ReturnContinuation};
pub use self::util::EnteredTraceSpan; pub use self::util::EnteredTraceSpan;
pub(crate) use self::util::create_static_alloc; pub(crate) use self::util::create_static_alloc;
pub use self::validity::{CtfeValidationMode, RangeSet, RefTracking}; pub use self::validity::{CtfeValidationMode, RangeSet, RefTracking};

View file

@ -81,7 +81,7 @@ pub struct Frame<'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> {
/// and its layout in the caller. This place is to be interpreted relative to the /// and its layout in the caller. This place is to be interpreted relative to the
/// *caller's* stack frame. We use a `PlaceTy` instead of an `MPlaceTy` since this /// *caller's* stack frame. We use a `PlaceTy` instead of an `MPlaceTy` since this
/// avoids having to move *all* return places into Miri's memory. /// avoids having to move *all* return places into Miri's memory.
pub return_place: PlaceTy<'tcx, Prov>, return_place: PlaceTy<'tcx, Prov>,
/// The list of locals for this stack frame, stored in order as /// The list of locals for this stack frame, stored in order as
/// `[return_ptr, arguments..., variables..., temporaries...]`. /// `[return_ptr, arguments..., variables..., temporaries...]`.
@ -127,19 +127,6 @@ pub enum ReturnContinuation {
Stop { cleanup: bool }, Stop { cleanup: bool },
} }
/// Return type of [`InterpCx::pop_stack_frame_raw`].
pub struct StackPopInfo<'tcx, Prov: Provenance> {
/// Additional information about the action to be performed when returning from the popped
/// stack frame.
pub return_action: ReturnAction,
/// [`return_cont`](Frame::return_cont) of the popped stack frame.
pub return_cont: ReturnContinuation,
/// [`return_place`](Frame::return_place) of the popped stack frame.
pub return_place: PlaceTy<'tcx, Prov>,
}
/// State of a local variable including a memoized layout /// State of a local variable including a memoized layout
#[derive(Clone)] #[derive(Clone)]
pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> { pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
@ -292,6 +279,14 @@ impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> {
self.instance self.instance
} }
pub fn return_place(&self) -> &PlaceTy<'tcx, Prov> {
&self.return_place
}
pub fn return_cont(&self) -> ReturnContinuation {
self.return_cont
}
/// Return the `SourceInfo` of the current instruction. /// Return the `SourceInfo` of the current instruction.
pub fn current_source_info(&self) -> Option<&mir::SourceInfo> { pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
self.loc.left().map(|loc| self.body.source_info(loc)) self.loc.left().map(|loc| self.body.source_info(loc))
@ -417,35 +412,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
interp_ok(()) interp_ok(())
} }
/// Low-level helper that pops a stack frame from the stack and returns some information about /// Low-level helper that pops a stack frame from the stack without any cleanup.
/// it. /// This invokes `before_stack_pop`.
/// /// After calling this function, you need to deal with the return value, and then
/// This also deallocates locals, if necessary. /// invoke `cleanup_stack_frame`.
/// `copy_ret_val` gets called after the frame has been taken from the stack but before the locals have been deallocated.
///
/// [`M::before_stack_pop`] and [`M::after_stack_pop`] are called by this function
/// automatically.
///
/// The high-level version of this is `return_from_current_stack_frame`.
///
/// [`M::before_stack_pop`]: Machine::before_stack_pop
/// [`M::after_stack_pop`]: Machine::after_stack_pop
pub(super) fn pop_stack_frame_raw( pub(super) fn pop_stack_frame_raw(
&mut self, &mut self,
unwinding: bool, ) -> InterpResult<'tcx, Frame<'tcx, M::Provenance, M::FrameExtra>> {
copy_ret_val: impl FnOnce(&mut Self, &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx>,
) -> InterpResult<'tcx, StackPopInfo<'tcx, M::Provenance>> {
M::before_stack_pop(self)?; M::before_stack_pop(self)?;
let frame = let frame =
self.stack_mut().pop().expect("tried to pop a stack frame, but there were none"); self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
interp_ok(frame)
// Copy return value (unless we are unwinding).
if !unwinding {
copy_ret_val(self, &frame.return_place)?;
} }
/// Deallocate local variables in the stack frame, and invoke `after_stack_pop`.
pub(super) fn cleanup_stack_frame(
&mut self,
unwinding: bool,
frame: Frame<'tcx, M::Provenance, M::FrameExtra>,
) -> InterpResult<'tcx, ReturnAction> {
let return_cont = frame.return_cont; let return_cont = frame.return_cont;
let return_place = frame.return_place.clone();
// Cleanup: deallocate locals. // Cleanup: deallocate locals.
// Usually we want to clean up (deallocate locals), but in a few rare cases we don't. // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
@ -455,7 +441,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
ReturnContinuation::Stop { cleanup, .. } => cleanup, ReturnContinuation::Stop { cleanup, .. } => cleanup,
}; };
let return_action = if cleanup { if cleanup {
for local in &frame.locals { for local in &frame.locals {
self.deallocate_local(local.value)?; self.deallocate_local(local.value)?;
} }
@ -466,13 +452,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Call the machine hook, which determines the next steps. // Call the machine hook, which determines the next steps.
let return_action = M::after_stack_pop(self, frame, unwinding)?; let return_action = M::after_stack_pop(self, frame, unwinding)?;
assert_ne!(return_action, ReturnAction::NoCleanup); assert_ne!(return_action, ReturnAction::NoCleanup);
return_action interp_ok(return_action)
} else { } else {
// We also skip the machine hook when there's no cleanup. This not a real "pop" anyway. // We also skip the machine hook when there's no cleanup. This not a real "pop" anyway.
ReturnAction::NoCleanup interp_ok(ReturnAction::NoCleanup)
}; }
interp_ok(StackPopInfo { return_action, return_cont, return_place })
} }
/// In the current stack frame, mark all locals as live that are not arguments and don't have /// In the current stack frame, mark all locals as live that are not arguments and don't have
@ -655,7 +639,7 @@ impl<'a, 'tcx: 'a, M: Machine<'tcx>> InterpCx<'tcx, M> {
let (_idx, callee_abi) = callee_abis.next().unwrap(); let (_idx, callee_abi) = callee_abis.next().unwrap();
assert!(self.check_argument_compat(caller_abi, callee_abi)?); assert!(self.check_argument_compat(caller_abi, callee_abi)?);
// FIXME: do we have to worry about in-place argument passing? // FIXME: do we have to worry about in-place argument passing?
let op = self.copy_fn_arg(fn_arg); let op = fn_arg.copy_fn_arg();
let mplace = self.allocate(op.layout, MemoryKind::Stack)?; let mplace = self.allocate(op.layout, MemoryKind::Stack)?;
self.copy_op(&op, &mplace)?; self.copy_op(&op, &mplace)?;

View file

@ -249,12 +249,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.write_immediate(*val, &dest)?; self.write_immediate(*val, &dest)?;
} }
ShallowInitBox(ref operand, _) => {
let src = self.eval_operand(operand, None)?;
let v = self.read_immediate(&src)?;
self.write_immediate(*v, &dest)?;
}
Cast(cast_kind, ref operand, cast_ty) => { Cast(cast_kind, ref operand, cast_ty) => {
let src = self.eval_operand(operand, None)?; let src = self.eval_operand(operand, None)?;
let cast_ty = let cast_ty =

View file

@ -647,13 +647,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
} }
} else { } else {
// This is not CTFE, so it's Miri with recursive checking. // This is not CTFE, so it's Miri with recursive checking.
// FIXME: we do *not* check behind boxes, since creating a new box first creates it uninitialized // FIXME: should we also `UnsafeCell` behind shared references? Currently that is not
// and then puts the value in there, so briefly we have a box with uninit contents.
// FIXME: should we also skip `UnsafeCell` behind shared references? Currently that is not
// needed since validation reads bypass Stacked Borrows and data race checks. // needed since validation reads bypass Stacked Borrows and data race checks.
if matches!(ptr_kind, PointerKind::Box) {
return interp_ok(());
}
} }
let path = &self.path; let path = &self.path;
ref_tracking.track(place, || { ref_tracking.track(place, || {

View file

@ -2,12 +2,11 @@ use std::any::Any;
use std::default::Default; use std::default::Default;
use std::iter; use std::iter;
use std::path::Component::Prefix; use std::path::Component::Prefix;
use std::path::{Path, PathBuf}; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use rustc_ast::attr::MarkedAttrs; use rustc_ast::attr::MarkedAttrs;
use rustc_ast::token::MetaVarKind;
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::visit::{AssocCtxt, Visitor};
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind, Safety}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind, Safety};
@ -22,14 +21,14 @@ use rustc_hir::limit::Limit;
use rustc_hir::{Stability, find_attr}; use rustc_hir::{Stability, find_attr};
use rustc_lint_defs::RegisteredTools; use rustc_lint_defs::RegisteredTools;
use rustc_parse::MACRO_ARGUMENTS; use rustc_parse::MACRO_ARGUMENTS;
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser}; use rustc_parse::parser::Parser;
use rustc_session::Session; use rustc_session::Session;
use rustc_session::parse::ParseSess; use rustc_session::parse::ParseSess;
use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind}; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind};
use rustc_span::source_map::SourceMap; use rustc_span::source_map::SourceMap;
use rustc_span::{DUMMY_SP, FileName, Ident, Span, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw};
use smallvec::{SmallVec, smallvec}; use smallvec::{SmallVec, smallvec};
use thin_vec::ThinVec; use thin_vec::ThinVec;
@ -1421,80 +1420,3 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe
} }
} }
} }
/// If this item looks like a specific enums from `rental`, emit a fatal error.
/// See #73345 and #83125 for more details.
/// FIXME(#73933): Remove this eventually.
fn pretty_printing_compatibility_hack(item: &Item, psess: &ParseSess) {
if let ast::ItemKind::Enum(ident, _, enum_def) = &item.kind
&& ident.name == sym::ProceduralMasqueradeDummyType
&& let [variant] = &*enum_def.variants
&& variant.ident.name == sym::Input
&& let FileName::Real(real) = psess.source_map().span_to_filename(ident.span)
&& let Some(c) = real
.local_path()
.unwrap_or(Path::new(""))
.components()
.flat_map(|c| c.as_os_str().to_str())
.find(|c| c.starts_with("rental") || c.starts_with("allsorts-rental"))
{
let crate_matches = if c.starts_with("allsorts-rental") {
true
} else {
let mut version = c.trim_start_matches("rental-").split('.');
version.next() == Some("0")
&& version.next() == Some("5")
&& version.next().and_then(|c| c.parse::<u32>().ok()).is_some_and(|v| v < 6)
};
if crate_matches {
psess.dcx().emit_fatal(errors::ProcMacroBackCompat {
crate_name: "rental".to_string(),
fixed_version: "0.5.6".to_string(),
});
}
}
}
pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, psess: &ParseSess) {
let item = match ann {
Annotatable::Item(item) => item,
Annotatable::Stmt(stmt) => match &stmt.kind {
ast::StmtKind::Item(item) => item,
_ => return,
},
_ => return,
};
pretty_printing_compatibility_hack(item, psess)
}
pub(crate) fn stream_pretty_printing_compatibility_hack(
kind: MetaVarKind,
stream: &TokenStream,
psess: &ParseSess,
) {
let item = match kind {
MetaVarKind::Item => {
let mut parser = Parser::new(psess, stream.clone(), None);
// No need to collect tokens for this simple check.
parser
.parse_item(ForceCollect::No, AllowConstBlockItems::No)
.expect("failed to reparse item")
.expect("an actual item")
}
MetaVarKind::Stmt => {
let mut parser = Parser::new(psess, stream.clone(), None);
// No need to collect tokens for this simple check.
let stmt = parser
.parse_stmt(ForceCollect::No)
.expect("failed to reparse")
.expect("an actual stmt");
match &stmt.kind {
ast::StmtKind::Item(item) => item.clone(),
_ => return,
}
}
_ => return,
};
pretty_printing_compatibility_hack(&item, psess)
}

View file

@ -446,18 +446,6 @@ pub(crate) struct GlobDelegationTraitlessQpath {
pub span: Span, pub span: Span,
} }
// This used to be the `proc_macro_back_compat` lint (#83125). It was later
// turned into a hard error.
#[derive(Diagnostic)]
#[diag("using an old version of `{$crate_name}`")]
#[note(
"older versions of the `{$crate_name}` crate no longer compile; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives"
)]
pub(crate) struct ProcMacroBackCompat {
pub crate_name: String,
pub fixed_version: String,
}
pub(crate) use metavar_exprs::*; pub(crate) use metavar_exprs::*;
mod metavar_exprs { mod metavar_exprs {
use super::*; use super::*;

View file

@ -105,11 +105,6 @@ impl MultiItemModifier for DeriveProcMacro {
// (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`) // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
let is_stmt = matches!(item, Annotatable::Stmt(..)); let is_stmt = matches!(item, Annotatable::Stmt(..));
// We used to have an alternative behaviour for crates that needed it.
// We had a lint for a long time, but now we just emit a hard error.
// Eventually we might remove the special case hard error check
// altogether. See #73345.
crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess.psess);
let input = item.to_tokens(); let input = item.to_tokens();
let invoc_id = ecx.current_expansion.id; let invoc_id = ecx.current_expansion.id;

View file

@ -103,8 +103,8 @@ impl ToInternal<token::LitKind> for LitKind {
} }
} }
impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStream, Span, Symbol>> { impl FromInternal<TokenStream> for Vec<TokenTree<TokenStream, Span, Symbol>> {
fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self { fn from_internal(stream: TokenStream) -> Self {
use rustc_ast::token::*; use rustc_ast::token::*;
// Estimate the capacity as `stream.len()` rounded up to the next power // Estimate the capacity as `stream.len()` rounded up to the next power
@ -115,22 +115,6 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
while let Some(tree) = iter.next() { while let Some(tree) = iter.next() {
let (Token { kind, span }, joint) = match tree.clone() { let (Token { kind, span }, joint) = match tree.clone() {
tokenstream::TokenTree::Delimited(span, _, mut delim, mut stream) => { tokenstream::TokenTree::Delimited(span, _, mut delim, mut stream) => {
// We used to have an alternative behaviour for crates that
// needed it: a hack used to pass AST fragments to
// attribute and derive macros as a single nonterminal
// token instead of a token stream. Such token needs to be
// "unwrapped" and not represented as a delimited group. We
// had a lint for a long time, but now we just emit a hard
// error. Eventually we might remove the special case hard
// error check altogether. See #73345.
if let Delimiter::Invisible(InvisibleOrigin::MetaVar(kind)) = delim {
crate::base::stream_pretty_printing_compatibility_hack(
kind,
&stream,
rustc.psess(),
);
}
// In `mk_delimited` we avoid nesting invisible delimited // In `mk_delimited` we avoid nesting invisible delimited
// of the same `MetaVarKind`. Here we do the same but // of the same `MetaVarKind`. Here we do the same but
// ignore the `MetaVarKind` because it is discarded when we // ignore the `MetaVarKind` because it is discarded when we
@ -687,7 +671,7 @@ impl server::Server for Rustc<'_, '_> {
&mut self, &mut self,
stream: Self::TokenStream, stream: Self::TokenStream,
) -> Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> { ) -> Vec<TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> {
FromInternal::from_internal((stream, self)) FromInternal::from_internal(stream)
} }
fn span_debug(&mut self, span: Self::Span) -> String { fn span_debug(&mut self, span: Self::Span) -> String {

View file

@ -1208,7 +1208,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_intrinsic_const_stable_indirect, Normal, rustc_intrinsic_const_stable_indirect, Normal,
template!(Word), WarnFollowing, EncodeCrossCrate::No, "this is an internal implementation detail", template!(Word), WarnFollowing, EncodeCrossCrate::No, "this is an internal implementation detail",
), ),
gated!( rustc_attr!(
rustc_allow_const_fn_unstable, Normal, rustc_allow_const_fn_unstable, Normal,
template!(Word, List: &["feat1, feat2, ..."]), DuplicatesOk, EncodeCrossCrate::No, template!(Word, List: &["feat1, feat2, ..."]), DuplicatesOk, EncodeCrossCrate::No,
"rustc_allow_const_fn_unstable side-steps feature gating and stability checks" "rustc_allow_const_fn_unstable side-steps feature gating and stability checks"

View file

@ -287,10 +287,6 @@ declare_features! (
(internal, panic_runtime, "1.10.0", Some(32837)), (internal, panic_runtime, "1.10.0", Some(32837)),
/// Allows using pattern types. /// Allows using pattern types.
(internal, pattern_types, "1.79.0", Some(123646)), (internal, pattern_types, "1.79.0", Some(123646)),
/// Allows using `#[rustc_allow_const_fn_unstable]`.
/// This is an attribute on `const fn` for the same
/// purpose as `#[allow_internal_unstable]`.
(internal, rustc_allow_const_fn_unstable, "1.49.0", Some(69399)),
/// Allows using compiler's own crates. /// Allows using compiler's own crates.
(unstable, rustc_private, "1.0.0", Some(27812)), (unstable, rustc_private, "1.0.0", Some(27812)),
/// Allows using internal rustdoc features like `doc(keyword)`. /// Allows using internal rustdoc features like `doc(keyword)`.
@ -493,7 +489,7 @@ declare_features! (
/// Allows the use of `#[ffi_pure]` on foreign functions. /// Allows the use of `#[ffi_pure]` on foreign functions.
(unstable, ffi_pure, "1.45.0", Some(58329)), (unstable, ffi_pure, "1.45.0", Some(58329)),
/// Allows marking trait functions as `final` to prevent overriding impls /// Allows marking trait functions as `final` to prevent overriding impls
(unstable, final_associated_functions, "CURRENT_RUSTC_VERSION", Some(1)), (unstable, final_associated_functions, "CURRENT_RUSTC_VERSION", Some(131179)),
/// Controlling the behavior of fmt::Debug /// Controlling the behavior of fmt::Debug
(unstable, fmt_debug, "1.82.0", Some(129709)), (unstable, fmt_debug, "1.82.0", Some(129709)),
/// Allows using `#[align(...)]` on function items /// Allows using `#[align(...)]` on function items

View file

@ -322,7 +322,7 @@ impl<'tcx> CleanVisitor<'tcx> {
if let Some(def_id) = dep_node.extract_def_id(self.tcx) { if let Some(def_id) = dep_node.extract_def_id(self.tcx) {
format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id)) format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id))
} else { } else {
format!("{:?}({:?})", dep_node.kind, dep_node.hash) format!("{:?}({:?})", dep_node.kind, dep_node.key_fingerprint)
} }
} }

View file

@ -1,10 +1,10 @@
//! This module defines the [`DepNode`] type which the compiler uses to represent //! This module defines the [`DepNode`] type which the compiler uses to represent
//! nodes in the [dependency graph]. A `DepNode` consists of a [`DepKind`] (which //! nodes in the [dependency graph]. A `DepNode` consists of a [`DepKind`] (which
//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc.) //! specifies the kind of thing it represents, like a piece of HIR, MIR, etc.)
//! and a [`Fingerprint`], a 128-bit hash value, the exact meaning of which //! and a "key fingerprint", a 128-bit hash value, the exact meaning of which
//! depends on the node's `DepKind`. Together, the kind and the fingerprint //! depends on the node's `DepKind`. Together, the kind and the key fingerprint
//! fully identify a dependency node, even across multiple compilation sessions. //! fully identify a dependency node, even across multiple compilation sessions.
//! In other words, the value of the fingerprint does not depend on anything //! In other words, the value of the key fingerprint does not depend on anything
//! that is specific to a given compilation session, like an unpredictable //! that is specific to a given compilation session, like an unpredictable
//! interning key (e.g., `NodeId`, `DefId`, `Symbol`) or the numeric value of a //! interning key (e.g., `NodeId`, `DefId`, `Symbol`) or the numeric value of a
//! pointer. The concept behind this could be compared to how git commit hashes //! pointer. The concept behind this could be compared to how git commit hashes
@ -41,17 +41,9 @@
//! `DepNode`s could represent global concepts with only one value. //! `DepNode`s could represent global concepts with only one value.
//! * Whether it is possible, in principle, to reconstruct a query key from a //! * Whether it is possible, in principle, to reconstruct a query key from a
//! given `DepNode`. Many `DepKind`s only require a single `DefId` parameter, //! given `DepNode`. Many `DepKind`s only require a single `DefId` parameter,
//! in which case it is possible to map the node's fingerprint back to the //! in which case it is possible to map the node's key fingerprint back to the
//! `DefId` it was computed from. In other cases, too much information gets //! `DefId` it was computed from. In other cases, too much information gets
//! lost during fingerprint computation. //! lost when computing a key fingerprint.
//!
//! `make_compile_codegen_unit` and `make_compile_mono_items`, together with
//! `DepNode::new()`, ensure that only valid `DepNode` instances can be
//! constructed. For example, the API does not allow for constructing
//! parameterless `DepNode`s with anything other than a zeroed out fingerprint.
//! More generally speaking, it relieves the user of the `DepNode` API of
//! having to know how to compute the expected fingerprint for a given set of
//! node parameters.
//! //!
//! [dependency graph]: https://rustc-dev-guide.rust-lang.org/query.html //! [dependency graph]: https://rustc-dev-guide.rust-lang.org/query.html
@ -65,7 +57,7 @@ use rustc_hir::definitions::DefPathHash;
use rustc_macros::{Decodable, Encodable}; use rustc_macros::{Decodable, Encodable};
use rustc_span::Symbol; use rustc_span::Symbol;
use super::{FingerprintStyle, SerializedDepNodeIndex}; use super::{KeyFingerprintStyle, SerializedDepNodeIndex};
use crate::ich::StableHashingContext; use crate::ich::StableHashingContext;
use crate::mir::mono::MonoItem; use crate::mir::mono::MonoItem;
use crate::ty::{TyCtxt, tls}; use crate::ty::{TyCtxt, tls};
@ -125,10 +117,20 @@ impl fmt::Debug for DepKind {
} }
} }
/// Combination of a [`DepKind`] and a key fingerprint that uniquely identifies
/// a node in the dep graph.
#[derive(Clone, Copy, PartialEq, Eq, Hash)] #[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct DepNode { pub struct DepNode {
pub kind: DepKind, pub kind: DepKind,
pub hash: PackedFingerprint,
/// This is _typically_ a hash of the query key, but sometimes not.
///
/// For example, `anon` nodes have a fingerprint that is derived from their
/// dependencies instead of a key.
///
/// In some cases the key value can be reconstructed from this fingerprint;
/// see [`KeyFingerprintStyle`].
pub key_fingerprint: PackedFingerprint,
} }
impl DepNode { impl DepNode {
@ -136,24 +138,23 @@ impl DepNode {
/// that the DepNode corresponding to the given DepKind actually /// that the DepNode corresponding to the given DepKind actually
/// does not require any parameters. /// does not require any parameters.
pub fn new_no_params<'tcx>(tcx: TyCtxt<'tcx>, kind: DepKind) -> DepNode { pub fn new_no_params<'tcx>(tcx: TyCtxt<'tcx>, kind: DepKind) -> DepNode {
debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit); debug_assert_eq!(tcx.key_fingerprint_style(kind), KeyFingerprintStyle::Unit);
DepNode { kind, hash: Fingerprint::ZERO.into() } DepNode { kind, key_fingerprint: Fingerprint::ZERO.into() }
} }
pub fn construct<'tcx, Key>(tcx: TyCtxt<'tcx>, kind: DepKind, arg: &Key) -> DepNode pub fn construct<'tcx, Key>(tcx: TyCtxt<'tcx>, kind: DepKind, key: &Key) -> DepNode
where where
Key: DepNodeKey<'tcx>, Key: DepNodeKey<'tcx>,
{ {
let hash = arg.to_fingerprint(tcx); let dep_node = DepNode { kind, key_fingerprint: key.to_fingerprint(tcx).into() };
let dep_node = DepNode { kind, hash: hash.into() };
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
if !tcx.fingerprint_style(kind).reconstructible() if !tcx.key_fingerprint_style(kind).reconstructible()
&& (tcx.sess.opts.unstable_opts.incremental_info && (tcx.sess.opts.unstable_opts.incremental_info
|| tcx.sess.opts.unstable_opts.query_dep_graph) || tcx.sess.opts.unstable_opts.query_dep_graph)
{ {
tcx.dep_graph.register_dep_node_debug_str(dep_node, || arg.to_debug_str(tcx)); tcx.dep_graph.register_dep_node_debug_str(dep_node, || key.to_debug_str(tcx));
} }
} }
@ -168,8 +169,8 @@ impl DepNode {
def_path_hash: DefPathHash, def_path_hash: DefPathHash,
kind: DepKind, kind: DepKind,
) -> Self { ) -> Self {
debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash); debug_assert!(tcx.key_fingerprint_style(kind) == KeyFingerprintStyle::DefPathHash);
DepNode { kind, hash: def_path_hash.0.into() } DepNode { kind, key_fingerprint: def_path_hash.0.into() }
} }
} }
@ -184,10 +185,10 @@ impl fmt::Debug for DepNode {
} else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) { } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) {
write!(f, "{s}")?; write!(f, "{s}")?;
} else { } else {
write!(f, "{}", self.hash)?; write!(f, "{}", self.key_fingerprint)?;
} }
} else { } else {
write!(f, "{}", self.hash)?; write!(f, "{}", self.key_fingerprint)?;
} }
Ok(()) Ok(())
})?; })?;
@ -198,7 +199,7 @@ impl fmt::Debug for DepNode {
/// Trait for query keys as seen by dependency-node tracking. /// Trait for query keys as seen by dependency-node tracking.
pub trait DepNodeKey<'tcx>: fmt::Debug + Sized { pub trait DepNodeKey<'tcx>: fmt::Debug + Sized {
fn fingerprint_style() -> FingerprintStyle; fn key_fingerprint_style() -> KeyFingerprintStyle;
/// This method turns a query key into an opaque `Fingerprint` to be used /// This method turns a query key into an opaque `Fingerprint` to be used
/// in `DepNode`. /// in `DepNode`.
@ -212,7 +213,7 @@ pub trait DepNodeKey<'tcx>: fmt::Debug + Sized {
/// `fingerprint_style()` is not `FingerprintStyle::Opaque`. /// `fingerprint_style()` is not `FingerprintStyle::Opaque`.
/// It is always valid to return `None` here, in which case incremental /// It is always valid to return `None` here, in which case incremental
/// compilation will treat the query as having changed instead of forcing it. /// compilation will treat the query as having changed instead of forcing it.
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>; fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self>;
} }
// Blanket impl of `DepNodeKey`, which is specialized by other impls elsewhere. // Blanket impl of `DepNodeKey`, which is specialized by other impls elsewhere.
@ -221,8 +222,8 @@ where
T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug, T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
{ {
#[inline(always)] #[inline(always)]
default fn fingerprint_style() -> FingerprintStyle { default fn key_fingerprint_style() -> KeyFingerprintStyle {
FingerprintStyle::Opaque KeyFingerprintStyle::Opaque
} }
#[inline(always)] #[inline(always)]
@ -243,7 +244,7 @@ where
} }
#[inline(always)] #[inline(always)]
default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> { default fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
None None
} }
} }
@ -264,10 +265,11 @@ pub struct DepKindVTable<'tcx> {
/// cached within one compiler invocation. /// cached within one compiler invocation.
pub is_eval_always: bool, pub is_eval_always: bool,
/// Indicates whether and how the query key can be recovered from its hashed fingerprint. /// Indicates whether and how a query key can be reconstructed from the
/// key fingerprint of a dep node with this [`DepKind`].
/// ///
/// The [`DepNodeKey`] trait determines the fingerprint style for each key type. /// The [`DepNodeKey`] trait determines the fingerprint style for each key type.
pub fingerprint_style: FingerprintStyle, pub key_fingerprint_style: KeyFingerprintStyle,
/// The red/green evaluation system will try to mark a specific DepNode in the /// The red/green evaluation system will try to mark a specific DepNode in the
/// dependency graph as green by recursively trying to mark the dependencies of /// dependency graph as green by recursively trying to mark the dependencies of
@ -279,7 +281,7 @@ pub struct DepKindVTable<'tcx> {
/// `force_from_dep_node()` implements. /// `force_from_dep_node()` implements.
/// ///
/// In the general case, a `DepNode` consists of a `DepKind` and an opaque /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint /// "key fingerprint" that will uniquely identify the node. This key fingerprint
/// is usually constructed by computing a stable hash of the query-key that the /// is usually constructed by computing a stable hash of the query-key that the
/// `DepNode` corresponds to. Consequently, it is not in general possible to go /// `DepNode` corresponds to. Consequently, it is not in general possible to go
/// back from hash to query-key (since hash functions are not reversible). For /// back from hash to query-key (since hash functions are not reversible). For
@ -293,7 +295,7 @@ pub struct DepKindVTable<'tcx> {
/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
/// Fortunately, we can use some contextual information that will allow us to /// Fortunately, we can use some contextual information that will allow us to
/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a /// enforce by construction that the key fingerprint of certain `DepNode`s is a
/// valid `DefPathHash`. Since we also always build a huge table that maps every /// valid `DefPathHash`. Since we also always build a huge table that maps every
/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
/// everything we need to re-run the query. /// everything we need to re-run the query.
@ -301,7 +303,7 @@ pub struct DepKindVTable<'tcx> {
/// Take the `mir_promoted` query as an example. Like many other queries, it /// Take the `mir_promoted` query as an example. Like many other queries, it
/// just has a single parameter: the `DefId` of the item it will compute the /// just has a single parameter: the `DefId` of the item it will compute the
/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` /// with kind `mir_promoted`, we know that the key fingerprint of the `DepNode`
/// is actually a `DefPathHash`, and can therefore just look up the corresponding /// is actually a `DefPathHash`, and can therefore just look up the corresponding
/// `DefId` in `tcx.def_path_hash_to_def_id`. /// `DefId` in `tcx.def_path_hash_to_def_id`.
pub force_from_dep_node: Option< pub force_from_dep_node: Option<
@ -472,8 +474,8 @@ impl DepNode {
/// refers to something from the previous compilation session that /// refers to something from the previous compilation session that
/// has been removed. /// has been removed.
pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> { pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash { if tcx.key_fingerprint_style(self.kind) == KeyFingerprintStyle::DefPathHash {
tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into())) tcx.def_path_hash_to_def_id(DefPathHash(self.key_fingerprint.into()))
} else { } else {
None None
} }
@ -486,10 +488,10 @@ impl DepNode {
) -> Result<DepNode, ()> { ) -> Result<DepNode, ()> {
let kind = dep_kind_from_label_string(label)?; let kind = dep_kind_from_label_string(label)?;
match tcx.fingerprint_style(kind) { match tcx.key_fingerprint_style(kind) {
FingerprintStyle::Opaque | FingerprintStyle::HirId => Err(()), KeyFingerprintStyle::Opaque | KeyFingerprintStyle::HirId => Err(()),
FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)), KeyFingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
FingerprintStyle::DefPathHash => { KeyFingerprintStyle::DefPathHash => {
Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind)) Ok(DepNode::from_def_path_hash(tcx, def_path_hash, kind))
} }
} }

View file

@ -3,13 +3,13 @@ use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId,
use rustc_hir::definitions::DefPathHash; use rustc_hir::definitions::DefPathHash;
use rustc_hir::{HirId, ItemLocalId, OwnerId}; use rustc_hir::{HirId, ItemLocalId, OwnerId};
use crate::dep_graph::{DepNode, DepNodeKey, FingerprintStyle}; use crate::dep_graph::{DepNode, DepNodeKey, KeyFingerprintStyle};
use crate::ty::TyCtxt; use crate::ty::TyCtxt;
impl<'tcx> DepNodeKey<'tcx> for () { impl<'tcx> DepNodeKey<'tcx> for () {
#[inline(always)] #[inline(always)]
fn fingerprint_style() -> FingerprintStyle { fn key_fingerprint_style() -> KeyFingerprintStyle {
FingerprintStyle::Unit KeyFingerprintStyle::Unit
} }
#[inline(always)] #[inline(always)]
@ -18,15 +18,15 @@ impl<'tcx> DepNodeKey<'tcx> for () {
} }
#[inline(always)] #[inline(always)]
fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> { fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
Some(()) Some(())
} }
} }
impl<'tcx> DepNodeKey<'tcx> for DefId { impl<'tcx> DepNodeKey<'tcx> for DefId {
#[inline(always)] #[inline(always)]
fn fingerprint_style() -> FingerprintStyle { fn key_fingerprint_style() -> KeyFingerprintStyle {
FingerprintStyle::DefPathHash KeyFingerprintStyle::DefPathHash
} }
#[inline(always)] #[inline(always)]
@ -40,15 +40,15 @@ impl<'tcx> DepNodeKey<'tcx> for DefId {
} }
#[inline(always)] #[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx) dep_node.extract_def_id(tcx)
} }
} }
impl<'tcx> DepNodeKey<'tcx> for LocalDefId { impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
#[inline(always)] #[inline(always)]
fn fingerprint_style() -> FingerprintStyle { fn key_fingerprint_style() -> KeyFingerprintStyle {
FingerprintStyle::DefPathHash KeyFingerprintStyle::DefPathHash
} }
#[inline(always)] #[inline(always)]
@ -62,15 +62,15 @@ impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
} }
#[inline(always)] #[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| id.expect_local()) dep_node.extract_def_id(tcx).map(|id| id.expect_local())
} }
} }
impl<'tcx> DepNodeKey<'tcx> for OwnerId { impl<'tcx> DepNodeKey<'tcx> for OwnerId {
#[inline(always)] #[inline(always)]
fn fingerprint_style() -> FingerprintStyle { fn key_fingerprint_style() -> KeyFingerprintStyle {
FingerprintStyle::DefPathHash KeyFingerprintStyle::DefPathHash
} }
#[inline(always)] #[inline(always)]
@ -84,15 +84,15 @@ impl<'tcx> DepNodeKey<'tcx> for OwnerId {
} }
#[inline(always)] #[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| OwnerId { def_id: id.expect_local() }) dep_node.extract_def_id(tcx).map(|id| OwnerId { def_id: id.expect_local() })
} }
} }
impl<'tcx> DepNodeKey<'tcx> for CrateNum { impl<'tcx> DepNodeKey<'tcx> for CrateNum {
#[inline(always)] #[inline(always)]
fn fingerprint_style() -> FingerprintStyle { fn key_fingerprint_style() -> KeyFingerprintStyle {
FingerprintStyle::DefPathHash KeyFingerprintStyle::DefPathHash
} }
#[inline(always)] #[inline(always)]
@ -107,15 +107,15 @@ impl<'tcx> DepNodeKey<'tcx> for CrateNum {
} }
#[inline(always)] #[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
dep_node.extract_def_id(tcx).map(|id| id.krate) dep_node.extract_def_id(tcx).map(|id| id.krate)
} }
} }
impl<'tcx> DepNodeKey<'tcx> for (DefId, DefId) { impl<'tcx> DepNodeKey<'tcx> for (DefId, DefId) {
#[inline(always)] #[inline(always)]
fn fingerprint_style() -> FingerprintStyle { fn key_fingerprint_style() -> KeyFingerprintStyle {
FingerprintStyle::Opaque KeyFingerprintStyle::Opaque
} }
// We actually would not need to specialize the implementation of this // We actually would not need to specialize the implementation of this
@ -141,8 +141,8 @@ impl<'tcx> DepNodeKey<'tcx> for (DefId, DefId) {
impl<'tcx> DepNodeKey<'tcx> for HirId { impl<'tcx> DepNodeKey<'tcx> for HirId {
#[inline(always)] #[inline(always)]
fn fingerprint_style() -> FingerprintStyle { fn key_fingerprint_style() -> KeyFingerprintStyle {
FingerprintStyle::HirId KeyFingerprintStyle::HirId
} }
// We actually would not need to specialize the implementation of this // We actually would not need to specialize the implementation of this
@ -166,9 +166,9 @@ impl<'tcx> DepNodeKey<'tcx> for HirId {
} }
#[inline(always)] #[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
if tcx.fingerprint_style(dep_node.kind) == FingerprintStyle::HirId { if tcx.key_fingerprint_style(dep_node.kind) == KeyFingerprintStyle::HirId {
let (local_hash, local_id) = Fingerprint::from(dep_node.hash).split(); let (local_hash, local_id) = Fingerprint::from(dep_node.key_fingerprint).split();
let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash); let def_path_hash = DefPathHash::new(tcx.stable_crate_id(LOCAL_CRATE), local_hash);
let def_id = tcx.def_path_hash_to_def_id(def_path_hash)?.expect_local(); let def_id = tcx.def_path_hash_to_def_id(def_path_hash)?.expect_local();
let local_id = local_id let local_id = local_id
@ -184,8 +184,8 @@ impl<'tcx> DepNodeKey<'tcx> for HirId {
impl<'tcx> DepNodeKey<'tcx> for ModDefId { impl<'tcx> DepNodeKey<'tcx> for ModDefId {
#[inline(always)] #[inline(always)]
fn fingerprint_style() -> FingerprintStyle { fn key_fingerprint_style() -> KeyFingerprintStyle {
FingerprintStyle::DefPathHash KeyFingerprintStyle::DefPathHash
} }
#[inline(always)] #[inline(always)]
@ -199,15 +199,15 @@ impl<'tcx> DepNodeKey<'tcx> for ModDefId {
} }
#[inline(always)] #[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
DefId::recover(tcx, dep_node).map(ModDefId::new_unchecked) DefId::try_recover_key(tcx, dep_node).map(ModDefId::new_unchecked)
} }
} }
impl<'tcx> DepNodeKey<'tcx> for LocalModDefId { impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
#[inline(always)] #[inline(always)]
fn fingerprint_style() -> FingerprintStyle { fn key_fingerprint_style() -> KeyFingerprintStyle {
FingerprintStyle::DefPathHash KeyFingerprintStyle::DefPathHash
} }
#[inline(always)] #[inline(always)]
@ -221,7 +221,7 @@ impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
} }
#[inline(always)] #[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> { fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
LocalDefId::recover(tcx, dep_node).map(LocalModDefId::new_unchecked) LocalDefId::try_recover_key(tcx, dep_node).map(LocalModDefId::new_unchecked)
} }
} }

View file

@ -142,15 +142,17 @@ impl DepGraph {
// Instantiate a node with zero dependencies only once for anonymous queries. // Instantiate a node with zero dependencies only once for anonymous queries.
let _green_node_index = current.alloc_new_node( let _green_node_index = current.alloc_new_node(
DepNode { kind: DepKind::ANON_ZERO_DEPS, hash: current.anon_id_seed.into() }, DepNode { kind: DepKind::ANON_ZERO_DEPS, key_fingerprint: current.anon_id_seed.into() },
EdgesVec::new(), EdgesVec::new(),
Fingerprint::ZERO, Fingerprint::ZERO,
); );
assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_ZERO_DEPS_ANON_NODE); assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_ZERO_DEPS_ANON_NODE);
// Instantiate a dependy-less red node only once for anonymous queries. // Create a single always-red node, with no dependencies of its own.
// Other nodes can use the always-red node as a fake dependency, to
// ensure that their dependency list will never be all-green.
let red_node_index = current.alloc_new_node( let red_node_index = current.alloc_new_node(
DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() }, DepNode { kind: DepKind::RED, key_fingerprint: Fingerprint::ZERO.into() },
EdgesVec::new(), EdgesVec::new(),
Fingerprint::ZERO, Fingerprint::ZERO,
); );
@ -418,7 +420,7 @@ impl DepGraphData {
// Fingerprint::combine() is faster than sending Fingerprint // Fingerprint::combine() is faster than sending Fingerprint
// through the StableHasher (at least as long as StableHasher // through the StableHasher (at least as long as StableHasher
// is so slow). // is so slow).
hash: self.current.anon_id_seed.combine(hasher.finish()).into(), key_fingerprint: self.current.anon_id_seed.combine(hasher.finish()).into(),
}; };
// The DepNodes generated by the process above are not unique. 2 queries could // The DepNodes generated by the process above are not unique. 2 queries could
@ -585,7 +587,7 @@ impl DepGraph {
data.current.record_edge( data.current.record_edge(
dep_node_index, dep_node_index,
node, node,
data.prev_fingerprint_of(prev_index), data.prev_value_fingerprint_of(prev_index),
); );
} }
@ -658,8 +660,8 @@ impl DepGraphData {
} }
#[inline] #[inline]
pub fn prev_fingerprint_of(&self, prev_index: SerializedDepNodeIndex) -> Fingerprint { pub fn prev_value_fingerprint_of(&self, prev_index: SerializedDepNodeIndex) -> Fingerprint {
self.previous.fingerprint_by_index(prev_index) self.previous.value_fingerprint_for_index(prev_index)
} }
#[inline] #[inline]
@ -679,7 +681,7 @@ impl DepGraphData {
let dep_node_index = self.current.encoder.send_new( let dep_node_index = self.current.encoder.send_new(
DepNode { DepNode {
kind: DepKind::SIDE_EFFECT, kind: DepKind::SIDE_EFFECT,
hash: PackedFingerprint::from(Fingerprint::ZERO), key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO),
}, },
Fingerprint::ZERO, Fingerprint::ZERO,
// We want the side effect node to always be red so it will be forced and emit the // We want the side effect node to always be red so it will be forced and emit the
@ -712,7 +714,7 @@ impl DepGraphData {
&self.colors, &self.colors,
DepNode { DepNode {
kind: DepKind::SIDE_EFFECT, kind: DepKind::SIDE_EFFECT,
hash: PackedFingerprint::from(Fingerprint::ZERO), key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO),
}, },
Fingerprint::ZERO, Fingerprint::ZERO,
std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(), std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(),
@ -727,12 +729,12 @@ impl DepGraphData {
&self, &self,
key: DepNode, key: DepNode,
edges: EdgesVec, edges: EdgesVec,
fingerprint: Option<Fingerprint>, value_fingerprint: Option<Fingerprint>,
) -> DepNodeIndex { ) -> DepNodeIndex {
if let Some(prev_index) = self.previous.node_to_index_opt(&key) { if let Some(prev_index) = self.previous.node_to_index_opt(&key) {
// Determine the color and index of the new `DepNode`. // Determine the color and index of the new `DepNode`.
let is_green = if let Some(fingerprint) = fingerprint { let is_green = if let Some(value_fingerprint) = value_fingerprint {
if fingerprint == self.previous.fingerprint_by_index(prev_index) { if value_fingerprint == self.previous.value_fingerprint_for_index(prev_index) {
// This is a green node: it existed in the previous compilation, // This is a green node: it existed in the previous compilation,
// its query was re-executed, and it has the same result as before. // its query was re-executed, and it has the same result as before.
true true
@ -749,22 +751,22 @@ impl DepGraphData {
false false
}; };
let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO); let value_fingerprint = value_fingerprint.unwrap_or(Fingerprint::ZERO);
let dep_node_index = self.current.encoder.send_and_color( let dep_node_index = self.current.encoder.send_and_color(
prev_index, prev_index,
&self.colors, &self.colors,
key, key,
fingerprint, value_fingerprint,
edges, edges,
is_green, is_green,
); );
self.current.record_node(dep_node_index, key, fingerprint); self.current.record_node(dep_node_index, key, value_fingerprint);
dep_node_index dep_node_index
} else { } else {
self.current.alloc_new_node(key, edges, fingerprint.unwrap_or(Fingerprint::ZERO)) self.current.alloc_new_node(key, edges, value_fingerprint.unwrap_or(Fingerprint::ZERO))
} }
} }
@ -781,7 +783,7 @@ impl DepGraphData {
self.current.record_edge( self.current.record_edge(
dep_node_index, dep_node_index,
*self.previous.index_to_node(prev_index), *self.previous.index_to_node(prev_index),
self.previous.fingerprint_by_index(prev_index), self.previous.value_fingerprint_for_index(prev_index),
); );
} }
@ -925,7 +927,7 @@ impl DepGraphData {
if !tcx.is_eval_always(dep_dep_node.kind) { if !tcx.is_eval_always(dep_dep_node.kind) {
debug!( debug!(
"state of dependency {:?} ({}) is unknown, trying to mark it green", "state of dependency {:?} ({}) is unknown, trying to mark it green",
dep_dep_node, dep_dep_node.hash, dep_dep_node, dep_dep_node.key_fingerprint,
); );
let node_index = self.try_mark_previous_green(tcx, parent_dep_node_index, Some(frame)); let node_index = self.try_mark_previous_green(tcx, parent_dep_node_index, Some(frame));
@ -1154,10 +1156,10 @@ pub(super) struct CurrentDepGraph {
encoder: GraphEncoder, encoder: GraphEncoder,
anon_node_to_index: ShardedHashMap<DepNode, DepNodeIndex>, anon_node_to_index: ShardedHashMap<DepNode, DepNodeIndex>,
/// This is used to verify that fingerprints do not change between the creation of a node /// This is used to verify that value fingerprints do not change between the
/// and its recomputation. /// creation of a node and its recomputation.
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
fingerprints: Lock<IndexVec<DepNodeIndex, Option<Fingerprint>>>, value_fingerprints: Lock<IndexVec<DepNodeIndex, Option<Fingerprint>>>,
/// Used to trap when a specific edge is added to the graph. /// Used to trap when a specific edge is added to the graph.
/// This is used for debug purposes and is only active with `debug_assertions`. /// This is used for debug purposes and is only active with `debug_assertions`.
@ -1224,7 +1226,7 @@ impl CurrentDepGraph {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
forbidden_edge, forbidden_edge,
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)), value_fingerprints: Lock::new(IndexVec::from_elem_n(None, new_node_count_estimate)),
nodes_in_current_session: new_node_dbg.then(|| { nodes_in_current_session: new_node_dbg.then(|| {
Lock::new(FxHashMap::with_capacity_and_hasher( Lock::new(FxHashMap::with_capacity_and_hasher(
new_node_count_estimate, new_node_count_estimate,
@ -1237,12 +1239,20 @@ impl CurrentDepGraph {
} }
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode, fingerprint: Fingerprint) { fn record_edge(
&self,
dep_node_index: DepNodeIndex,
key: DepNode,
value_fingerprint: Fingerprint,
) {
if let Some(forbidden_edge) = &self.forbidden_edge { if let Some(forbidden_edge) = &self.forbidden_edge {
forbidden_edge.index_to_node.lock().insert(dep_node_index, key); forbidden_edge.index_to_node.lock().insert(dep_node_index, key);
} }
let previous = *self.fingerprints.lock().get_or_insert_with(dep_node_index, || fingerprint); let prior_value_fingerprint = *self
assert_eq!(previous, fingerprint, "Unstable fingerprints for {:?}", key); .value_fingerprints
.lock()
.get_or_insert_with(dep_node_index, || value_fingerprint);
assert_eq!(prior_value_fingerprint, value_fingerprint, "Unstable fingerprints for {key:?}");
} }
#[inline(always)] #[inline(always)]
@ -1250,10 +1260,10 @@ impl CurrentDepGraph {
&self, &self,
dep_node_index: DepNodeIndex, dep_node_index: DepNodeIndex,
key: DepNode, key: DepNode,
_current_fingerprint: Fingerprint, _value_fingerprint: Fingerprint,
) { ) {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
self.record_edge(dep_node_index, key, _current_fingerprint); self.record_edge(dep_node_index, key, _value_fingerprint);
if let Some(ref nodes_in_current_session) = self.nodes_in_current_session { if let Some(ref nodes_in_current_session) = self.nodes_in_current_session {
outline(|| { outline(|| {
@ -1271,11 +1281,11 @@ impl CurrentDepGraph {
&self, &self,
key: DepNode, key: DepNode,
edges: EdgesVec, edges: EdgesVec,
current_fingerprint: Fingerprint, value_fingerprint: Fingerprint,
) -> DepNodeIndex { ) -> DepNodeIndex {
let dep_node_index = self.encoder.send_new(key, current_fingerprint, edges); let dep_node_index = self.encoder.send_new(key, value_fingerprint, edges);
self.record_node(dep_node_index, key, current_fingerprint); self.record_node(dep_node_index, key, value_fingerprint);
dep_node_index dep_node_index
} }

View file

@ -30,7 +30,7 @@ mod serialized;
/// This is mainly for determining whether and how we can reconstruct a key /// This is mainly for determining whether and how we can reconstruct a key
/// from the fingerprint. /// from the fingerprint.
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum FingerprintStyle { pub enum KeyFingerprintStyle {
/// The fingerprint is actually a DefPathHash. /// The fingerprint is actually a DefPathHash.
DefPathHash, DefPathHash,
/// The fingerprint is actually a HirId. /// The fingerprint is actually a HirId.
@ -41,14 +41,14 @@ pub enum FingerprintStyle {
Opaque, Opaque,
} }
impl FingerprintStyle { impl KeyFingerprintStyle {
#[inline] #[inline]
pub const fn reconstructible(self) -> bool { pub const fn reconstructible(self) -> bool {
match self { match self {
FingerprintStyle::DefPathHash | FingerprintStyle::Unit | FingerprintStyle::HirId => { KeyFingerprintStyle::DefPathHash
true | KeyFingerprintStyle::Unit
} | KeyFingerprintStyle::HirId => true,
FingerprintStyle::Opaque => false, KeyFingerprintStyle::Opaque => false,
} }
} }
} }
@ -86,8 +86,8 @@ impl<'tcx> TyCtxt<'tcx> {
} }
#[inline(always)] #[inline(always)]
pub fn fingerprint_style(self, kind: DepKind) -> FingerprintStyle { pub fn key_fingerprint_style(self, kind: DepKind) -> KeyFingerprintStyle {
self.dep_kind_vtable(kind).fingerprint_style self.dep_kind_vtable(kind).key_fingerprint_style
} }
/// Try to force a dep node to execute and see if it's green. /// Try to force a dep node to execute and see if it's green.

View file

@ -90,9 +90,13 @@ const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2;
pub struct SerializedDepGraph { pub struct SerializedDepGraph {
/// The set of all DepNodes in the graph /// The set of all DepNodes in the graph
nodes: IndexVec<SerializedDepNodeIndex, DepNode>, nodes: IndexVec<SerializedDepNodeIndex, DepNode>,
/// The set of all Fingerprints in the graph. Each Fingerprint corresponds to /// A value fingerprint associated with each [`DepNode`] in [`Self::nodes`],
/// the DepNode at the same index in the nodes vector. /// typically a hash of the value returned by the node's query in the
fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>, /// previous incremental-compilation session.
///
/// Some nodes don't have a meaningful value hash (e.g. queries with `no_hash`),
/// so they store a dummy value here instead (e.g. [`Fingerprint::ZERO`]).
value_fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
/// For each DepNode, stores the list of edges originating from that /// For each DepNode, stores the list of edges originating from that
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data, /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
/// which holds the actual DepNodeIndices of the target nodes. /// which holds the actual DepNodeIndices of the target nodes.
@ -100,8 +104,8 @@ pub struct SerializedDepGraph {
/// A flattened list of all edge targets in the graph, stored in the same /// A flattened list of all edge targets in the graph, stored in the same
/// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices. /// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices.
edge_list_data: Vec<u8>, edge_list_data: Vec<u8>,
/// Stores a map from fingerprints to nodes per dep node kind. /// For each dep kind, stores a map from key fingerprints back to the index
/// This is the reciprocal of `nodes`. /// of the corresponding node. This is the inverse of `nodes`.
index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>, index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>,
/// The number of previous compilation sessions. This is used to generate /// The number of previous compilation sessions. This is used to generate
/// unique anon dep nodes per session. /// unique anon dep nodes per session.
@ -138,12 +142,15 @@ impl SerializedDepGraph {
#[inline] #[inline]
pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> { pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option<SerializedDepNodeIndex> {
self.index.get(dep_node.kind.as_usize())?.get(&dep_node.hash).cloned() self.index.get(dep_node.kind.as_usize())?.get(&dep_node.key_fingerprint).copied()
} }
#[inline] #[inline]
pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint { pub fn value_fingerprint_for_index(
self.fingerprints[dep_node_index] &self,
dep_node_index: SerializedDepNodeIndex,
) -> Fingerprint {
self.value_fingerprints[dep_node_index]
} }
#[inline] #[inline]
@ -212,10 +219,13 @@ impl SerializedDepGraph {
let graph_bytes = d.len() - (3 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position(); let graph_bytes = d.len() - (3 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position();
let mut nodes = IndexVec::from_elem_n( let mut nodes = IndexVec::from_elem_n(
DepNode { kind: DepKind::NULL, hash: PackedFingerprint::from(Fingerprint::ZERO) }, DepNode {
kind: DepKind::NULL,
key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO),
},
node_max, node_max,
); );
let mut fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, node_max); let mut value_fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, node_max);
let mut edge_list_indices = let mut edge_list_indices =
IndexVec::from_elem_n(EdgeHeader { repr: 0, num_edges: 0 }, node_max); IndexVec::from_elem_n(EdgeHeader { repr: 0, num_edges: 0 }, node_max);
@ -243,7 +253,7 @@ impl SerializedDepGraph {
assert!(node_header.node().kind != DepKind::NULL && node.kind == DepKind::NULL); assert!(node_header.node().kind != DepKind::NULL && node.kind == DepKind::NULL);
*node = node_header.node(); *node = node_header.node();
fingerprints[index] = node_header.fingerprint(); value_fingerprints[index] = node_header.value_fingerprint();
// If the length of this node's edge list is small, the length is stored in the header. // If the length of this node's edge list is small, the length is stored in the header.
// If it is not, we fall back to another decoder call. // If it is not, we fall back to another decoder call.
@ -275,7 +285,7 @@ impl SerializedDepGraph {
let session_count = d.read_u64(); let session_count = d.read_u64();
for (idx, node) in nodes.iter_enumerated() { for (idx, node) in nodes.iter_enumerated() {
if index[node.kind.as_usize()].insert(node.hash, idx).is_some() { if index[node.kind.as_usize()].insert(node.key_fingerprint, idx).is_some() {
// Empty nodes and side effect nodes can have duplicates // Empty nodes and side effect nodes can have duplicates
if node.kind != DepKind::NULL && node.kind != DepKind::SIDE_EFFECT { if node.kind != DepKind::NULL && node.kind != DepKind::SIDE_EFFECT {
let name = node.kind.name(); let name = node.kind.name();
@ -291,7 +301,7 @@ impl SerializedDepGraph {
Arc::new(SerializedDepGraph { Arc::new(SerializedDepGraph {
nodes, nodes,
fingerprints, value_fingerprints,
edge_list_indices, edge_list_indices,
edge_list_data, edge_list_data,
index, index,
@ -303,8 +313,8 @@ impl SerializedDepGraph {
/// A packed representation of all the fixed-size fields in a `NodeInfo`. /// A packed representation of all the fixed-size fields in a `NodeInfo`.
/// ///
/// This stores in one byte array: /// This stores in one byte array:
/// * The `Fingerprint` in the `NodeInfo` /// * The value `Fingerprint` in the `NodeInfo`
/// * The `Fingerprint` in `DepNode` that is in this `NodeInfo` /// * The key `Fingerprint` in `DepNode` that is in this `NodeInfo`
/// * The `DepKind`'s discriminant (a u16, but not all bits are used...) /// * The `DepKind`'s discriminant (a u16, but not all bits are used...)
/// * The byte width of the encoded edges for this node /// * The byte width of the encoded edges for this node
/// * In whatever bits remain, the length of the edge list for this node, if it fits /// * In whatever bits remain, the length of the edge list for this node, if it fits
@ -323,8 +333,8 @@ struct Unpacked {
bytes_per_index: usize, bytes_per_index: usize,
kind: DepKind, kind: DepKind,
index: SerializedDepNodeIndex, index: SerializedDepNodeIndex,
hash: PackedFingerprint, key_fingerprint: PackedFingerprint,
fingerprint: Fingerprint, value_fingerprint: Fingerprint,
} }
// Bit fields, where // Bit fields, where
@ -345,7 +355,7 @@ impl SerializedNodeHeader {
fn new( fn new(
node: &DepNode, node: &DepNode,
index: DepNodeIndex, index: DepNodeIndex,
fingerprint: Fingerprint, value_fingerprint: Fingerprint,
edge_max_index: u32, edge_max_index: u32,
edge_count: usize, edge_count: usize,
) -> Self { ) -> Self {
@ -363,19 +373,19 @@ impl SerializedNodeHeader {
head |= (edge_count as u16 + 1) << (Self::KIND_BITS + Self::WIDTH_BITS); head |= (edge_count as u16 + 1) << (Self::KIND_BITS + Self::WIDTH_BITS);
} }
let hash: Fingerprint = node.hash.into(); let hash: Fingerprint = node.key_fingerprint.into();
// Using half-open ranges ensures an unconditional panic if we get the magic numbers wrong. // Using half-open ranges ensures an unconditional panic if we get the magic numbers wrong.
let mut bytes = [0u8; 38]; let mut bytes = [0u8; 38];
bytes[..2].copy_from_slice(&head.to_le_bytes()); bytes[..2].copy_from_slice(&head.to_le_bytes());
bytes[2..6].copy_from_slice(&index.as_u32().to_le_bytes()); bytes[2..6].copy_from_slice(&index.as_u32().to_le_bytes());
bytes[6..22].copy_from_slice(&hash.to_le_bytes()); bytes[6..22].copy_from_slice(&hash.to_le_bytes());
bytes[22..].copy_from_slice(&fingerprint.to_le_bytes()); bytes[22..].copy_from_slice(&value_fingerprint.to_le_bytes());
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
let res = Self { bytes }; let res = Self { bytes };
assert_eq!(fingerprint, res.fingerprint()); assert_eq!(value_fingerprint, res.value_fingerprint());
assert_eq!(*node, res.node()); assert_eq!(*node, res.node());
if let Some(len) = res.len() { if let Some(len) = res.len() {
assert_eq!(edge_count, len as usize); assert_eq!(edge_count, len as usize);
@ -388,8 +398,8 @@ impl SerializedNodeHeader {
fn unpack(&self) -> Unpacked { fn unpack(&self) -> Unpacked {
let head = u16::from_le_bytes(self.bytes[..2].try_into().unwrap()); let head = u16::from_le_bytes(self.bytes[..2].try_into().unwrap());
let index = u32::from_le_bytes(self.bytes[2..6].try_into().unwrap()); let index = u32::from_le_bytes(self.bytes[2..6].try_into().unwrap());
let hash = self.bytes[6..22].try_into().unwrap(); let key_fingerprint = self.bytes[6..22].try_into().unwrap();
let fingerprint = self.bytes[22..].try_into().unwrap(); let value_fingerprint = self.bytes[22..].try_into().unwrap();
let kind = head & mask(Self::KIND_BITS) as u16; let kind = head & mask(Self::KIND_BITS) as u16;
let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16; let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16;
@ -400,8 +410,8 @@ impl SerializedNodeHeader {
bytes_per_index: bytes_per_index as usize + 1, bytes_per_index: bytes_per_index as usize + 1,
kind: DepKind::new(kind), kind: DepKind::new(kind),
index: SerializedDepNodeIndex::from_u32(index), index: SerializedDepNodeIndex::from_u32(index),
hash: Fingerprint::from_le_bytes(hash).into(), key_fingerprint: Fingerprint::from_le_bytes(key_fingerprint).into(),
fingerprint: Fingerprint::from_le_bytes(fingerprint), value_fingerprint: Fingerprint::from_le_bytes(value_fingerprint),
} }
} }
@ -421,14 +431,14 @@ impl SerializedNodeHeader {
} }
#[inline] #[inline]
fn fingerprint(&self) -> Fingerprint { fn value_fingerprint(&self) -> Fingerprint {
self.unpack().fingerprint self.unpack().value_fingerprint
} }
#[inline] #[inline]
fn node(&self) -> DepNode { fn node(&self) -> DepNode {
let Unpacked { kind, hash, .. } = self.unpack(); let Unpacked { kind, key_fingerprint, .. } = self.unpack();
DepNode { kind, hash } DepNode { kind, key_fingerprint }
} }
#[inline] #[inline]
@ -443,15 +453,20 @@ impl SerializedNodeHeader {
#[derive(Debug)] #[derive(Debug)]
struct NodeInfo { struct NodeInfo {
node: DepNode, node: DepNode,
fingerprint: Fingerprint, value_fingerprint: Fingerprint,
edges: EdgesVec, edges: EdgesVec,
} }
impl NodeInfo { impl NodeInfo {
fn encode(&self, e: &mut MemEncoder, index: DepNodeIndex) { fn encode(&self, e: &mut MemEncoder, index: DepNodeIndex) {
let NodeInfo { ref node, fingerprint, ref edges } = *self; let NodeInfo { ref node, value_fingerprint, ref edges } = *self;
let header = let header = SerializedNodeHeader::new(
SerializedNodeHeader::new(node, index, fingerprint, edges.max_index(), edges.len()); node,
index,
value_fingerprint,
edges.max_index(),
edges.len(),
);
e.write_array(header.bytes); e.write_array(header.bytes);
if header.len().is_none() { if header.len().is_none() {
@ -476,7 +491,7 @@ impl NodeInfo {
e: &mut MemEncoder, e: &mut MemEncoder,
node: &DepNode, node: &DepNode,
index: DepNodeIndex, index: DepNodeIndex,
fingerprint: Fingerprint, value_fingerprint: Fingerprint,
prev_index: SerializedDepNodeIndex, prev_index: SerializedDepNodeIndex,
colors: &DepNodeColorMap, colors: &DepNodeColorMap,
previous: &SerializedDepGraph, previous: &SerializedDepGraph,
@ -488,7 +503,8 @@ impl NodeInfo {
let edge_max = let edge_max =
edges.clone().map(|i| colors.current(i).unwrap().as_u32()).max().unwrap_or(0); edges.clone().map(|i| colors.current(i).unwrap().as_u32()).max().unwrap_or(0);
let header = SerializedNodeHeader::new(node, index, fingerprint, edge_max, edge_count); let header =
SerializedNodeHeader::new(node, index, value_fingerprint, edge_max, edge_count);
e.write_array(header.bytes); e.write_array(header.bytes);
if header.len().is_none() { if header.len().is_none() {
@ -676,12 +692,12 @@ impl EncoderState {
local: &mut LocalEncoderState, local: &mut LocalEncoderState,
) { ) {
let node = self.previous.index_to_node(prev_index); let node = self.previous.index_to_node(prev_index);
let fingerprint = self.previous.fingerprint_by_index(prev_index); let value_fingerprint = self.previous.value_fingerprint_for_index(prev_index);
let edge_count = NodeInfo::encode_promoted( let edge_count = NodeInfo::encode_promoted(
&mut local.encoder, &mut local.encoder,
node, node,
index, index,
fingerprint, value_fingerprint,
prev_index, prev_index,
colors, colors,
&self.previous, &self.previous,
@ -857,11 +873,11 @@ impl GraphEncoder {
pub(crate) fn send_new( pub(crate) fn send_new(
&self, &self,
node: DepNode, node: DepNode,
fingerprint: Fingerprint, value_fingerprint: Fingerprint,
edges: EdgesVec, edges: EdgesVec,
) -> DepNodeIndex { ) -> DepNodeIndex {
let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph"); let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph");
let node = NodeInfo { node, fingerprint, edges }; let node = NodeInfo { node, value_fingerprint, edges };
let mut local = self.status.local.borrow_mut(); let mut local = self.status.local.borrow_mut();
let index = self.status.next_index(&mut *local); let index = self.status.next_index(&mut *local);
self.status.bump_index(&mut *local); self.status.bump_index(&mut *local);
@ -877,12 +893,12 @@ impl GraphEncoder {
prev_index: SerializedDepNodeIndex, prev_index: SerializedDepNodeIndex,
colors: &DepNodeColorMap, colors: &DepNodeColorMap,
node: DepNode, node: DepNode,
fingerprint: Fingerprint, value_fingerprint: Fingerprint,
edges: EdgesVec, edges: EdgesVec,
is_green: bool, is_green: bool,
) -> DepNodeIndex { ) -> DepNodeIndex {
let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph"); let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph");
let node = NodeInfo { node, fingerprint, edges }; let node = NodeInfo { node, value_fingerprint, edges };
let mut local = self.status.local.borrow_mut(); let mut local = self.status.local.borrow_mut();

View file

@ -1237,10 +1237,6 @@ impl<'tcx> Debug for Rvalue<'tcx> {
} }
} }
ShallowInitBox(ref place, ref ty) => {
with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {ty})"))
}
WrapUnsafeBinder(ref op, ty) => { WrapUnsafeBinder(ref op, ty) => {
with_no_trimmed_paths!(write!(fmt, "wrap_binder!({op:?}; {ty})")) with_no_trimmed_paths!(write!(fmt, "wrap_binder!({op:?}; {ty})"))
} }

View file

@ -747,11 +747,6 @@ impl<'tcx> ConstOperand<'tcx> {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Rvalues // Rvalues
pub enum RvalueInitializationState {
Shallow,
Deep,
}
impl<'tcx> Rvalue<'tcx> { impl<'tcx> Rvalue<'tcx> {
/// Returns true if rvalue can be safely removed when the result is unused. /// Returns true if rvalue can be safely removed when the result is unused.
#[inline] #[inline]
@ -786,7 +781,6 @@ impl<'tcx> Rvalue<'tcx> {
| Rvalue::UnaryOp(_, _) | Rvalue::UnaryOp(_, _)
| Rvalue::Discriminant(_) | Rvalue::Discriminant(_)
| Rvalue::Aggregate(_, _) | Rvalue::Aggregate(_, _)
| Rvalue::ShallowInitBox(_, _)
| Rvalue::WrapUnsafeBinder(_, _) => true, | Rvalue::WrapUnsafeBinder(_, _) => true,
} }
} }
@ -833,21 +827,10 @@ impl<'tcx> Rvalue<'tcx> {
} }
AggregateKind::RawPtr(ty, mutability) => Ty::new_ptr(tcx, ty, mutability), AggregateKind::RawPtr(ty, mutability) => Ty::new_ptr(tcx, ty, mutability),
}, },
Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty, Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
Rvalue::WrapUnsafeBinder(_, ty) => ty, Rvalue::WrapUnsafeBinder(_, ty) => ty,
} }
} }
#[inline]
/// Returns `true` if this rvalue is deeply initialized (most rvalues) or
/// whether its only shallowly initialized (`Rvalue::Box`).
pub fn initialization_state(&self) -> RvalueInitializationState {
match *self {
Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow,
_ => RvalueInitializationState::Deep,
}
}
} }
impl BorrowKind { impl BorrowKind {

View file

@ -1458,13 +1458,6 @@ pub enum Rvalue<'tcx> {
/// coroutine lowering, `Coroutine` aggregate kinds are disallowed too. /// coroutine lowering, `Coroutine` aggregate kinds are disallowed too.
Aggregate(Box<AggregateKind<'tcx>>, IndexVec<FieldIdx, Operand<'tcx>>), Aggregate(Box<AggregateKind<'tcx>>, IndexVec<FieldIdx, Operand<'tcx>>),
/// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
///
/// This is different from a normal transmute because dataflow analysis will treat the box as
/// initialized but its content as uninitialized. Like other pointer casts, this in general
/// affects alias analysis.
ShallowInitBox(Operand<'tcx>, Ty<'tcx>),
/// A CopyForDeref is equivalent to a read from a place at the /// A CopyForDeref is equivalent to a read from a place at the
/// codegen level, but is treated specially by drop elaboration. When such a read happens, it /// codegen level, but is treated specially by drop elaboration. When such a read happens, it
/// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator) /// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator)

View file

@ -810,11 +810,6 @@ macro_rules! make_mir_visitor {
} }
} }
Rvalue::ShallowInitBox(operand, ty) => {
self.visit_operand(operand, location);
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
Rvalue::WrapUnsafeBinder(op, ty) => { Rvalue::WrapUnsafeBinder(op, ty) => {
self.visit_operand(op, location); self.visit_operand(op, location);
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));

View file

@ -67,7 +67,7 @@ where
#[inline] #[inline]
fn complete(&self, key: K, value: V, index: DepNodeIndex) { fn complete(&self, key: K, value: V, index: DepNodeIndex) {
// We may be overwriting another value. This is all right, since the dep-graph // We may be overwriting another value. This is all right, since the dep-graph
// will check that the fingerprint matches. // will check that the value fingerprint matches.
self.cache.insert(key, (value, index)); self.cache.insert(key, (value, index));
} }

View file

@ -25,7 +25,7 @@ pub fn incremental_verify_ich<'tcx, V>(
tcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result)) tcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result))
}); });
let old_hash = dep_graph_data.prev_fingerprint_of(prev_index); let old_hash = dep_graph_data.prev_value_fingerprint_of(prev_index);
if new_hash != old_hash { if new_hash != old_hash {
incremental_verify_ich_failed(tcx, prev_index, &|| format_value(result)); incremental_verify_ich_failed(tcx, prev_index, &|| format_value(result));

View file

@ -86,7 +86,6 @@ where
Rvalue::Cast(..) Rvalue::Cast(..)
| Rvalue::Ref(_, BorrowKind::Fake(_), _) | Rvalue::Ref(_, BorrowKind::Fake(_), _)
| Rvalue::ShallowInitBox(..)
| Rvalue::Use(..) | Rvalue::Use(..)
| Rvalue::ThreadLocalRef(..) | Rvalue::ThreadLocalRef(..)
| Rvalue::Repeat(..) | Rvalue::Repeat(..)

View file

@ -391,15 +391,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
} }
StatementKind::Assign(box (place, rval)) => { StatementKind::Assign(box (place, rval)) => {
self.create_move_path(*place); self.create_move_path(*place);
if let RvalueInitializationState::Shallow = rval.initialization_state() {
// Box starts out uninitialized - need to create a separate
// move-path for the interior so it will be separate from
// the exterior.
self.create_move_path(self.tcx.mk_place_deref(*place));
self.gather_init(place.as_ref(), InitKind::Shallow);
} else {
self.gather_init(place.as_ref(), InitKind::Deep); self.gather_init(place.as_ref(), InitKind::Deep);
}
self.gather_rvalue(rval); self.gather_rvalue(rval);
} }
StatementKind::FakeRead(box (_, place)) => { StatementKind::FakeRead(box (_, place)) => {
@ -435,7 +427,6 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
Rvalue::Use(ref operand) Rvalue::Use(ref operand)
| Rvalue::Repeat(ref operand, _) | Rvalue::Repeat(ref operand, _)
| Rvalue::Cast(_, ref operand, _) | Rvalue::Cast(_, ref operand, _)
| Rvalue::ShallowInitBox(ref operand, _)
| Rvalue::UnaryOp(_, ref operand) | Rvalue::UnaryOp(_, ref operand)
| Rvalue::WrapUnsafeBinder(ref operand, _) => self.gather_operand(operand), | Rvalue::WrapUnsafeBinder(ref operand, _) => self.gather_operand(operand),
Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) => { Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) => {

View file

@ -467,7 +467,6 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map), Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map),
Rvalue::Use(operand) => return self.handle_operand(operand, state), Rvalue::Use(operand) => return self.handle_operand(operand, state),
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"), Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"),
Rvalue::ShallowInitBox(..) => bug!("`ShallowInitBox` in runtime MIR"),
Rvalue::Ref(..) | Rvalue::RawPtr(..) => { Rvalue::Ref(..) | Rvalue::RawPtr(..) => {
// We don't track such places. // We don't track such places.
return ValueOrPlace::TOP; return ValueOrPlace::TOP;

View file

@ -1,12 +1,8 @@
//! This pass transforms derefs of Box into a deref of the pointer inside Box. //! This pass transforms derefs of Box into a deref of the pointer inside Box.
//! //!
//! Box is not actually a pointer so it is incorrect to dereference it directly. //! Box is not actually a pointer so it is incorrect to dereference it directly.
//!
//! `ShallowInitBox` being a device for drop elaboration to understand deferred assignment to box
//! contents, we do not need this any more on runtime MIR.
use rustc_abi::{FieldIdx, VariantIdx}; use rustc_abi::FieldIdx;
use rustc_index::{IndexVec, indexvec};
use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::visit::MutVisitor;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::span_bug; use rustc_middle::span_bug;
@ -89,68 +85,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
self.super_place(place, context, location); self.super_place(place, context, location);
} }
fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) {
self.super_statement(stmt, location);
let tcx = self.tcx;
let source_info = stmt.source_info;
if let StatementKind::Assign(box (_, ref mut rvalue)) = stmt.kind
&& let Rvalue::ShallowInitBox(ref mut mutptr_to_u8, pointee) = *rvalue
&& let ty::Adt(box_adt, box_args) = Ty::new_box(tcx, pointee).kind()
{
let args = tcx.mk_args(&[pointee.into()]);
let (unique_ty, nonnull_ty, ptr_ty) =
build_ptr_tys(tcx, pointee, self.unique_def, self.nonnull_def);
let adt_kind = |def: ty::AdtDef<'tcx>, args| {
Box::new(AggregateKind::Adt(def.did(), VariantIdx::ZERO, args, None, None))
};
let zst = |ty| {
Operand::Constant(Box::new(ConstOperand {
span: source_info.span,
user_ty: None,
const_: Const::zero_sized(ty),
}))
};
let constptr = self.patch.new_temp(ptr_ty, source_info.span);
self.patch.add_assign(
location,
constptr.into(),
Rvalue::Cast(CastKind::Transmute, mutptr_to_u8.clone(), ptr_ty),
);
let nonnull = self.patch.new_temp(nonnull_ty, source_info.span);
self.patch.add_assign(
location,
nonnull.into(),
Rvalue::Aggregate(
adt_kind(self.nonnull_def, args),
indexvec![Operand::Move(constptr.into())],
),
);
let unique = self.patch.new_temp(unique_ty, source_info.span);
let phantomdata_ty =
self.unique_def.non_enum_variant().fields[FieldIdx::ONE].ty(tcx, args);
self.patch.add_assign(
location,
unique.into(),
Rvalue::Aggregate(
adt_kind(self.unique_def, args),
indexvec![Operand::Move(nonnull.into()), zst(phantomdata_ty)],
),
);
let global_alloc_ty =
box_adt.non_enum_variant().fields[FieldIdx::ONE].ty(tcx, box_args);
*rvalue = Rvalue::Aggregate(
adt_kind(*box_adt, box_args),
indexvec![Operand::Move(unique.into()), zst(global_alloc_ty)],
);
}
}
} }
pub(super) struct ElaborateBoxDerefs; pub(super) struct ElaborateBoxDerefs;

View file

@ -1069,7 +1069,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
// Unsupported values. // Unsupported values.
Rvalue::ThreadLocalRef(..) => return None, Rvalue::ThreadLocalRef(..) => return None,
Rvalue::CopyForDeref(_) | Rvalue::ShallowInitBox(..) => { Rvalue::CopyForDeref(_) => {
bug!("forbidden in runtime MIR: {rvalue:?}") bug!("forbidden in runtime MIR: {rvalue:?}")
} }
}; };

View file

@ -443,7 +443,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
| Rvalue::CopyForDeref(..) | Rvalue::CopyForDeref(..)
| Rvalue::Repeat(..) | Rvalue::Repeat(..)
| Rvalue::Cast(..) | Rvalue::Cast(..)
| Rvalue::ShallowInitBox(..)
| Rvalue::Discriminant(..) | Rvalue::Discriminant(..)
| Rvalue::WrapUnsafeBinder(..) => {} | Rvalue::WrapUnsafeBinder(..) => {}
} }
@ -605,8 +604,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
Ref(..) | RawPtr(..) => return None, Ref(..) | RawPtr(..) => return None,
ShallowInitBox(..) => return None,
Cast(ref kind, ref value, to) => match kind { Cast(ref kind, ref value, to) => match kind {
CastKind::IntToInt | CastKind::IntToFloat => { CastKind::IntToInt | CastKind::IntToFloat => {
let value = self.eval_operand(value)?; let value = self.eval_operand(value)?;

View file

@ -85,7 +85,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> {
| Rvalue::Repeat(..) | Rvalue::Repeat(..)
| Rvalue::Aggregate(..) | Rvalue::Aggregate(..)
| Rvalue::Cast(..) | Rvalue::Cast(..)
| Rvalue::ShallowInitBox(..)
| Rvalue::WrapUnsafeBinder(..) => true, | Rvalue::WrapUnsafeBinder(..) => true,
Rvalue::ThreadLocalRef(..) Rvalue::ThreadLocalRef(..)
| Rvalue::UnaryOp(..) | Rvalue::UnaryOp(..)

View file

@ -1,5 +1,6 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use std::sync::atomic::Ordering;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_middle::mir::{Body, MirDumper, MirPhase, RuntimePhase}; use rustc_middle::mir::{Body, MirDumper, MirPhase, RuntimePhase};
@ -285,6 +286,19 @@ fn run_passes_inner<'tcx>(
continue; continue;
}; };
if is_optimization_stage(body, phase_change, optimizations)
&& let Some(limit) = &tcx.sess.opts.unstable_opts.mir_opt_bisect_limit
{
if limited_by_opt_bisect(
tcx,
tcx.def_path_debug_str(body.source.def_id()),
*limit,
*pass,
) {
continue;
}
}
let dumper = if pass.is_mir_dump_enabled() let dumper = if pass.is_mir_dump_enabled()
&& let Some(dumper) = MirDumper::new(tcx, pass_name, body) && let Some(dumper) = MirDumper::new(tcx, pass_name, body)
{ {
@ -356,3 +370,46 @@ pub(super) fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tc
dumper.set_show_pass_num().set_disambiguator(&"after").dump_mir(body) dumper.set_show_pass_num().set_disambiguator(&"after").dump_mir(body)
} }
} }
fn is_optimization_stage(
body: &Body<'_>,
phase_change: Option<MirPhase>,
optimizations: Optimizations,
) -> bool {
optimizations == Optimizations::Allowed
&& body.phase == MirPhase::Runtime(RuntimePhase::PostCleanup)
&& phase_change == Some(MirPhase::Runtime(RuntimePhase::Optimized))
}
fn limited_by_opt_bisect<'tcx, P>(
tcx: TyCtxt<'tcx>,
def_path: String,
limit: usize,
pass: &P,
) -> bool
where
P: MirPass<'tcx> + ?Sized,
{
let current_opt_bisect_count =
tcx.sess.mir_opt_bisect_eval_count.fetch_add(1, Ordering::Relaxed);
let can_run = current_opt_bisect_count < limit;
if can_run {
eprintln!(
"BISECT: running pass ({}) {} on {}",
current_opt_bisect_count + 1,
pass.name(),
def_path
);
} else {
eprintln!(
"BISECT: NOT running pass ({}) {} on {}",
current_opt_bisect_count + 1,
pass.name(),
def_path
);
}
!can_run
}

View file

@ -449,8 +449,6 @@ impl<'tcx> Validator<'_, 'tcx> {
self.validate_operand(operand)?; self.validate_operand(operand)?;
} }
Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
Rvalue::UnaryOp(op, operand) => { Rvalue::UnaryOp(op, operand) => {
match op { match op {
// These operations can never fail. // These operations can never fail.

View file

@ -85,7 +85,7 @@ impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts {
} }
fn is_required(&self) -> bool { fn is_required(&self) -> bool {
true false
} }
} }

View file

@ -1259,14 +1259,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
} }
} }
} }
Rvalue::ShallowInitBox(operand, _) => {
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location, format!("ShallowInitBox after ElaborateBoxDerefs"))
}
let a = operand.ty(&self.body.local_decls, self.tcx);
check_kinds!(a, "Cannot shallow init type {:?}", ty::RawPtr(..));
}
Rvalue::Cast(kind, operand, target_type) => { Rvalue::Cast(kind, operand, target_type) => {
let op_ty = operand.ty(self.body, self.tcx); let op_ty = operand.ty(self.body, self.tcx);
match kind { match kind {

View file

@ -567,13 +567,6 @@ pub enum Rvalue {
/// [#74836]: https://github.com/rust-lang/rust/issues/74836 /// [#74836]: https://github.com/rust-lang/rust/issues/74836
Repeat(Operand, TyConst), Repeat(Operand, TyConst),
/// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
///
/// This is different from a normal transmute because dataflow analysis will treat the box as
/// initialized but its content as uninitialized. Like other pointer casts, this in general
/// affects alias analysis.
ShallowInitBox(Operand, Ty),
/// Creates a pointer/reference to the given thread local. /// Creates a pointer/reference to the given thread local.
/// ///
/// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
@ -651,7 +644,6 @@ impl Rvalue {
} }
AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)), AggregateKind::RawPtr(ty, mutability) => Ok(Ty::new_ptr(ty, mutability)),
}, },
Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
Rvalue::CopyForDeref(place) => place.ty(locals), Rvalue::CopyForDeref(place) => place.ty(locals),
} }
} }

View file

@ -383,7 +383,6 @@ fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
Rvalue::Repeat(op, cnst) => { Rvalue::Repeat(op, cnst) => {
write!(writer, "[{}; {}]", pretty_operand(op), pretty_ty_const(cnst)) write!(writer, "[{}; {}]", pretty_operand(op), pretty_ty_const(cnst))
} }
Rvalue::ShallowInitBox(_, _) => Ok(()),
Rvalue::ThreadLocalRef(item) => { Rvalue::ThreadLocalRef(item) => {
write!(writer, "thread_local_ref{item:?}") write!(writer, "thread_local_ref{item:?}")
} }

View file

@ -277,10 +277,6 @@ macro_rules! make_mir_visitor {
self.visit_operand(op, location); self.visit_operand(op, location);
self.visit_ty_const(constant, location); self.visit_ty_const(constant, location);
} }
Rvalue::ShallowInitBox(op, ty) => {
self.visit_ty(ty, location);
self.visit_operand(op, location)
}
Rvalue::ThreadLocalRef(_) => {} Rvalue::ThreadLocalRef(_) => {}
Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => { Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => {
self.visit_operand(op, location); self.visit_operand(op, location);

View file

@ -240,9 +240,6 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
let operands = operands.iter().map(|op| op.stable(tables, cx)).collect(); let operands = operands.iter().map(|op| op.stable(tables, cx)).collect();
crate::mir::Rvalue::Aggregate(agg_kind.stable(tables, cx), operands) crate::mir::Rvalue::Aggregate(agg_kind.stable(tables, cx), operands)
} }
ShallowInitBox(op, ty) => {
crate::mir::Rvalue::ShallowInitBox(op.stable(tables, cx), ty.stable(tables, cx))
}
CopyForDeref(place) => crate::mir::Rvalue::CopyForDeref(place.stable(tables, cx)), CopyForDeref(place) => crate::mir::Rvalue::CopyForDeref(place.stable(tables, cx)),
WrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"), WrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
} }

View file

@ -1,5 +1,5 @@
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::dep_graph::{DepKindVTable, DepNodeKey, FingerprintStyle}; use rustc_middle::dep_graph::{DepKindVTable, DepNodeKey, KeyFingerprintStyle};
use rustc_middle::query::QueryCache; use rustc_middle::query::QueryCache;
use crate::plumbing::{force_from_dep_node_inner, try_load_from_on_disk_cache_inner}; use crate::plumbing::{force_from_dep_node_inner, try_load_from_on_disk_cache_inner};
@ -15,7 +15,7 @@ mod non_query {
DepKindVTable { DepKindVTable {
is_anon: false, is_anon: false,
is_eval_always: false, is_eval_always: false,
fingerprint_style: FingerprintStyle::Unit, key_fingerprint_style: KeyFingerprintStyle::Unit,
force_from_dep_node: Some(|_, dep_node, _| { force_from_dep_node: Some(|_, dep_node, _| {
bug!("force_from_dep_node: encountered {dep_node:?}") bug!("force_from_dep_node: encountered {dep_node:?}")
}), }),
@ -29,7 +29,7 @@ mod non_query {
DepKindVTable { DepKindVTable {
is_anon: false, is_anon: false,
is_eval_always: false, is_eval_always: false,
fingerprint_style: FingerprintStyle::Unit, key_fingerprint_style: KeyFingerprintStyle::Unit,
force_from_dep_node: Some(|_, dep_node, _| { force_from_dep_node: Some(|_, dep_node, _| {
bug!("force_from_dep_node: encountered {dep_node:?}") bug!("force_from_dep_node: encountered {dep_node:?}")
}), }),
@ -42,7 +42,7 @@ mod non_query {
DepKindVTable { DepKindVTable {
is_anon: false, is_anon: false,
is_eval_always: false, is_eval_always: false,
fingerprint_style: FingerprintStyle::Unit, key_fingerprint_style: KeyFingerprintStyle::Unit,
force_from_dep_node: Some(|tcx, _, prev_index| { force_from_dep_node: Some(|tcx, _, prev_index| {
tcx.dep_graph.force_diagnostic_node(tcx, prev_index); tcx.dep_graph.force_diagnostic_node(tcx, prev_index);
true true
@ -56,7 +56,7 @@ mod non_query {
DepKindVTable { DepKindVTable {
is_anon: true, is_anon: true,
is_eval_always: false, is_eval_always: false,
fingerprint_style: FingerprintStyle::Opaque, key_fingerprint_style: KeyFingerprintStyle::Opaque,
force_from_dep_node: Some(|_, _, _| bug!("cannot force an anon node")), force_from_dep_node: Some(|_, _, _| bug!("cannot force an anon node")),
try_load_from_on_disk_cache: None, try_load_from_on_disk_cache: None,
name: &"AnonZeroDeps", name: &"AnonZeroDeps",
@ -67,7 +67,7 @@ mod non_query {
DepKindVTable { DepKindVTable {
is_anon: true, is_anon: true,
is_eval_always: false, is_eval_always: false,
fingerprint_style: FingerprintStyle::Unit, key_fingerprint_style: KeyFingerprintStyle::Unit,
force_from_dep_node: None, force_from_dep_node: None,
try_load_from_on_disk_cache: None, try_load_from_on_disk_cache: None,
name: &"TraitSelect", name: &"TraitSelect",
@ -78,7 +78,7 @@ mod non_query {
DepKindVTable { DepKindVTable {
is_anon: false, is_anon: false,
is_eval_always: false, is_eval_always: false,
fingerprint_style: FingerprintStyle::Opaque, key_fingerprint_style: KeyFingerprintStyle::Opaque,
force_from_dep_node: None, force_from_dep_node: None,
try_load_from_on_disk_cache: None, try_load_from_on_disk_cache: None,
name: &"CompileCodegenUnit", name: &"CompileCodegenUnit",
@ -89,7 +89,7 @@ mod non_query {
DepKindVTable { DepKindVTable {
is_anon: false, is_anon: false,
is_eval_always: false, is_eval_always: false,
fingerprint_style: FingerprintStyle::Opaque, key_fingerprint_style: KeyFingerprintStyle::Opaque,
force_from_dep_node: None, force_from_dep_node: None,
try_load_from_on_disk_cache: None, try_load_from_on_disk_cache: None,
name: &"CompileMonoItem", name: &"CompileMonoItem",
@ -100,7 +100,7 @@ mod non_query {
DepKindVTable { DepKindVTable {
is_anon: false, is_anon: false,
is_eval_always: false, is_eval_always: false,
fingerprint_style: FingerprintStyle::Unit, key_fingerprint_style: KeyFingerprintStyle::Unit,
force_from_dep_node: None, force_from_dep_node: None,
try_load_from_on_disk_cache: None, try_load_from_on_disk_cache: None,
name: &"Metadata", name: &"Metadata",
@ -118,17 +118,17 @@ where
Cache: QueryCache + 'tcx, Cache: QueryCache + 'tcx,
{ {
let is_anon = FLAGS.is_anon; let is_anon = FLAGS.is_anon;
let fingerprint_style = if is_anon { let key_fingerprint_style = if is_anon {
FingerprintStyle::Opaque KeyFingerprintStyle::Opaque
} else { } else {
<Cache::Key as DepNodeKey<'tcx>>::fingerprint_style() <Cache::Key as DepNodeKey<'tcx>>::key_fingerprint_style()
}; };
if is_anon || !fingerprint_style.reconstructible() { if is_anon || !key_fingerprint_style.reconstructible() {
return DepKindVTable { return DepKindVTable {
is_anon, is_anon,
is_eval_always, is_eval_always,
fingerprint_style, key_fingerprint_style,
force_from_dep_node: None, force_from_dep_node: None,
try_load_from_on_disk_cache: None, try_load_from_on_disk_cache: None,
name: Q::NAME, name: Q::NAME,
@ -138,7 +138,7 @@ where
DepKindVTable { DepKindVTable {
is_anon, is_anon,
is_eval_always, is_eval_always,
fingerprint_style, key_fingerprint_style,
force_from_dep_node: Some(|tcx, dep_node, _| { force_from_dep_node: Some(|tcx, dep_node, _| {
force_from_dep_node_inner(Q::query_dispatcher(tcx), tcx, dep_node) force_from_dep_node_inner(Q::query_dispatcher(tcx), tcx, dep_node)
}), }),

View file

@ -509,7 +509,7 @@ fn try_load_from_disk_and_cache_in_memory<'tcx, C: QueryCache, const FLAGS: Quer
dep_graph_data.mark_debug_loaded_from_disk(*dep_node) dep_graph_data.mark_debug_loaded_from_disk(*dep_node)
} }
let prev_fingerprint = dep_graph_data.prev_fingerprint_of(prev_dep_node_index); let prev_fingerprint = dep_graph_data.prev_value_fingerprint_of(prev_dep_node_index);
// If `-Zincremental-verify-ich` is specified, re-hash results from // If `-Zincremental-verify-ich` is specified, re-hash results from
// the cache and make sure that they have the expected fingerprint. // the cache and make sure that they have the expected fingerprint.
// //
@ -538,7 +538,7 @@ fn try_load_from_disk_and_cache_in_memory<'tcx, C: QueryCache, const FLAGS: Quer
// can be forced from `DepNode`. // can be forced from `DepNode`.
debug_assert!( debug_assert!(
!query.will_cache_on_disk_for_key(tcx, key) !query.will_cache_on_disk_for_key(tcx, key)
|| !tcx.fingerprint_style(dep_node.kind).reconstructible(), || !tcx.key_fingerprint_style(dep_node.kind).reconstructible(),
"missing on-disk cache entry for {dep_node:?}" "missing on-disk cache entry for {dep_node:?}"
); );

View file

@ -396,8 +396,11 @@ pub(crate) fn try_load_from_on_disk_cache_inner<'tcx, C: QueryCache, const FLAGS
) { ) {
debug_assert!(tcx.dep_graph.is_green(&dep_node)); debug_assert!(tcx.dep_graph.is_green(&dep_node));
let key = C::Key::recover(tcx, &dep_node).unwrap_or_else(|| { let key = C::Key::try_recover_key(tcx, &dep_node).unwrap_or_else(|| {
panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash) panic!(
"Failed to recover key for {dep_node:?} with key fingerprint {}",
dep_node.key_fingerprint
)
}); });
if query.will_cache_on_disk_for_key(tcx, &key) { if query.will_cache_on_disk_for_key(tcx, &key) {
// Call `tcx.$query(key)` for its side-effect of loading the disk-cached // Call `tcx.$query(key)` for its side-effect of loading the disk-cached
@ -462,7 +465,7 @@ pub(crate) fn force_from_dep_node_inner<'tcx, C: QueryCache, const FLAGS: QueryF
"calling force_from_dep_node() on dep_kinds::codegen_unit" "calling force_from_dep_node() on dep_kinds::codegen_unit"
); );
if let Some(key) = C::Key::recover(tcx, &dep_node) { if let Some(key) = C::Key::try_recover_key(tcx, &dep_node) {
force_query(query, tcx, key, dep_node); force_query(query, tcx, key, dep_node);
true true
} else { } else {

View file

@ -371,6 +371,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// - A glob decl is overwritten by its clone after setting ambiguity in it. // - A glob decl is overwritten by its clone after setting ambiguity in it.
// FIXME: avoid this by removing `warn_ambiguity`, or by triggering glob re-fetch // FIXME: avoid this by removing `warn_ambiguity`, or by triggering glob re-fetch
// with the same decl in some way. // with the same decl in some way.
// - A glob decl is overwritten by a glob decl with larger visibility.
// FIXME: avoid this by updating this visibility in place.
// - A glob decl is overwritten by a glob decl re-fetching an // - A glob decl is overwritten by a glob decl re-fetching an
// overwritten decl from other module (the recursive case). // overwritten decl from other module (the recursive case).
// Here we are detecting all such re-fetches and overwrite old decls // Here we are detecting all such re-fetches and overwrite old decls
@ -384,7 +386,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// FIXME: reenable the asserts when `warn_ambiguity` is removed (#149195). // FIXME: reenable the asserts when `warn_ambiguity` is removed (#149195).
// assert_ne!(old_deep_decl, deep_decl); // assert_ne!(old_deep_decl, deep_decl);
// assert!(old_deep_decl.is_glob_import()); // assert!(old_deep_decl.is_glob_import());
assert!(!deep_decl.is_glob_import()); // FIXME: reenable the assert when visibility is updated in place.
// assert!(!deep_decl.is_glob_import());
if old_glob_decl.ambiguity.get().is_some() && glob_decl.ambiguity.get().is_none() { if old_glob_decl.ambiguity.get().is_some() && glob_decl.ambiguity.get().is_none() {
// Do not lose glob ambiguities when re-fetching the glob. // Do not lose glob ambiguities when re-fetching the glob.
glob_decl.ambiguity.set_unchecked(old_glob_decl.ambiguity.get()); glob_decl.ambiguity.set_unchecked(old_glob_decl.ambiguity.get());

View file

@ -4060,17 +4060,23 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
"instead, you are more likely to want" "instead, you are more likely to want"
}; };
let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand; let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand;
let mut sugg_is_str_to_string = false;
let mut sugg = vec![(lt.span, String::new())]; let mut sugg = vec![(lt.span, String::new())];
if let Some((kind, _span)) = self.diag_metadata.current_function if let Some((kind, _span)) = self.diag_metadata.current_function
&& let FnKind::Fn(_, _, ast::Fn { sig, .. }) = kind && let FnKind::Fn(_, _, ast::Fn { sig, .. }) = kind
&& let ast::FnRetTy::Ty(ty) = &sig.decl.output
{ {
let mut lt_finder = let mut lt_finder =
LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] }; LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
lt_finder.visit_ty(&ty); for param in &sig.decl.inputs {
lt_finder.visit_ty(&param.ty);
}
if let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output {
lt_finder.visit_ty(ret_ty);
let mut ret_lt_finder =
LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
ret_lt_finder.visit_ty(ret_ty);
if let [Ty { span, kind: TyKind::Ref(_, mut_ty), .. }] = if let [Ty { span, kind: TyKind::Ref(_, mut_ty), .. }] =
&lt_finder.seen[..] &ret_lt_finder.seen[..]
{ {
// We might have a situation like // We might have a situation like
// fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()> // fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()>
@ -4080,6 +4086,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
sugg = vec![(span.with_hi(mut_ty.ty.span.lo()), String::new())]; sugg = vec![(span.with_hi(mut_ty.ty.span.lo()), String::new())];
owned_sugg = true; owned_sugg = true;
} }
}
if let Some(ty) = lt_finder.found { if let Some(ty) = lt_finder.found {
if let TyKind::Path(None, path) = &ty.kind { if let TyKind::Path(None, path) = &ty.kind {
// Check if the path being borrowed is likely to be owned. // Check if the path being borrowed is likely to be owned.
@ -4098,6 +4105,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
lt.span.with_hi(ty.span.hi()), lt.span.with_hi(ty.span.hi()),
"String".to_string(), "String".to_string(),
)]; )];
sugg_is_str_to_string = true;
} }
Some(Res::PrimTy(..)) => {} Some(Res::PrimTy(..)) => {}
Some(Res::Def( Some(Res::Def(
@ -4124,6 +4132,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
lt.span.with_hi(ty.span.hi()), lt.span.with_hi(ty.span.hi()),
"String".to_string(), "String".to_string(),
)]; )];
sugg_is_str_to_string = true;
} }
Res::PrimTy(..) => {} Res::PrimTy(..) => {}
Res::Def( Res::Def(
@ -4158,6 +4167,12 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
} }
} }
if owned_sugg { if owned_sugg {
if let Some(span) =
self.find_ref_prefix_span_for_owned_suggestion(lt.span)
&& !sugg_is_str_to_string
{
sugg = vec![(span, String::new())];
}
err.multipart_suggestion_verbose( err.multipart_suggestion_verbose(
format!("{pre} to return an owned value"), format!("{pre} to return an owned value"),
sugg, sugg,
@ -4184,6 +4199,23 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
} }
} }
} }
fn find_ref_prefix_span_for_owned_suggestion(&self, lifetime: Span) -> Option<Span> {
let mut finder = RefPrefixSpanFinder { lifetime, span: None };
if let Some(item) = self.diag_metadata.current_item {
finder.visit_item(item);
} else if let Some((kind, _span)) = self.diag_metadata.current_function
&& let FnKind::Fn(_, _, ast::Fn { sig, .. }) = kind
{
for param in &sig.decl.inputs {
finder.visit_ty(&param.ty);
}
if let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output {
finder.visit_ty(ret_ty);
}
}
finder.span
}
} }
fn mk_where_bound_predicate( fn mk_where_bound_predicate(
@ -4285,6 +4317,26 @@ impl<'ast> Visitor<'ast> for LifetimeFinder<'ast> {
} }
} }
struct RefPrefixSpanFinder {
lifetime: Span,
span: Option<Span>,
}
impl<'ast> Visitor<'ast> for RefPrefixSpanFinder {
fn visit_ty(&mut self, t: &'ast Ty) {
if self.span.is_some() {
return;
}
if let TyKind::Ref(_, mut_ty) | TyKind::PinnedRef(_, mut_ty) = &t.kind
&& t.span.lo() == self.lifetime.lo()
{
self.span = Some(t.span.with_hi(mut_ty.ty.span.lo()));
return;
}
walk_ty(self, t);
}
}
/// Shadowing involving a label is only a warning for historical reasons. /// Shadowing involving a label is only a warning for historical reasons.
//FIXME: make this a proper lint. //FIXME: make this a proper lint.
pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) { pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {

View file

@ -2481,6 +2481,9 @@ options! {
mir_include_spans: MirIncludeSpans = (MirIncludeSpans::default(), parse_mir_include_spans, [UNTRACKED], mir_include_spans: MirIncludeSpans = (MirIncludeSpans::default(), parse_mir_include_spans, [UNTRACKED],
"include extra comments in mir pretty printing, like line numbers and statement indices, \ "include extra comments in mir pretty printing, like line numbers and statement indices, \
details about types, etc. (boolean for all passes, 'nll' to enable in NLL MIR only, default: 'nll')"), details about types, etc. (boolean for all passes, 'nll' to enable in NLL MIR only, default: 'nll')"),
mir_opt_bisect_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
"limit the number of MIR optimization pass executions (global across all bodies). \
Pass executions after this limit are skipped and reported. (default: no limit)"),
#[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")] #[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED], mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"), "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),

View file

@ -2,7 +2,7 @@ use std::any::Any;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::AtomicBool; use std::sync::atomic::{AtomicBool, AtomicUsize};
use std::{env, io}; use std::{env, io};
use rand::{RngCore, rng}; use rand::{RngCore, rng};
@ -161,6 +161,12 @@ pub struct Session {
/// Does the codegen backend support ThinLTO? /// Does the codegen backend support ThinLTO?
pub thin_lto_supported: bool, pub thin_lto_supported: bool,
/// Global per-session counter for MIR optimization pass applications.
///
/// Used by `-Zmir-opt-bisect-limit` to assign an index to each
/// optimization-pass execution candidate during this compilation.
pub mir_opt_bisect_eval_count: AtomicUsize,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -1101,6 +1107,7 @@ pub fn build_session(
invocation_temp, invocation_temp,
replaced_intrinsics: FxHashSet::default(), // filled by `run_compiler` replaced_intrinsics: FxHashSet::default(), // filled by `run_compiler`
thin_lto_supported: true, // filled by `run_compiler` thin_lto_supported: true, // filled by `run_compiler`
mir_opt_bisect_eval_count: AtomicUsize::new(0),
}; };
validate_commandline_args_with_session_available(&sess); validate_commandline_args_with_session_available(&sess);

View file

@ -327,7 +327,6 @@ symbols! {
Pointer, Pointer,
Poll, Poll,
ProcMacro, ProcMacro,
ProceduralMasqueradeDummyType,
Range, Range,
RangeBounds, RangeBounds,
RangeCopy, RangeCopy,

View file

@ -300,6 +300,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let rebased_args = alias.args.rebase_onto(tcx, trait_def_id, impl_substs); let rebased_args = alias.args.rebase_onto(tcx, trait_def_id, impl_substs);
let impl_item_def_id = leaf_def.item.def_id; let impl_item_def_id = leaf_def.item.def_id;
if !tcx.check_args_compatible(impl_item_def_id, rebased_args) {
return false;
}
let impl_assoc_ty = tcx.type_of(impl_item_def_id).instantiate(tcx, rebased_args); let impl_assoc_ty = tcx.type_of(impl_item_def_id).instantiate(tcx, rebased_args);
self.infcx.can_eq(param_env, impl_assoc_ty, concrete) self.infcx.can_eq(param_env, impl_assoc_ty, concrete)

View file

@ -11,7 +11,7 @@ use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::print::RegionHighlightMode; use rustc_middle::ty::print::RegionHighlightMode;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
use rustc_span::Span; use rustc_span::{Ident, Span};
use tracing::debug; use tracing::debug;
use crate::error_reporting::infer::nice_region_error::NiceRegionError; use crate::error_reporting::infer::nice_region_error::NiceRegionError;
@ -99,7 +99,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
// Get the span of all the used type parameters in the method. // Get the span of all the used type parameters in the method.
let assoc_item = self.tcx().associated_item(trait_item_def_id); let assoc_item = self.tcx().associated_item(trait_item_def_id);
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] }; let mut visitor =
TypeParamSpanVisitor { tcx: self.tcx(), types: vec![], elided_lifetime_paths: vec![] };
match assoc_item.kind { match assoc_item.kind {
ty::AssocKind::Fn { .. } => { ty::AssocKind::Fn { .. } => {
if let Some(hir_id) = if let Some(hir_id) =
@ -122,13 +123,49 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
found, found,
}; };
self.tcx().dcx().emit_err(diag) let mut diag = self.tcx().dcx().create_err(diag);
// A limit not to make diag verbose.
const ELIDED_LIFETIME_NOTE_LIMIT: usize = 5;
let elided_lifetime_paths = visitor.elided_lifetime_paths;
let total_elided_lifetime_paths = elided_lifetime_paths.len();
let shown_elided_lifetime_paths = if tcx.sess.opts.verbose {
total_elided_lifetime_paths
} else {
ELIDED_LIFETIME_NOTE_LIMIT
};
for elided in elided_lifetime_paths.into_iter().take(shown_elided_lifetime_paths) {
diag.span_note(
elided.span,
format!("`{}` here is elided as `{}`", elided.ident, elided.shorthand),
);
} }
if total_elided_lifetime_paths > shown_elided_lifetime_paths {
diag.note(format!(
"and {} more elided lifetime{} in type paths",
total_elided_lifetime_paths - shown_elided_lifetime_paths,
if total_elided_lifetime_paths - shown_elided_lifetime_paths == 1 {
""
} else {
"s"
},
));
}
diag.emit()
}
}
#[derive(Clone)]
struct ElidedLifetimeInPath {
span: Span,
ident: Ident,
shorthand: String,
} }
struct TypeParamSpanVisitor<'tcx> { struct TypeParamSpanVisitor<'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
types: Vec<Span>, types: Vec<Span>,
elided_lifetime_paths: Vec<ElidedLifetimeInPath>,
} }
impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
@ -138,6 +175,83 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
self.tcx self.tcx
} }
fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, _span: Span) {
fn record_elided_lifetimes(
tcx: TyCtxt<'_>,
elided_lifetime_paths: &mut Vec<ElidedLifetimeInPath>,
segment: &hir::PathSegment<'_>,
) {
let Some(args) = segment.args else { return };
if args.parenthesized != hir::GenericArgsParentheses::No {
// Our diagnostic rendering below uses `<...>` syntax; skip cases like `Fn(..) -> ..`.
return;
}
let elided_count = args
.args
.iter()
.filter(|arg| {
let hir::GenericArg::Lifetime(l) = arg else { return false };
l.syntax == hir::LifetimeSyntax::Implicit
&& matches!(l.source, hir::LifetimeSource::Path { .. })
})
.count();
if elided_count == 0
|| elided_lifetime_paths.iter().any(|p| p.span == segment.ident.span)
{
return;
}
let sm = tcx.sess.source_map();
let mut parts = args
.args
.iter()
.map(|arg| match arg {
hir::GenericArg::Lifetime(l) => {
if l.syntax == hir::LifetimeSyntax::Implicit
&& matches!(l.source, hir::LifetimeSource::Path { .. })
{
"'_".to_string()
} else {
sm.span_to_snippet(l.ident.span)
.unwrap_or_else(|_| format!("'{}", l.ident.name))
}
}
hir::GenericArg::Type(ty) => {
sm.span_to_snippet(ty.span).unwrap_or_else(|_| "..".to_string())
}
hir::GenericArg::Const(ct) => {
sm.span_to_snippet(ct.span).unwrap_or_else(|_| "..".to_string())
}
hir::GenericArg::Infer(_) => "_".to_string(),
})
.collect::<Vec<_>>();
parts.extend(args.constraints.iter().map(|constraint| {
sm.span_to_snippet(constraint.span)
.unwrap_or_else(|_| format!("{} = ..", constraint.ident))
}));
let shorthand = format!("{}<{}>", segment.ident, parts.join(", "));
elided_lifetime_paths.push(ElidedLifetimeInPath {
span: segment.ident.span,
ident: segment.ident,
shorthand,
});
}
match qpath {
hir::QPath::Resolved(_, path) => {
for segment in path.segments {
record_elided_lifetimes(self.tcx, &mut self.elided_lifetime_paths, segment);
}
}
hir::QPath::TypeRelative(_, segment) => {
record_elided_lifetimes(self.tcx, &mut self.elided_lifetime_paths, segment);
}
}
hir::intravisit::walk_qpath(self, qpath, id);
}
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) { fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) {
match arg.kind { match arg.kind {
hir::TyKind::Ref(_, ref mut_ty) => { hir::TyKind::Ref(_, ref mut_ty) => {

View file

@ -182,7 +182,6 @@
#![feature(negative_impls)] #![feature(negative_impls)]
#![feature(never_type)] #![feature(never_type)]
#![feature(optimize_attribute)] #![feature(optimize_attribute)]
#![feature(rustc_allow_const_fn_unstable)]
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![feature(slice_internals)] #![feature(slice_internals)]
#![feature(staged_api)] #![feature(staged_api)]

View file

@ -159,7 +159,6 @@
#![feature(pattern_types)] #![feature(pattern_types)]
#![feature(prelude_import)] #![feature(prelude_import)]
#![feature(repr_simd)] #![feature(repr_simd)]
#![feature(rustc_allow_const_fn_unstable)]
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![feature(rustdoc_internals)] #![feature(rustdoc_internals)]
#![feature(simd_ffi)] #![feature(simd_ffi)]

View file

@ -2481,7 +2481,8 @@ macro_rules! int_impl {
/// ///
/// Returns a tuple of the addition along with a boolean indicating /// Returns a tuple of the addition along with a boolean indicating
/// whether an arithmetic overflow would occur. If an overflow would have /// whether an arithmetic overflow would occur. If an overflow would have
/// occurred then the wrapped value is returned. /// occurred then the wrapped value is returned (negative if overflowed
/// above [`MAX`](Self::MAX), non-negative if below [`MIN`](Self::MIN)).
/// ///
/// # Examples /// # Examples
/// ///
@ -2516,6 +2517,9 @@ macro_rules! int_impl {
/// The output boolean returned by this method is *not* a carry flag, /// The output boolean returned by this method is *not* a carry flag,
/// and should *not* be added to a more significant word. /// and should *not* be added to a more significant word.
/// ///
/// If overflow occurred, the wrapped value is returned (negative if overflowed
/// above [`MAX`](Self::MAX), non-negative if below [`MIN`](Self::MIN)).
///
/// If the input carry is false, this method is equivalent to /// If the input carry is false, this method is equivalent to
/// [`overflowing_add`](Self::overflowing_add). /// [`overflowing_add`](Self::overflowing_add).
/// ///
@ -2583,7 +2587,8 @@ macro_rules! int_impl {
/// Calculates `self` - `rhs`. /// Calculates `self` - `rhs`.
/// ///
/// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow /// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
/// would occur. If an overflow would have occurred then the wrapped value is returned. /// would occur. If an overflow would have occurred then the wrapped value is returned
/// (negative if overflowed above [`MAX`](Self::MAX), non-negative if below [`MIN`](Self::MIN)).
/// ///
/// # Examples /// # Examples
/// ///
@ -2619,6 +2624,9 @@ macro_rules! int_impl {
/// The output boolean returned by this method is *not* a borrow flag, /// The output boolean returned by this method is *not* a borrow flag,
/// and should *not* be subtracted from a more significant word. /// and should *not* be subtracted from a more significant word.
/// ///
/// If overflow occurred, the wrapped value is returned (negative if overflowed
/// above [`MAX`](Self::MAX), non-negative if below [`MIN`](Self::MIN)).
///
/// If the input borrow is false, this method is equivalent to /// If the input borrow is false, this method is equivalent to
/// [`overflowing_sub`](Self::overflowing_sub). /// [`overflowing_sub`](Self::overflowing_sub).
/// ///

View file

@ -487,8 +487,8 @@ macro_rules! uint_impl {
/// Performs a carry-less multiplication, returning the lower bits. /// Performs a carry-less multiplication, returning the lower bits.
/// ///
/// This operation is similar to long multiplication, except that exclusive or is used /// This operation is similar to long multiplication in base 2, except that exclusive or is
/// instead of addition. The implementation is equivalent to: /// used instead of addition. The implementation is equivalent to:
/// ///
/// ```no_run /// ```no_run
#[doc = concat!("pub fn carryless_mul(lhs: ", stringify!($SelfT), ", rhs: ", stringify!($SelfT), ") -> ", stringify!($SelfT), "{")] #[doc = concat!("pub fn carryless_mul(lhs: ", stringify!($SelfT), ", rhs: ", stringify!($SelfT), ") -> ", stringify!($SelfT), "{")]

View file

@ -164,7 +164,7 @@ mod imp {
// of this used `[[NSProcessInfo processInfo] arguments]`. // of this used `[[NSProcessInfo processInfo] arguments]`.
#[cfg(target_vendor = "apple")] #[cfg(target_vendor = "apple")]
mod imp { mod imp {
use crate::ffi::{c_char, c_int}; use crate::ffi::c_char;
pub unsafe fn init(_argc: isize, _argv: *const *const u8) { pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
// No need to initialize anything in here, `libdyld.dylib` has already // No need to initialize anything in here, `libdyld.dylib` has already
@ -172,12 +172,6 @@ mod imp {
} }
pub fn argc_argv() -> (isize, *const *const c_char) { pub fn argc_argv() -> (isize, *const *const c_char) {
unsafe extern "C" {
// These functions are in crt_externs.h.
fn _NSGetArgc() -> *mut c_int;
fn _NSGetArgv() -> *mut *mut *mut c_char;
}
// SAFETY: The returned pointer points to a static initialized early // SAFETY: The returned pointer points to a static initialized early
// in the program lifetime by `libdyld.dylib`, and as such is always // in the program lifetime by `libdyld.dylib`, and as such is always
// valid. // valid.
@ -187,9 +181,9 @@ mod imp {
// doesn't exist a lock that we can take. Instead, it is generally // doesn't exist a lock that we can take. Instead, it is generally
// expected that it's only modified in `main` / before other code // expected that it's only modified in `main` / before other code
// runs, so reading this here should be fine. // runs, so reading this here should be fine.
let argc = unsafe { _NSGetArgc().read() }; let argc = unsafe { libc::_NSGetArgc().read() };
// SAFETY: Same as above. // SAFETY: Same as above.
let argv = unsafe { _NSGetArgv().read() }; let argv = unsafe { libc::_NSGetArgv().read() };
// Cast from `*mut *mut c_char` to `*const *const c_char` // Cast from `*mut *mut c_char` to `*const *const c_char`
(argc as isize, argv.cast()) (argc as isize, argv.cast())

View file

@ -393,7 +393,7 @@ Heres how these different lint controls interact:
warning: 1 warning emitted warning: 1 warning emitted
``` ```
3. [CLI level flags](#via-compiler-flag) take precedence over attributes. 3. [CLI level flags](#via-compiler-flag) override the default level of a lint. They essentially behave like crate-level attributes. Attributes within the source code take precedence over CLI flags, except for `-F`/`--forbid`, which cannot be overridden.
The order of the flags matter; flags on the right take precedence over earlier flags. The order of the flags matter; flags on the right take precedence over earlier flags.

View file

@ -194,7 +194,6 @@ fn check_rvalue<'tcx>(
)) ))
} }
}, },
Rvalue::ShallowInitBox(_, _) => Ok(()),
Rvalue::UnaryOp(_, operand) => { Rvalue::UnaryOp(_, operand) => {
let ty = operand.ty(body, cx.tcx); let ty = operand.ty(body, cx.tcx);
if ty.is_integral() || ty.is_bool() { if ty.is_integral() || ty.is_bool() {

View file

@ -343,8 +343,8 @@ impl VisitProvenance for Thread<'_> {
impl VisitProvenance for Frame<'_, Provenance, FrameExtra<'_>> { impl VisitProvenance for Frame<'_, Provenance, FrameExtra<'_>> {
fn visit_provenance(&self, visit: &mut VisitWith<'_>) { fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
let return_place = self.return_place();
let Frame { let Frame {
return_place,
locals, locals,
extra, extra,
// There are some private fields we cannot access; they contain no tags. // There are some private fields we cannot access; they contain no tags.

View file

@ -493,7 +493,7 @@ pub fn report_result<'tcx>(
for (i, frame) in ecx.active_thread_stack().iter().enumerate() { for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
trace!("-------------------"); trace!("-------------------");
trace!("Frame {}", i); trace!("Frame {}", i);
trace!(" return: {:?}", frame.return_place); trace!(" return: {:?}", frame.return_place());
for (i, local) in frame.locals.iter().enumerate() { for (i, local) in frame.locals.iter().enumerate() {
trace!(" local {}: {:?}", i, local); trace!(" local {}: {:?}", i, local);
} }

View file

@ -1235,7 +1235,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
// to run extra MIR), and Ok(Some(body)) if we found MIR to run for the // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the
// foreign function // foreign function
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`. // Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
let args = ecx.copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit? let args = MiriInterpCx::copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit?
let link_name = Symbol::intern(ecx.tcx.symbol_name(instance).name); let link_name = Symbol::intern(ecx.tcx.symbol_name(instance).name);
return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind); return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
} }
@ -1262,7 +1262,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
ret: Option<mir::BasicBlock>, ret: Option<mir::BasicBlock>,
unwind: mir::UnwindAction, unwind: mir::UnwindAction,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
let args = ecx.copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit? let args = MiriInterpCx::copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit?
ecx.emulate_dyn_sym(fn_val, abi, &args, dest, ret, unwind) ecx.emulate_dyn_sym(fn_val, abi, &args, dest, ret, unwind)
} }

View file

@ -14,8 +14,8 @@ LL | let local = 0;
help: ALLOC was deallocated here: help: ALLOC was deallocated here:
--> tests/fail/tail_calls/dangling-local-var.rs:LL:CC --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
| |
LL | f(std::ptr::null()); LL | let _val = unsafe { *x };
| ^^^^^^^^^^^^^^^^^^^ | ^^^^
= note: stack backtrace: = note: stack backtrace:
0: g 0: g
at tests/fail/tail_calls/dangling-local-var.rs:LL:CC at tests/fail/tail_calls/dangling-local-var.rs:LL:CC

View file

@ -0,0 +1,8 @@
//@compile-flags: -Zmiri-recursive-validation
fn main() {
let x = 3u8;
let xref = &x;
let xref_wrong_type: Box<bool> = unsafe { std::mem::transmute(xref) }; //~ERROR: encountered 0x03, but expected a boolean
let _val = *xref_wrong_type;
}

View file

@ -0,0 +1,13 @@
error: Undefined Behavior: constructing invalid value at .<deref>: encountered 0x03, but expected a boolean
--> tests/fail/validity/recursive-validity-box-bool.rs:LL:CC
|
LL | let xref_wrong_type: Box<bool> = unsafe { std::mem::transmute(xref) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View file

@ -4,6 +4,7 @@
fn main() { fn main() {
assert_eq!(factorial(10), 3_628_800); assert_eq!(factorial(10), 3_628_800);
assert_eq!(mutually_recursive_identity(1000), 1000); assert_eq!(mutually_recursive_identity(1000), 1000);
non_scalar();
} }
fn factorial(n: u32) -> u32 { fn factorial(n: u32) -> u32 {
@ -37,3 +38,14 @@ fn mutually_recursive_identity(x: u32) -> u32 {
switch(x, 0) switch(x, 0)
} }
fn non_scalar() {
fn f(x: [usize; 2], i: u32) {
if i == 0 {
return;
}
become f(x, i - 1);
}
f([5, 5], 2);
}

View file

@ -1,5 +1,5 @@
//@ compile-flags: -Copt-level=3 //@ compile-flags: -Copt-level=3
#![feature(panic_internals, const_eval_select, rustc_allow_const_fn_unstable, core_intrinsics)] #![feature(panic_internals, const_eval_select, rustc_attrs, core_intrinsics)]
#![crate_type = "lib"] #![crate_type = "lib"]
// check that assert! and const_assert! emit branch weights // check that assert! and const_assert! emit branch weights

View file

@ -15,13 +15,14 @@ pub fn add_noopt() -> i32 {
#[optimize(none)] #[optimize(none)]
pub fn const_branch() -> i32 { pub fn const_branch() -> i32 {
// CHECK-LABEL: fn const_branch( // CHECK-LABEL: fn const_branch(
// CHECK: switchInt(const true) -> [0: [[FALSE:bb[0-9]+]], otherwise: [[TRUE:bb[0-9]+]]]; // CHECK: [[BOOL:_[0-9]+]] = const true;
// CHECK: switchInt(move [[BOOL]]) -> [0: [[BB_FALSE:bb[0-9]+]], otherwise: [[BB_TRUE:bb[0-9]+]]];
// CHECK-NEXT: } // CHECK-NEXT: }
// CHECK: [[FALSE]]: { // CHECK: [[BB_FALSE]]: {
// CHECK-NEXT: _0 = const 0 // CHECK-NEXT: _0 = const 0
// CHECK-NEXT: goto // CHECK-NEXT: goto
// CHECK-NEXT: } // CHECK-NEXT: }
// CHECK: [[TRUE]]: { // CHECK: [[BB_TRUE]]: {
// CHECK-NEXT: _0 = const 1 // CHECK-NEXT: _0 = const 1
// CHECK-NEXT: goto // CHECK-NEXT: goto
// CHECK-NEXT: } // CHECK-NEXT: }

View file

@ -0,0 +1,11 @@
#![crate_type = "lib"]
#![no_std]
#[inline(never)]
pub fn callee(x: u64) -> u64 {
x.wrapping_mul(3).wrapping_add(7)
}
pub fn caller(a: u64, b: u64) -> u64 {
callee(a) + callee(b)
}

View file

@ -0,0 +1,119 @@
use std::path::Path;
use run_make_support::{CompletedProcess, rfs, rustc};
struct Case {
name: &'static str,
flags: &'static [&'static str],
expect_inline_dump: bool,
expect_running: ExpectedCount,
expect_not_running: ExpectedCount,
}
enum ExpectedCount {
Exactly(usize),
AtLeastOne,
Zero,
}
fn main() {
let cases = [
Case {
name: "limit0",
flags: &["-Zmir-opt-bisect-limit=0"],
expect_inline_dump: false,
expect_running: ExpectedCount::Exactly(0),
expect_not_running: ExpectedCount::AtLeastOne,
},
Case {
name: "limit1",
flags: &["-Zmir-opt-bisect-limit=1"],
expect_inline_dump: false,
expect_running: ExpectedCount::Exactly(1),
expect_not_running: ExpectedCount::AtLeastOne,
},
Case {
name: "huge_limit",
flags: &["-Zmir-opt-bisect-limit=1000000000"],
expect_inline_dump: true,
expect_running: ExpectedCount::AtLeastOne,
expect_not_running: ExpectedCount::Zero,
},
Case {
name: "limit0_with_force_enable_inline",
flags: &["-Zmir-opt-bisect-limit=0", "-Zmir-enable-passes=+Inline"],
expect_inline_dump: false,
expect_running: ExpectedCount::Exactly(0),
expect_not_running: ExpectedCount::AtLeastOne,
},
];
for case in cases {
let (inline_dumped, running_count, not_running_count, output) =
compile_case(case.name, case.flags);
assert_eq!(
inline_dumped, case.expect_inline_dump,
"{}: unexpected Inline dump presence",
case.name
);
assert_expected_count(
running_count,
case.expect_running,
&format!("{}: running count", case.name),
);
assert_expected_count(
not_running_count,
case.expect_not_running,
&format!("{}: NOT running count", case.name),
);
}
}
fn compile_case(dump_dir: &str, extra_flags: &[&str]) -> (bool, usize, usize, CompletedProcess) {
if Path::new(dump_dir).exists() {
rfs::remove_dir_all(dump_dir);
}
rfs::create_dir_all(dump_dir);
let mut cmd = rustc();
cmd.input("main.rs")
.arg("--emit=mir")
.arg("-Zmir-opt-level=2")
.arg("-Copt-level=2")
.arg("-Zthreads=1")
.arg("-Zdump-mir=Inline")
.arg(format!("-Zdump-mir-dir={dump_dir}"));
for &flag in extra_flags {
cmd.arg(flag);
}
let output = cmd.run();
let (running_count, not_running_count) = bisect_line_counts(&output);
(has_inline_dump_file(dump_dir), running_count, not_running_count, output)
}
fn assert_expected_count(actual: usize, expected: ExpectedCount, context: &str) {
match expected {
ExpectedCount::Exactly(n) => assert_eq!(actual, n, "{context}"),
ExpectedCount::AtLeastOne => assert!(actual > 0, "{context}"),
ExpectedCount::Zero => assert_eq!(actual, 0, "{context}"),
}
}
fn has_inline_dump_file(dir: &str) -> bool {
rfs::read_dir(dir)
.flatten()
.any(|entry| entry.file_name().to_string_lossy().contains(".Inline."))
}
fn bisect_line_counts(output: &CompletedProcess) -> (usize, usize) {
let stderr = output.stderr_utf8();
let running_count =
stderr.lines().filter(|line| line.starts_with("BISECT: running pass (")).count();
let not_running_count =
stderr.lines().filter(|line| line.starts_with("BISECT: NOT running pass (")).count();
(running_count, not_running_count)
}

View file

@ -0,0 +1,18 @@
//@ compile-flags: -Znext-solver=globally
// Regression test for https://github.com/rust-lang/rust/issues/152684.
#![feature(associated_type_defaults)]
trait Foo {
type Assoc<T = u8> = T;
//~^ ERROR defaults for generic parameters are not allowed here
fn foo() -> Self::Assoc;
}
impl Foo for () {
fn foo() -> Self::Assoc {
[] //~ ERROR mismatched types
}
}
fn main() {}

View file

@ -0,0 +1,20 @@
error: defaults for generic parameters are not allowed here
--> $DIR/suggest-param-env-shadowing-incompatible-args.rs:8:16
|
LL | type Assoc<T = u8> = T;
| ^^^^^^
error[E0308]: mismatched types
--> $DIR/suggest-param-env-shadowing-incompatible-args.rs:14:9
|
LL | fn foo() -> Self::Assoc {
| ----------- expected `<() as Foo>::Assoc` because of return type
LL | []
| ^^ expected `u8`, found `[_; 0]`
|
= note: expected type `u8`
found array `[_; 0]`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -2,7 +2,6 @@
// We enable a bunch of features to not get feature-gate errs in this test. // We enable a bunch of features to not get feature-gate errs in this test.
#![deny(invalid_doc_attributes)] #![deny(invalid_doc_attributes)]
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![feature(rustc_allow_const_fn_unstable)]
#![feature(allow_internal_unstable)] #![feature(allow_internal_unstable)]
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
#![feature(fn_align)] #![feature(fn_align)]

View file

@ -1,5 +1,5 @@
error[E0539]: malformed `cfg` attribute input error[E0539]: malformed `cfg` attribute input
--> $DIR/malformed-attrs.rs:107:1 --> $DIR/malformed-attrs.rs:106:1
| |
LL | #[cfg] LL | #[cfg]
| ^^^^^^ | ^^^^^^
@ -10,7 +10,7 @@ LL | #[cfg]
= note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
error[E0539]: malformed `cfg_attr` attribute input error[E0539]: malformed `cfg_attr` attribute input
--> $DIR/malformed-attrs.rs:109:1 --> $DIR/malformed-attrs.rs:108:1
| |
LL | #[cfg_attr] LL | #[cfg_attr]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -21,13 +21,13 @@ LL | #[cfg_attr]
= note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
error[E0463]: can't find crate for `wloop` error[E0463]: can't find crate for `wloop`
--> $DIR/malformed-attrs.rs:215:1 --> $DIR/malformed-attrs.rs:214:1
| |
LL | extern crate wloop; LL | extern crate wloop;
| ^^^^^^^^^^^^^^^^^^^ can't find crate | ^^^^^^^^^^^^^^^^^^^ can't find crate
error: malformed `allow` attribute input error: malformed `allow` attribute input
--> $DIR/malformed-attrs.rs:181:1 --> $DIR/malformed-attrs.rs:180:1
| |
LL | #[allow] LL | #[allow]
| ^^^^^^^^ | ^^^^^^^^
@ -43,7 +43,7 @@ LL | #[allow(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++ | +++++++++++++++++++++++++++++++++++++
error: malformed `expect` attribute input error: malformed `expect` attribute input
--> $DIR/malformed-attrs.rs:183:1 --> $DIR/malformed-attrs.rs:182:1
| |
LL | #[expect] LL | #[expect]
| ^^^^^^^^^ | ^^^^^^^^^
@ -59,7 +59,7 @@ LL | #[expect(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++ | +++++++++++++++++++++++++++++++++++++
error: malformed `warn` attribute input error: malformed `warn` attribute input
--> $DIR/malformed-attrs.rs:185:1 --> $DIR/malformed-attrs.rs:184:1
| |
LL | #[warn] LL | #[warn]
| ^^^^^^^ | ^^^^^^^
@ -75,7 +75,7 @@ LL | #[warn(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++ | +++++++++++++++++++++++++++++++++++++
error: malformed `deny` attribute input error: malformed `deny` attribute input
--> $DIR/malformed-attrs.rs:187:1 --> $DIR/malformed-attrs.rs:186:1
| |
LL | #[deny] LL | #[deny]
| ^^^^^^^ | ^^^^^^^
@ -91,7 +91,7 @@ LL | #[deny(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++ | +++++++++++++++++++++++++++++++++++++
error: malformed `forbid` attribute input error: malformed `forbid` attribute input
--> $DIR/malformed-attrs.rs:189:1 --> $DIR/malformed-attrs.rs:188:1
| |
LL | #[forbid] LL | #[forbid]
| ^^^^^^^^^ | ^^^^^^^^^
@ -107,25 +107,25 @@ LL | #[forbid(lint1, lint2, lint3, reason = "...")]
| +++++++++++++++++++++++++++++++++++++ | +++++++++++++++++++++++++++++++++++++
error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type
--> $DIR/malformed-attrs.rs:104:1 --> $DIR/malformed-attrs.rs:103:1
| |
LL | #[proc_macro = 18] LL | #[proc_macro = 18]
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type
--> $DIR/malformed-attrs.rs:121:1 --> $DIR/malformed-attrs.rs:120:1
| |
LL | #[proc_macro_attribute = 19] LL | #[proc_macro_attribute = 19]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
--> $DIR/malformed-attrs.rs:128:1 --> $DIR/malformed-attrs.rs:127:1
| |
LL | #[proc_macro_derive] LL | #[proc_macro_derive]
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^
error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint error[E0658]: allow_internal_unsafe side-steps the unsafe_code lint
--> $DIR/malformed-attrs.rs:220:1 --> $DIR/malformed-attrs.rs:219:1
| |
LL | #[allow_internal_unsafe = 1] LL | #[allow_internal_unsafe = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -134,7 +134,7 @@ LL | #[allow_internal_unsafe = 1]
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0539]: malformed `windows_subsystem` attribute input error[E0539]: malformed `windows_subsystem` attribute input
--> $DIR/malformed-attrs.rs:27:1 --> $DIR/malformed-attrs.rs:26:1
| |
LL | #![windows_subsystem] LL | #![windows_subsystem]
| ^^^-----------------^ | ^^^-----------------^
@ -150,25 +150,25 @@ LL | #![windows_subsystem = "windows"]
| +++++++++++ | +++++++++++
error[E0539]: malformed `export_name` attribute input error[E0539]: malformed `export_name` attribute input
--> $DIR/malformed-attrs.rs:30:1 --> $DIR/malformed-attrs.rs:29:1
| |
LL | #[unsafe(export_name)] LL | #[unsafe(export_name)]
| ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]` | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]`
error: `rustc_allow_const_fn_unstable` expects a list of feature names error: `rustc_allow_const_fn_unstable` expects a list of feature names
--> $DIR/malformed-attrs.rs:32:1 --> $DIR/malformed-attrs.rs:31:1
| |
LL | #[rustc_allow_const_fn_unstable] LL | #[rustc_allow_const_fn_unstable]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `allow_internal_unstable` expects a list of feature names error: `allow_internal_unstable` expects a list of feature names
--> $DIR/malformed-attrs.rs:35:1 --> $DIR/malformed-attrs.rs:34:1
| |
LL | #[allow_internal_unstable] LL | #[allow_internal_unstable]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0539]: malformed `rustc_confusables` attribute input error[E0539]: malformed `rustc_confusables` attribute input
--> $DIR/malformed-attrs.rs:37:1 --> $DIR/malformed-attrs.rs:36:1
| |
LL | #[rustc_confusables] LL | #[rustc_confusables]
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^
@ -177,7 +177,7 @@ LL | #[rustc_confusables]
| help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` | help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]`
error: `#[rustc_confusables]` attribute cannot be used on functions error: `#[rustc_confusables]` attribute cannot be used on functions
--> $DIR/malformed-attrs.rs:37:1 --> $DIR/malformed-attrs.rs:36:1
| |
LL | #[rustc_confusables] LL | #[rustc_confusables]
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^
@ -185,7 +185,7 @@ LL | #[rustc_confusables]
= help: `#[rustc_confusables]` can only be applied to inherent methods = help: `#[rustc_confusables]` can only be applied to inherent methods
error[E0539]: malformed `deprecated` attribute input error[E0539]: malformed `deprecated` attribute input
--> $DIR/malformed-attrs.rs:40:1 --> $DIR/malformed-attrs.rs:39:1
| |
LL | #[deprecated = 5] LL | #[deprecated = 5]
| ^^^^^^^^^^^^^^^-^ | ^^^^^^^^^^^^^^^-^
@ -193,7 +193,7 @@ LL | #[deprecated = 5]
| expected a string literal here | expected a string literal here
error[E0539]: malformed `rustc_macro_transparency` attribute input error[E0539]: malformed `rustc_macro_transparency` attribute input
--> $DIR/malformed-attrs.rs:44:1 --> $DIR/malformed-attrs.rs:43:1
| |
LL | #[rustc_macro_transparency] LL | #[rustc_macro_transparency]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -208,7 +208,7 @@ LL | #[rustc_macro_transparency = "transparent"]
| +++++++++++++++ | +++++++++++++++
error: `#[rustc_macro_transparency]` attribute cannot be used on functions error: `#[rustc_macro_transparency]` attribute cannot be used on functions
--> $DIR/malformed-attrs.rs:44:1 --> $DIR/malformed-attrs.rs:43:1
| |
LL | #[rustc_macro_transparency] LL | #[rustc_macro_transparency]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -216,7 +216,7 @@ LL | #[rustc_macro_transparency]
= help: `#[rustc_macro_transparency]` can only be applied to macro defs = help: `#[rustc_macro_transparency]` can only be applied to macro defs
error[E0539]: malformed `repr` attribute input error[E0539]: malformed `repr` attribute input
--> $DIR/malformed-attrs.rs:47:1 --> $DIR/malformed-attrs.rs:46:1
| |
LL | #[repr] LL | #[repr]
| ^^^^^^^ expected this to be a list | ^^^^^^^ expected this to be a list
@ -224,7 +224,7 @@ LL | #[repr]
= note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations> = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations>
error[E0565]: malformed `rustc_as_ptr` attribute input error[E0565]: malformed `rustc_as_ptr` attribute input
--> $DIR/malformed-attrs.rs:50:1 --> $DIR/malformed-attrs.rs:49:1
| |
LL | #[rustc_as_ptr = 5] LL | #[rustc_as_ptr = 5]
| ^^^^^^^^^^^^^^^---^ | ^^^^^^^^^^^^^^^---^
@ -233,7 +233,7 @@ LL | #[rustc_as_ptr = 5]
| help: must be of the form: `#[rustc_as_ptr]` | help: must be of the form: `#[rustc_as_ptr]`
error[E0539]: malformed `rustc_align` attribute input error[E0539]: malformed `rustc_align` attribute input
--> $DIR/malformed-attrs.rs:55:1 --> $DIR/malformed-attrs.rs:54:1
| |
LL | #[rustc_align] LL | #[rustc_align]
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
@ -242,7 +242,7 @@ LL | #[rustc_align]
| help: must be of the form: `#[rustc_align(<alignment in bytes>)]` | help: must be of the form: `#[rustc_align(<alignment in bytes>)]`
error[E0539]: malformed `optimize` attribute input error[E0539]: malformed `optimize` attribute input
--> $DIR/malformed-attrs.rs:57:1 --> $DIR/malformed-attrs.rs:56:1
| |
LL | #[optimize] LL | #[optimize]
| ^^^^^^^^^^^ expected this to be a list | ^^^^^^^^^^^ expected this to be a list
@ -257,7 +257,7 @@ LL | #[optimize(speed)]
| +++++++ | +++++++
error[E0565]: malformed `cold` attribute input error[E0565]: malformed `cold` attribute input
--> $DIR/malformed-attrs.rs:59:1 --> $DIR/malformed-attrs.rs:58:1
| |
LL | #[cold = 1] LL | #[cold = 1]
| ^^^^^^^---^ | ^^^^^^^---^
@ -266,7 +266,7 @@ LL | #[cold = 1]
| help: must be of the form: `#[cold]` | help: must be of the form: `#[cold]`
error[E0539]: malformed `must_use` attribute input error[E0539]: malformed `must_use` attribute input
--> $DIR/malformed-attrs.rs:61:1 --> $DIR/malformed-attrs.rs:60:1
| |
LL | #[must_use()] LL | #[must_use()]
| ^^^^^^^^^^--^ | ^^^^^^^^^^--^
@ -284,7 +284,7 @@ LL + #[must_use]
| |
error[E0565]: malformed `no_mangle` attribute input error[E0565]: malformed `no_mangle` attribute input
--> $DIR/malformed-attrs.rs:63:1 --> $DIR/malformed-attrs.rs:62:1
| |
LL | #[no_mangle = 1] LL | #[no_mangle = 1]
| ^^^^^^^^^^^^---^ | ^^^^^^^^^^^^---^
@ -293,7 +293,7 @@ LL | #[no_mangle = 1]
| help: must be of the form: `#[no_mangle]` | help: must be of the form: `#[no_mangle]`
error[E0565]: malformed `naked` attribute input error[E0565]: malformed `naked` attribute input
--> $DIR/malformed-attrs.rs:65:1 --> $DIR/malformed-attrs.rs:64:1
| |
LL | #[unsafe(naked())] LL | #[unsafe(naked())]
| ^^^^^^^^^^^^^^--^^ | ^^^^^^^^^^^^^^--^^
@ -302,7 +302,7 @@ LL | #[unsafe(naked())]
| help: must be of the form: `#[naked]` | help: must be of the form: `#[naked]`
error[E0565]: malformed `track_caller` attribute input error[E0565]: malformed `track_caller` attribute input
--> $DIR/malformed-attrs.rs:67:1 --> $DIR/malformed-attrs.rs:66:1
| |
LL | #[track_caller()] LL | #[track_caller()]
| ^^^^^^^^^^^^^^--^ | ^^^^^^^^^^^^^^--^
@ -311,13 +311,13 @@ LL | #[track_caller()]
| help: must be of the form: `#[track_caller]` | help: must be of the form: `#[track_caller]`
error[E0539]: malformed `export_name` attribute input error[E0539]: malformed `export_name` attribute input
--> $DIR/malformed-attrs.rs:69:1 --> $DIR/malformed-attrs.rs:68:1
| |
LL | #[export_name()] LL | #[export_name()]
| ^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]` | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[export_name = "name"]`
error[E0805]: malformed `used` attribute input error[E0805]: malformed `used` attribute input
--> $DIR/malformed-attrs.rs:71:1 --> $DIR/malformed-attrs.rs:70:1
| |
LL | #[used()] LL | #[used()]
| ^^^^^^--^ | ^^^^^^--^
@ -335,7 +335,7 @@ LL + #[used]
| |
error: `#[used]` attribute cannot be used on functions error: `#[used]` attribute cannot be used on functions
--> $DIR/malformed-attrs.rs:71:1 --> $DIR/malformed-attrs.rs:70:1
| |
LL | #[used()] LL | #[used()]
| ^^^^^^^^^ | ^^^^^^^^^
@ -343,13 +343,13 @@ LL | #[used()]
= help: `#[used]` can only be applied to statics = help: `#[used]` can only be applied to statics
error[E0539]: malformed `crate_name` attribute input error[E0539]: malformed `crate_name` attribute input
--> $DIR/malformed-attrs.rs:74:1 --> $DIR/malformed-attrs.rs:73:1
| |
LL | #[crate_name] LL | #[crate_name]
| ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]` | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]`
error[E0539]: malformed `target_feature` attribute input error[E0539]: malformed `target_feature` attribute input
--> $DIR/malformed-attrs.rs:79:1 --> $DIR/malformed-attrs.rs:78:1
| |
LL | #[target_feature] LL | #[target_feature]
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
@ -358,7 +358,7 @@ LL | #[target_feature]
| help: must be of the form: `#[target_feature(enable = "feat1, feat2")]` | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]`
error[E0565]: malformed `export_stable` attribute input error[E0565]: malformed `export_stable` attribute input
--> $DIR/malformed-attrs.rs:81:1 --> $DIR/malformed-attrs.rs:80:1
| |
LL | #[export_stable = 1] LL | #[export_stable = 1]
| ^^^^^^^^^^^^^^^^---^ | ^^^^^^^^^^^^^^^^---^
@ -367,7 +367,7 @@ LL | #[export_stable = 1]
| help: must be of the form: `#[export_stable]` | help: must be of the form: `#[export_stable]`
error[E0539]: malformed `link` attribute input error[E0539]: malformed `link` attribute input
--> $DIR/malformed-attrs.rs:83:1 --> $DIR/malformed-attrs.rs:82:1
| |
LL | #[link] LL | #[link]
| ^^^^^^^ expected this to be a list | ^^^^^^^ expected this to be a list
@ -375,7 +375,7 @@ LL | #[link]
= note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
error[E0539]: malformed `link_name` attribute input error[E0539]: malformed `link_name` attribute input
--> $DIR/malformed-attrs.rs:87:1 --> $DIR/malformed-attrs.rs:86:1
| |
LL | #[link_name] LL | #[link_name]
| ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]` | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]`
@ -383,7 +383,7 @@ LL | #[link_name]
= note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute>
error[E0539]: malformed `link_section` attribute input error[E0539]: malformed `link_section` attribute input
--> $DIR/malformed-attrs.rs:91:1 --> $DIR/malformed-attrs.rs:90:1
| |
LL | #[link_section] LL | #[link_section]
| ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]` | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]`
@ -391,7 +391,7 @@ LL | #[link_section]
= note: for more information, visit <https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute>
error[E0539]: malformed `coverage` attribute input error[E0539]: malformed `coverage` attribute input
--> $DIR/malformed-attrs.rs:93:1 --> $DIR/malformed-attrs.rs:92:1
| |
LL | #[coverage] LL | #[coverage]
| ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument | ^^^^^^^^^^^ this attribute is only valid with either `on` or `off` as an argument
@ -404,13 +404,13 @@ LL | #[coverage(on)]
| ++++ | ++++
error[E0539]: malformed `sanitize` attribute input error[E0539]: malformed `sanitize` attribute input
--> $DIR/malformed-attrs.rs:95:1 --> $DIR/malformed-attrs.rs:94:1
| |
LL | #[sanitize] LL | #[sanitize]
| ^^^^^^^^^^^ expected this to be a list | ^^^^^^^^^^^ expected this to be a list
error[E0565]: malformed `no_implicit_prelude` attribute input error[E0565]: malformed `no_implicit_prelude` attribute input
--> $DIR/malformed-attrs.rs:100:1 --> $DIR/malformed-attrs.rs:99:1
| |
LL | #[no_implicit_prelude = 23] LL | #[no_implicit_prelude = 23]
| ^^^^^^^^^^^^^^^^^^^^^^----^ | ^^^^^^^^^^^^^^^^^^^^^^----^
@ -419,7 +419,7 @@ LL | #[no_implicit_prelude = 23]
| help: must be of the form: `#[no_implicit_prelude]` | help: must be of the form: `#[no_implicit_prelude]`
error[E0565]: malformed `proc_macro` attribute input error[E0565]: malformed `proc_macro` attribute input
--> $DIR/malformed-attrs.rs:104:1 --> $DIR/malformed-attrs.rs:103:1
| |
LL | #[proc_macro = 18] LL | #[proc_macro = 18]
| ^^^^^^^^^^^^^----^ | ^^^^^^^^^^^^^----^
@ -428,7 +428,7 @@ LL | #[proc_macro = 18]
| help: must be of the form: `#[proc_macro]` | help: must be of the form: `#[proc_macro]`
error[E0539]: malformed `instruction_set` attribute input error[E0539]: malformed `instruction_set` attribute input
--> $DIR/malformed-attrs.rs:111:1 --> $DIR/malformed-attrs.rs:110:1
| |
LL | #[instruction_set] LL | #[instruction_set]
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
@ -439,7 +439,7 @@ LL | #[instruction_set]
= note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute>
error[E0539]: malformed `patchable_function_entry` attribute input error[E0539]: malformed `patchable_function_entry` attribute input
--> $DIR/malformed-attrs.rs:113:1 --> $DIR/malformed-attrs.rs:112:1
| |
LL | #[patchable_function_entry] LL | #[patchable_function_entry]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -448,7 +448,7 @@ LL | #[patchable_function_entry]
| help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` | help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]`
error[E0565]: malformed `coroutine` attribute input error[E0565]: malformed `coroutine` attribute input
--> $DIR/malformed-attrs.rs:116:5 --> $DIR/malformed-attrs.rs:115:5
| |
LL | #[coroutine = 63] || {} LL | #[coroutine = 63] || {}
| ^^^^^^^^^^^^----^ | ^^^^^^^^^^^^----^
@ -457,7 +457,7 @@ LL | #[coroutine = 63] || {}
| help: must be of the form: `#[coroutine]` | help: must be of the form: `#[coroutine]`
error[E0565]: malformed `proc_macro_attribute` attribute input error[E0565]: malformed `proc_macro_attribute` attribute input
--> $DIR/malformed-attrs.rs:121:1 --> $DIR/malformed-attrs.rs:120:1
| |
LL | #[proc_macro_attribute = 19] LL | #[proc_macro_attribute = 19]
| ^^^^^^^^^^^^^^^^^^^^^^^----^ | ^^^^^^^^^^^^^^^^^^^^^^^----^
@ -466,7 +466,7 @@ LL | #[proc_macro_attribute = 19]
| help: must be of the form: `#[proc_macro_attribute]` | help: must be of the form: `#[proc_macro_attribute]`
error[E0539]: malformed `must_use` attribute input error[E0539]: malformed `must_use` attribute input
--> $DIR/malformed-attrs.rs:124:1 --> $DIR/malformed-attrs.rs:123:1
| |
LL | #[must_use = 1] LL | #[must_use = 1]
| ^^^^^^^^^^^^^-^ | ^^^^^^^^^^^^^-^
@ -484,7 +484,7 @@ LL + #[must_use]
| |
error[E0539]: malformed `proc_macro_derive` attribute input error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/malformed-attrs.rs:128:1 --> $DIR/malformed-attrs.rs:127:1
| |
LL | #[proc_macro_derive] LL | #[proc_macro_derive]
| ^^^^^^^^^^^^^^^^^^^^ expected this to be a list | ^^^^^^^^^^^^^^^^^^^^ expected this to be a list
@ -498,7 +498,7 @@ LL | #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
| ++++++++++++++++++++++++++++++++++++++++++ | ++++++++++++++++++++++++++++++++++++++++++
error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input
--> $DIR/malformed-attrs.rs:133:1 --> $DIR/malformed-attrs.rs:132:1
| |
LL | #[rustc_layout_scalar_valid_range_start] LL | #[rustc_layout_scalar_valid_range_start]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -507,7 +507,7 @@ LL | #[rustc_layout_scalar_valid_range_start]
| help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]`
error[E0539]: malformed `rustc_layout_scalar_valid_range_end` attribute input error[E0539]: malformed `rustc_layout_scalar_valid_range_end` attribute input
--> $DIR/malformed-attrs.rs:135:1 --> $DIR/malformed-attrs.rs:134:1
| |
LL | #[rustc_layout_scalar_valid_range_end] LL | #[rustc_layout_scalar_valid_range_end]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -516,7 +516,7 @@ LL | #[rustc_layout_scalar_valid_range_end]
| help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]` | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]`
error[E0539]: malformed `must_not_suspend` attribute input error[E0539]: malformed `must_not_suspend` attribute input
--> $DIR/malformed-attrs.rs:137:1 --> $DIR/malformed-attrs.rs:136:1
| |
LL | #[must_not_suspend()] LL | #[must_not_suspend()]
| ^^^^^^^^^^^^^^^^^^--^ | ^^^^^^^^^^^^^^^^^^--^
@ -532,7 +532,7 @@ LL + #[must_not_suspend]
| |
error[E0539]: malformed `cfi_encoding` attribute input error[E0539]: malformed `cfi_encoding` attribute input
--> $DIR/malformed-attrs.rs:139:1 --> $DIR/malformed-attrs.rs:138:1
| |
LL | #[cfi_encoding = ""] LL | #[cfi_encoding = ""]
| ^^^^^^^^^^^^^^^^^--^ | ^^^^^^^^^^^^^^^^^--^
@ -541,7 +541,7 @@ LL | #[cfi_encoding = ""]
| help: must be of the form: `#[cfi_encoding = "encoding"]` | help: must be of the form: `#[cfi_encoding = "encoding"]`
error[E0565]: malformed `marker` attribute input error[E0565]: malformed `marker` attribute input
--> $DIR/malformed-attrs.rs:158:1 --> $DIR/malformed-attrs.rs:157:1
| |
LL | #[marker = 3] LL | #[marker = 3]
| ^^^^^^^^^---^ | ^^^^^^^^^---^
@ -550,7 +550,7 @@ LL | #[marker = 3]
| help: must be of the form: `#[marker]` | help: must be of the form: `#[marker]`
error[E0565]: malformed `fundamental` attribute input error[E0565]: malformed `fundamental` attribute input
--> $DIR/malformed-attrs.rs:160:1 --> $DIR/malformed-attrs.rs:159:1
| |
LL | #[fundamental()] LL | #[fundamental()]
| ^^^^^^^^^^^^^--^ | ^^^^^^^^^^^^^--^
@ -559,7 +559,7 @@ LL | #[fundamental()]
| help: must be of the form: `#[fundamental]` | help: must be of the form: `#[fundamental]`
error[E0565]: malformed `ffi_pure` attribute input error[E0565]: malformed `ffi_pure` attribute input
--> $DIR/malformed-attrs.rs:168:5 --> $DIR/malformed-attrs.rs:167:5
| |
LL | #[unsafe(ffi_pure = 1)] LL | #[unsafe(ffi_pure = 1)]
| ^^^^^^^^^^^^^^^^^^---^^ | ^^^^^^^^^^^^^^^^^^---^^
@ -568,7 +568,7 @@ LL | #[unsafe(ffi_pure = 1)]
| help: must be of the form: `#[ffi_pure]` | help: must be of the form: `#[ffi_pure]`
error[E0539]: malformed `link_ordinal` attribute input error[E0539]: malformed `link_ordinal` attribute input
--> $DIR/malformed-attrs.rs:170:5 --> $DIR/malformed-attrs.rs:169:5
| |
LL | #[link_ordinal] LL | #[link_ordinal]
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
@ -579,7 +579,7 @@ LL | #[link_ordinal]
= note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute>
error[E0565]: malformed `ffi_const` attribute input error[E0565]: malformed `ffi_const` attribute input
--> $DIR/malformed-attrs.rs:174:5 --> $DIR/malformed-attrs.rs:173:5
| |
LL | #[unsafe(ffi_const = 1)] LL | #[unsafe(ffi_const = 1)]
| ^^^^^^^^^^^^^^^^^^^---^^ | ^^^^^^^^^^^^^^^^^^^---^^
@ -588,13 +588,13 @@ LL | #[unsafe(ffi_const = 1)]
| help: must be of the form: `#[ffi_const]` | help: must be of the form: `#[ffi_const]`
error[E0539]: malformed `linkage` attribute input error[E0539]: malformed `linkage` attribute input
--> $DIR/malformed-attrs.rs:176:5 --> $DIR/malformed-attrs.rs:175:5
| |
LL | #[linkage] LL | #[linkage]
| ^^^^^^^^^^ expected this to be of the form `linkage = "..."` | ^^^^^^^^^^ expected this to be of the form `linkage = "..."`
error[E0539]: malformed `debugger_visualizer` attribute input error[E0539]: malformed `debugger_visualizer` attribute input
--> $DIR/malformed-attrs.rs:191:1 --> $DIR/malformed-attrs.rs:190:1
| |
LL | #[debugger_visualizer] LL | #[debugger_visualizer]
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
@ -605,7 +605,7 @@ LL | #[debugger_visualizer]
= note: for more information, visit <https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute> = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute>
error[E0565]: malformed `automatically_derived` attribute input error[E0565]: malformed `automatically_derived` attribute input
--> $DIR/malformed-attrs.rs:193:1 --> $DIR/malformed-attrs.rs:192:1
| |
LL | #[automatically_derived = 18] LL | #[automatically_derived = 18]
| ^^^^^^^^^^^^^^^^^^^^^^^^----^ | ^^^^^^^^^^^^^^^^^^^^^^^^----^
@ -614,7 +614,7 @@ LL | #[automatically_derived = 18]
| help: must be of the form: `#[automatically_derived]` | help: must be of the form: `#[automatically_derived]`
error[E0565]: malformed `non_exhaustive` attribute input error[E0565]: malformed `non_exhaustive` attribute input
--> $DIR/malformed-attrs.rs:201:1 --> $DIR/malformed-attrs.rs:200:1
| |
LL | #[non_exhaustive = 1] LL | #[non_exhaustive = 1]
| ^^^^^^^^^^^^^^^^^---^ | ^^^^^^^^^^^^^^^^^---^
@ -623,7 +623,7 @@ LL | #[non_exhaustive = 1]
| help: must be of the form: `#[non_exhaustive]` | help: must be of the form: `#[non_exhaustive]`
error[E0565]: malformed `thread_local` attribute input error[E0565]: malformed `thread_local` attribute input
--> $DIR/malformed-attrs.rs:207:1 --> $DIR/malformed-attrs.rs:206:1
| |
LL | #[thread_local()] LL | #[thread_local()]
| ^^^^^^^^^^^^^^--^ | ^^^^^^^^^^^^^^--^
@ -632,7 +632,7 @@ LL | #[thread_local()]
| help: must be of the form: `#[thread_local]` | help: must be of the form: `#[thread_local]`
error[E0565]: malformed `no_link` attribute input error[E0565]: malformed `no_link` attribute input
--> $DIR/malformed-attrs.rs:211:1 --> $DIR/malformed-attrs.rs:210:1
| |
LL | #[no_link()] LL | #[no_link()]
| ^^^^^^^^^--^ | ^^^^^^^^^--^
@ -641,7 +641,7 @@ LL | #[no_link()]
| help: must be of the form: `#[no_link]` | help: must be of the form: `#[no_link]`
error[E0539]: malformed `macro_use` attribute input error[E0539]: malformed `macro_use` attribute input
--> $DIR/malformed-attrs.rs:213:1 --> $DIR/malformed-attrs.rs:212:1
| |
LL | #[macro_use = 1] LL | #[macro_use = 1]
| ^^^^^^^^^^^^---^ | ^^^^^^^^^^^^---^
@ -659,7 +659,7 @@ LL + #[macro_use]
| |
error[E0539]: malformed `macro_export` attribute input error[E0539]: malformed `macro_export` attribute input
--> $DIR/malformed-attrs.rs:218:1 --> $DIR/malformed-attrs.rs:217:1
| |
LL | #[macro_export = 18] LL | #[macro_export = 18]
| ^^^^^^^^^^^^^^^----^ | ^^^^^^^^^^^^^^^----^
@ -676,7 +676,7 @@ LL + #[macro_export]
| |
error[E0565]: malformed `allow_internal_unsafe` attribute input error[E0565]: malformed `allow_internal_unsafe` attribute input
--> $DIR/malformed-attrs.rs:220:1 --> $DIR/malformed-attrs.rs:219:1
| |
LL | #[allow_internal_unsafe = 1] LL | #[allow_internal_unsafe = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^---^ | ^^^^^^^^^^^^^^^^^^^^^^^^---^
@ -685,7 +685,7 @@ LL | #[allow_internal_unsafe = 1]
| help: must be of the form: `#[allow_internal_unsafe]` | help: must be of the form: `#[allow_internal_unsafe]`
error: attribute should be applied to `const fn` error: attribute should be applied to `const fn`
--> $DIR/malformed-attrs.rs:32:1 --> $DIR/malformed-attrs.rs:31:1
| |
LL | #[rustc_allow_const_fn_unstable] LL | #[rustc_allow_const_fn_unstable]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -697,7 +697,7 @@ LL | | }
| |_- not a `const fn` | |_- not a `const fn`
warning: attribute should be applied to an `extern` block with non-Rust ABI warning: attribute should be applied to an `extern` block with non-Rust ABI
--> $DIR/malformed-attrs.rs:83:1 --> $DIR/malformed-attrs.rs:82:1
| |
LL | #[link] LL | #[link]
| ^^^^^^^ | ^^^^^^^
@ -712,19 +712,19 @@ LL | | }
= note: requested on the command line with `-W unused-attributes` = note: requested on the command line with `-W unused-attributes`
error: `#[repr(align(...))]` is not supported on functions error: `#[repr(align(...))]` is not supported on functions
--> $DIR/malformed-attrs.rs:47:1 --> $DIR/malformed-attrs.rs:46:1
| |
LL | #[repr] LL | #[repr]
| ^^^^^^^ | ^^^^^^^
| |
help: use `#[rustc_align(...)]` instead help: use `#[rustc_align(...)]` instead
--> $DIR/malformed-attrs.rs:47:1 --> $DIR/malformed-attrs.rs:46:1
| |
LL | #[repr] LL | #[repr]
| ^^^^^^^ | ^^^^^^^
warning: missing options for `on_unimplemented` attribute warning: missing options for `on_unimplemented` attribute
--> $DIR/malformed-attrs.rs:143:1 --> $DIR/malformed-attrs.rs:142:1
| |
LL | #[diagnostic::on_unimplemented] LL | #[diagnostic::on_unimplemented]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -733,7 +733,7 @@ LL | #[diagnostic::on_unimplemented]
= note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default = note: `#[warn(malformed_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default
warning: malformed `on_unimplemented` attribute warning: malformed `on_unimplemented` attribute
--> $DIR/malformed-attrs.rs:145:1 --> $DIR/malformed-attrs.rs:144:1
| |
LL | #[diagnostic::on_unimplemented = 1] LL | #[diagnostic::on_unimplemented = 1]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here
@ -741,7 +741,7 @@ LL | #[diagnostic::on_unimplemented = 1]
= help: only `message`, `note` and `label` are allowed as options = help: only `message`, `note` and `label` are allowed as options
error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]`
--> $DIR/malformed-attrs.rs:42:1 --> $DIR/malformed-attrs.rs:41:1
| |
LL | #[doc] LL | #[doc]
| ^^^^^^ | ^^^^^^
@ -753,7 +753,7 @@ LL | #![deny(invalid_doc_attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
--> $DIR/malformed-attrs.rs:52:1 --> $DIR/malformed-attrs.rs:51:1
| |
LL | #[inline = 5] LL | #[inline = 5]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
@ -763,13 +763,13 @@ LL | #[inline = 5]
= note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]`
--> $DIR/malformed-attrs.rs:74:1 --> $DIR/malformed-attrs.rs:73:1
| |
LL | #[crate_name] LL | #[crate_name]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
| |
note: this attribute does not have an `!`, which means it is applied to this function note: this attribute does not have an `!`, which means it is applied to this function
--> $DIR/malformed-attrs.rs:115:1 --> $DIR/malformed-attrs.rs:114:1
| |
LL | / fn test() { LL | / fn test() {
LL | | #[coroutine = 63] || {} LL | | #[coroutine = 63] || {}
@ -778,13 +778,13 @@ LL | | }
| |_^ | |_^
error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]` error: valid forms for the attribute are `#[doc = "string"]`, `#[doc(alias)]`, `#[doc(attribute)]`, `#[doc(auto_cfg)]`, `#[doc(cfg)]`, `#[doc(fake_variadic)]`, `#[doc(hidden)]`, `#[doc(html_favicon_url)]`, `#[doc(html_logo_url)]`, `#[doc(html_no_source)]`, `#[doc(html_playground_url)]`, `#[doc(html_root_url)]`, `#[doc(include)]`, `#[doc(inline)]`, `#[doc(issue_tracker_base_url)]`, `#[doc(keyword)]`, `#[doc(masked)]`, `#[doc(no_default_passes)]`, `#[doc(no_inline)]`, `#[doc(notable_trait)]`, `#[doc(passes)]`, `#[doc(plugins)]`, `#[doc(rust_logo)]`, `#[doc(search_unbox)]`, `#[doc(spotlight)]`, and `#[doc(test)]`
--> $DIR/malformed-attrs.rs:77:1 --> $DIR/malformed-attrs.rs:76:1
| |
LL | #[doc] LL | #[doc]
| ^^^^^^ | ^^^^^^
warning: `#[link_name]` attribute cannot be used on functions warning: `#[link_name]` attribute cannot be used on functions
--> $DIR/malformed-attrs.rs:87:1 --> $DIR/malformed-attrs.rs:86:1
| |
LL | #[link_name] LL | #[link_name]
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
@ -793,7 +793,7 @@ LL | #[link_name]
= help: `#[link_name]` can be applied to foreign functions and foreign statics = help: `#[link_name]` can be applied to foreign functions and foreign statics
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
--> $DIR/malformed-attrs.rs:97:1 --> $DIR/malformed-attrs.rs:96:1
| |
LL | #[ignore()] LL | #[ignore()]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -802,7 +802,7 @@ LL | #[ignore()]
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571> = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
warning: `#[no_implicit_prelude]` attribute cannot be used on functions warning: `#[no_implicit_prelude]` attribute cannot be used on functions
--> $DIR/malformed-attrs.rs:100:1 --> $DIR/malformed-attrs.rs:99:1
| |
LL | #[no_implicit_prelude = 23] LL | #[no_implicit_prelude = 23]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -811,13 +811,13 @@ LL | #[no_implicit_prelude = 23]
= help: `#[no_implicit_prelude]` can be applied to crates and modules = help: `#[no_implicit_prelude]` can be applied to crates and modules
warning: `#[diagnostic::do_not_recommend]` does not expect any arguments warning: `#[diagnostic::do_not_recommend]` does not expect any arguments
--> $DIR/malformed-attrs.rs:152:1 --> $DIR/malformed-attrs.rs:151:1
| |
LL | #[diagnostic::do_not_recommend()] LL | #[diagnostic::do_not_recommend()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: `#[automatically_derived]` attribute cannot be used on modules warning: `#[automatically_derived]` attribute cannot be used on modules
--> $DIR/malformed-attrs.rs:193:1 --> $DIR/malformed-attrs.rs:192:1
| |
LL | #[automatically_derived = 18] LL | #[automatically_derived = 18]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -826,7 +826,7 @@ LL | #[automatically_derived = 18]
= help: `#[automatically_derived]` can only be applied to trait impl blocks = help: `#[automatically_derived]` can only be applied to trait impl blocks
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
--> $DIR/malformed-attrs.rs:227:1 --> $DIR/malformed-attrs.rs:226:1
| |
LL | #[ignore = 1] LL | #[ignore = 1]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
@ -835,7 +835,7 @@ LL | #[ignore = 1]
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571> = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/malformed-attrs.rs:116:23 --> $DIR/malformed-attrs.rs:115:23
| |
LL | fn test() { LL | fn test() {
| - help: a return type might be missing here: `-> _` | - help: a return type might be missing here: `-> _`
@ -843,7 +843,7 @@ LL | #[coroutine = 63] || {}
| ^^^^^ expected `()`, found coroutine | ^^^^^ expected `()`, found coroutine
| |
= note: expected unit type `()` = note: expected unit type `()`
found coroutine `{coroutine@$DIR/malformed-attrs.rs:116:23: 116:25}` found coroutine `{coroutine@$DIR/malformed-attrs.rs:115:23: 115:25}`
error: aborting due to 75 previous errors; 8 warnings emitted error: aborting due to 75 previous errors; 8 warnings emitted
@ -851,7 +851,7 @@ Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805
For more information about an error, try `rustc --explain E0308`. For more information about an error, try `rustc --explain E0308`.
Future incompatibility report: Future breakage diagnostic: Future incompatibility report: Future breakage diagnostic:
error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
--> $DIR/malformed-attrs.rs:52:1 --> $DIR/malformed-attrs.rs:51:1
| |
LL | #[inline = 5] LL | #[inline = 5]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
@ -862,7 +862,7 @@ LL | #[inline = 5]
Future breakage diagnostic: Future breakage diagnostic:
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
--> $DIR/malformed-attrs.rs:97:1 --> $DIR/malformed-attrs.rs:96:1
| |
LL | #[ignore()] LL | #[ignore()]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
@ -873,7 +873,7 @@ LL | #[ignore()]
Future breakage diagnostic: Future breakage diagnostic:
error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
--> $DIR/malformed-attrs.rs:227:1 --> $DIR/malformed-attrs.rs:226:1
| |
LL | #[ignore = 1] LL | #[ignore = 1]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^

View file

@ -2,7 +2,7 @@
//@ compile-flags: --crate-type=lib -Cinstrument-coverage -Zno-profiler-runtime //@ compile-flags: --crate-type=lib -Cinstrument-coverage -Zno-profiler-runtime
//@[allow] check-pass //@[allow] check-pass
#![feature(staged_api, rustc_allow_const_fn_unstable)] #![feature(staged_api, rustc_attrs)]
#![stable(feature = "rust_test", since = "1.0.0")] #![stable(feature = "rust_test", since = "1.0.0")]
#[stable(feature = "rust_test", since = "1.0.0")] #[stable(feature = "rust_test", since = "1.0.0")]

View file

@ -4,7 +4,7 @@ error[E0658]: `final` on trait functions is experimental
LL | final fn bar() {} LL | final fn bar() {}
| ^^^^^ | ^^^^^
| |
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information = note: see issue #131179 <https://github.com/rust-lang/rust/issues/131179> for more information
= help: add `#![feature(final_associated_functions)]` to the crate attributes to enable = help: add `#![feature(final_associated_functions)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

View file

@ -1,6 +1,6 @@
#![allow(unused_macros)] #![allow(unused_macros)]
#[rustc_allow_const_fn_unstable()] //~ ERROR rustc_allow_const_fn_unstable side-steps #[rustc_allow_const_fn_unstable()] //~ ERROR use of an internal attribute
const fn foo() { } const fn foo() { }
fn main() {} fn main() {}

View file

@ -1,12 +1,12 @@
error[E0658]: rustc_allow_const_fn_unstable side-steps feature gating and stability checks error[E0658]: use of an internal attribute
--> $DIR/feature-gate-rustc-allow-const-fn-unstable.rs:3:1 --> $DIR/feature-gate-rustc-allow-const-fn-unstable.rs:3:1
| |
LL | #[rustc_allow_const_fn_unstable()] LL | #[rustc_allow_const_fn_unstable()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= note: see issue #69399 <https://github.com/rust-lang/rust/issues/69399> for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
= help: add `#![feature(rustc_allow_const_fn_unstable)]` to the crate attributes to enable = note: the `#[rustc_allow_const_fn_unstable]` attribute is an internal implementation detail that will never be stable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: rustc_allow_const_fn_unstable side-steps feature gating and stability checks
error: aborting due to 1 previous error error: aborting due to 1 previous error

View file

@ -0,0 +1,14 @@
// Regression test for issue #152606.
//@ check-pass
mod outer {
mod inner {
use super::*; // should go before the ambiguous glob imports
}
use crate::*;
pub use crate::*;
}
fn main() {}

View file

@ -0,0 +1,29 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/150077>
//! Tests that `&mut T` suggests `T`, not `mut T`, `&mut str` suggests `String`, not `str`,
//! when recommending an owned value.
fn with_fn(_f: impl Fn() -> &mut ()) {}
//~^ ERROR: missing lifetime specifier
fn with_ref_mut_str(_f: impl Fn() -> &mut str) {}
//~^ ERROR: missing lifetime specifier
fn with_fn_has_return(_f: impl Fn() -> &mut ()) -> i32 {
//~^ ERROR: missing lifetime specifier
2
}
fn with_dyn(_f: Box<dyn Fn() -> &mut i32>) {}
//~^ ERROR: missing lifetime specifier
fn trait_bound<F: Fn() -> &mut i32>(_f: F) {}
//~^ ERROR: missing lifetime specifier
fn nested_result(_f: impl Fn() -> Result<&mut i32, ()>) {}
//~^ ERROR: missing lifetime specifier
struct Holder<F: Fn() -> &mut i32> {
//~^ ERROR: missing lifetime specifier
f: F,
}
fn main() {}

View file

@ -0,0 +1,137 @@
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:4:29
|
LL | fn with_fn(_f: impl Fn() -> &mut ()) {}
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | fn with_fn(_f: impl Fn() -> &'static mut ()) {}
| +++++++
help: instead, you are more likely to want to return an owned value
|
LL - fn with_fn(_f: impl Fn() -> &mut ()) {}
LL + fn with_fn(_f: impl Fn() -> ()) {}
|
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:7:38
|
LL | fn with_ref_mut_str(_f: impl Fn() -> &mut str) {}
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | fn with_ref_mut_str(_f: impl Fn() -> &'static mut str) {}
| +++++++
help: instead, you are more likely to want to return an owned value
|
LL - fn with_ref_mut_str(_f: impl Fn() -> &mut str) {}
LL + fn with_ref_mut_str(_f: impl Fn() -> String) {}
|
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:10:40
|
LL | fn with_fn_has_return(_f: impl Fn() -> &mut ()) -> i32 {
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | fn with_fn_has_return(_f: impl Fn() -> &'static mut ()) -> i32 {
| +++++++
help: consider making the bound lifetime-generic with a new `'a` lifetime
|
LL - fn with_fn_has_return(_f: impl Fn() -> &mut ()) -> i32 {
LL + fn with_fn_has_return(_f: impl for<'a> Fn() -> &'a ()) -> i32 {
|
help: consider introducing a named lifetime parameter
|
LL - fn with_fn_has_return(_f: impl Fn() -> &mut ()) -> i32 {
LL + fn with_fn_has_return<'a>(_f: impl Fn() -> &'a ()) -> i32 {
|
help: alternatively, you might want to return an owned value
|
LL - fn with_fn_has_return(_f: impl Fn() -> &mut ()) -> i32 {
LL + fn with_fn_has_return(_f: impl Fn() -> ()) -> i32 {
|
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:15:33
|
LL | fn with_dyn(_f: Box<dyn Fn() -> &mut i32>) {}
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | fn with_dyn(_f: Box<dyn Fn() -> &'static mut i32>) {}
| +++++++
help: instead, you are more likely to want to return an owned value
|
LL - fn with_dyn(_f: Box<dyn Fn() -> &mut i32>) {}
LL + fn with_dyn(_f: Box<dyn Fn() -> i32>) {}
|
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:18:27
|
LL | fn trait_bound<F: Fn() -> &mut i32>(_f: F) {}
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | fn trait_bound<F: Fn() -> &'static mut i32>(_f: F) {}
| +++++++
help: instead, you are more likely to want to change the argument to be borrowed...
|
LL | fn trait_bound<F: Fn() -> &mut i32>(_f: &F) {}
| +
help: ...or alternatively, you might want to return an owned value
|
LL - fn trait_bound<F: Fn() -> &mut i32>(_f: F) {}
LL + fn trait_bound<F: Fn() -> i32>(_f: F) {}
|
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:21:42
|
LL | fn nested_result(_f: impl Fn() -> Result<&mut i32, ()>) {}
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | fn nested_result(_f: impl Fn() -> Result<&'static mut i32, ()>) {}
| +++++++
help: instead, you are more likely to want to return an owned value
|
LL - fn nested_result(_f: impl Fn() -> Result<&mut i32, ()>) {}
LL + fn nested_result(_f: impl Fn() -> Result<i32, ()>) {}
|
error[E0106]: missing lifetime specifier
--> $DIR/mut-ref-owned-suggestion.rs:24:26
|
LL | struct Holder<F: Fn() -> &mut i32> {
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
|
LL | struct Holder<F: Fn() -> &'static mut i32> {
| +++++++
help: instead, you are more likely to want to return an owned value
|
LL - struct Holder<F: Fn() -> &mut i32> {
LL + struct Holder<F: Fn() -> i32> {
|
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0106`.

View file

@ -0,0 +1,49 @@
// Regression test for https://github.com/rust-lang/rust/issues/65866.
mod plain {
struct Foo;
struct Re<'a> {
_data: &'a u16,
}
trait Bar {
fn bar(&self, r: &mut Re);
//~^ NOTE expected
//~| NOTE `Re` here is elided as `Re<'_>`
}
impl Bar for Foo {
fn bar<'a, 'b>(&'a self, _r: &'b mut Re<'a>) {}
//~^ ERROR `impl` item signature doesn't match `trait` item signature
//~| NOTE expected signature
//~| NOTE found
//~| HELP the lifetime requirements
//~| HELP verify the lifetime relationships
}
}
mod with_type_args {
struct Foo;
struct Re<'a, T> {
_data: (&'a u16, T),
}
trait Bar {
fn bar(&self, r: &mut Re<u8>);
//~^ NOTE expected
//~| NOTE `Re` here is elided as `Re<'_, u8>`
}
impl Bar for Foo {
fn bar<'a, 'b>(&'a self, _r: &'b mut Re<'a, u8>) {}
//~^ ERROR `impl` item signature doesn't match `trait` item signature
//~| NOTE expected signature
//~| NOTE found
//~| HELP the lifetime requirements
//~| HELP verify the lifetime relationships
}
}
fn main() {}

View file

@ -0,0 +1,40 @@
error: `impl` item signature doesn't match `trait` item signature
--> $DIR/trait-impl-mismatch-elided-lifetime-issue-65866.rs:17:9
|
LL | fn bar(&self, r: &mut Re);
| -------------------------- expected `fn(&'1 plain::Foo, &'2 mut plain::Re<'3>)`
...
LL | fn bar<'a, 'b>(&'a self, _r: &'b mut Re<'a>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 plain::Foo, &'2 mut plain::Re<'1>)`
|
= note: expected signature `fn(&'1 plain::Foo, &'2 mut plain::Re<'3>)`
found signature `fn(&'1 plain::Foo, &'2 mut plain::Re<'1>)`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
note: `Re` here is elided as `Re<'_>`
--> $DIR/trait-impl-mismatch-elided-lifetime-issue-65866.rs:11:31
|
LL | fn bar(&self, r: &mut Re);
| ^^
error: `impl` item signature doesn't match `trait` item signature
--> $DIR/trait-impl-mismatch-elided-lifetime-issue-65866.rs:40:9
|
LL | fn bar(&self, r: &mut Re<u8>);
| ------------------------------ expected `fn(&'1 with_type_args::Foo, &'2 mut with_type_args::Re<'3, u8>)`
...
LL | fn bar<'a, 'b>(&'a self, _r: &'b mut Re<'a, u8>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 with_type_args::Foo, &'2 mut with_type_args::Re<'1, u8>)`
|
= note: expected signature `fn(&'1 with_type_args::Foo, &'2 mut with_type_args::Re<'3, u8>)`
found signature `fn(&'1 with_type_args::Foo, &'2 mut with_type_args::Re<'1, u8>)`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
note: `Re` here is elided as `Re<'_, u8>`
--> $DIR/trait-impl-mismatch-elided-lifetime-issue-65866.rs:34:31
|
LL | fn bar(&self, r: &mut Re<u8>);
| ^^
error: aborting due to 2 previous errors

View file

@ -1,12 +0,0 @@
//@ proc-macro: test-macros.rs
//@ compile-flags: -Z span-debug
//@ check-pass
#![no_std] // Don't load unnecessary hygiene information from std
extern crate std;
#[macro_use] extern crate test_macros;
include!("pretty-print-hack/rental-0.5.6/src/lib.rs");
fn main() {}

View file

@ -1,21 +0,0 @@
PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input }
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "enum",
span: $DIR/pretty-print-hack/rental-0.5.6/src/lib.rs:4:1: 4:5 (#0),
},
Ident {
ident: "ProceduralMasqueradeDummyType",
span: $DIR/pretty-print-hack/rental-0.5.6/src/lib.rs:4:6: 4:35 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [
Ident {
ident: "Input",
span: $DIR/pretty-print-hack/rental-0.5.6/src/lib.rs:13:5: 13:10 (#0),
},
],
span: $DIR/pretty-print-hack/rental-0.5.6/src/lib.rs:4:36: 14:2 (#0),
},
]

View file

@ -1,6 +0,0 @@
error: using an old version of `rental`
|
= note: older versions of the `rental` crate no longer compile; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
error: aborting due to 1 previous error

View file

@ -1,6 +0,0 @@
error: using an old version of `rental`
|
= note: older versions of the `rental` crate no longer compile; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives
error: aborting due to 1 previous error

View file

@ -1,21 +0,0 @@
//@ proc-macro: test-macros.rs
//@ compile-flags: -Z span-debug
//@ revisions: local remapped
//@ [remapped] remap-src-base
#![no_std] // Don't load unnecessary hygiene information from std
extern crate std;
#[macro_use] extern crate test_macros;
mod first {
include!("pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs");
}
mod second {
include!("pretty-print-hack/rental-0.5.5/src/lib.rs");
}
fn main() {}
//~? ERROR using an old version of `rental`

View file

@ -1,14 +0,0 @@
//@ ignore-auxiliary (used by `../../../pretty-print-hack-show.rs`)
#[derive(Print)]
enum ProceduralMasqueradeDummyType {
//~^ ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
Input
}

View file

@ -1,14 +0,0 @@
//@ ignore-auxiliary (used by `../../../pretty-print-hack-show.rs`)
#[derive(Print)]
enum ProceduralMasqueradeDummyType {
//~^ ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
Input
}

View file

@ -1,14 +0,0 @@
//@ ignore-auxiliary (used by `../../../pretty-print-hack/hide.rs`)
#[derive(Print)]
enum ProceduralMasqueradeDummyType {
//~^ ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
//~| ERROR using
//~| WARN this was previously
Input
}

View file

@ -0,0 +1,21 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/147958>
//@ check-pass
#![feature(decl_macro)]
macro_rules! exported {
() => {
#[macro_export]
macro_rules! exported {
() => {};
}
};
}
use inner1::*;
exported!();
mod inner1 {
pub macro exported() {}
}
fn main() {}

View file

@ -1,4 +1,5 @@
//@ compile-flags: --test //@ compile-flags: --test
//@ reference: attributes.testing.test.allowed-positions
fn align_offset_weird_strides() { fn align_offset_weird_strides() {
#[test] #[test]

View file

@ -1,5 +1,5 @@
error: the `#[test]` attribute may only be used on a free function error: the `#[test]` attribute may only be used on a free function
--> $DIR/issue-109816.rs:4:5 --> $DIR/issue-109816.rs:5:5
| |
LL | #[test] LL | #[test]
| ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions | ^^^^^^^ the `#[test]` macro causes a function to be run as a test and has no effect on non-functions

View file

@ -1,4 +1,5 @@
//@ compile-flags:--test //@ compile-flags:--test
//@ reference: attributes.testing.test.allowed-positions
struct A {} struct A {}

Some files were not shown because too many files have changed in this diff Show more