Compare commits

...
Sign in to create a new pull request.

43 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
Esteban Küber
257a415e05 Make suggestion verbose and fix incorrect suggestion usage 2026-02-17 16:51:53 +00:00
Esteban Küber
c73b3d20c6 Unify wording of resolve error
Remove "failed to resolve" 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`
```
2026-02-17 16:51:44 +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
364 changed files with 2037 additions and 1545 deletions

View file

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

View file

@ -297,8 +297,9 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
Rvalue::Use(operand)
| Rvalue::Repeat(operand, _)
| Rvalue::UnaryOp(_ /*un_op*/, operand)
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/)
| Rvalue::ShallowInitBox(operand, _ /*ty*/) => self.consume_operand(location, operand),
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/) => {
self.consume_operand(location, operand)
}
&Rvalue::Discriminant(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) => {
match *cast_kind {
CastKind::PointerCoercion(
@ -2231,7 +2220,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
| Rvalue::Ref(..)
| Rvalue::RawPtr(..)
| Rvalue::Cast(..)
| Rvalue::ShallowInitBox(..)
| Rvalue::BinaryOp(..)
| Rvalue::CopyForDeref(..)
| 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);
}
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"),
Rvalue::ShallowInitBox(..) => bug!("`ShallowInitBox` in codegen"),
}
}
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 }
}
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::ShallowInitBox(_, _) => {}
Rvalue::UnaryOp(op, operand) => {
let ty = operand.ty(self.body, self.tcx);
match op {

View file

@ -237,8 +237,7 @@ where
Rvalue::Use(operand)
| Rvalue::Repeat(operand, _)
| Rvalue::UnaryOp(_, operand)
| Rvalue::Cast(_, operand, _)
| Rvalue::ShallowInitBox(operand, _) => in_operand::<Q, _>(cx, in_local, operand),
| Rvalue::Cast(_, operand, _) => in_operand::<Q, _>(cx, in_local, operand),
Rvalue::BinaryOp(_, box (lhs, 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::ShallowInitBox(..)
| mir::Rvalue::Use(..)
| mir::Rvalue::CopyForDeref(..)
| mir::Rvalue::ThreadLocalRef(..)

View file

@ -236,7 +236,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> {
if self.tcx.is_lang_item(def_id, LangItem::PanicDisplay)
|| 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
assert!(args.len() == 1);

View file

@ -19,8 +19,8 @@ use tracing::{info, instrument, trace};
use super::{
CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy,
Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, StackPopInfo, interp_ok,
throw_ub, throw_ub_custom,
Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, interp_ok, throw_ub,
throw_ub_custom,
};
use crate::enter_trace_span;
use crate::interpret::EnteredTraceSpan;
@ -43,25 +43,22 @@ impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> {
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
/// original memory occurs.
pub fn copy_fn_arg(&self, arg: &FnArg<'tcx, M::Provenance>) -> OpTy<'tcx, M::Provenance> {
match arg {
pub fn copy_fn_arg(&self) -> OpTy<'tcx, Prov> {
match self {
FnArg::Copy(op) => op.clone(),
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
/// original memory occurs.
pub fn copy_fn_args(
&self,
args: &[FnArg<'tcx, M::Provenance>],
) -> Vec<OpTy<'tcx, M::Provenance>> {
args.iter().map(|fn_arg| self.copy_fn_arg(fn_arg)).collect()
pub fn copy_fn_args(args: &[FnArg<'tcx, M::Provenance>]) -> Vec<OpTy<'tcx, M::Provenance>> {
args.iter().map(|fn_arg| fn_arg.copy_fn_arg()).collect()
}
/// 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
// 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.
let caller_arg_copy = self.copy_fn_arg(caller_arg);
let caller_arg_copy = caller_arg.copy_fn_arg();
if !already_live {
let local = callee_arg.as_local().unwrap();
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(
self,
instance,
&self.copy_fn_args(args),
&Self::copy_fn_args(args),
destination,
target,
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
// really pass the argument in-place anyway, and we are constructing a new
// `Immediate` receiver.
let mut receiver = self.copy_fn_arg(&args[0]);
let mut receiver = args[0].copy_fn_arg();
let receiver_place = loop {
match receiver.layout.ty.kind() {
ty::Ref(..) | ty::RawPtr(..) => {
@ -824,41 +821,50 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
with_caller_location: bool,
) -> InterpResult<'tcx> {
trace!("init_fn_tail_call: {:#?}", fn_val);
// This is the "canonical" implementation of tails calls,
// a pop of the current stack frame, followed by a normal call
// which pushes a new stack frame, with the return address from
// the popped stack frame.
//
// Note that we are using `pop_stack_frame_raw` and not `return_from_current_stack_frame`,
// as the latter "executes" the goto to the return block, but we don't want to,
// Note that we cannot use `return_from_current_stack_frame`,
// 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.
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);
// Take the "stack pop cleanup" info, and use that to initiate the next call.
let ReturnContinuation::Goto { ret, unwind } = return_cont else {
bug!("can't tailcall as root");
// The arguments need to all be copied since the current stack frame will be removed
// before the callee even starts executing.
// FIXME(explicit_tail_calls,#144855): does this match what codegen does?
let args = args.iter().map(|fn_arg| FnArg::Copy(fn_arg.copy_fn_arg())).collect::<Vec<_>>();
// 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):
// we should check if both caller&callee can/n't unwind,
// see <https://github.com/rust-lang/rust/pull/113128#issuecomment-1614979803>
// Now push the new stack frame.
self.init_fn_call(
fn_val,
(caller_abi, caller_fn_abi),
args,
&*args,
with_caller_location,
&return_place,
frame.return_place(),
ret,
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(
@ -953,14 +959,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// local's value out.
let return_op =
self.local_to_op(mir::RETURN_PLACE, None).expect("return place should always be live");
// Do the actual pop + copy.
let stack_pop_info = self.pop_stack_frame_raw(unwinding, |this, return_place| {
this.copy_op_allow_transmute(&return_op, return_place)?;
trace!("return value: {:?}", this.dump_place(return_place));
interp_ok(())
})?;
match stack_pop_info.return_action {
// Remove the frame from the stack.
let frame = self.pop_stack_frame_raw()?;
// Copy the return value and remember the return continuation.
if !unwinding {
self.copy_op_allow_transmute(&return_op, frame.return_place())?;
trace!("return value: {:?}", self.dump_place(frame.return_place()));
}
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::NoJump => {
// The hook already did everything.
@ -978,7 +988,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Normal return, figure out where to jump.
if unwinding {
// Follow the unwind edge.
match stack_pop_info.return_cont {
match return_cont {
ReturnContinuation::Goto { unwind, .. } => {
// This must be the very last thing that happens, since it can in fact push a new stack frame.
self.unwind_to_block(unwind)
@ -989,7 +999,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
} else {
// Follow the normal return edge.
match stack_pop_info.return_cont {
match return_cont {
ReturnContinuation::Goto { ret, .. } => self.return_to_block(ret),
ReturnContinuation::Stop { .. } => {
assert!(

View file

@ -36,7 +36,7 @@ pub use self::operand::{ImmTy, Immediate, OpTy};
pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable};
use self::place::{MemPlace, Place};
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(crate) use self::util::create_static_alloc;
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
/// *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.
pub return_place: PlaceTy<'tcx, Prov>,
return_place: PlaceTy<'tcx, Prov>,
/// The list of locals for this stack frame, stored in order as
/// `[return_ptr, arguments..., variables..., temporaries...]`.
@ -127,19 +127,6 @@ pub enum ReturnContinuation {
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
#[derive(Clone)]
pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> {
@ -292,6 +279,14 @@ impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> {
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.
pub fn current_source_info(&self) -> Option<&mir::SourceInfo> {
self.loc.left().map(|loc| self.body.source_info(loc))
@ -417,35 +412,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
interp_ok(())
}
/// Low-level helper that pops a stack frame from the stack and returns some information about
/// it.
///
/// This also deallocates locals, if necessary.
/// `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
/// Low-level helper that pops a stack frame from the stack without any cleanup.
/// This invokes `before_stack_pop`.
/// After calling this function, you need to deal with the return value, and then
/// invoke `cleanup_stack_frame`.
pub(super) fn pop_stack_frame_raw(
&mut self,
unwinding: bool,
copy_ret_val: impl FnOnce(&mut Self, &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx>,
) -> InterpResult<'tcx, StackPopInfo<'tcx, M::Provenance>> {
) -> InterpResult<'tcx, Frame<'tcx, M::Provenance, M::FrameExtra>> {
M::before_stack_pop(self)?;
let frame =
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_place = frame.return_place.clone();
// Cleanup: deallocate locals.
// 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,
};
let return_action = if cleanup {
if cleanup {
for local in &frame.locals {
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.
let return_action = M::after_stack_pop(self, frame, unwinding)?;
assert_ne!(return_action, ReturnAction::NoCleanup);
return_action
interp_ok(return_action)
} else {
// We also skip the machine hook when there's no cleanup. This not a real "pop" anyway.
ReturnAction::NoCleanup
};
interp_ok(StackPopInfo { return_action, return_cont, return_place })
interp_ok(ReturnAction::NoCleanup)
}
}
/// 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();
assert!(self.check_argument_compat(caller_abi, callee_abi)?);
// 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)?;
self.copy_op(&op, &mplace)?;

View file

@ -249,12 +249,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
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) => {
let src = self.eval_operand(operand, None)?;
let cast_ty =

View file

@ -647,13 +647,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
}
} else {
// 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
// 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
// FIXME: should we also `UnsafeCell` behind shared references? Currently that is not
// needed since validation reads bypass Stacked Borrows and data race checks.
if matches!(ptr_kind, PointerKind::Box) {
return interp_ok(());
}
}
let path = &self.path;
ref_tracking.track(place, || {

View file

@ -2,12 +2,11 @@ use std::any::Any;
use std::default::Default;
use std::iter;
use std::path::Component::Prefix;
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use std::rc::Rc;
use std::sync::Arc;
use rustc_ast::attr::MarkedAttrs;
use rustc_ast::token::MetaVarKind;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{AssocCtxt, Visitor};
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_lint_defs::RegisteredTools;
use rustc_parse::MACRO_ARGUMENTS;
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser};
use rustc_parse::parser::Parser;
use rustc_session::Session;
use rustc_session::parse::ParseSess;
use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
use rustc_span::edition::Edition;
use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind};
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 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,
}
// 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::*;
mod metavar_exprs {
use super::*;

View file

@ -105,11 +105,6 @@ impl MultiItemModifier for DeriveProcMacro {
// (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
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 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>> {
fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self {
impl FromInternal<TokenStream> for Vec<TokenTree<TokenStream, Span, Symbol>> {
fn from_internal(stream: TokenStream) -> Self {
use rustc_ast::token::*;
// 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() {
let (Token { kind, span }, joint) = match tree.clone() {
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
// of the same `MetaVarKind`. Here we do the same but
// ignore the `MetaVarKind` because it is discarded when we
@ -687,7 +671,7 @@ impl server::Server for Rustc<'_, '_> {
&mut self,
stream: Self::TokenStream,
) -> 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 {

View file

@ -1208,7 +1208,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_intrinsic_const_stable_indirect, Normal,
template!(Word), WarnFollowing, EncodeCrossCrate::No, "this is an internal implementation detail",
),
gated!(
rustc_attr!(
rustc_allow_const_fn_unstable, Normal,
template!(Word, List: &["feat1, feat2, ..."]), DuplicatesOk, EncodeCrossCrate::No,
"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)),
/// Allows using pattern types.
(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.
(unstable, rustc_private, "1.0.0", Some(27812)),
/// Allows using internal rustdoc features like `doc(keyword)`.
@ -493,7 +489,7 @@ declare_features! (
/// Allows the use of `#[ffi_pure]` on foreign functions.
(unstable, ffi_pure, "1.45.0", Some(58329)),
/// 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
(unstable, fmt_debug, "1.82.0", Some(129709)),
/// 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) {
format!("{:?}({})", dep_node.kind, self.tcx.def_path_str(def_id))
} 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
//! 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.)
//! and a [`Fingerprint`], a 128-bit hash value, the exact meaning of which
//! depends on the node's `DepKind`. Together, the kind and the fingerprint
//! 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 key fingerprint
//! 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
//! 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
@ -41,17 +41,9 @@
//! `DepNode`s could represent global concepts with only one value.
//! * Whether it is possible, in principle, to reconstruct a query key from a
//! 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
//! lost during fingerprint computation.
//!
//! `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.
//! lost when computing a key fingerprint.
//!
//! [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_span::Symbol;
use super::{FingerprintStyle, SerializedDepNodeIndex};
use super::{KeyFingerprintStyle, SerializedDepNodeIndex};
use crate::ich::StableHashingContext;
use crate::mir::mono::MonoItem;
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)]
pub struct DepNode {
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 {
@ -136,24 +138,23 @@ impl DepNode {
/// that the DepNode corresponding to the given DepKind actually
/// does not require any parameters.
pub fn new_no_params<'tcx>(tcx: TyCtxt<'tcx>, kind: DepKind) -> DepNode {
debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit);
DepNode { kind, hash: Fingerprint::ZERO.into() }
debug_assert_eq!(tcx.key_fingerprint_style(kind), KeyFingerprintStyle::Unit);
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
Key: DepNodeKey<'tcx>,
{
let hash = arg.to_fingerprint(tcx);
let dep_node = DepNode { kind, hash: hash.into() };
let dep_node = DepNode { kind, key_fingerprint: key.to_fingerprint(tcx).into() };
#[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.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,
kind: DepKind,
) -> Self {
debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash);
DepNode { kind, hash: def_path_hash.0.into() }
debug_assert!(tcx.key_fingerprint_style(kind) == KeyFingerprintStyle::DefPathHash);
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) {
write!(f, "{s}")?;
} else {
write!(f, "{}", self.hash)?;
write!(f, "{}", self.key_fingerprint)?;
}
} else {
write!(f, "{}", self.hash)?;
write!(f, "{}", self.key_fingerprint)?;
}
Ok(())
})?;
@ -198,7 +199,7 @@ impl fmt::Debug for DepNode {
/// Trait for query keys as seen by dependency-node tracking.
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
/// in `DepNode`.
@ -212,7 +213,7 @@ pub trait DepNodeKey<'tcx>: fmt::Debug + Sized {
/// `fingerprint_style()` is not `FingerprintStyle::Opaque`.
/// It is always valid to return `None` here, in which case incremental
/// 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.
@ -221,8 +222,8 @@ where
T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
{
#[inline(always)]
default fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::Opaque
default fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::Opaque
}
#[inline(always)]
@ -243,7 +244,7 @@ where
}
#[inline(always)]
default fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
default fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
None
}
}
@ -264,10 +265,11 @@ pub struct DepKindVTable<'tcx> {
/// cached within one compiler invocation.
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.
pub fingerprint_style: FingerprintStyle,
pub key_fingerprint_style: KeyFingerprintStyle,
/// 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
@ -279,7 +281,7 @@ pub struct DepKindVTable<'tcx> {
/// `force_from_dep_node()` implements.
///
/// 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
/// `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
@ -293,7 +295,7 @@ pub struct DepKindVTable<'tcx> {
/// 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
/// 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
/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
/// 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
/// 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`
/// 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
/// `DefId` in `tcx.def_path_hash_to_def_id`.
pub force_from_dep_node: Option<
@ -472,8 +474,8 @@ impl DepNode {
/// refers to something from the previous compilation session that
/// has been removed.
pub fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash {
tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()))
if tcx.key_fingerprint_style(self.kind) == KeyFingerprintStyle::DefPathHash {
tcx.def_path_hash_to_def_id(DefPathHash(self.key_fingerprint.into()))
} else {
None
}
@ -486,10 +488,10 @@ impl DepNode {
) -> Result<DepNode, ()> {
let kind = dep_kind_from_label_string(label)?;
match tcx.fingerprint_style(kind) {
FingerprintStyle::Opaque | FingerprintStyle::HirId => Err(()),
FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
FingerprintStyle::DefPathHash => {
match tcx.key_fingerprint_style(kind) {
KeyFingerprintStyle::Opaque | KeyFingerprintStyle::HirId => Err(()),
KeyFingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
KeyFingerprintStyle::DefPathHash => {
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::{HirId, ItemLocalId, OwnerId};
use crate::dep_graph::{DepNode, DepNodeKey, FingerprintStyle};
use crate::dep_graph::{DepNode, DepNodeKey, KeyFingerprintStyle};
use crate::ty::TyCtxt;
impl<'tcx> DepNodeKey<'tcx> for () {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::Unit
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::Unit
}
#[inline(always)]
@ -18,15 +18,15 @@ impl<'tcx> DepNodeKey<'tcx> for () {
}
#[inline(always)]
fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
fn try_recover_key(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
Some(())
}
}
impl<'tcx> DepNodeKey<'tcx> for DefId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -40,15 +40,15 @@ impl<'tcx> DepNodeKey<'tcx> for DefId {
}
#[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)
}
}
impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -62,15 +62,15 @@ impl<'tcx> DepNodeKey<'tcx> for LocalDefId {
}
#[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())
}
}
impl<'tcx> DepNodeKey<'tcx> for OwnerId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -84,15 +84,15 @@ impl<'tcx> DepNodeKey<'tcx> for OwnerId {
}
#[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() })
}
}
impl<'tcx> DepNodeKey<'tcx> for CrateNum {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -107,15 +107,15 @@ impl<'tcx> DepNodeKey<'tcx> for CrateNum {
}
#[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)
}
}
impl<'tcx> DepNodeKey<'tcx> for (DefId, DefId) {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::Opaque
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::Opaque
}
// 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 {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::HirId
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::HirId
}
// We actually would not need to specialize the implementation of this
@ -166,9 +166,9 @@ impl<'tcx> DepNodeKey<'tcx> for HirId {
}
#[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
if tcx.fingerprint_style(dep_node.kind) == FingerprintStyle::HirId {
let (local_hash, local_id) = Fingerprint::from(dep_node.hash).split();
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
if tcx.key_fingerprint_style(dep_node.kind) == KeyFingerprintStyle::HirId {
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_id = tcx.def_path_hash_to_def_id(def_path_hash)?.expect_local();
let local_id = local_id
@ -184,8 +184,8 @@ impl<'tcx> DepNodeKey<'tcx> for HirId {
impl<'tcx> DepNodeKey<'tcx> for ModDefId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -199,15 +199,15 @@ impl<'tcx> DepNodeKey<'tcx> for ModDefId {
}
#[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
DefId::recover(tcx, dep_node).map(ModDefId::new_unchecked)
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
DefId::try_recover_key(tcx, dep_node).map(ModDefId::new_unchecked)
}
}
impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
#[inline(always)]
fn fingerprint_style() -> FingerprintStyle {
FingerprintStyle::DefPathHash
fn key_fingerprint_style() -> KeyFingerprintStyle {
KeyFingerprintStyle::DefPathHash
}
#[inline(always)]
@ -221,7 +221,7 @@ impl<'tcx> DepNodeKey<'tcx> for LocalModDefId {
}
#[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
LocalDefId::recover(tcx, dep_node).map(LocalModDefId::new_unchecked)
fn try_recover_key(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
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.
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(),
Fingerprint::ZERO,
);
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(
DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() },
DepNode { kind: DepKind::RED, key_fingerprint: Fingerprint::ZERO.into() },
EdgesVec::new(),
Fingerprint::ZERO,
);
@ -418,7 +420,7 @@ impl DepGraphData {
// Fingerprint::combine() is faster than sending Fingerprint
// through the StableHasher (at least as long as StableHasher
// 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
@ -585,7 +587,7 @@ impl DepGraph {
data.current.record_edge(
dep_node_index,
node,
data.prev_fingerprint_of(prev_index),
data.prev_value_fingerprint_of(prev_index),
);
}
@ -658,8 +660,8 @@ impl DepGraphData {
}
#[inline]
pub fn prev_fingerprint_of(&self, prev_index: SerializedDepNodeIndex) -> Fingerprint {
self.previous.fingerprint_by_index(prev_index)
pub fn prev_value_fingerprint_of(&self, prev_index: SerializedDepNodeIndex) -> Fingerprint {
self.previous.value_fingerprint_for_index(prev_index)
}
#[inline]
@ -679,7 +681,7 @@ impl DepGraphData {
let dep_node_index = self.current.encoder.send_new(
DepNode {
kind: DepKind::SIDE_EFFECT,
hash: PackedFingerprint::from(Fingerprint::ZERO),
key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO),
},
Fingerprint::ZERO,
// 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,
DepNode {
kind: DepKind::SIDE_EFFECT,
hash: PackedFingerprint::from(Fingerprint::ZERO),
key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO),
},
Fingerprint::ZERO,
std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(),
@ -727,12 +729,12 @@ impl DepGraphData {
&self,
key: DepNode,
edges: EdgesVec,
fingerprint: Option<Fingerprint>,
value_fingerprint: Option<Fingerprint>,
) -> DepNodeIndex {
if let Some(prev_index) = self.previous.node_to_index_opt(&key) {
// Determine the color and index of the new `DepNode`.
let is_green = if let Some(fingerprint) = fingerprint {
if fingerprint == self.previous.fingerprint_by_index(prev_index) {
let is_green = if let Some(value_fingerprint) = value_fingerprint {
if value_fingerprint == self.previous.value_fingerprint_for_index(prev_index) {
// This is a green node: it existed in the previous compilation,
// its query was re-executed, and it has the same result as before.
true
@ -749,22 +751,22 @@ impl DepGraphData {
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(
prev_index,
&self.colors,
key,
fingerprint,
value_fingerprint,
edges,
is_green,
);
self.current.record_node(dep_node_index, key, fingerprint);
self.current.record_node(dep_node_index, key, value_fingerprint);
dep_node_index
} 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(
dep_node_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) {
debug!(
"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));
@ -1154,10 +1156,10 @@ pub(super) struct CurrentDepGraph {
encoder: GraphEncoder,
anon_node_to_index: ShardedHashMap<DepNode, DepNodeIndex>,
/// This is used to verify that fingerprints do not change between the creation of a node
/// and its recomputation.
/// This is used to verify that value fingerprints do not change between the
/// creation of a node and its recomputation.
#[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.
/// This is used for debug purposes and is only active with `debug_assertions`.
@ -1224,7 +1226,7 @@ impl CurrentDepGraph {
#[cfg(debug_assertions)]
forbidden_edge,
#[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(|| {
Lock::new(FxHashMap::with_capacity_and_hasher(
new_node_count_estimate,
@ -1237,12 +1239,20 @@ impl CurrentDepGraph {
}
#[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 {
forbidden_edge.index_to_node.lock().insert(dep_node_index, key);
}
let previous = *self.fingerprints.lock().get_or_insert_with(dep_node_index, || fingerprint);
assert_eq!(previous, fingerprint, "Unstable fingerprints for {:?}", key);
let prior_value_fingerprint = *self
.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)]
@ -1250,10 +1260,10 @@ impl CurrentDepGraph {
&self,
dep_node_index: DepNodeIndex,
key: DepNode,
_current_fingerprint: Fingerprint,
_value_fingerprint: Fingerprint,
) {
#[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 {
outline(|| {
@ -1271,11 +1281,11 @@ impl CurrentDepGraph {
&self,
key: DepNode,
edges: EdgesVec,
current_fingerprint: Fingerprint,
value_fingerprint: Fingerprint,
) -> 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
}

View file

@ -30,7 +30,7 @@ mod serialized;
/// This is mainly for determining whether and how we can reconstruct a key
/// from the fingerprint.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum FingerprintStyle {
pub enum KeyFingerprintStyle {
/// The fingerprint is actually a DefPathHash.
DefPathHash,
/// The fingerprint is actually a HirId.
@ -41,14 +41,14 @@ pub enum FingerprintStyle {
Opaque,
}
impl FingerprintStyle {
impl KeyFingerprintStyle {
#[inline]
pub const fn reconstructible(self) -> bool {
match self {
FingerprintStyle::DefPathHash | FingerprintStyle::Unit | FingerprintStyle::HirId => {
true
}
FingerprintStyle::Opaque => false,
KeyFingerprintStyle::DefPathHash
| KeyFingerprintStyle::Unit
| KeyFingerprintStyle::HirId => true,
KeyFingerprintStyle::Opaque => false,
}
}
}
@ -86,8 +86,8 @@ impl<'tcx> TyCtxt<'tcx> {
}
#[inline(always)]
pub fn fingerprint_style(self, kind: DepKind) -> FingerprintStyle {
self.dep_kind_vtable(kind).fingerprint_style
pub fn key_fingerprint_style(self, kind: DepKind) -> KeyFingerprintStyle {
self.dep_kind_vtable(kind).key_fingerprint_style
}
/// 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 {
/// The set of all DepNodes in the graph
nodes: IndexVec<SerializedDepNodeIndex, DepNode>,
/// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
/// the DepNode at the same index in the nodes vector.
fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
/// A value fingerprint associated with each [`DepNode`] in [`Self::nodes`],
/// typically a hash of the value returned by the node's query in the
/// 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
/// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
/// 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
/// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices.
edge_list_data: Vec<u8>,
/// Stores a map from fingerprints to nodes per dep node kind.
/// This is the reciprocal of `nodes`.
/// For each dep kind, stores a map from key fingerprints back to the index
/// of the corresponding node. This is the inverse of `nodes`.
index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>,
/// The number of previous compilation sessions. This is used to generate
/// unique anon dep nodes per session.
@ -138,12 +142,15 @@ impl SerializedDepGraph {
#[inline]
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]
pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint {
self.fingerprints[dep_node_index]
pub fn value_fingerprint_for_index(
&self,
dep_node_index: SerializedDepNodeIndex,
) -> Fingerprint {
self.value_fingerprints[dep_node_index]
}
#[inline]
@ -212,10 +219,13 @@ impl SerializedDepGraph {
let graph_bytes = d.len() - (3 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position();
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,
);
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 =
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);
*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 it is not, we fall back to another decoder call.
@ -275,7 +285,7 @@ impl SerializedDepGraph {
let session_count = d.read_u64();
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
if node.kind != DepKind::NULL && node.kind != DepKind::SIDE_EFFECT {
let name = node.kind.name();
@ -291,7 +301,7 @@ impl SerializedDepGraph {
Arc::new(SerializedDepGraph {
nodes,
fingerprints,
value_fingerprints,
edge_list_indices,
edge_list_data,
index,
@ -303,8 +313,8 @@ impl SerializedDepGraph {
/// A packed representation of all the fixed-size fields in a `NodeInfo`.
///
/// This stores in one byte array:
/// * The `Fingerprint` in the `NodeInfo`
/// * The `Fingerprint` in `DepNode` that is in this `NodeInfo`
/// * The value `Fingerprint` in the `NodeInfo`
/// * The key `Fingerprint` in `DepNode` that is in this `NodeInfo`
/// * The `DepKind`'s discriminant (a u16, but not all bits are used...)
/// * 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
@ -323,8 +333,8 @@ struct Unpacked {
bytes_per_index: usize,
kind: DepKind,
index: SerializedDepNodeIndex,
hash: PackedFingerprint,
fingerprint: Fingerprint,
key_fingerprint: PackedFingerprint,
value_fingerprint: Fingerprint,
}
// Bit fields, where
@ -345,7 +355,7 @@ impl SerializedNodeHeader {
fn new(
node: &DepNode,
index: DepNodeIndex,
fingerprint: Fingerprint,
value_fingerprint: Fingerprint,
edge_max_index: u32,
edge_count: usize,
) -> Self {
@ -363,19 +373,19 @@ impl SerializedNodeHeader {
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.
let mut bytes = [0u8; 38];
bytes[..2].copy_from_slice(&head.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[22..].copy_from_slice(&fingerprint.to_le_bytes());
bytes[22..].copy_from_slice(&value_fingerprint.to_le_bytes());
#[cfg(debug_assertions)]
{
let res = Self { bytes };
assert_eq!(fingerprint, res.fingerprint());
assert_eq!(value_fingerprint, res.value_fingerprint());
assert_eq!(*node, res.node());
if let Some(len) = res.len() {
assert_eq!(edge_count, len as usize);
@ -388,8 +398,8 @@ impl SerializedNodeHeader {
fn unpack(&self) -> Unpacked {
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 hash = self.bytes[6..22].try_into().unwrap();
let fingerprint = self.bytes[22..].try_into().unwrap();
let key_fingerprint = self.bytes[6..22].try_into().unwrap();
let value_fingerprint = self.bytes[22..].try_into().unwrap();
let kind = head & mask(Self::KIND_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,
kind: DepKind::new(kind),
index: SerializedDepNodeIndex::from_u32(index),
hash: Fingerprint::from_le_bytes(hash).into(),
fingerprint: Fingerprint::from_le_bytes(fingerprint),
key_fingerprint: Fingerprint::from_le_bytes(key_fingerprint).into(),
value_fingerprint: Fingerprint::from_le_bytes(value_fingerprint),
}
}
@ -421,14 +431,14 @@ impl SerializedNodeHeader {
}
#[inline]
fn fingerprint(&self) -> Fingerprint {
self.unpack().fingerprint
fn value_fingerprint(&self) -> Fingerprint {
self.unpack().value_fingerprint
}
#[inline]
fn node(&self) -> DepNode {
let Unpacked { kind, hash, .. } = self.unpack();
DepNode { kind, hash }
let Unpacked { kind, key_fingerprint, .. } = self.unpack();
DepNode { kind, key_fingerprint }
}
#[inline]
@ -443,15 +453,20 @@ impl SerializedNodeHeader {
#[derive(Debug)]
struct NodeInfo {
node: DepNode,
fingerprint: Fingerprint,
value_fingerprint: Fingerprint,
edges: EdgesVec,
}
impl NodeInfo {
fn encode(&self, e: &mut MemEncoder, index: DepNodeIndex) {
let NodeInfo { ref node, fingerprint, ref edges } = *self;
let header =
SerializedNodeHeader::new(node, index, fingerprint, edges.max_index(), edges.len());
let NodeInfo { ref node, value_fingerprint, ref edges } = *self;
let header = SerializedNodeHeader::new(
node,
index,
value_fingerprint,
edges.max_index(),
edges.len(),
);
e.write_array(header.bytes);
if header.len().is_none() {
@ -476,7 +491,7 @@ impl NodeInfo {
e: &mut MemEncoder,
node: &DepNode,
index: DepNodeIndex,
fingerprint: Fingerprint,
value_fingerprint: Fingerprint,
prev_index: SerializedDepNodeIndex,
colors: &DepNodeColorMap,
previous: &SerializedDepGraph,
@ -488,7 +503,8 @@ impl NodeInfo {
let edge_max =
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);
if header.len().is_none() {
@ -676,12 +692,12 @@ impl EncoderState {
local: &mut LocalEncoderState,
) {
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(
&mut local.encoder,
node,
index,
fingerprint,
value_fingerprint,
prev_index,
colors,
&self.previous,
@ -857,11 +873,11 @@ impl GraphEncoder {
pub(crate) fn send_new(
&self,
node: DepNode,
fingerprint: Fingerprint,
value_fingerprint: Fingerprint,
edges: EdgesVec,
) -> DepNodeIndex {
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 index = self.status.next_index(&mut *local);
self.status.bump_index(&mut *local);
@ -877,12 +893,12 @@ impl GraphEncoder {
prev_index: SerializedDepNodeIndex,
colors: &DepNodeColorMap,
node: DepNode,
fingerprint: Fingerprint,
value_fingerprint: Fingerprint,
edges: EdgesVec,
is_green: bool,
) -> DepNodeIndex {
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();

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) => {
with_no_trimmed_paths!(write!(fmt, "wrap_binder!({op:?}; {ty})"))
}

View file

@ -747,11 +747,6 @@ impl<'tcx> ConstOperand<'tcx> {
///////////////////////////////////////////////////////////////////////////
// Rvalues
pub enum RvalueInitializationState {
Shallow,
Deep,
}
impl<'tcx> Rvalue<'tcx> {
/// Returns true if rvalue can be safely removed when the result is unused.
#[inline]
@ -786,7 +781,6 @@ impl<'tcx> Rvalue<'tcx> {
| Rvalue::UnaryOp(_, _)
| Rvalue::Discriminant(_)
| Rvalue::Aggregate(_, _)
| Rvalue::ShallowInitBox(_, _)
| Rvalue::WrapUnsafeBinder(_, _) => true,
}
}
@ -833,21 +827,10 @@ impl<'tcx> Rvalue<'tcx> {
}
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::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 {

View file

@ -1458,13 +1458,6 @@ pub enum Rvalue<'tcx> {
/// coroutine lowering, `Coroutine` aggregate kinds are disallowed too.
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
/// 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)

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) => {
self.visit_operand(op, location);
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));

View file

@ -67,7 +67,7 @@ where
#[inline]
fn complete(&self, key: K, value: V, index: DepNodeIndex) {
// 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));
}

View file

@ -25,7 +25,7 @@ pub fn incremental_verify_ich<'tcx, V>(
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 {
incremental_verify_ich_failed(tcx, prev_index, &|| format_value(result));

View file

@ -86,7 +86,6 @@ where
Rvalue::Cast(..)
| Rvalue::Ref(_, BorrowKind::Fake(_), _)
| Rvalue::ShallowInitBox(..)
| Rvalue::Use(..)
| Rvalue::ThreadLocalRef(..)
| 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)) => {
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);
}
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::Repeat(ref operand, _)
| Rvalue::Cast(_, ref operand, _)
| Rvalue::ShallowInitBox(ref operand, _)
| Rvalue::UnaryOp(_, ref operand)
| Rvalue::WrapUnsafeBinder(ref operand, _) => self.gather_operand(operand),
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::Use(operand) => return self.handle_operand(operand, state),
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"),
Rvalue::ShallowInitBox(..) => bug!("`ShallowInitBox` in runtime MIR"),
Rvalue::Ref(..) | Rvalue::RawPtr(..) => {
// We don't track such places.
return ValueOrPlace::TOP;

View file

@ -1,12 +1,8 @@
//! 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.
//!
//! `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_index::{IndexVec, indexvec};
use rustc_abi::FieldIdx;
use rustc_middle::mir::visit::MutVisitor;
use rustc_middle::mir::*;
use rustc_middle::span_bug;
@ -89,68 +85,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
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;

View file

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

View file

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

View file

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

View file

@ -1,5 +1,6 @@
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::sync::atomic::Ordering;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_middle::mir::{Body, MirDumper, MirPhase, RuntimePhase};
@ -285,6 +286,19 @@ fn run_passes_inner<'tcx>(
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 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)
}
}
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)?;
}
Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
Rvalue::UnaryOp(op, operand) => {
match op {
// These operations can never fail.

View file

@ -85,7 +85,7 @@ impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts {
}
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) => {
let op_ty = operand.ty(self.body, self.tcx);
match kind {

View file

@ -567,13 +567,6 @@ pub enum Rvalue {
/// [#74836]: https://github.com/rust-lang/rust/issues/74836
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.
///
/// 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)),
},
Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)),
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) => {
write!(writer, "[{}; {}]", pretty_operand(op), pretty_ty_const(cnst))
}
Rvalue::ShallowInitBox(_, _) => Ok(()),
Rvalue::ThreadLocalRef(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_ty_const(constant, location);
}
Rvalue::ShallowInitBox(op, ty) => {
self.visit_ty(ty, location);
self.visit_operand(op, location)
}
Rvalue::ThreadLocalRef(_) => {}
Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => {
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();
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)),
WrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
}

View file

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

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));
let key = C::Key::recover(tcx, &dep_node).unwrap_or_else(|| {
panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)
let key = C::Key::try_recover_key(tcx, &dep_node).unwrap_or_else(|| {
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) {
// 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"
);
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);
true
} else {

View file

@ -469,9 +469,15 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
PathResult::NonModule(partial_res) => {
expected_found_error(partial_res.expect_full_res())
}
PathResult::Failed { span, label, suggestion, .. } => {
Err(VisResolutionError::FailedToResolve(span, label, suggestion))
}
PathResult::Failed {
span, label, suggestion, message, segment_name, ..
} => Err(VisResolutionError::FailedToResolve(
span,
segment_name,
label,
suggestion,
message,
)),
PathResult::Indeterminate => Err(VisResolutionError::Indeterminate(path.span)),
}
}

View file

@ -32,7 +32,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym};
use rustc_span::{BytePos, Ident, RemapPathScopeComponents, Span, Symbol, SyntaxContext, kw, sym};
use thin_vec::{ThinVec, thin_vec};
use tracing::{debug, instrument};
@ -899,9 +899,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
self.dcx().create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
}
ResolutionError::FailedToResolve { segment, label, suggestion, module } => {
let mut err =
struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {label}");
ResolutionError::FailedToResolve { segment, label, suggestion, module, message } => {
let mut err = struct_span_code_err!(self.dcx(), span, E0433, "{message}");
err.span_label(span, label);
if let Some((suggestions, msg, applicability)) = suggestion {
@ -909,16 +908,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
err.help(msg);
return err;
}
err.multipart_suggestion(msg, suggestions, applicability);
err.multipart_suggestion_verbose(msg, suggestions, applicability);
}
if let Some(segment) = segment {
let module = match module {
Some(ModuleOrUniformRoot::Module(m)) if let Some(id) = m.opt_def_id() => id,
_ => CRATE_DEF_ID.to_def_id(),
};
self.find_cfg_stripped(&mut err, &segment, module);
}
let module = match module {
Some(ModuleOrUniformRoot::Module(m)) if let Some(id) = m.opt_def_id() => id,
_ => CRATE_DEF_ID.to_def_id(),
};
self.find_cfg_stripped(&mut err, &segment, module);
err
}
@ -1108,10 +1105,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
VisResolutionError::AncestorOnly(span) => {
self.dcx().create_err(errs::AncestorOnly(span))
}
VisResolutionError::FailedToResolve(span, label, suggestion) => self.into_struct_error(
span,
ResolutionError::FailedToResolve { segment: None, label, suggestion, module: None },
),
VisResolutionError::FailedToResolve(span, segment, label, suggestion, message) => self
.into_struct_error(
span,
ResolutionError::FailedToResolve {
segment,
label,
suggestion,
module: None,
message,
},
),
VisResolutionError::ExpectedFound(span, path_str, res) => {
self.dcx().create_err(errs::ExpectedModuleFound { span, res, path_str })
}
@ -2438,13 +2442,25 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
failed_segment_idx: usize,
ident: Ident,
diag_metadata: Option<&DiagMetadata<'_>>,
) -> (String, Option<Suggestion>) {
) -> (String, String, Option<Suggestion>) {
let is_last = failed_segment_idx == path.len() - 1;
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
let module_res = match module {
Some(ModuleOrUniformRoot::Module(module)) => module.res(),
_ => None,
};
let scope = match &path[..failed_segment_idx] {
[.., prev] => {
if prev.ident.name == kw::PathRoot {
format!("the crate root")
} else {
format!("`{}`", prev.ident)
}
}
_ => format!("this scope"),
};
let message = format!("cannot find `{ident}` in {scope}");
if module_res == self.graph_root.res() {
let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _));
let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod);
@ -2462,6 +2478,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
Path { segments, span: Span::default(), tokens: None }
};
(
message,
String::from("unresolved import"),
Some((
vec![(ident.span, pprust::path_to_string(&path))],
@ -2471,6 +2488,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
)
} else if ident.name == sym::core {
(
message,
format!("you might be missing crate `{ident}`"),
Some((
vec![(ident.span, "std".to_string())],
@ -2479,9 +2497,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
)),
)
} else if ident.name == kw::Underscore {
(format!("`_` is not a valid crate or module name"), None)
(
"invalid crate or module name `_`".to_string(),
"`_` is not a valid crate or module name".to_string(),
None,
)
} else if self.tcx.sess.is_rust_2015() {
(
format!("cannot find module or crate `{ident}` in {scope}"),
format!("use of unresolved module or unlinked crate `{ident}`"),
Some((
vec![(
@ -2490,8 +2513,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
)],
if was_invoked_from_cargo() {
format!(
"if you wanted to use a crate named `{ident}`, use `cargo add {ident}` \
to add it to your `Cargo.toml` and import it in your code",
"if you wanted to use a crate named `{ident}`, use `cargo add \
{ident}` to add it to your `Cargo.toml` and import it in your \
code",
)
} else {
format!(
@ -2503,7 +2527,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
)),
)
} else {
(format!("could not find `{ident}` in the crate root"), None)
(message, format!("could not find `{ident}` in the crate root"), None)
}
} else if failed_segment_idx > 0 {
let parent = path[failed_segment_idx - 1].ident.name;
@ -2569,15 +2593,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
);
};
}
(msg, None)
(message, msg, None)
} else if ident.name == kw::SelfUpper {
// As mentioned above, `opt_ns` being `None` indicates a module path in import.
// We can use this to improve a confusing error for, e.g. `use Self::Variant` in an
// impl
if opt_ns.is_none() {
("`Self` cannot be used in imports".to_string(), None)
(message, "`Self` cannot be used in imports".to_string(), None)
} else {
(
message,
"`Self` is only available in impls, traits, and type definitions".to_string(),
None,
)
@ -2608,12 +2633,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// }
// ```
Some(LateDecl::RibDef(Res::Local(id))) => {
Some(*self.pat_span_map.get(&id).unwrap())
Some((*self.pat_span_map.get(&id).unwrap(), "a", "local binding"))
}
// Name matches item from a local name binding
// created by `use` declaration. For example:
// ```
// pub Foo: &str = "";
// pub const Foo: &str = "";
//
// mod submod {
// use super::Foo;
@ -2621,18 +2646,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// // binding `Foo`.
// }
// ```
Some(LateDecl::Decl(name_binding)) => Some(name_binding.span),
Some(LateDecl::Decl(name_binding)) => Some((
name_binding.span,
name_binding.res().article(),
name_binding.res().descr(),
)),
_ => None,
};
let suggestion = match_span.map(|span| {
(
vec![(span, String::from(""))],
format!("`{ident}` is defined here, but is not a type"),
Applicability::MaybeIncorrect,
)
});
(format!("use of undeclared type `{ident}`"), suggestion)
let message = format!("cannot find type `{ident}` in {scope}");
let label = if let Some((span, article, descr)) = match_span {
format!(
"`{ident}` is declared as {article} {descr} at `{}`, not a type",
self.tcx
.sess
.source_map()
.span_to_short_string(span, RemapPathScopeComponents::DIAGNOSTICS)
)
} else {
format!("use of undeclared type `{ident}`")
};
(message, label, None)
} else {
let mut suggestion = None;
if ident.name == sym::alloc {
@ -2663,7 +2697,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
ignore_import,
) {
let descr = binding.res().descr();
(format!("{descr} `{ident}` is not a crate or module"), suggestion)
let message = format!("cannot find module or crate `{ident}` in {scope}");
(message, format!("{descr} `{ident}` is not a crate or module"), suggestion)
} else {
let suggestion = if suggestion.is_some() {
suggestion
@ -2685,7 +2720,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
Applicability::MaybeIncorrect,
))
};
(format!("use of unresolved module or unlinked crate `{ident}`"), suggestion)
let message = format!("cannot find module or crate `{ident}` in {scope}");
(
message,
format!("use of unresolved module or unlinked crate `{ident}`"),
suggestion,
)
}
}
}

View file

@ -1775,7 +1775,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
finalize.is_some(),
module_had_parse_errors,
module,
|| ("there are too many leading `super` keywords".to_string(), None),
|| {
(
"too many leading `super` keywords".to_string(),
"there are too many leading `super` keywords".to_string(),
None,
)
},
);
}
if segment_idx == 0 {
@ -1823,16 +1829,24 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
module,
|| {
let name_str = if name == kw::PathRoot {
"crate root".to_string()
"the crate root".to_string()
} else {
format!("`{name}`")
};
let label = if segment_idx == 1 && path[0].ident.name == kw::PathRoot {
format!("global paths cannot start with {name_str}")
let (message, label) = if segment_idx == 1
&& path[0].ident.name == kw::PathRoot
{
(
format!("global paths cannot start with {name_str}"),
"cannot start with this".to_string(),
)
} else {
format!("{name_str} in paths can only be used in start position")
(
format!("{name_str} in paths can only be used in start position"),
"can only be used in path start position".to_string(),
)
};
(label, None)
(message, label, None)
},
);
}
@ -1948,7 +1962,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
res.article(),
res.descr()
);
(label, None)
let scope = match &path[..segment_idx] {
[.., prev] => {
if prev.ident.name == kw::PathRoot {
format!("the crate root")
} else {
format!("`{}`", prev.ident)
}
}
_ => format!("this scope"),
};
// FIXME: reword, as the reason we expected a module is because of
// the following path segment.
let message = format!("cannot find module `{ident}` in {scope}");
(message, label, None)
},
);
}

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.
// FIXME: avoid this by removing `warn_ambiguity`, or by triggering glob re-fetch
// 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
// overwritten decl from other module (the recursive case).
// 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).
// assert_ne!(old_deep_decl, deep_decl);
// 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() {
// Do not lose glob ambiguities when re-fetching the glob.
glob_decl.ambiguity.set_unchecked(old_glob_decl.ambiguity.get());
@ -1042,16 +1045,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
suggestion,
module,
error_implied_by_parse_error: _,
message,
} => {
if no_ambiguity {
assert!(import.imported_module.get().is_none());
self.report_error(
span,
ResolutionError::FailedToResolve {
segment: Some(segment_name),
segment: segment_name,
label,
suggestion,
module,
message,
},
);
}

View file

@ -4890,14 +4890,16 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
module,
segment_name,
error_implied_by_parse_error: _,
message,
} => {
return Err(respan(
span,
ResolutionError::FailedToResolve {
segment: Some(segment_name),
segment: segment_name,
label,
suggestion,
module,
message,
},
));
}

View file

@ -4060,25 +4060,32 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
"instead, you are more likely to want"
};
let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand;
let mut sugg_is_str_to_string = false;
let mut sugg = vec![(lt.span, String::new())];
if let Some((kind, _span)) = self.diag_metadata.current_function
&& let FnKind::Fn(_, _, ast::Fn { sig, .. }) = kind
&& let ast::FnRetTy::Ty(ty) = &sig.decl.output
{
let mut lt_finder =
LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] };
lt_finder.visit_ty(&ty);
if let [Ty { span, kind: TyKind::Ref(_, mut_ty), .. }] =
&lt_finder.seen[..]
{
// We might have a situation like
// fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()>
// but `lt.span` only points at `'_`, so to suggest `-> Option<()>`
// we need to find a more accurate span to end up with
// fn g<'a>(mut x: impl Iterator<Item = &'_ ()>) -> Option<()>
sugg = vec![(span.with_hi(mut_ty.ty.span.lo()), String::new())];
owned_sugg = true;
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), .. }] =
&ret_lt_finder.seen[..]
{
// We might have a situation like
// fn g(mut x: impl Iterator<Item = &'_ ()>) -> Option<&'_ ()>
// but `lt.span` only points at `'_`, so to suggest `-> Option<()>`
// we need to find a more accurate span to end up with
// fn g<'a>(mut x: impl Iterator<Item = &'_ ()>) -> Option<()>
sugg = vec![(span.with_hi(mut_ty.ty.span.lo()), String::new())];
owned_sugg = true;
}
}
if let Some(ty) = lt_finder.found {
if let TyKind::Path(None, path) = &ty.kind {
@ -4098,6 +4105,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
lt.span.with_hi(ty.span.hi()),
"String".to_string(),
)];
sugg_is_str_to_string = true;
}
Some(Res::PrimTy(..)) => {}
Some(Res::Def(
@ -4124,6 +4132,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
lt.span.with_hi(ty.span.hi()),
"String".to_string(),
)];
sugg_is_str_to_string = true;
}
Res::PrimTy(..) => {}
Res::Def(
@ -4158,6 +4167,12 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
}
}
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(
format!("{pre} to return an owned value"),
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(
@ -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.
//FIXME: make this a proper lint.
pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {

View file

@ -280,10 +280,11 @@ enum ResolutionError<'ra> {
SelfImportOnlyInImportListWithNonEmptyPrefix,
/// Error E0433: failed to resolve.
FailedToResolve {
segment: Option<Symbol>,
segment: Symbol,
label: String,
suggestion: Option<Suggestion>,
module: Option<ModuleOrUniformRoot<'ra>>,
message: String,
},
/// Error E0434: can't capture dynamic environment in a fn item.
CannotCaptureDynamicEnvironmentInFnItem,
@ -342,7 +343,7 @@ enum ResolutionError<'ra> {
enum VisResolutionError<'a> {
Relative2018(Span, &'a ast::Path),
AncestorOnly(Span),
FailedToResolve(Span, String, Option<Suggestion>),
FailedToResolve(Span, Symbol, String, Option<Suggestion>, String),
ExpectedFound(Span, String, Res),
Indeterminate(Span),
ModuleOnly(Span),
@ -486,6 +487,7 @@ enum PathResult<'ra> {
/// The segment name of target
segment_name: Symbol,
error_implied_by_parse_error: bool,
message: String,
},
}
@ -496,10 +498,14 @@ impl<'ra> PathResult<'ra> {
finalize: bool,
error_implied_by_parse_error: bool,
module: Option<ModuleOrUniformRoot<'ra>>,
label_and_suggestion: impl FnOnce() -> (String, Option<Suggestion>),
label_and_suggestion: impl FnOnce() -> (String, String, Option<Suggestion>),
) -> PathResult<'ra> {
let (label, suggestion) =
if finalize { label_and_suggestion() } else { (String::new(), None) };
let (message, label, suggestion) = if finalize {
label_and_suggestion()
} else {
// FIXME: this output isn't actually present in the test suite.
(format!("cannot find `{ident}` in this scope"), String::new(), None)
};
PathResult::Failed {
span: ident.span,
segment_name: ident.name,
@ -508,6 +514,7 @@ impl<'ra> PathResult<'ra> {
is_error_from_last_segment,
module,
error_implied_by_parse_error,
message,
}
}
}

View file

@ -908,10 +908,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
),
path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => {
let mut suggestion = None;
let (span, label, module, segment) =
if let PathResult::Failed { span, label, module, segment_name, .. } =
path_res
{
let (span, message, label, module, segment) = match path_res {
PathResult::Failed {
span, label, module, segment_name, message, ..
} => {
// try to suggest if it's not a macro, maybe a function
if let PathResult::NonModule(partial_res) = self
.cm()
@ -930,26 +930,52 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
Applicability::MaybeIncorrect,
));
}
(span, label, module, segment_name)
} else {
(span, message, label, module, segment_name)
}
PathResult::NonModule(partial_res) => {
let found_an = partial_res.base_res().article();
let found_descr = partial_res.base_res().descr();
let scope = match &path[..partial_res.unresolved_segments()] {
[.., prev] => {
format!("{found_descr} `{}`", prev.ident)
}
_ => found_descr.to_string(),
};
let expected_an = kind.article();
let expected_descr = kind.descr();
let expected_name = path[partial_res.unresolved_segments()].ident;
(
path_span,
format!(
"partially resolved path in {} {}",
kind.article(),
kind.descr()
"cannot find {expected_descr} `{expected_name}` in {scope}"
),
match partial_res.base_res() {
Res::Def(
DefKind::Mod | DefKind::Macro(..) | DefKind::ExternCrate,
_,
) => format!(
"partially resolved path in {expected_an} {expected_descr}",
),
_ => format!(
"{expected_an} {expected_descr} can't exist within \
{found_an} {found_descr}"
),
},
None,
path.last().map(|segment| segment.ident.name).unwrap(),
)
};
}
_ => unreachable!(),
};
self.report_error(
span,
ResolutionError::FailedToResolve {
segment: Some(segment),
segment,
label,
suggestion,
module,
message,
},
);
}

View file

@ -2481,6 +2481,9 @@ options! {
mir_include_spans: MirIncludeSpans = (MirIncludeSpans::default(), parse_mir_include_spans, [UNTRACKED],
"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')"),
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")]
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)"),

View file

@ -2,7 +2,7 @@ use std::any::Any;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::{AtomicBool, AtomicUsize};
use std::{env, io};
use rand::{RngCore, rng};
@ -161,6 +161,12 @@ pub struct Session {
/// Does the codegen backend support ThinLTO?
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)]
@ -1101,6 +1107,7 @@ pub fn build_session(
invocation_temp,
replaced_intrinsics: FxHashSet::default(), // 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);

View file

@ -327,7 +327,6 @@ symbols! {
Pointer,
Poll,
ProcMacro,
ProceduralMasqueradeDummyType,
Range,
RangeBounds,
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 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);
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::print::RegionHighlightMode;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
use rustc_span::Span;
use rustc_span::{Ident, Span};
use tracing::debug;
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.
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 {
ty::AssocKind::Fn { .. } => {
if let Some(hir_id) =
@ -122,13 +123,49 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
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> {
tcx: TyCtxt<'tcx>,
types: Vec<Span>,
elided_lifetime_paths: Vec<ElidedLifetimeInPath>,
}
impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
@ -138,6 +175,83 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'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>) {
match arg.kind {
hir::TyKind::Ref(_, ref mut_ty) => {

View file

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

View file

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

View file

@ -2481,7 +2481,8 @@ macro_rules! int_impl {
///
/// Returns a tuple of the addition along with a boolean indicating
/// 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
///
@ -2516,6 +2517,9 @@ macro_rules! int_impl {
/// The output boolean returned by this method is *not* a carry flag,
/// 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
/// [`overflowing_add`](Self::overflowing_add).
///
@ -2583,7 +2587,8 @@ macro_rules! int_impl {
/// Calculates `self` - `rhs`.
///
/// 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
///
@ -2619,6 +2624,9 @@ macro_rules! int_impl {
/// The output boolean returned by this method is *not* a borrow flag,
/// 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
/// [`overflowing_sub`](Self::overflowing_sub).
///

View file

@ -487,8 +487,8 @@ macro_rules! uint_impl {
/// Performs a carry-less multiplication, returning the lower bits.
///
/// This operation is similar to long multiplication, except that exclusive or is used
/// instead of addition. The implementation is equivalent to:
/// This operation is similar to long multiplication in base 2, except that exclusive or is
/// used instead of addition. The implementation is equivalent to:
///
/// ```no_run
#[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]`.
#[cfg(target_vendor = "apple")]
mod imp {
use crate::ffi::{c_char, c_int};
use crate::ffi::c_char;
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
// 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) {
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
// in the program lifetime by `libdyld.dylib`, and as such is always
// valid.
@ -187,9 +181,9 @@ mod imp {
// doesn't exist a lock that we can take. Instead, it is generally
// expected that it's only modified in `main` / before other code
// runs, so reading this here should be fine.
let argc = unsafe { _NSGetArgc().read() };
let argc = unsafe { libc::_NSGetArgc().read() };
// 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`
(argc as isize, argv.cast())

View file

@ -393,7 +393,7 @@ Heres how these different lint controls interact:
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.

View file

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

View file

@ -2,7 +2,7 @@ struct Foo(isize, isize, isize, isize);
pub fn main() {
let Self::anything_here_kills_it(a, b, ..) = Foo(5, 5, 5, 5);
//~^ ERROR: failed to resolve
//~^ ERROR: cannot find `Self` in this scope
match [5, 5, 5, 5] {
[..] => {},
}

View file

@ -1,4 +1,4 @@
error[E0433]: failed to resolve: `Self` is only available in impls, traits, and type definitions
error[E0433]: cannot find `Self` in this scope
--> tests/ui/crashes/unreachable-array-or-slice.rs:4:9
|
LL | let Self::anything_here_kills_it(a, b, ..) = Foo(5, 5, 5, 5);

View file

@ -343,8 +343,8 @@ impl VisitProvenance for Thread<'_> {
impl VisitProvenance for Frame<'_, Provenance, FrameExtra<'_>> {
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
let return_place = self.return_place();
let Frame {
return_place,
locals,
extra,
// 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() {
trace!("-------------------");
trace!("Frame {}", i);
trace!(" return: {:?}", frame.return_place);
trace!(" return: {:?}", frame.return_place());
for (i, local) in frame.locals.iter().enumerate() {
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
// foreign function
// 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);
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>,
unwind: mir::UnwindAction,
) -> 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)
}

View file

@ -4,7 +4,7 @@ struct Struct<T>(T);
impl<T> std::ops::Deref for Struct<T> {
type Target = dyn Fn(T);
fn deref(&self) -> &assert_mem_uninitialized_valid::Target {
//~^ERROR: use of unresolved module or unlinked crate
//~^ERROR: cannot find module or crate `assert_mem_uninitialized_valid` in this scope
unimplemented!()
}
}

View file

@ -1,4 +1,4 @@
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `assert_mem_uninitialized_valid`
error[E0433]: cannot find module or crate `assert_mem_uninitialized_valid` in this scope
--> tests/fail/rustc-error2.rs:LL:CC
|
LL | fn deref(&self) -> &assert_mem_uninitialized_valid::Target {

View file

@ -14,8 +14,8 @@ LL | let local = 0;
help: ALLOC was deallocated here:
--> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
|
LL | f(std::ptr::null());
| ^^^^^^^^^^^^^^^^^^^
LL | let _val = unsafe { *x };
| ^^^^
= note: stack backtrace:
0: g
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() {
assert_eq!(factorial(10), 3_628_800);
assert_eq!(mutually_recursive_identity(1000), 1000);
non_scalar();
}
fn factorial(n: u32) -> u32 {
@ -37,3 +38,14 @@ fn mutually_recursive_identity(x: u32) -> u32 {
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
#![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"]
// check that assert! and const_assert! emit branch weights

View file

@ -15,13 +15,14 @@ pub fn add_noopt() -> i32 {
#[optimize(none)]
pub fn const_branch() -> i32 {
// 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: [[FALSE]]: {
// CHECK: [[BB_FALSE]]: {
// CHECK-NEXT: _0 = const 0
// CHECK-NEXT: goto
// CHECK-NEXT: }
// CHECK: [[TRUE]]: {
// CHECK: [[BB_TRUE]]: {
// CHECK-NEXT: _0 = const 1
// CHECK-NEXT: goto
// CHECK-NEXT: }

View file

@ -1,4 +1,4 @@
error[E0433]: failed to resolve: use of undeclared type `Complete`
error[E0433]: cannot find type `Complete` in this scope
--> foo.rs:3:12
|
3 | x.push(Complete::Item { name: "hello" });

View file

@ -1,4 +1,4 @@
error[E0433]: failed to resolve: use of undeclared type `Complete`
error[E0433]: cannot find type `Complete` in this scope
--> foo.rs:3:12
|
3 | x.push(Complete::Item { name: "hello" });

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

@ -1,6 +1,6 @@
// Regression test for issue #95879.
use unresolved_crate::module::Name; //~ ERROR failed to resolve
use unresolved_crate::module::Name; //~ ERROR cannot find
/// [Name]
pub struct S;

View file

@ -1,4 +1,4 @@
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `unresolved_crate`
error[E0433]: cannot find module or crate `unresolved_crate` in the crate root
--> $DIR/unresolved-import-recovery.rs:3:5
|
LL | use unresolved_crate::module::Name;

View file

@ -1,4 +1,4 @@
// This previously triggered an ICE.
pub(in crate::r#mod) fn main() {}
//~^ ERROR failed to resolve: use of unresolved module or unlinked crate `r#mod`
//~^ ERROR cannot find module or crate `r#mod` in `crate`

View file

@ -1,4 +1,4 @@
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `r#mod`
error[E0433]: cannot find module or crate `r#mod` in `crate`
--> $DIR/issue-61732.rs:3:15
|
LL | pub(in crate::r#mod) fn main() {}

View file

@ -137,7 +137,7 @@ struct MessageWrongType {
struct InvalidPathFieldAttr {
#[nonsense]
//~^ ERROR `#[nonsense]` is not a valid attribute
//~^^ ERROR cannot find attribute `nonsense` in this scope
//~| ERROR cannot find attribute `nonsense` in this scope
foo: String,
}

View file

@ -90,6 +90,14 @@ struct G {
var: String,
}
#[derive(Subdiagnostic)]
#[label("...")]
struct H {
#[primary_span]
span: Span,
var: String,
}
#[derive(Subdiagnostic)]
#[label(slug = 4)]
//~^ ERROR no nested attribute expected here

View file

@ -35,109 +35,109 @@ LL | #[label(bug = "...")]
| ^
error: derive(Diagnostic): no nested attribute expected here
--> $DIR/subdiagnostic-derive-inline.rs:94:9
--> $DIR/subdiagnostic-derive-inline.rs:102:9
|
LL | #[label(slug = 4)]
| ^^^^
error: derive(Diagnostic): diagnostic message must be first argument of a `#[label(...)]` attribute
--> $DIR/subdiagnostic-derive-inline.rs:94:1
--> $DIR/subdiagnostic-derive-inline.rs:102:1
|
LL | #[label(slug = 4)]
| ^
error: derive(Diagnostic): no nested attribute expected here
--> $DIR/subdiagnostic-derive-inline.rs:104:9
--> $DIR/subdiagnostic-derive-inline.rs:112:9
|
LL | #[label(slug("..."))]
| ^^^^
error: derive(Diagnostic): diagnostic message must be first argument of a `#[label(...)]` attribute
--> $DIR/subdiagnostic-derive-inline.rs:104:1
--> $DIR/subdiagnostic-derive-inline.rs:112:1
|
LL | #[label(slug("..."))]
| ^
error: derive(Diagnostic): diagnostic message must be first argument of a `#[label(...)]` attribute
--> $DIR/subdiagnostic-derive-inline.rs:114:1
--> $DIR/subdiagnostic-derive-inline.rs:122:1
|
LL | #[label()]
| ^
error: derive(Diagnostic): no nested attribute expected here
--> $DIR/subdiagnostic-derive-inline.rs:123:28
--> $DIR/subdiagnostic-derive-inline.rs:131:28
|
LL | #[label("example message", code = "...")]
| ^^^^
error: derive(Diagnostic): no nested attribute expected here
--> $DIR/subdiagnostic-derive-inline.rs:132:28
--> $DIR/subdiagnostic-derive-inline.rs:140:28
|
LL | #[label("example message", applicability = "machine-applicable")]
| ^^^^^^^^^^^^^
error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum
--> $DIR/subdiagnostic-derive-inline.rs:141:1
--> $DIR/subdiagnostic-derive-inline.rs:149:1
|
LL | #[foo]
| ^
error: derive(Diagnostic): `#[bar]` is not a valid attribute
--> $DIR/subdiagnostic-derive-inline.rs:155:5
--> $DIR/subdiagnostic-derive-inline.rs:163:5
|
LL | #[bar]
| ^
error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
--> $DIR/subdiagnostic-derive-inline.rs:167:5
--> $DIR/subdiagnostic-derive-inline.rs:175:5
|
LL | #[bar = "..."]
| ^
error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
--> $DIR/subdiagnostic-derive-inline.rs:179:5
--> $DIR/subdiagnostic-derive-inline.rs:187:5
|
LL | #[bar = 4]
| ^
error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive-inline.rs:191:5
--> $DIR/subdiagnostic-derive-inline.rs:199:5
|
LL | #[bar("...")]
| ^
error: derive(Diagnostic): no nested attribute expected here
--> $DIR/subdiagnostic-derive-inline.rs:203:13
--> $DIR/subdiagnostic-derive-inline.rs:211:13
|
LL | #[label(code = "...")]
| ^^^^
error: derive(Diagnostic): diagnostic message must be first argument of a `#[label(...)]` attribute
--> $DIR/subdiagnostic-derive-inline.rs:203:5
--> $DIR/subdiagnostic-derive-inline.rs:211:5
|
LL | #[label(code = "...")]
| ^
error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
--> $DIR/subdiagnostic-derive-inline.rs:232:5
--> $DIR/subdiagnostic-derive-inline.rs:240:5
|
LL | #[primary_span]
| ^
error: derive(Diagnostic): label without `#[primary_span]` field
--> $DIR/subdiagnostic-derive-inline.rs:229:1
--> $DIR/subdiagnostic-derive-inline.rs:237:1
|
LL | #[label("example message")]
| ^
error: derive(Diagnostic): `#[applicability]` is only valid on suggestions
--> $DIR/subdiagnostic-derive-inline.rs:242:5
--> $DIR/subdiagnostic-derive-inline.rs:250:5
|
LL | #[applicability]
| ^
error: derive(Diagnostic): `#[bar]` is not a valid attribute
--> $DIR/subdiagnostic-derive-inline.rs:252:5
--> $DIR/subdiagnostic-derive-inline.rs:260:5
|
LL | #[bar]
| ^
@ -145,13 +145,13 @@ LL | #[bar]
= help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
--> $DIR/subdiagnostic-derive-inline.rs:263:5
--> $DIR/subdiagnostic-derive-inline.rs:271:5
|
LL | #[bar = "..."]
| ^
error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive-inline.rs:274:5
--> $DIR/subdiagnostic-derive-inline.rs:282:5
|
LL | #[bar("...")]
| ^
@ -159,7 +159,7 @@ LL | #[bar("...")]
= help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
error: unexpected unsupported untagged union
--> $DIR/subdiagnostic-derive-inline.rs:290:1
--> $DIR/subdiagnostic-derive-inline.rs:298:1
|
LL | / union AC {
LL | |
@ -169,97 +169,97 @@ LL | | }
| |_^
error: expected this path to be an identifier
--> $DIR/subdiagnostic-derive-inline.rs:305:28
--> $DIR/subdiagnostic-derive-inline.rs:313:28
|
LL | #[label("example message", no_crate::example)]
| ^^^^^^^^^^^^^^^^^
error: derive(Diagnostic): attribute specified multiple times
--> $DIR/subdiagnostic-derive-inline.rs:318:5
--> $DIR/subdiagnostic-derive-inline.rs:326:5
|
LL | #[primary_span]
| ^
|
note: previously specified here
--> $DIR/subdiagnostic-derive-inline.rs:315:5
--> $DIR/subdiagnostic-derive-inline.rs:323:5
|
LL | #[primary_span]
| ^
error: derive(Diagnostic): subdiagnostic kind not specified
--> $DIR/subdiagnostic-derive-inline.rs:324:8
--> $DIR/subdiagnostic-derive-inline.rs:332:8
|
LL | struct AG {
| ^^
error: derive(Diagnostic): attribute specified multiple times
--> $DIR/subdiagnostic-derive-inline.rs:361:47
--> $DIR/subdiagnostic-derive-inline.rs:369:47
|
LL | #[suggestion("example message", code = "...", code = "...")]
| ^^^^
|
note: previously specified here
--> $DIR/subdiagnostic-derive-inline.rs:361:33
--> $DIR/subdiagnostic-derive-inline.rs:369:33
|
LL | #[suggestion("example message", code = "...", code = "...")]
| ^^^^
error: derive(Diagnostic): attribute specified multiple times
--> $DIR/subdiagnostic-derive-inline.rs:379:5
--> $DIR/subdiagnostic-derive-inline.rs:387:5
|
LL | #[applicability]
| ^
|
note: previously specified here
--> $DIR/subdiagnostic-derive-inline.rs:376:5
--> $DIR/subdiagnostic-derive-inline.rs:384:5
|
LL | #[applicability]
| ^
error: derive(Diagnostic): the `#[applicability]` attribute can only be applied to fields of type `Applicability`
--> $DIR/subdiagnostic-derive-inline.rs:389:5
--> $DIR/subdiagnostic-derive-inline.rs:397:5
|
LL | #[applicability]
| ^
error: derive(Diagnostic): suggestion without `code = "..."`
--> $DIR/subdiagnostic-derive-inline.rs:402:1
--> $DIR/subdiagnostic-derive-inline.rs:410:1
|
LL | #[suggestion("example message")]
| ^
error: derive(Diagnostic): invalid applicability
--> $DIR/subdiagnostic-derive-inline.rs:412:63
--> $DIR/subdiagnostic-derive-inline.rs:420:63
|
LL | #[suggestion("example message", code = "...", applicability = "foo")]
| ^^^^^
error: derive(Diagnostic): suggestion without `#[primary_span]` field
--> $DIR/subdiagnostic-derive-inline.rs:430:1
--> $DIR/subdiagnostic-derive-inline.rs:438:1
|
LL | #[suggestion("example message", code = "...")]
| ^
error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum
--> $DIR/subdiagnostic-derive-inline.rs:444:1
--> $DIR/subdiagnostic-derive-inline.rs:452:1
|
LL | #[label]
| ^
error: derive(Diagnostic): `var` doesn't refer to a field on this type
--> $DIR/subdiagnostic-derive-inline.rs:464:40
--> $DIR/subdiagnostic-derive-inline.rs:472:40
|
LL | #[suggestion("example message", code = "{var}", applicability = "machine-applicable")]
| ^^^^^^^
error: derive(Diagnostic): `var` doesn't refer to a field on this type
--> $DIR/subdiagnostic-derive-inline.rs:483:44
--> $DIR/subdiagnostic-derive-inline.rs:491:44
|
LL | #[suggestion("example message", code = "{var}", applicability = "machine-applicable")]
| ^^^^^^^
error: derive(Diagnostic): `#[suggestion_part]` is not a valid attribute
--> $DIR/subdiagnostic-derive-inline.rs:506:5
--> $DIR/subdiagnostic-derive-inline.rs:514:5
|
LL | #[suggestion_part]
| ^
@ -267,7 +267,7 @@ LL | #[suggestion_part]
= help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
error: derive(Diagnostic): `#[suggestion_part(...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive-inline.rs:509:5
--> $DIR/subdiagnostic-derive-inline.rs:517:5
|
LL | #[suggestion_part(code = "...")]
| ^
@ -275,13 +275,13 @@ LL | #[suggestion_part(code = "...")]
= help: `#[suggestion_part(...)]` is only valid in multipart suggestions
error: derive(Diagnostic): suggestion without `#[primary_span]` field
--> $DIR/subdiagnostic-derive-inline.rs:503:1
--> $DIR/subdiagnostic-derive-inline.rs:511:1
|
LL | #[suggestion("example message", code = "...")]
| ^
error: derive(Diagnostic): invalid nested attribute
--> $DIR/subdiagnostic-derive-inline.rs:518:43
--> $DIR/subdiagnostic-derive-inline.rs:526:43
|
LL | #[multipart_suggestion("example message", code = "...", applicability = "machine-applicable")]
| ^^^^
@ -289,25 +289,25 @@ LL | #[multipart_suggestion("example message", code = "...", applicability = "ma
= help: only `style` and `applicability` are valid nested attributes
error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields
--> $DIR/subdiagnostic-derive-inline.rs:518:1
--> $DIR/subdiagnostic-derive-inline.rs:526:1
|
LL | #[multipart_suggestion("example message", code = "...", applicability = "machine-applicable")]
| ^
error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
--> $DIR/subdiagnostic-derive-inline.rs:528:5
--> $DIR/subdiagnostic-derive-inline.rs:536:5
|
LL | #[suggestion_part]
| ^
error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
--> $DIR/subdiagnostic-derive-inline.rs:536:5
--> $DIR/subdiagnostic-derive-inline.rs:544:5
|
LL | #[suggestion_part()]
| ^
error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
--> $DIR/subdiagnostic-derive-inline.rs:545:5
--> $DIR/subdiagnostic-derive-inline.rs:553:5
|
LL | #[primary_span]
| ^
@ -315,127 +315,127 @@ LL | #[primary_span]
= help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields
--> $DIR/subdiagnostic-derive-inline.rs:542:1
--> $DIR/subdiagnostic-derive-inline.rs:550:1
|
LL | #[multipart_suggestion("example message")]
| ^
error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
--> $DIR/subdiagnostic-derive-inline.rs:553:5
--> $DIR/subdiagnostic-derive-inline.rs:561:5
|
LL | #[suggestion_part]
| ^
error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
--> $DIR/subdiagnostic-derive-inline.rs:556:5
--> $DIR/subdiagnostic-derive-inline.rs:564:5
|
LL | #[suggestion_part()]
| ^
error: derive(Diagnostic): `code` is the only valid nested attribute
--> $DIR/subdiagnostic-derive-inline.rs:559:23
--> $DIR/subdiagnostic-derive-inline.rs:567:23
|
LL | #[suggestion_part(foo = "bar")]
| ^^^
error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
--> $DIR/subdiagnostic-derive-inline.rs:563:5
--> $DIR/subdiagnostic-derive-inline.rs:571:5
|
LL | #[suggestion_part(code = "...")]
| ^
error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
--> $DIR/subdiagnostic-derive-inline.rs:566:5
--> $DIR/subdiagnostic-derive-inline.rs:574:5
|
LL | #[suggestion_part()]
| ^
error: expected `,`
--> $DIR/subdiagnostic-derive-inline.rs:559:27
--> $DIR/subdiagnostic-derive-inline.rs:567:27
|
LL | #[suggestion_part(foo = "bar")]
| ^
error: derive(Diagnostic): attribute specified multiple times
--> $DIR/subdiagnostic-derive-inline.rs:574:37
--> $DIR/subdiagnostic-derive-inline.rs:582:37
|
LL | #[suggestion_part(code = "...", code = ",,,")]
| ^^^^
|
note: previously specified here
--> $DIR/subdiagnostic-derive-inline.rs:574:23
--> $DIR/subdiagnostic-derive-inline.rs:582:23
|
LL | #[suggestion_part(code = "...", code = ",,,")]
| ^^^^
error: derive(Diagnostic): `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."`
--> $DIR/subdiagnostic-derive-inline.rs:603:5
--> $DIR/subdiagnostic-derive-inline.rs:611:5
|
LL | #[applicability]
| ^
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
--> $DIR/subdiagnostic-derive-inline.rs:651:28
--> $DIR/subdiagnostic-derive-inline.rs:659:28
|
LL | #[suggestion_part(code("foo"))]
| ^^^^^
error: unexpected token, expected `)`
--> $DIR/subdiagnostic-derive-inline.rs:651:28
--> $DIR/subdiagnostic-derive-inline.rs:659:28
|
LL | #[suggestion_part(code("foo"))]
| ^^^^^
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
--> $DIR/subdiagnostic-derive-inline.rs:661:28
--> $DIR/subdiagnostic-derive-inline.rs:669:28
|
LL | #[suggestion_part(code("foo", "bar"))]
| ^^^^^
error: unexpected token, expected `)`
--> $DIR/subdiagnostic-derive-inline.rs:661:28
--> $DIR/subdiagnostic-derive-inline.rs:669:28
|
LL | #[suggestion_part(code("foo", "bar"))]
| ^^^^^
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
--> $DIR/subdiagnostic-derive-inline.rs:671:28
--> $DIR/subdiagnostic-derive-inline.rs:679:28
|
LL | #[suggestion_part(code(3))]
| ^
error: unexpected token, expected `)`
--> $DIR/subdiagnostic-derive-inline.rs:671:28
--> $DIR/subdiagnostic-derive-inline.rs:679:28
|
LL | #[suggestion_part(code(3))]
| ^
error: derive(Diagnostic): expected exactly one string literal for `code = ...`
--> $DIR/subdiagnostic-derive-inline.rs:681:28
--> $DIR/subdiagnostic-derive-inline.rs:689:28
|
LL | #[suggestion_part(code())]
| ^
error: expected string literal
--> $DIR/subdiagnostic-derive-inline.rs:690:30
--> $DIR/subdiagnostic-derive-inline.rs:698:30
|
LL | #[suggestion_part(code = 3)]
| ^
error: derive(Diagnostic): attribute specified multiple times
--> $DIR/subdiagnostic-derive-inline.rs:732:1
--> $DIR/subdiagnostic-derive-inline.rs:740:1
|
LL | #[suggestion("example message", code = "", style = "hidden", style = "normal")]
| ^
|
note: previously specified here
--> $DIR/subdiagnostic-derive-inline.rs:732:1
--> $DIR/subdiagnostic-derive-inline.rs:740:1
|
LL | #[suggestion("example message", code = "", style = "hidden", style = "normal")]
| ^
error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive-inline.rs:741:1
--> $DIR/subdiagnostic-derive-inline.rs:749:1
|
LL | #[suggestion_hidden("example message", code = "")]
| ^
@ -443,7 +443,7 @@ LL | #[suggestion_hidden("example message", code = "")]
= help: Use `#[suggestion(..., style = "hidden")]` instead
error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive-inline.rs:749:1
--> $DIR/subdiagnostic-derive-inline.rs:757:1
|
LL | #[suggestion_hidden("example message", code = "", style = "normal")]
| ^
@ -451,7 +451,7 @@ LL | #[suggestion_hidden("example message", code = "", style = "normal")]
= help: Use `#[suggestion(..., style = "hidden")]` instead
error: derive(Diagnostic): invalid suggestion style
--> $DIR/subdiagnostic-derive-inline.rs:757:52
--> $DIR/subdiagnostic-derive-inline.rs:765:52
|
LL | #[suggestion("example message", code = "", style = "foo")]
| ^^^^^
@ -459,25 +459,25 @@ LL | #[suggestion("example message", code = "", style = "foo")]
= help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`
error: expected string literal
--> $DIR/subdiagnostic-derive-inline.rs:765:52
--> $DIR/subdiagnostic-derive-inline.rs:773:52
|
LL | #[suggestion("example message", code = "", style = 42)]
| ^^
error: expected `=`
--> $DIR/subdiagnostic-derive-inline.rs:773:49
--> $DIR/subdiagnostic-derive-inline.rs:781:49
|
LL | #[suggestion("example message", code = "", style)]
| ^
error: expected `=`
--> $DIR/subdiagnostic-derive-inline.rs:781:49
--> $DIR/subdiagnostic-derive-inline.rs:789:49
|
LL | #[suggestion("example message", code = "", style("foo"))]
| ^
error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
--> $DIR/subdiagnostic-derive-inline.rs:792:5
--> $DIR/subdiagnostic-derive-inline.rs:800:5
|
LL | #[primary_span]
| ^
@ -486,7 +486,7 @@ LL | #[primary_span]
= help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead
error: derive(Diagnostic): suggestion without `#[primary_span]` field
--> $DIR/subdiagnostic-derive-inline.rs:789:1
--> $DIR/subdiagnostic-derive-inline.rs:797:1
|
LL | #[suggestion("example message", code = "")]
| ^
@ -498,49 +498,49 @@ LL | #[foo]
| ^^^
error: cannot find attribute `foo` in this scope
--> $DIR/subdiagnostic-derive-inline.rs:141:3
--> $DIR/subdiagnostic-derive-inline.rs:149:3
|
LL | #[foo]
| ^^^
error: cannot find attribute `bar` in this scope
--> $DIR/subdiagnostic-derive-inline.rs:155:7
--> $DIR/subdiagnostic-derive-inline.rs:163:7
|
LL | #[bar]
| ^^^
error: cannot find attribute `bar` in this scope
--> $DIR/subdiagnostic-derive-inline.rs:167:7
--> $DIR/subdiagnostic-derive-inline.rs:175:7
|
LL | #[bar = "..."]
| ^^^
error: cannot find attribute `bar` in this scope
--> $DIR/subdiagnostic-derive-inline.rs:179:7
--> $DIR/subdiagnostic-derive-inline.rs:187:7
|
LL | #[bar = 4]
| ^^^
error: cannot find attribute `bar` in this scope
--> $DIR/subdiagnostic-derive-inline.rs:191:7
--> $DIR/subdiagnostic-derive-inline.rs:199:7
|
LL | #[bar("...")]
| ^^^
error: cannot find attribute `bar` in this scope
--> $DIR/subdiagnostic-derive-inline.rs:252:7
--> $DIR/subdiagnostic-derive-inline.rs:260:7
|
LL | #[bar]
| ^^^
error: cannot find attribute `bar` in this scope
--> $DIR/subdiagnostic-derive-inline.rs:263:7
--> $DIR/subdiagnostic-derive-inline.rs:271:7
|
LL | #[bar = "..."]
| ^^^
error: cannot find attribute `bar` in this scope
--> $DIR/subdiagnostic-derive-inline.rs:274:7
--> $DIR/subdiagnostic-derive-inline.rs:282:7
|
LL | #[bar("...")]
| ^^^

View file

@ -56,7 +56,7 @@ fn main() {
// Check that the path of an attribute without a name is printed correctly (issue #140082)
#[::a]
//~^ ERROR attribute incompatible with `#[unsafe(naked)]`
//~| ERROR failed to resolve: use of unresolved module or unlinked crate `a`
//~| ERROR cannot find module or crate `a` in the crate root
#[unsafe(naked)]
extern "C" fn issue_140082() {
naked_asm!("")

View file

@ -1,4 +1,4 @@
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `a`
error[E0433]: cannot find module or crate `a` in the crate root
--> $DIR/naked-invalid-attr.rs:57:5
|
LL | #[::a]

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

@ -1,8 +1,8 @@
// Regression test for https://github.com/rust-lang/rust/issues/143789
#[must_use::skip]
//~^ ERROR failed to resolve: use of unresolved module or unlinked crate `must_use`
//~^ ERROR: cannot find module or crate `must_use`
fn main() { }
// Regression test for https://github.com/rust-lang/rust/issues/137590
struct S(#[stable::skip] u8, u16, u32);
//~^ ERROR failed to resolve: use of unresolved module or unlinked crate `stable`
//~^ ERROR: cannot find module or crate `stable`

View file

@ -1,10 +1,10 @@
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `stable`
error[E0433]: cannot find module or crate `stable` in this scope
--> $DIR/builtin-attribute-prefix.rs:7:12
|
LL | struct S(#[stable::skip] u8, u16, u32);
| ^^^^^^ use of unresolved module or unlinked crate `stable`
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `must_use`
error[E0433]: cannot find module or crate `must_use` in this scope
--> $DIR/builtin-attribute-prefix.rs:2:3
|
LL | #[must_use::skip]

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