From cdbe8e5d281dfecaa3621dc32b1507b4901aef58 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Oct 2024 17:07:33 +0200 Subject: [PATCH 01/56] Remove usage of `allow(unused)` attribute on `no_run` doctests --- src/librustdoc/doctest/runner.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index 326ca4ee1e68..3d0db4d11eb7 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -208,10 +208,6 @@ fn generate_mergeable_doctest( } else { writeln!(output, "mod {test_id} {{\n{}{}", doctest.crates, doctest.maybe_crate_attrs) .unwrap(); - if scraped_test.langstr.no_run { - // To prevent having warnings about unused items since they're not called. - writeln!(output, "#![allow(unused)]").unwrap(); - } if doctest.has_main_fn { output.push_str(&doctest.everything_else); } else { From b073ddcce51aafde86e888d27c640f6d506e0d9d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 1 Oct 2024 17:08:01 +0200 Subject: [PATCH 02/56] Add regression tests for #130681 --- tests/rustdoc-ui/doctest/dead-code-2024.rs | 15 ++++++++++ .../rustdoc-ui/doctest/dead-code-2024.stdout | 29 +++++++++++++++++++ tests/rustdoc-ui/doctest/dead-code.rs | 15 ++++++++++ tests/rustdoc-ui/doctest/dead-code.stdout | 29 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 tests/rustdoc-ui/doctest/dead-code-2024.rs create mode 100644 tests/rustdoc-ui/doctest/dead-code-2024.stdout create mode 100644 tests/rustdoc-ui/doctest/dead-code.rs create mode 100644 tests/rustdoc-ui/doctest/dead-code.stdout diff --git a/tests/rustdoc-ui/doctest/dead-code-2024.rs b/tests/rustdoc-ui/doctest/dead-code-2024.rs new file mode 100644 index 000000000000..4c77112e61a6 --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-2024.rs @@ -0,0 +1,15 @@ +// This test ensures that the 2024 edition merged doctest will not use `#[allow(unused)]`. + +//@ compile-flags:--test -Zunstable-options --edition 2024 +//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +/// Example +/// +/// ```rust,no_run +/// trait T { fn f(); } +/// ``` +pub fn f() {} diff --git a/tests/rustdoc-ui/doctest/dead-code-2024.stdout b/tests/rustdoc-ui/doctest/dead-code-2024.stdout new file mode 100644 index 000000000000..69dd4e2ede1a --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code-2024.stdout @@ -0,0 +1,29 @@ + +running 1 test +test $DIR/dead-code-2024.rs - f (line 12) - compile ... FAILED + +failures: + +---- $DIR/dead-code-2024.rs - f (line 12) stdout ---- +error: trait `T` is never used + --> $DIR/dead-code-2024.rs:13:7 + | +LL | trait T { fn f(); } + | ^ + | +note: the lint level is defined here + --> $DIR/dead-code-2024.rs:11:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code-2024.rs - f (line 12) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/dead-code.rs b/tests/rustdoc-ui/doctest/dead-code.rs new file mode 100644 index 000000000000..cb9b4c28f6ce --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code.rs @@ -0,0 +1,15 @@ +// This test ensures that the doctest will not use `#[allow(unused)]`. + +//@ compile-flags:--test +//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ failure-status: 101 + +#![doc(test(attr(allow(unused_variables), deny(warnings))))] + +/// Example +/// +/// ```rust,no_run +/// trait T { fn f(); } +/// ``` +pub fn f() {} diff --git a/tests/rustdoc-ui/doctest/dead-code.stdout b/tests/rustdoc-ui/doctest/dead-code.stdout new file mode 100644 index 000000000000..38d15d5c1bc6 --- /dev/null +++ b/tests/rustdoc-ui/doctest/dead-code.stdout @@ -0,0 +1,29 @@ + +running 1 test +test $DIR/dead-code.rs - f (line 12) - compile ... FAILED + +failures: + +---- $DIR/dead-code.rs - f (line 12) stdout ---- +error: trait `T` is never used + --> $DIR/dead-code.rs:13:7 + | +LL | trait T { fn f(); } + | ^ + | +note: the lint level is defined here + --> $DIR/dead-code.rs:11:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]` + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/dead-code.rs - f (line 12) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + From 1819b4fa2339fcf416c8f3856f19190cab8c54ff Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 26 Oct 2024 17:46:22 -0700 Subject: [PATCH 03/56] rustdoc: make doctest span tweak a 2024 edition change Fixes #132203 This is a compatibility hack, because I think the new behavior is better. When an A `include_str!` B, and B `include_str!` C, the path to C should be resolved relative to B, not A. That's how `include!` itself works, so that's how `include_str!` with should work. --- src/librustdoc/doctest/rust.rs | 14 ++++++++++- .../doctest/auxiliary/extern_macros_2024.rs | 10 ++++++++ .../doctest/auxiliary/relative-dir-empty-file | 0 .../doctest/auxiliary/relative-dir.md | 3 +++ .../doctest/doctest-output-include-fail.rs | 3 ++- .../doctest/doctest-output.edition2015.stdout | 8 +++++++ .../doctest/doctest-output.edition2024.stdout | 8 +++++++ tests/rustdoc-ui/doctest/doctest-output.rs | 10 +++++--- .../rustdoc-ui/doctest/doctest-output.stdout | 8 ------- ...th-include-bytes-132203.edition2015.stdout | 24 +++++++++++++++++++ ...th-include-bytes-132203.edition2024.stdout | 6 +++++ .../relative-path-include-bytes-132203.rs | 17 +++++++++++++ 12 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 tests/rustdoc-ui/doctest/auxiliary/extern_macros_2024.rs create mode 100644 tests/rustdoc-ui/doctest/auxiliary/relative-dir-empty-file create mode 100644 tests/rustdoc-ui/doctest/auxiliary/relative-dir.md create mode 100644 tests/rustdoc-ui/doctest/doctest-output.edition2015.stdout create mode 100644 tests/rustdoc-ui/doctest/doctest-output.edition2024.stdout delete mode 100644 tests/rustdoc-ui/doctest/doctest-output.stdout create mode 100644 tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout create mode 100644 tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2024.stdout create mode 100644 tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index a9ab02e29cd9..27d0be133fea 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -113,7 +113,19 @@ impl<'tcx> HirCollector<'tcx> { let attrs = Attributes::from_ast(ast_attrs); if let Some(doc) = attrs.opt_doc_value() { let span = span_of_fragments(&attrs.doc_strings).unwrap_or(sp); - self.collector.position = span; + self.collector.position = if span.edition().at_least_rust_2024() { + span + } else { + // this span affects filesystem path resolution, + // so we need to keep it the same as it was previously + ast_attrs + .iter() + .find(|attr| attr.doc_str().is_some()) + .map(|attr| { + attr.span.ctxt().outer_expn().expansion_cause().unwrap_or(attr.span) + }) + .unwrap_or(DUMMY_SP) + }; markdown::find_testable_code( &doc, &mut self.collector, diff --git a/tests/rustdoc-ui/doctest/auxiliary/extern_macros_2024.rs b/tests/rustdoc-ui/doctest/auxiliary/extern_macros_2024.rs new file mode 100644 index 000000000000..354427000bf7 --- /dev/null +++ b/tests/rustdoc-ui/doctest/auxiliary/extern_macros_2024.rs @@ -0,0 +1,10 @@ +//@ edition:2024 +//@ compile-flags:-Z unstable-options +#![crate_name="extern_macros"] +#[macro_export] +macro_rules! attrs_on_struct { + ( $( #[$attr:meta] )* ) => { + $( #[$attr] )* + pub struct ExpandedStruct; + } +} diff --git a/tests/rustdoc-ui/doctest/auxiliary/relative-dir-empty-file b/tests/rustdoc-ui/doctest/auxiliary/relative-dir-empty-file new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/rustdoc-ui/doctest/auxiliary/relative-dir.md b/tests/rustdoc-ui/doctest/auxiliary/relative-dir.md new file mode 100644 index 000000000000..90097ce82fb0 --- /dev/null +++ b/tests/rustdoc-ui/doctest/auxiliary/relative-dir.md @@ -0,0 +1,3 @@ +```rust +let x = include_bytes!("relative-dir-empty-file"); +``` diff --git a/tests/rustdoc-ui/doctest/doctest-output-include-fail.rs b/tests/rustdoc-ui/doctest/doctest-output-include-fail.rs index 4fc0674a0c98..bae61992eb21 100644 --- a/tests/rustdoc-ui/doctest/doctest-output-include-fail.rs +++ b/tests/rustdoc-ui/doctest/doctest-output-include-fail.rs @@ -1,4 +1,5 @@ -//@ compile-flags:--test --test-args=--test-threads=1 +//@ edition:2024 +//@ compile-flags:--test --test-args=--test-threads=1 -Z unstable-options //@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" //@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME" //@ failure-status: 101 diff --git a/tests/rustdoc-ui/doctest/doctest-output.edition2015.stdout b/tests/rustdoc-ui/doctest/doctest-output.edition2015.stdout new file mode 100644 index 000000000000..0e2e30390ad9 --- /dev/null +++ b/tests/rustdoc-ui/doctest/doctest-output.edition2015.stdout @@ -0,0 +1,8 @@ + +running 3 tests +test $DIR/doctest-output.rs - (line 12) ... ok +test $DIR/doctest-output.rs - ExpandedStruct (line 28) ... ok +test $DIR/doctest-output.rs - foo::bar (line 22) ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/doctest-output.edition2024.stdout b/tests/rustdoc-ui/doctest/doctest-output.edition2024.stdout new file mode 100644 index 000000000000..0e2e30390ad9 --- /dev/null +++ b/tests/rustdoc-ui/doctest/doctest-output.edition2024.stdout @@ -0,0 +1,8 @@ + +running 3 tests +test $DIR/doctest-output.rs - (line 12) ... ok +test $DIR/doctest-output.rs - ExpandedStruct (line 28) ... ok +test $DIR/doctest-output.rs - foo::bar (line 22) ... ok + +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/doctest-output.rs b/tests/rustdoc-ui/doctest/doctest-output.rs index 72394a4bed31..0e5ccf0b090b 100644 --- a/tests/rustdoc-ui/doctest/doctest-output.rs +++ b/tests/rustdoc-ui/doctest/doctest-output.rs @@ -1,6 +1,10 @@ -//@ edition:2018 -//@ aux-build:extern_macros.rs -//@ compile-flags:--test --test-args=--test-threads=1 +//@ revisions: edition2015 edition2024 +//@[edition2015]edition:2015 +//@[edition2015]aux-build:extern_macros.rs +//@[edition2015]compile-flags:--test --test-args=--test-threads=1 +//@[edition2024]edition:2015 +//@[edition2024]aux-build:extern_macros.rs +//@[edition2024]compile-flags:--test --test-args=--test-threads=1 -Z unstable-options //@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" //@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME" //@ check-pass diff --git a/tests/rustdoc-ui/doctest/doctest-output.stdout b/tests/rustdoc-ui/doctest/doctest-output.stdout deleted file mode 100644 index c3b1570c43ec..000000000000 --- a/tests/rustdoc-ui/doctest/doctest-output.stdout +++ /dev/null @@ -1,8 +0,0 @@ - -running 3 tests -test $DIR/doctest-output.rs - (line 8) ... ok -test $DIR/doctest-output.rs - ExpandedStruct (line 25) ... ok -test $DIR/doctest-output.rs - foo::bar (line 18) ... ok - -test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME - diff --git a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout new file mode 100644 index 000000000000..535d68175019 --- /dev/null +++ b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout @@ -0,0 +1,24 @@ + +running 1 test +test $DIR/relative-path-include-bytes-132203.rs - (line 17) ... FAILED + +failures: + +---- $DIR/relative-path-include-bytes-132203.rs - (line 17) stdout ---- +error: couldn't read `$DIR/relative-dir-empty-file`: No such file or directory (os error 2) + --> $DIR/relative-path-include-bytes-132203.rs:18:9 + | +LL | let x = include_bytes!("relative-dir-empty-file"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + $DIR/relative-path-include-bytes-132203.rs - (line 17) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2024.stdout b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2024.stdout new file mode 100644 index 000000000000..e4c657030819 --- /dev/null +++ b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2024.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/auxiliary/relative-dir.md - (line 1) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs new file mode 100644 index 000000000000..6ec41a3c0528 --- /dev/null +++ b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs @@ -0,0 +1,17 @@ +//@ revisions: edition2015 edition2024 +//@[edition2015]edition:2015 +//@[edition2015]check-fail +//@[edition2015]failure-status: 101 +//@[edition2015]compile-flags:--test --test-args=--test-threads=1 +//@[edition2024]edition:2024 +//@[edition2024]check-pass +//@[edition2024]compile-flags:--test --test-args=--test-threads=1 -Z unstable-options +//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME" + +// https://github.com/rust-lang/rust/issues/132203 +// This version, because it's edition2024, passes thanks to the new +// relative path. The edition2015 version fails, because paths are +// resolved relative to the rs file instead of relative to the md file. + +#![doc=include_str!("auxiliary/relative-dir.md")] From a201fab20881499d79e5694ee8f195ce50c5b724 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 17 Apr 2024 17:08:58 +1000 Subject: [PATCH 04/56] Tweak `expand_incomplete_parse` warning. By using `token_descr`, as is done for many other errors, we can get slightly better descriptions in error messages, e.g. "macro expansion ignores token `let` and any following" becomes "macro expansion ignores keyword `let` and any tokens following". This will be more important once invisible delimiters start being mentioned in error messages -- without this commit, that leads to error messages such as "error at ``" because invisible delimiters are pretty printed as an empty string. --- compiler/rustc_expand/messages.ftl | 2 +- compiler/rustc_expand/src/errors.rs | 2 +- compiler/rustc_expand/src/expand.rs | 5 +++-- compiler/rustc_parse/src/parser/mod.rs | 2 +- tests/ui/macros/issue-118786.rs | 2 +- tests/ui/macros/issue-118786.stderr | 2 +- tests/ui/macros/issue-30007.rs | 2 +- tests/ui/macros/issue-30007.stderr | 2 +- tests/ui/macros/issue-54441.rs | 2 +- tests/ui/macros/issue-54441.stderr | 2 +- tests/ui/macros/macro-context.rs | 6 +++--- tests/ui/macros/macro-context.stderr | 6 +++--- tests/ui/macros/macro-in-expression-context.fixed | 2 +- tests/ui/macros/macro-in-expression-context.rs | 2 +- tests/ui/macros/macro-in-expression-context.stderr | 2 +- tests/ui/macros/syntax-error-recovery.rs | 2 +- tests/ui/macros/syntax-error-recovery.stderr | 2 +- tests/ui/parser/macro/macro-expand-to-match-arm.rs | 2 +- tests/ui/parser/macro/macro-expand-to-match-arm.stderr | 2 +- tests/ui/parser/macro/macro-incomplete-parse.rs | 4 ++-- tests/ui/parser/macro/macro-incomplete-parse.stderr | 4 ++-- tests/ui/parser/macro/trait-non-item-macros.rs | 2 +- tests/ui/parser/macro/trait-non-item-macros.stderr | 2 +- tests/ui/proc-macro/attr-invalid-exprs.rs | 4 ++-- tests/ui/proc-macro/attr-invalid-exprs.stderr | 4 ++-- tests/ui/proc-macro/expand-expr.rs | 4 ++-- tests/ui/proc-macro/expand-expr.stderr | 4 ++-- 27 files changed, 39 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index fcf3352bfc59..f26c7c1ba0bc 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -74,7 +74,7 @@ expand_helper_attribute_name_invalid = `{$name}` cannot be a name of derive helper attribute expand_incomplete_parse = - macro expansion ignores token `{$token}` and any following + macro expansion ignores {$descr} and any tokens following .label = caused by the macro expansion here .note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context .suggestion_add_semi = you might be missing a semicolon here diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 5682c574552b..7bd7c3055391 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -275,7 +275,7 @@ pub(crate) struct UnsupportedKeyValue { pub(crate) struct IncompleteParse<'a> { #[primary_span] pub span: Span, - pub token: Cow<'a, str>, + pub descr: String, #[label] pub label_span: Span, pub macro_path: &'a ast::Path, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 5ffafcaa5426..04ac7891023f 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -21,6 +21,7 @@ use rustc_errors::PResult; use rustc_feature::Features; use rustc_parse::parser::{ AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma, + token_descr, }; use rustc_parse::validate_attr; use rustc_session::lint::BuiltinLintDiag; @@ -1013,7 +1014,7 @@ pub(crate) fn ensure_complete_parse<'a>( span: Span, ) { if parser.token != token::Eof { - let token = pprust::token_to_string(&parser.token); + let descr = token_descr(&parser.token); // Avoid emitting backtrace info twice. let def_site_span = parser.token.span.with_ctxt(SyntaxContext::root()); @@ -1029,7 +1030,7 @@ pub(crate) fn ensure_complete_parse<'a>( parser.dcx().emit_err(IncompleteParse { span: def_site_span, - token, + descr, label_span: span, macro_path, kind_name, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 77ad4fdeeb17..50a8b6542df4 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -424,7 +424,7 @@ impl TokenDescription { } } -pub(super) fn token_descr(token: &Token) -> String { +pub fn token_descr(token: &Token) -> String { let name = pprust::token_to_string(token).to_string(); let kind = match (TokenDescription::from_token(token), &token.kind) { diff --git a/tests/ui/macros/issue-118786.rs b/tests/ui/macros/issue-118786.rs index a41372e4ea84..a73b737fe07e 100644 --- a/tests/ui/macros/issue-118786.rs +++ b/tests/ui/macros/issue-118786.rs @@ -5,7 +5,7 @@ macro_rules! make_macro { ($macro_name:tt) => { macro_rules! $macro_name { - //~^ ERROR macro expansion ignores token `{` and any following + //~^ ERROR macro expansion ignores `{` and any tokens following //~| ERROR cannot find macro `macro_rules` in this scope //~| put a macro name here () => {} diff --git a/tests/ui/macros/issue-118786.stderr b/tests/ui/macros/issue-118786.stderr index 256b742ee160..7fa5c2b83ddd 100644 --- a/tests/ui/macros/issue-118786.stderr +++ b/tests/ui/macros/issue-118786.stderr @@ -13,7 +13,7 @@ help: add a semicolon LL | macro_rules! $macro_name; { | + -error: macro expansion ignores token `{` and any following +error: macro expansion ignores `{` and any tokens following --> $DIR/issue-118786.rs:7:34 | LL | macro_rules! $macro_name { diff --git a/tests/ui/macros/issue-30007.rs b/tests/ui/macros/issue-30007.rs index 918a821bae92..e36e47a3e7c2 100644 --- a/tests/ui/macros/issue-30007.rs +++ b/tests/ui/macros/issue-30007.rs @@ -1,5 +1,5 @@ macro_rules! t { - () => ( String ; ); //~ ERROR macro expansion ignores token `;` + () => ( String ; ); //~ ERROR macro expansion ignores `;` } fn main() { diff --git a/tests/ui/macros/issue-30007.stderr b/tests/ui/macros/issue-30007.stderr index f303221cf8aa..129733ed69ab 100644 --- a/tests/ui/macros/issue-30007.stderr +++ b/tests/ui/macros/issue-30007.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `;` and any following +error: macro expansion ignores `;` and any tokens following --> $DIR/issue-30007.rs:2:20 | LL | () => ( String ; ); diff --git a/tests/ui/macros/issue-54441.rs b/tests/ui/macros/issue-54441.rs index b24d7e1f6bee..37ab4e636475 100644 --- a/tests/ui/macros/issue-54441.rs +++ b/tests/ui/macros/issue-54441.rs @@ -1,6 +1,6 @@ macro_rules! m { () => { - let //~ ERROR macro expansion ignores token `let` and any following + let //~ ERROR macro expansion ignores keyword `let` and any tokens following }; } diff --git a/tests/ui/macros/issue-54441.stderr b/tests/ui/macros/issue-54441.stderr index fb2c103139b9..f5f8b8ca2b26 100644 --- a/tests/ui/macros/issue-54441.stderr +++ b/tests/ui/macros/issue-54441.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `let` and any following +error: macro expansion ignores keyword `let` and any tokens following --> $DIR/issue-54441.rs:3:9 | LL | let diff --git a/tests/ui/macros/macro-context.rs b/tests/ui/macros/macro-context.rs index d09fdf118e6f..a31470263a0a 100644 --- a/tests/ui/macros/macro-context.rs +++ b/tests/ui/macros/macro-context.rs @@ -1,9 +1,9 @@ // (typeof used because it's surprisingly hard to find an unparsed token after a stmt) macro_rules! m { () => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof` - //~| ERROR macro expansion ignores token `typeof` - //~| ERROR macro expansion ignores token `;` - //~| ERROR macro expansion ignores token `;` + //~| ERROR macro expansion ignores reserved keyword `typeof` + //~| ERROR macro expansion ignores `;` + //~| ERROR macro expansion ignores `;` //~| ERROR cannot find type `i` in this scope //~| ERROR cannot find value `i` in this scope //~| WARN trailing semicolon in macro diff --git a/tests/ui/macros/macro-context.stderr b/tests/ui/macros/macro-context.stderr index 7785f4159462..4820a43f00c7 100644 --- a/tests/ui/macros/macro-context.stderr +++ b/tests/ui/macros/macro-context.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `;` and any following +error: macro expansion ignores `;` and any tokens following --> $DIR/macro-context.rs:3:15 | LL | () => ( i ; typeof ); @@ -9,7 +9,7 @@ LL | let a: m!(); | = note: the usage of `m!` is likely invalid in type context -error: macro expansion ignores token `typeof` and any following +error: macro expansion ignores reserved keyword `typeof` and any tokens following --> $DIR/macro-context.rs:3:17 | LL | () => ( i ; typeof ); @@ -20,7 +20,7 @@ LL | let i = m!(); | = note: the usage of `m!` is likely invalid in expression context -error: macro expansion ignores token `;` and any following +error: macro expansion ignores `;` and any tokens following --> $DIR/macro-context.rs:3:15 | LL | () => ( i ; typeof ); diff --git a/tests/ui/macros/macro-in-expression-context.fixed b/tests/ui/macros/macro-in-expression-context.fixed index f4d04ca37bf5..7c830707ffd9 100644 --- a/tests/ui/macros/macro-in-expression-context.fixed +++ b/tests/ui/macros/macro-in-expression-context.fixed @@ -11,7 +11,7 @@ macro_rules! foo { //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default assert_eq!("B", "B"); } - //~^^ ERROR macro expansion ignores token `assert_eq` and any following + //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following //~| NOTE the usage of `foo!` is likely invalid in expression context } diff --git a/tests/ui/macros/macro-in-expression-context.rs b/tests/ui/macros/macro-in-expression-context.rs index 8921a0563772..da95017aa5f7 100644 --- a/tests/ui/macros/macro-in-expression-context.rs +++ b/tests/ui/macros/macro-in-expression-context.rs @@ -11,7 +11,7 @@ macro_rules! foo { //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default assert_eq!("B", "B"); } - //~^^ ERROR macro expansion ignores token `assert_eq` and any following + //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following //~| NOTE the usage of `foo!` is likely invalid in expression context } diff --git a/tests/ui/macros/macro-in-expression-context.stderr b/tests/ui/macros/macro-in-expression-context.stderr index 2eee63f307af..43419f2678c2 100644 --- a/tests/ui/macros/macro-in-expression-context.stderr +++ b/tests/ui/macros/macro-in-expression-context.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `assert_eq` and any following +error: macro expansion ignores `assert_eq` and any tokens following --> $DIR/macro-in-expression-context.rs:12:9 | LL | assert_eq!("B", "B"); diff --git a/tests/ui/macros/syntax-error-recovery.rs b/tests/ui/macros/syntax-error-recovery.rs index f6178c137db9..016e4def2849 100644 --- a/tests/ui/macros/syntax-error-recovery.rs +++ b/tests/ui/macros/syntax-error-recovery.rs @@ -10,7 +10,7 @@ macro_rules! values { }; } //~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)` -//~| ERROR macro expansion ignores token `(String)` and any following +//~| ERROR macro expansion ignores type `(String)` and any tokens following values!(STRING(1) as (String) => cfg(test),); //~^ ERROR expected one of `!` or `::`, found `` diff --git a/tests/ui/macros/syntax-error-recovery.stderr b/tests/ui/macros/syntax-error-recovery.stderr index 6218bf43a1ef..3cfbd8ce82b5 100644 --- a/tests/ui/macros/syntax-error-recovery.stderr +++ b/tests/ui/macros/syntax-error-recovery.stderr @@ -10,7 +10,7 @@ LL | values!(STRING(1) as (String) => cfg(test),); = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` = note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info) -error: macro expansion ignores token `(String)` and any following +error: macro expansion ignores type `(String)` and any tokens following --> $DIR/syntax-error-recovery.rs:7:26 | LL | $token $($inner)? = $value, diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.rs b/tests/ui/parser/macro/macro-expand-to-match-arm.rs index db38fa0d7bc6..0e27836b718b 100644 --- a/tests/ui/parser/macro/macro-expand-to-match-arm.rs +++ b/tests/ui/parser/macro/macro-expand-to-match-arm.rs @@ -1,7 +1,7 @@ macro_rules! arm { ($pattern:pat => $block:block) => { $pattern => $block - //~^ ERROR macro expansion ignores token `=>` and any following + //~^ ERROR macro expansion ignores `=>` and any tokens following //~| NOTE the usage of `arm!` is likely invalid in pattern context //~| NOTE macros cannot expand to match arms }; diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.stderr b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr index e3e7ff89c813..1927d80fd724 100644 --- a/tests/ui/parser/macro/macro-expand-to-match-arm.stderr +++ b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `=>` and any following +error: macro expansion ignores `=>` and any tokens following --> $DIR/macro-expand-to-match-arm.rs:3:18 | LL | $pattern => $block diff --git a/tests/ui/parser/macro/macro-incomplete-parse.rs b/tests/ui/parser/macro/macro-incomplete-parse.rs index 544e4aa7b1b0..612196aa4b27 100644 --- a/tests/ui/parser/macro/macro-incomplete-parse.rs +++ b/tests/ui/parser/macro/macro-incomplete-parse.rs @@ -2,7 +2,7 @@ macro_rules! ignored_item { () => { fn foo() {} fn bar() {} - , //~ ERROR macro expansion ignores token `,` + , //~ ERROR macro expansion ignores `,` } } @@ -13,7 +13,7 @@ macro_rules! ignored_expr { } macro_rules! ignored_pat { - () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,` + () => ( 1, 2 ) //~ ERROR macro expansion ignores `,` } ignored_item!(); diff --git a/tests/ui/parser/macro/macro-incomplete-parse.stderr b/tests/ui/parser/macro/macro-incomplete-parse.stderr index 707417b725e9..096b5f718ae1 100644 --- a/tests/ui/parser/macro/macro-incomplete-parse.stderr +++ b/tests/ui/parser/macro/macro-incomplete-parse.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `,` and any following +error: macro expansion ignores `,` and any tokens following --> $DIR/macro-incomplete-parse.rs:5:9 | LL | , @@ -20,7 +20,7 @@ LL | ignored_expr!(); | = note: this error originates in the macro `ignored_expr` (in Nightly builds, run with -Z macro-backtrace for more info) -error: macro expansion ignores token `,` and any following +error: macro expansion ignores `,` and any tokens following --> $DIR/macro-incomplete-parse.rs:16:14 | LL | () => ( 1, 2 ) diff --git a/tests/ui/parser/macro/trait-non-item-macros.rs b/tests/ui/parser/macro/trait-non-item-macros.rs index 97fb564bf647..e93000193b6e 100644 --- a/tests/ui/parser/macro/trait-non-item-macros.rs +++ b/tests/ui/parser/macro/trait-non-item-macros.rs @@ -1,7 +1,7 @@ macro_rules! bah { ($a:expr) => { $a - }; //~^ ERROR macro expansion ignores token `2` and any following + }; //~^ ERROR macro expansion ignores expression `2` and any tokens following } trait Bar { diff --git a/tests/ui/parser/macro/trait-non-item-macros.stderr b/tests/ui/parser/macro/trait-non-item-macros.stderr index db20e6b24aa0..1a8284837789 100644 --- a/tests/ui/parser/macro/trait-non-item-macros.stderr +++ b/tests/ui/parser/macro/trait-non-item-macros.stderr @@ -1,4 +1,4 @@ -error: macro expansion ignores token `2` and any following +error: macro expansion ignores expression `2` and any tokens following --> $DIR/trait-non-item-macros.rs:3:9 | LL | $a diff --git a/tests/ui/proc-macro/attr-invalid-exprs.rs b/tests/ui/proc-macro/attr-invalid-exprs.rs index 3d8806ee8003..ec0b79469a45 100644 --- a/tests/ui/proc-macro/attr-invalid-exprs.rs +++ b/tests/ui/proc-macro/attr-invalid-exprs.rs @@ -13,7 +13,7 @@ fn main() { //~^ ERROR expected expression, found end of macro arguments let _ = #[duplicate] "Hello, world!"; - //~^ ERROR macro expansion ignores token `,` and any following + //~^ ERROR macro expansion ignores `,` and any tokens following let _ = { #[no_output] @@ -22,7 +22,7 @@ fn main() { let _ = { #[duplicate] - //~^ ERROR macro expansion ignores token `,` and any following + //~^ ERROR macro expansion ignores `,` and any tokens following "Hello, world!" }; } diff --git a/tests/ui/proc-macro/attr-invalid-exprs.stderr b/tests/ui/proc-macro/attr-invalid-exprs.stderr index f96939bb6efc..0d500c871453 100644 --- a/tests/ui/proc-macro/attr-invalid-exprs.stderr +++ b/tests/ui/proc-macro/attr-invalid-exprs.stderr @@ -4,7 +4,7 @@ error: expected expression, found end of macro arguments LL | let _ = #[no_output] "Hello, world!"; | ^^^^^^^^^^^^ -error: macro expansion ignores token `,` and any following +error: macro expansion ignores `,` and any tokens following --> $DIR/attr-invalid-exprs.rs:15:13 | LL | let _ = #[duplicate] "Hello, world!"; @@ -16,7 +16,7 @@ help: you might be missing a semicolon here LL | let _ = #[duplicate]; "Hello, world!"; | + -error: macro expansion ignores token `,` and any following +error: macro expansion ignores `,` and any tokens following --> $DIR/attr-invalid-exprs.rs:24:9 | LL | #[duplicate] diff --git a/tests/ui/proc-macro/expand-expr.rs b/tests/ui/proc-macro/expand-expr.rs index 5f7375d7450d..e06ddc51a297 100644 --- a/tests/ui/proc-macro/expand-expr.rs +++ b/tests/ui/proc-macro/expand-expr.rs @@ -114,8 +114,8 @@ expand_expr_fail!(echo_pm!($)); //~ ERROR: expected expression, found `$` // We get errors reported and recover during macro expansion if the macro // doesn't produce a valid expression. -expand_expr_is!("string", echo_tts!("string"; hello)); //~ ERROR: macro expansion ignores token `hello` and any following -expand_expr_is!("string", echo_pm!("string"; hello)); //~ ERROR: macro expansion ignores token `;` and any following +expand_expr_is!("string", echo_tts!("string"; hello)); //~ ERROR: macro expansion ignores `hello` and any tokens following +expand_expr_is!("string", echo_pm!("string"; hello)); //~ ERROR: macro expansion ignores `;` and any tokens following // For now, fail if a non-literal expression is expanded. expand_expr_fail!(arbitrary_expression() + "etc"); diff --git a/tests/ui/proc-macro/expand-expr.stderr b/tests/ui/proc-macro/expand-expr.stderr index 2b92472e5ab7..8b1df177cfa6 100644 --- a/tests/ui/proc-macro/expand-expr.stderr +++ b/tests/ui/proc-macro/expand-expr.stderr @@ -22,7 +22,7 @@ error: expected expression, found `$` LL | expand_expr_fail!(echo_pm!($)); | ^ expected expression -error: macro expansion ignores token `hello` and any following +error: macro expansion ignores `hello` and any tokens following --> $DIR/expand-expr.rs:117:47 | LL | expand_expr_is!("string", echo_tts!("string"; hello)); @@ -34,7 +34,7 @@ help: you might be missing a semicolon here LL | expand_expr_is!("string", echo_tts!("string"; hello);); | + -error: macro expansion ignores token `;` and any following +error: macro expansion ignores `;` and any tokens following --> $DIR/expand-expr.rs:118:44 | LL | expand_expr_is!("string", echo_pm!("string"; hello)); From dd2b027d5d509dd95c5ef6f83ea6283f3e98d5ed Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 25 Jun 2024 12:52:15 +1000 Subject: [PATCH 05/56] Tweak more warnings. Much like the previous commit. I think the removal of "the token" in each message is fine here. There are many more error messages that mention tokens without saying "the token" than those that do say it. --- compiler/rustc_expand/src/mbe/diagnostics.rs | 13 +++---------- compiler/rustc_expand/src/mbe/macro_parser.rs | 5 ++--- .../array-slice-vec/vec-macro-with-comma-only.rs | 2 +- .../vec-macro-with-comma-only.stderr | 2 +- .../editions/edition-keywords-2015-2015-parsing.rs | 4 ++-- .../edition-keywords-2015-2015-parsing.stderr | 4 ++-- .../editions/edition-keywords-2015-2018-parsing.rs | 4 ++-- .../edition-keywords-2015-2018-parsing.stderr | 4 ++-- .../editions/edition-keywords-2018-2015-parsing.rs | 4 ++-- .../edition-keywords-2018-2015-parsing.stderr | 6 +++--- .../editions/edition-keywords-2018-2018-parsing.rs | 4 ++-- .../edition-keywords-2018-2018-parsing.stderr | 6 +++--- tests/ui/fail-simple.rs | 2 +- tests/ui/fail-simple.stderr | 2 +- .../assert-trailing-junk.with-generic-asset.stderr | 4 ++-- ...sert-trailing-junk.without-generic-asset.stderr | 4 ++-- tests/ui/macros/best-failure.rs | 2 +- tests/ui/macros/best-failure.stderr | 2 +- .../macros/expr_2021_inline_const.edi2021.stderr | 4 ++-- .../macros/expr_2021_inline_const.edi2024.stderr | 2 +- tests/ui/macros/expr_2021_inline_const.rs | 4 ++-- .../expr_2024_underscore_expr.edi2021.stderr | 4 ++-- .../expr_2024_underscore_expr.edi2024.stderr | 2 +- tests/ui/macros/expr_2024_underscore_expr.rs | 4 ++-- tests/ui/macros/macro-at-most-once-rep-2015.rs | 14 +++++++------- tests/ui/macros/macro-at-most-once-rep-2015.stderr | 14 +++++++------- tests/ui/macros/macro-at-most-once-rep-2018.rs | 14 +++++++------- tests/ui/macros/macro-at-most-once-rep-2018.stderr | 14 +++++++------- tests/ui/macros/macro-non-lifetime.rs | 2 +- tests/ui/macros/macro-non-lifetime.stderr | 2 +- tests/ui/macros/missing-comma.rs | 10 +++++----- tests/ui/macros/missing-comma.stderr | 10 +++++----- tests/ui/macros/nonterminal-matching.rs | 10 +++++----- tests/ui/macros/nonterminal-matching.stderr | 14 +++++++------- tests/ui/macros/trace_faulty_macros.stderr | 2 +- tests/ui/offset-of/offset-of-arg-count.rs | 2 +- tests/ui/offset-of/offset-of-arg-count.stderr | 2 +- tests/ui/offset-of/offset-of-tuple.stderr | 2 +- .../or-patterns/or-patterns-syntactic-fail-2018.rs | 4 ++-- .../or-patterns-syntactic-fail-2018.stderr | 4 ++-- tests/ui/parser/macro/macro-doc-comments-1.rs | 2 +- tests/ui/parser/macro/macro-doc-comments-1.stderr | 2 +- tests/ui/parser/macro/macro-doc-comments-2.rs | 2 +- tests/ui/parser/macro/macro-doc-comments-2.stderr | 2 +- .../ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs | 2 +- .../rfcs/rfc-2294-if-let-guard/feature-gate.stderr | 2 +- .../ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs | 2 +- .../rfc-2497-if-let-chains/feature-gate.stderr | 2 +- tests/ui/underscore-ident-matcher.rs | 2 +- tests/ui/underscore-ident-matcher.stderr | 2 +- 50 files changed, 113 insertions(+), 121 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 103bbb05e7ff..ffcce1e52f67 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -2,10 +2,9 @@ use std::borrow::Cow; use rustc_ast::token::{self, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage}; use rustc_macros::Subdiagnostic; -use rustc_parse::parser::{Parser, Recovery}; +use rustc_parse::parser::{Parser, Recovery, token_descr}; use rustc_session::parse::ParseSess; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Ident; @@ -336,17 +335,11 @@ pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Spa /// other tokens, this is "unexpected token...". pub(super) fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> { if let Some(expected_token) = expected_token { - Cow::from(format!( - "expected `{}`, found `{}`", - pprust::token_to_string(expected_token), - pprust::token_to_string(tok), - )) + Cow::from(format!("expected {}, found {}", token_descr(expected_token), token_descr(tok))) } else { match tok.kind { token::Eof => Cow::from("unexpected end of macro invocation"), - _ => { - Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok))) - } + _ => Cow::from(format!("no rules expected {}", token_descr(tok))), } } } diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 3903203da3db..a54b0a5e0132 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -78,11 +78,10 @@ use std::rc::Rc; pub(crate) use NamedMatch::*; pub(crate) use ParseResult::*; use rustc_ast::token::{self, DocComment, NonterminalKind, Token}; -use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_lint_defs::pluralize; -use rustc_parse::parser::{ParseNtResult, Parser}; +use rustc_parse::parser::{ParseNtResult, Parser, token_descr}; use rustc_span::Span; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent}; @@ -150,7 +149,7 @@ impl Display for MatcherLoc { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { MatcherLoc::Token { token } | MatcherLoc::SequenceSep { separator: token } => { - write!(f, "`{}`", pprust::token_to_string(token)) + write!(f, "{}", token_descr(token)) } MatcherLoc::MetaVarDecl { bind, kind, .. } => { write!(f, "meta-variable `${bind}")?; diff --git a/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs b/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs index 574a53c58fea..0f99f6b1b1e0 100644 --- a/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs +++ b/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs @@ -1,3 +1,3 @@ pub fn main() { - vec![,]; //~ ERROR no rules expected the token `,` + vec![,]; //~ ERROR no rules expected `,` } diff --git a/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr b/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr index b3f953af6d27..d76d493eca83 100644 --- a/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr +++ b/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `,` +error: no rules expected `,` --> $DIR/vec-macro-with-comma-only.rs:2:10 | LL | vec![,]; diff --git a/tests/ui/editions/edition-keywords-2015-2015-parsing.rs b/tests/ui/editions/edition-keywords-2015-2015-parsing.rs index 07104bdf217d..4751d280467c 100644 --- a/tests/ui/editions/edition-keywords-2015-2015-parsing.rs +++ b/tests/ui/editions/edition-keywords-2015-2015-parsing.rs @@ -13,8 +13,8 @@ pub fn check_async() { let mut r#async = 1; // OK r#async = consumes_async!(async); // OK - r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` - r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` + r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async` + r#async = consumes_async_raw!(async); //~ ERROR no rules expected `async` r#async = consumes_async_raw!(r#async); // OK if passes_ident!(async) == 1 {} // OK diff --git a/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr index 39944622d07b..2519a9fded2e 100644 --- a/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `r#async` +error: no rules expected `r#async` --> $DIR/edition-keywords-2015-2015-parsing.rs:16:31 | LL | r#async = consumes_async!(r#async); @@ -10,7 +10,7 @@ note: while trying to match `async` LL | (async) => (1) | ^^^^^ -error: no rules expected the token `async` +error: no rules expected `async` --> $DIR/edition-keywords-2015-2015-parsing.rs:17:35 | LL | r#async = consumes_async_raw!(async); diff --git a/tests/ui/editions/edition-keywords-2015-2018-parsing.rs b/tests/ui/editions/edition-keywords-2015-2018-parsing.rs index 3c294f95cd26..4404ea26fb30 100644 --- a/tests/ui/editions/edition-keywords-2015-2018-parsing.rs +++ b/tests/ui/editions/edition-keywords-2015-2018-parsing.rs @@ -13,8 +13,8 @@ pub fn check_async() { let mut r#async = 1; // OK r#async = consumes_async!(async); // OK - r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` - r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` + r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async` + r#async = consumes_async_raw!(async); //~ ERROR no rules expected `async` r#async = consumes_async_raw!(r#async); // OK if passes_ident!(async) == 1 {} // OK diff --git a/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr index fa83908e6666..0c0e57384151 100644 --- a/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `r#async` +error: no rules expected `r#async` --> $DIR/edition-keywords-2015-2018-parsing.rs:16:31 | LL | r#async = consumes_async!(r#async); @@ -10,7 +10,7 @@ note: while trying to match `async` LL | (async) => (1) | ^^^^^ -error: no rules expected the token `async` +error: no rules expected `async` --> $DIR/edition-keywords-2015-2018-parsing.rs:17:35 | LL | r#async = consumes_async_raw!(async); diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs index 591845432740..c346be508560 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs @@ -17,8 +17,8 @@ pub fn check_async() { let mut r#async = 1; // OK r#async = consumes_async!(async); // OK - r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` - r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` + r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async` + r#async = consumes_async_raw!(async); //~ ERROR no rules expected keyword `async` r#async = consumes_async_raw!(r#async); // OK if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr index 42db75f66597..aed5837abeaf 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -20,19 +20,19 @@ help: escape `async` to use it as an identifier LL | module::r#async(); | ++ -error: no rules expected the token `r#async` +error: no rules expected `r#async` --> $DIR/edition-keywords-2018-2015-parsing.rs:20:31 | LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call | -note: while trying to match `async` +note: while trying to match keyword `async` --> $DIR/auxiliary/edition-kw-macro-2015.rs:17:6 | LL | (async) => (1) | ^^^^^ -error: no rules expected the token `async` +error: no rules expected keyword `async` --> $DIR/edition-keywords-2018-2015-parsing.rs:21:35 | LL | r#async = consumes_async_raw!(async); diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs index 4975246fa942..b75b68b3febb 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs @@ -24,8 +24,8 @@ pub fn check_async() { let mut r#async = 1; // OK r#async = consumes_async!(async); // OK - r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async` - r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async` + r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async` + r#async = consumes_async_raw!(async); //~ ERROR no rules expected keyword `async` r#async = consumes_async_raw!(r#async); // OK if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr index 4bbe1597233c..6503e9cc73cf 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -20,19 +20,19 @@ help: escape `async` to use it as an identifier LL | module::r#async(); | ++ -error: no rules expected the token `r#async` +error: no rules expected `r#async` --> $DIR/edition-keywords-2018-2018-parsing.rs:27:31 | LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call | -note: while trying to match `async` +note: while trying to match keyword `async` --> $DIR/auxiliary/edition-kw-macro-2018.rs:17:6 | LL | (async) => (1) | ^^^^^ -error: no rules expected the token `async` +error: no rules expected keyword `async` --> $DIR/edition-keywords-2018-2018-parsing.rs:28:35 | LL | r#async = consumes_async_raw!(async); diff --git a/tests/ui/fail-simple.rs b/tests/ui/fail-simple.rs index cd81a5d0a0fc..55e547ee72b0 100644 --- a/tests/ui/fail-simple.rs +++ b/tests/ui/fail-simple.rs @@ -1,3 +1,3 @@ fn main() { - panic!(@); //~ ERROR no rules expected the token `@` + panic!(@); //~ ERROR no rules expected `@` } diff --git a/tests/ui/fail-simple.stderr b/tests/ui/fail-simple.stderr index 39fec3e2517b..50c350b3ef55 100644 --- a/tests/ui/fail-simple.stderr +++ b/tests/ui/fail-simple.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `@` +error: no rules expected `@` --> $DIR/fail-simple.rs:2:12 | LL | panic!(@); diff --git a/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr index 1e73320e4391..7582c8e8659b 100644 --- a/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr +++ b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr @@ -10,7 +10,7 @@ error: expected one of `,`, `.`, `?`, or an operator, found `some` LL | assert!(true some extra junk); | ^^^^ expected one of `,`, `.`, `?`, or an operator -error: no rules expected the token `blah` +error: no rules expected `blah` --> $DIR/assert-trailing-junk.rs:15:30 | LL | assert!(true, "whatever" blah); @@ -28,7 +28,7 @@ LL | assert!(true "whatever" blah); | | | help: try adding a comma -error: no rules expected the token `blah` +error: no rules expected `blah` --> $DIR/assert-trailing-junk.rs:18:29 | LL | assert!(true "whatever" blah); diff --git a/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr index 1e73320e4391..7582c8e8659b 100644 --- a/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr +++ b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr @@ -10,7 +10,7 @@ error: expected one of `,`, `.`, `?`, or an operator, found `some` LL | assert!(true some extra junk); | ^^^^ expected one of `,`, `.`, `?`, or an operator -error: no rules expected the token `blah` +error: no rules expected `blah` --> $DIR/assert-trailing-junk.rs:15:30 | LL | assert!(true, "whatever" blah); @@ -28,7 +28,7 @@ LL | assert!(true "whatever" blah); | | | help: try adding a comma -error: no rules expected the token `blah` +error: no rules expected `blah` --> $DIR/assert-trailing-junk.rs:18:29 | LL | assert!(true "whatever" blah); diff --git a/tests/ui/macros/best-failure.rs b/tests/ui/macros/best-failure.rs index bbdd465d5ec9..1b73066c8749 100644 --- a/tests/ui/macros/best-failure.rs +++ b/tests/ui/macros/best-failure.rs @@ -2,7 +2,7 @@ macro_rules! number { (neg false, $self:ident) => { $self }; ($signed:tt => $ty:ty;) => { number!(neg $signed, $self); - //~^ ERROR no rules expected the token `$` + //~^ ERROR no rules expected `$` }; } diff --git a/tests/ui/macros/best-failure.stderr b/tests/ui/macros/best-failure.stderr index c5f8b9abc19a..914ff7fd8207 100644 --- a/tests/ui/macros/best-failure.stderr +++ b/tests/ui/macros/best-failure.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `$` +error: no rules expected `$` --> $DIR/best-failure.rs:4:30 | LL | macro_rules! number { diff --git a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr index 22d662aaaf2f..bf7eb3888b33 100644 --- a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr +++ b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `const` +error: no rules expected keyword `const` --> $DIR/expr_2021_inline_const.rs:23:12 | LL | macro_rules! m2021 { @@ -13,7 +13,7 @@ note: while trying to match meta-variable `$e:expr_2021` LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ -error: no rules expected the token `const` +error: no rules expected keyword `const` --> $DIR/expr_2021_inline_const.rs:24:12 | LL | macro_rules! m2024 { diff --git a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr index 2555e4f757a5..1028ddc4267f 100644 --- a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr +++ b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `const` +error: no rules expected keyword `const` --> $DIR/expr_2021_inline_const.rs:23:12 | LL | macro_rules! m2021 { diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs index 39a542fe4d94..312256f1879c 100644 --- a/tests/ui/macros/expr_2021_inline_const.rs +++ b/tests/ui/macros/expr_2021_inline_const.rs @@ -20,8 +20,8 @@ macro_rules! test { } fn main() { - m2021!(const { 1 }); //~ ERROR: no rules expected the token `const` - m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected the token `const` + m2021!(const { 1 }); //~ ERROR: no rules expected keyword `const` + m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected keyword `const` test!(expr); } diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr index 34df20a69ef5..7b3ca54bb713 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr +++ b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `_` +error: no rules expected reserved identifier `_` --> $DIR/expr_2024_underscore_expr.rs:19:12 | LL | macro_rules! m2021 { @@ -13,7 +13,7 @@ note: while trying to match meta-variable `$e:expr_2021` LL | ($e:expr_2021) => { | ^^^^^^^^^^^^ -error: no rules expected the token `_` +error: no rules expected reserved identifier `_` --> $DIR/expr_2024_underscore_expr.rs:20:12 | LL | macro_rules! m2024 { diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr index 372c5d8637c9..59104dafa181 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr +++ b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `_` +error: no rules expected reserved identifier `_` --> $DIR/expr_2024_underscore_expr.rs:19:12 | LL | macro_rules! m2021 { diff --git a/tests/ui/macros/expr_2024_underscore_expr.rs b/tests/ui/macros/expr_2024_underscore_expr.rs index 86e313745068..6f8ec139109b 100644 --- a/tests/ui/macros/expr_2024_underscore_expr.rs +++ b/tests/ui/macros/expr_2024_underscore_expr.rs @@ -16,6 +16,6 @@ macro_rules! m2024 { } fn main() { - m2021!(_); //~ ERROR: no rules expected the token `_` - m2024!(_); //[edi2021]~ ERROR: no rules expected the token `_` + m2021!(_); //~ ERROR: no rules expected reserved identifier `_` + m2024!(_); //[edi2021]~ ERROR: no rules expected reserved identifier `_` } diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.rs b/tests/ui/macros/macro-at-most-once-rep-2015.rs index 8f2531a25aea..08967b82531c 100644 --- a/tests/ui/macros/macro-at-most-once-rep-2015.rs +++ b/tests/ui/macros/macro-at-most-once-rep-2015.rs @@ -22,21 +22,21 @@ macro_rules! barstar { pub fn main() { foo!(); foo!(a); - foo!(a?); //~ ERROR no rules expected the token `?` - foo!(a?a); //~ ERROR no rules expected the token `?` - foo!(a?a?a); //~ ERROR no rules expected the token `?` + foo!(a?); //~ ERROR no rules expected `?` + foo!(a?a); //~ ERROR no rules expected `?` + foo!(a?a?a); //~ ERROR no rules expected `?` barplus!(); //~ERROR unexpected end of macro invocation barplus!(a); //~ERROR unexpected end of macro invocation - barplus!(a?); //~ ERROR no rules expected the token `?` - barplus!(a?a); //~ ERROR no rules expected the token `?` + barplus!(a?); //~ ERROR no rules expected `?` + barplus!(a?a); //~ ERROR no rules expected `?` barplus!(a+); barplus!(+); barstar!(); //~ERROR unexpected end of macro invocation barstar!(a); //~ERROR unexpected end of macro invocation - barstar!(a?); //~ ERROR no rules expected the token `?` - barstar!(a?a); //~ ERROR no rules expected the token `?` + barstar!(a?); //~ ERROR no rules expected `?` + barstar!(a?a); //~ ERROR no rules expected `?` barstar!(a*); barstar!(*); } diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.stderr b/tests/ui/macros/macro-at-most-once-rep-2015.stderr index 7c45b85bc8d4..7f161cdc8d0b 100644 --- a/tests/ui/macros/macro-at-most-once-rep-2015.stderr +++ b/tests/ui/macros/macro-at-most-once-rep-2015.stderr @@ -4,7 +4,7 @@ error: the `?` macro repetition operator does not take a separator LL | ($(a),?) => {}; | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:25:11 | LL | macro_rules! foo { @@ -15,7 +15,7 @@ LL | foo!(a?); | = note: while trying to match sequence end -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:26:11 | LL | macro_rules! foo { @@ -26,7 +26,7 @@ LL | foo!(a?a); | = note: while trying to match sequence end -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:27:11 | LL | macro_rules! foo { @@ -67,7 +67,7 @@ note: while trying to match `+` LL | ($(a)?+) => {}; // ok. matches "a+" and "+" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:31:15 | LL | macro_rules! barplus { @@ -82,7 +82,7 @@ note: while trying to match `+` LL | ($(a)?+) => {}; // ok. matches "a+" and "+" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:32:15 | LL | macro_rules! barplus { @@ -127,7 +127,7 @@ note: while trying to match `*` LL | ($(a)?*) => {}; // ok. matches "a*" and "*" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:38:15 | LL | macro_rules! barstar { @@ -142,7 +142,7 @@ note: while trying to match `*` LL | ($(a)?*) => {}; // ok. matches "a*" and "*" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2015.rs:39:15 | LL | macro_rules! barstar { diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.rs b/tests/ui/macros/macro-at-most-once-rep-2018.rs index 7f43055ded6f..98fbb2ad2073 100644 --- a/tests/ui/macros/macro-at-most-once-rep-2018.rs +++ b/tests/ui/macros/macro-at-most-once-rep-2018.rs @@ -22,21 +22,21 @@ macro_rules! barstar { pub fn main() { foo!(); foo!(a); - foo!(a?); //~ ERROR no rules expected the token `?` - foo!(a?a); //~ ERROR no rules expected the token `?` - foo!(a?a?a); //~ ERROR no rules expected the token `?` + foo!(a?); //~ ERROR no rules expected `?` + foo!(a?a); //~ ERROR no rules expected `?` + foo!(a?a?a); //~ ERROR no rules expected `?` barplus!(); //~ERROR unexpected end of macro invocation barplus!(a); //~ERROR unexpected end of macro invocation - barplus!(a?); //~ ERROR no rules expected the token `?` - barplus!(a?a); //~ ERROR no rules expected the token `?` + barplus!(a?); //~ ERROR no rules expected `?` + barplus!(a?a); //~ ERROR no rules expected `?` barplus!(a+); barplus!(+); barstar!(); //~ERROR unexpected end of macro invocation barstar!(a); //~ERROR unexpected end of macro invocation - barstar!(a?); //~ ERROR no rules expected the token `?` - barstar!(a?a); //~ ERROR no rules expected the token `?` + barstar!(a?); //~ ERROR no rules expected `?` + barstar!(a?a); //~ ERROR no rules expected `?` barstar!(a*); barstar!(*); } diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.stderr b/tests/ui/macros/macro-at-most-once-rep-2018.stderr index 696520b28268..f165a199b10b 100644 --- a/tests/ui/macros/macro-at-most-once-rep-2018.stderr +++ b/tests/ui/macros/macro-at-most-once-rep-2018.stderr @@ -4,7 +4,7 @@ error: the `?` macro repetition operator does not take a separator LL | ($(a),?) => {}; | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:25:11 | LL | macro_rules! foo { @@ -15,7 +15,7 @@ LL | foo!(a?); | = note: while trying to match sequence end -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:26:11 | LL | macro_rules! foo { @@ -26,7 +26,7 @@ LL | foo!(a?a); | = note: while trying to match sequence end -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:27:11 | LL | macro_rules! foo { @@ -67,7 +67,7 @@ note: while trying to match `+` LL | ($(a)?+) => {}; // ok. matches "a+" and "+" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:31:15 | LL | macro_rules! barplus { @@ -82,7 +82,7 @@ note: while trying to match `+` LL | ($(a)?+) => {}; // ok. matches "a+" and "+" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:32:15 | LL | macro_rules! barplus { @@ -127,7 +127,7 @@ note: while trying to match `*` LL | ($(a)?*) => {}; // ok. matches "a*" and "*" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:38:15 | LL | macro_rules! barstar { @@ -142,7 +142,7 @@ note: while trying to match `*` LL | ($(a)?*) => {}; // ok. matches "a*" and "*" | ^ -error: no rules expected the token `?` +error: no rules expected `?` --> $DIR/macro-at-most-once-rep-2018.rs:39:15 | LL | macro_rules! barstar { diff --git a/tests/ui/macros/macro-non-lifetime.rs b/tests/ui/macros/macro-non-lifetime.rs index 26e1f2afa91b..3defffd29604 100644 --- a/tests/ui/macros/macro-non-lifetime.rs +++ b/tests/ui/macros/macro-non-lifetime.rs @@ -4,5 +4,5 @@ macro_rules! m { ($x:lifetime) => { } } fn main() { m!(a); - //~^ ERROR no rules expected the token `a` + //~^ ERROR no rules expected `a` } diff --git a/tests/ui/macros/macro-non-lifetime.stderr b/tests/ui/macros/macro-non-lifetime.stderr index 9ff3d741c01d..35040a2229bd 100644 --- a/tests/ui/macros/macro-non-lifetime.stderr +++ b/tests/ui/macros/macro-non-lifetime.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `a` +error: no rules expected `a` --> $DIR/macro-non-lifetime.rs:6:8 | LL | macro_rules! m { ($x:lifetime) => { } } diff --git a/tests/ui/macros/missing-comma.rs b/tests/ui/macros/missing-comma.rs index 92f8a7795058..64cfb0db31a0 100644 --- a/tests/ui/macros/missing-comma.rs +++ b/tests/ui/macros/missing-comma.rs @@ -19,16 +19,16 @@ fn main() { println!("{}" a); //~^ ERROR expected `,`, found `a` foo!(a b); - //~^ ERROR no rules expected the token `b` + //~^ ERROR no rules expected `b` foo!(a, b, c, d e); - //~^ ERROR no rules expected the token `e` + //~^ ERROR no rules expected `e` foo!(a, b, c d, e); - //~^ ERROR no rules expected the token `d` + //~^ ERROR no rules expected `d` foo!(a, b, c d e); - //~^ ERROR no rules expected the token `d` + //~^ ERROR no rules expected `d` bar!(Level::Error, ); //~^ ERROR unexpected end of macro invocation check!(::fmt, "fmt"); check!(::fmt, "fmt",); - //~^ ERROR no rules expected the token `,` + //~^ ERROR no rules expected `,` } diff --git a/tests/ui/macros/missing-comma.stderr b/tests/ui/macros/missing-comma.stderr index 81877a29ed8a..9913ba349192 100644 --- a/tests/ui/macros/missing-comma.stderr +++ b/tests/ui/macros/missing-comma.stderr @@ -4,7 +4,7 @@ error: expected `,`, found `a` LL | println!("{}" a); | ^ expected `,` -error: no rules expected the token `b` +error: no rules expected `b` --> $DIR/missing-comma.rs:21:12 | LL | macro_rules! foo { @@ -21,7 +21,7 @@ note: while trying to match meta-variable `$a:ident` LL | ($a:ident) => (); | ^^^^^^^^ -error: no rules expected the token `e` +error: no rules expected `e` --> $DIR/missing-comma.rs:23:21 | LL | macro_rules! foo { @@ -38,7 +38,7 @@ note: while trying to match meta-variable `$d:ident` LL | ($a:ident, $b:ident, $c:ident, $d:ident) => (); | ^^^^^^^^ -error: no rules expected the token `d` +error: no rules expected `d` --> $DIR/missing-comma.rs:25:18 | LL | macro_rules! foo { @@ -55,7 +55,7 @@ note: while trying to match meta-variable `$c:ident` LL | ($a:ident, $b:ident, $c:ident) => (); | ^^^^^^^^ -error: no rules expected the token `d` +error: no rules expected `d` --> $DIR/missing-comma.rs:27:18 | LL | macro_rules! foo { @@ -85,7 +85,7 @@ note: while trying to match meta-variable `$arg:tt` LL | ($lvl:expr, $($arg:tt)+) => {} | ^^^^^^^ -error: no rules expected the token `,` +error: no rules expected `,` --> $DIR/missing-comma.rs:32:38 | LL | macro_rules! check { diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs index 5f0d6b2f90ee..a655b6651031 100644 --- a/tests/ui/macros/nonterminal-matching.rs +++ b/tests/ui/macros/nonterminal-matching.rs @@ -16,7 +16,7 @@ macro complex_nonterminal($nt_item: item) { struct S; } - n!(a $nt_item b); //~ ERROR no rules expected the token `enum E {}` + n!(a $nt_item b); //~ ERROR no rules expected item `enum E {}` } simple_nonterminal!(a, 'a, (x, y, z)); // OK @@ -29,10 +29,10 @@ macro_rules! foo { (ident $x:ident) => { bar!(ident $x); }; (lifetime $x:lifetime) => { bar!(lifetime $x); }; (tt $x:tt) => { bar!(tt $x); }; - (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected the token `3` - (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected the token `4` - (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected the token `a::b::c` - (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected the token `let abc = 0` + (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected expression `3` + (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected literal `4` + (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected path `a::b::c` + (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected statement `let abc = 0` } macro_rules! bar { diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr index 3ee88b5f52ef..e283dfcb8fdc 100644 --- a/tests/ui/macros/nonterminal-matching.stderr +++ b/tests/ui/macros/nonterminal-matching.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `enum E {}` +error: no rules expected item `enum E {}` --> $DIR/nonterminal-matching.rs:19:10 | LL | macro n(a $nt_item b) { @@ -10,7 +10,7 @@ LL | n!(a $nt_item b); LL | complex_nonterminal!(enum E {}); | ------------------------------- in this macro invocation | -note: while trying to match `enum E {}` +note: while trying to match item `enum E {}` --> $DIR/nonterminal-matching.rs:15:15 | LL | macro n(a $nt_item b) { @@ -23,7 +23,7 @@ LL | complex_nonterminal!(enum E {}); = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `3` +error: no rules expected expression `3` --> $DIR/nonterminal-matching.rs:32:35 | LL | (expr $x:expr) => { bar!(expr $x); }; @@ -45,7 +45,7 @@ LL | (expr 3) => {}; = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `4` +error: no rules expected literal `4` --> $DIR/nonterminal-matching.rs:33:44 | LL | (literal $x:literal) => { bar!(literal $x); }; @@ -67,7 +67,7 @@ LL | (literal 4) => {}; = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `a::b::c` +error: no rules expected path `a::b::c` --> $DIR/nonterminal-matching.rs:34:35 | LL | (path $x:path) => { bar!(path $x); }; @@ -89,7 +89,7 @@ LL | (path a::b::c) => {}; = help: try using `:tt` instead in the macro definition = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `let abc = 0` +error: no rules expected statement `let abc = 0` --> $DIR/nonterminal-matching.rs:35:35 | LL | (stmt $x:stmt) => { bar!(stmt $x); }; @@ -101,7 +101,7 @@ LL | macro_rules! bar { LL | foo!(stmt let abc = 0); | ---------------------- in this macro invocation | -note: while trying to match `let` +note: while trying to match keyword `let` --> $DIR/nonterminal-matching.rs:45:11 | LL | (stmt let abc = 0) => {}; diff --git a/tests/ui/macros/trace_faulty_macros.stderr b/tests/ui/macros/trace_faulty_macros.stderr index 66d7b76bb072..10ad3faab161 100644 --- a/tests/ui/macros/trace_faulty_macros.stderr +++ b/tests/ui/macros/trace_faulty_macros.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `bcd` +error: no rules expected `bcd` --> $DIR/trace_faulty_macros.rs:7:26 | LL | macro_rules! my_faulty_macro { diff --git a/tests/ui/offset-of/offset-of-arg-count.rs b/tests/ui/offset-of/offset-of-arg-count.rs index c86e61a61a72..f4c8b91d7dae 100644 --- a/tests/ui/offset-of/offset-of-arg-count.rs +++ b/tests/ui/offset-of/offset-of-arg-count.rs @@ -3,7 +3,7 @@ use std::mem::offset_of; fn main() { offset_of!(NotEnoughArguments); //~ ERROR unexpected end of macro invocation offset_of!(NotEnoughArgumentsWithAComma, ); //~ ERROR unexpected end of macro invocation - offset_of!(Container, field, too many arguments); //~ ERROR no rules expected the token `too` + offset_of!(Container, field, too many arguments); //~ ERROR no rules expected `too` offset_of!(S, f); // compiles fine offset_of!(S, f,); // also compiles fine offset_of!(S, f.); //~ ERROR unexpected token: `)` diff --git a/tests/ui/offset-of/offset-of-arg-count.stderr b/tests/ui/offset-of/offset-of-arg-count.stderr index 4cb24b3d034b..0772bb18e0c6 100644 --- a/tests/ui/offset-of/offset-of-arg-count.stderr +++ b/tests/ui/offset-of/offset-of-arg-count.stderr @@ -16,7 +16,7 @@ LL | offset_of!(NotEnoughArgumentsWithAComma, ); note: while trying to match meta-variable `$fields:expr` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -error: no rules expected the token `too` +error: no rules expected `too` --> $DIR/offset-of-arg-count.rs:6:34 | LL | offset_of!(Container, field, too many arguments); diff --git a/tests/ui/offset-of/offset-of-tuple.stderr b/tests/ui/offset-of/offset-of-tuple.stderr index dd20859e04e1..38ce49c9179b 100644 --- a/tests/ui/offset-of/offset-of-tuple.stderr +++ b/tests/ui/offset-of/offset-of-tuple.stderr @@ -76,7 +76,7 @@ error: suffixes on a tuple index are invalid LL | offset_of!((u8, u8), 1_u8); | ^^^^ invalid suffix `u8` -error: no rules expected the token `+` +error: no rules expected `+` --> $DIR/offset-of-tuple.rs:11:26 | LL | offset_of!((u8, u8), +1); diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs index 7a94c96b79d8..fb227bf0e915 100644 --- a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs +++ b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs @@ -9,5 +9,5 @@ macro_rules! accept_pat { ($p:pat) => {}; } -accept_pat!(p | q); //~ ERROR no rules expected the token `|` -accept_pat!(|p| q); //~ ERROR no rules expected the token `|` +accept_pat!(p | q); //~ ERROR no rules expected `|` +accept_pat!(|p| q); //~ ERROR no rules expected `|` diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr index acc2099bbc6a..47dac84ee494 100644 --- a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr +++ b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `|` +error: no rules expected `|` --> $DIR/or-patterns-syntactic-fail-2018.rs:12:15 | LL | macro_rules! accept_pat { @@ -13,7 +13,7 @@ note: while trying to match meta-variable `$p:pat` LL | ($p:pat) => {}; | ^^^^^^ -error: no rules expected the token `|` +error: no rules expected `|` --> $DIR/or-patterns-syntactic-fail-2018.rs:13:13 | LL | macro_rules! accept_pat { diff --git a/tests/ui/parser/macro/macro-doc-comments-1.rs b/tests/ui/parser/macro/macro-doc-comments-1.rs index 8d8103bb1e06..1aaa993e0721 100644 --- a/tests/ui/parser/macro/macro-doc-comments-1.rs +++ b/tests/ui/parser/macro/macro-doc-comments-1.rs @@ -4,6 +4,6 @@ macro_rules! outer { outer! { //! Inner -} //~^ ERROR no rules expected the token `!` +} //~^ ERROR no rules expected `!` fn main() { } diff --git a/tests/ui/parser/macro/macro-doc-comments-1.stderr b/tests/ui/parser/macro/macro-doc-comments-1.stderr index 9d2d1bc00725..6b7e758980c2 100644 --- a/tests/ui/parser/macro/macro-doc-comments-1.stderr +++ b/tests/ui/parser/macro/macro-doc-comments-1.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `!` +error: no rules expected `!` --> $DIR/macro-doc-comments-1.rs:6:5 | LL | macro_rules! outer { diff --git a/tests/ui/parser/macro/macro-doc-comments-2.rs b/tests/ui/parser/macro/macro-doc-comments-2.rs index 8f33720ae80e..2bee2435ef87 100644 --- a/tests/ui/parser/macro/macro-doc-comments-2.rs +++ b/tests/ui/parser/macro/macro-doc-comments-2.rs @@ -4,6 +4,6 @@ macro_rules! inner { inner! { /// Outer -} //~^ ERROR no rules expected the token `[` +} //~^ ERROR no rules expected `[` fn main() { } diff --git a/tests/ui/parser/macro/macro-doc-comments-2.stderr b/tests/ui/parser/macro/macro-doc-comments-2.stderr index 22efd995b463..02c12bf95911 100644 --- a/tests/ui/parser/macro/macro-doc-comments-2.stderr +++ b/tests/ui/parser/macro/macro-doc-comments-2.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `[` +error: no rules expected `[` --> $DIR/macro-doc-comments-2.rs:6:5 | LL | macro_rules! inner { diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs index b8c0eb3e6d6d..4b2fc4a03b62 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs @@ -68,7 +68,7 @@ fn _macros() { _ => {} } use_expr!(let 0 = 1); - //~^ ERROR no rules expected the token `let` + //~^ ERROR no rules expected keyword `let` } fn main() {} diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr index 2341dbbbdbd0..1c710b04897c 100644 --- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr +++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr @@ -131,7 +131,7 @@ LL | use_expr!((let 0 = 1)); | = note: only supported directly in conditions of `if` and `while` expressions -error: no rules expected the token `let` +error: no rules expected keyword `let` --> $DIR/feature-gate.rs:70:15 | LL | macro_rules! use_expr { diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs index bca7564efd83..2087fc42cf10 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs @@ -54,7 +54,7 @@ fn _macros() { #[cfg(FALSE)] (let 0 = 1); //~^ ERROR expected expression, found `let` statement use_expr!(let 0 = 1); - //~^ ERROR no rules expected the token `let` + //~^ ERROR no rules expected keyword `let` } fn main() {} diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr index 2b1a49be3daa..7c874ae78a8a 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr @@ -14,7 +14,7 @@ LL | noop_expr!((let 0 = 1)); | = note: only supported directly in conditions of `if` and `while` expressions -error: no rules expected the token `let` +error: no rules expected keyword `let` --> $DIR/feature-gate.rs:56:15 | LL | macro_rules! use_expr { diff --git a/tests/ui/underscore-ident-matcher.rs b/tests/ui/underscore-ident-matcher.rs index bddc8c80a7b9..77ec70d43d54 100644 --- a/tests/ui/underscore-ident-matcher.rs +++ b/tests/ui/underscore-ident-matcher.rs @@ -5,5 +5,5 @@ macro_rules! identity { } fn main() { - let identity!(_) = 10; //~ ERROR no rules expected the token `_` + let identity!(_) = 10; //~ ERROR no rules expected reserved identifier `_` } diff --git a/tests/ui/underscore-ident-matcher.stderr b/tests/ui/underscore-ident-matcher.stderr index a663f34cde1b..0c3f980cf6c7 100644 --- a/tests/ui/underscore-ident-matcher.stderr +++ b/tests/ui/underscore-ident-matcher.stderr @@ -1,4 +1,4 @@ -error: no rules expected the token `_` +error: no rules expected reserved identifier `_` --> $DIR/underscore-ident-matcher.rs:8:19 | LL | macro_rules! identity { From 5cf6b8bdee5d93f3e26a4a682cf517f8c6482120 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 28 Oct 2024 18:22:33 +0300 Subject: [PATCH 06/56] force-recompile library changes on download-rustc="if-unchanged" This makes download-rustc="if-unchanged" more functional and useful for library developers. Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/compile.rs | 1 - src/bootstrap/src/core/config/config.rs | 37 +++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index e13d4ccc6182..99ddf58104ce 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -153,7 +153,6 @@ impl Step for Std { // NOTE: the beta compiler may generate different artifacts than the downloaded compiler, so // its artifacts can't be reused. && compiler.stage != 0 - // This check is specific to testing std itself; see `test::Std` for more details. && !self.force_recompile { let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false }); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 139ca7eb52e7..8115aea033d9 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2767,25 +2767,32 @@ impl Config { } }; - let files_to_track = - &["compiler", "library", "src/version", "src/stage0", "src/ci/channel"]; + let mut files_to_track = vec!["compiler", "src/version", "src/stage0", "src/ci/channel"]; + + // In CI, disable ci-rustc if there are changes in the library tree. But for non-CI, ignore + // these changes to speed up the build process for library developers. This provides consistent + // functionality for library developers between `download-rustc=true` and `download-rustc="if-unchanged"` + // options. + if CiEnv::is_ci() { + files_to_track.push("library"); + } // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. - let commit = match self.last_modified_commit(files_to_track, "download-rustc", if_unchanged) - { - Some(commit) => commit, - None => { - if if_unchanged { - return None; + let commit = + match self.last_modified_commit(&files_to_track, "download-rustc", if_unchanged) { + Some(commit) => commit, + None => { + if if_unchanged { + return None; + } + println!("ERROR: could not find commit hash for downloading rustc"); + println!("HELP: maybe your repository history is too shallow?"); + println!("HELP: consider disabling `download-rustc`"); + println!("HELP: or fetch enough history to include one upstream commit"); + crate::exit!(1); } - println!("ERROR: could not find commit hash for downloading rustc"); - println!("HELP: maybe your repository history is too shallow?"); - println!("HELP: consider disabling `download-rustc`"); - println!("HELP: or fetch enough history to include one upstream commit"); - crate::exit!(1); - } - }; + }; if CiEnv::is_ci() && { let head_sha = From 7e064e791d747ef6509c7a5cfe9823104e51f30f Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Mon, 28 Oct 2024 18:59:37 +0300 Subject: [PATCH 07/56] update download-rustc doc in config.example.toml Signed-off-by: onur-ozkan --- config.example.toml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/config.example.toml b/config.example.toml index d5b904ebf3d5..9072a83551a7 100644 --- a/config.example.toml +++ b/config.example.toml @@ -497,11 +497,12 @@ #debug = false # Whether to download the stage 1 and 2 compilers from CI. -# This is mostly useful for tools; if you have changes to `compiler/` or `library/` they will be ignored. +# This is useful if you are working on tools, doc-comments, or library (you will be able to build +# the standard library without needing to build the compiler). # -# Set this to "if-unchanged" to only download if the compiler and standard library have not been modified. -# Set this to `true` to download unconditionally. This is useful if you are working on tools, doc-comments, -# or library (you will be able to build the standard library without needing to build the compiler). +# Set this to "if-unchanged" to only download if the compiler (and library if running on CI) have +# not been modified. +# Set this to `true` to download unconditionally. #download-rustc = false # Number of codegen units to use for each compiler invocation. A value of 0 From 826e0ca885f5c1747172e96cda5493f6344f9425 Mon Sep 17 00:00:00 2001 From: David Tenty Date: Tue, 29 Oct 2024 10:00:40 -0400 Subject: [PATCH 08/56] powerpc64-ibm-aix: update maintainters Chaofan and Kai will be passing over maintainership for the target over to David Tenty and Chris Cambly. --- src/doc/rustc/src/platform-support/aix.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/src/platform-support/aix.md b/src/doc/rustc/src/platform-support/aix.md index c3ce71a18356..5a198062b952 100644 --- a/src/doc/rustc/src/platform-support/aix.md +++ b/src/doc/rustc/src/platform-support/aix.md @@ -6,8 +6,8 @@ Rust for AIX operating system, currently only 64-bit PowerPC is supported. ## Target maintainers -- QIU Chaofan `qiucofan@cn.ibm.com`, https://github.com/ecnelises -- Kai LUO, `lkail@cn.ibm.com`, https://github.com/bzEq +- David Tenty `daltenty@ibm.com`, https://github.com/daltenty +- Chris Cambly, `ccambly@ca.ibm.com`, https://github.com/gilamn5tr ## Requirements From f51ec110a714fea09105586b26c7f8e6a2a57018 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 18 Oct 2024 00:28:43 +0200 Subject: [PATCH 09/56] TypingMode :thinking: --- compiler/rustc_borrowck/src/lib.rs | 4 +- .../src/region_infer/opaque_types.rs | 14 +-- compiler/rustc_codegen_ssa/src/base.rs | 4 +- .../src/check_consts/check.rs | 4 +- .../rustc_const_eval/src/check_consts/ops.rs | 4 +- .../src/check_consts/qualifs.rs | 10 +- .../src/interpret/eval_context.rs | 6 +- .../src/util/compare_types.rs | 5 +- .../rustc_hir_analysis/src/check/check.rs | 8 +- .../src/check/compare_impl_item.rs | 14 +-- .../src/check/compare_impl_item/refine.rs | 4 +- .../rustc_hir_analysis/src/check/dropck.rs | 4 +- .../rustc_hir_analysis/src/check/entry.rs | 4 +- compiler/rustc_hir_analysis/src/check/mod.rs | 6 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 6 +- .../src/coherence/builtin.rs | 8 +- .../src/coherence/orphan.rs | 4 +- compiler/rustc_hir_analysis/src/collect.rs | 10 +- .../src/hir_ty_lowering/mod.rs | 6 +- .../rustc_hir_analysis/src/hir_wf_check.rs | 4 +- .../src/impl_wf_check/min_specialization.rs | 8 +- .../rustc_hir_typeck/src/typeck_root_ctxt.rs | 5 +- compiler/rustc_infer/src/infer/at.rs | 38 +++++-- .../src/infer/canonical/canonicalizer.rs | 6 +- compiler/rustc_infer/src/infer/context.rs | 17 ++-- compiler/rustc_infer/src/infer/mod.rs | 99 +++++++------------ .../rustc_infer/src/infer/opaque_types/mod.rs | 49 ++++----- .../src/infer/relate/generalize.rs | 11 ++- compiler/rustc_lint/src/builtin.rs | 8 +- compiler/rustc_lint/src/context.rs | 12 ++- .../src/for_loops_over_fallibles.rs | 2 +- .../rustc_lint/src/impl_trait_overcaptures.rs | 4 +- compiler/rustc_lint/src/non_fmt_panic.rs | 2 +- .../src/opaque_hidden_inferred_bound.rs | 2 +- compiler/rustc_middle/src/query/plumbing.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 18 ++-- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/sty.rs | 1 + compiler/rustc_mir_build/src/build/mod.rs | 10 +- .../src/thir/pattern/const_to_pat.rs | 6 +- compiler/rustc_mir_transform/src/coroutine.rs | 8 +- compiler/rustc_mir_transform/src/validate.rs | 4 +- .../rustc_next_trait_solver/src/delegate.rs | 4 +- .../src/solve/assembly/mod.rs | 14 ++- .../src/solve/eval_ctxt/canonical.rs | 3 +- .../src/solve/eval_ctxt/mod.rs | 23 ++--- .../src/solve/normalizes_to/mod.rs | 17 ++-- .../src/solve/normalizes_to/opaque_types.rs | 50 +++++----- .../src/solve/trait_goals.rs | 49 +++++---- compiler/rustc_passes/src/check_attr.rs | 4 +- compiler/rustc_passes/src/layout_test.rs | 3 +- .../src/solve/delegate.rs | 24 ++--- .../src/traits/auto_trait.rs | 5 +- .../src/traits/coherence.rs | 16 +-- .../src/traits/dyn_compatibility.rs | 4 +- .../src/traits/fulfill.rs | 17 ++-- .../rustc_trait_selection/src/traits/misc.rs | 6 +- .../rustc_trait_selection/src/traits/mod.rs | 18 ++-- .../src/traits/project.rs | 36 ++----- .../src/traits/query/evaluate_obligation.rs | 1 - .../src/traits/select/candidate_assembly.rs | 11 ++- .../src/traits/select/mod.rs | 93 ++++++----------- .../src/traits/specialize/mod.rs | 6 +- .../src/traits/vtable.rs | 5 +- compiler/rustc_traits/src/codegen.rs | 4 +- .../src/normalize_erasing_regions.rs | 4 +- compiler/rustc_ty_utils/src/common_traits.rs | 4 +- compiler/rustc_ty_utils/src/instance.rs | 4 +- .../rustc_ty_utils/src/structural_match.rs | 4 +- compiler/rustc_type_ir/src/canonical.rs | 4 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 68 ++++++++++++- compiler/rustc_type_ir/src/interner.rs | 23 ++--- compiler/rustc_type_ir/src/relate/combine.rs | 18 ++-- .../rustc_type_ir/src/search_graph/mod.rs | 21 +--- compiler/rustc_type_ir/src/solve/mod.rs | 13 --- 75 files changed, 513 insertions(+), 506 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 698fdafc9361..742d68ad076e 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -34,7 +34,7 @@ use rustc_infer::infer::{ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::*; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt}; +use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::{ @@ -440,7 +440,7 @@ pub struct BorrowckInferCtxt<'tcx> { impl<'tcx> BorrowckInferCtxt<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { - let infcx = tcx.infer_ctxt().with_opaque_type_inference(def_id).build(); + let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id)); BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) } } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index abce98265b3c..741dac9e7639 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -9,6 +9,7 @@ use rustc_macros::extension; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ self, GenericArgKind, GenericArgs, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, + TypingMode, }; use rustc_span::Span; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; @@ -340,14 +341,13 @@ fn check_opaque_type_well_formed<'tcx>( parent_def_id = tcx.local_parent(parent_def_id); } - // FIXME(-Znext-solver): We probably should use `&[]` instead of - // and prepopulate this `InferCtxt` with known opaque values, rather than - // allowing opaque types to be defined and checking them after the fact. + // FIXME(#132279): This should eventually use the already defined hidden types + // instead. Alternatively we'll entirely remove this function given we also check + // the opaque in `check_opaque_meets_bounds` later. let infcx = tcx .infer_ctxt() .with_next_trait_solver(next_trait_solver) - .with_opaque_type_inference(parent_def_id) - .build(); + .build(TypingMode::analysis_in_body(tcx, parent_def_id)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let identity_args = GenericArgs::identity_for_item(tcx, def_id); @@ -517,7 +517,9 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> { }, ); - let infcx = tcx.infer_ctxt().build(); + // FIXME(#132279): It feels wrong to use `non_body_analysis` here given that we're + // in a body here. + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new(&infcx); let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| { diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index b954633f4532..cb4c9c078b19 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -21,7 +21,7 @@ use rustc_middle::mir::BinOp; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypingMode}; use rustc_session::Session; use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_span::symbol::sym; @@ -119,7 +119,7 @@ pub fn validate_trivial_unsize<'tcx>( ) -> bool { match (source_data.principal(), target_data.principal()) { (Some(hr_source_principal), Some(hr_target_principal)) => { - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); let universe = infcx.universe(); let ocx = ObligationCtxt::new(&infcx); infcx.enter_forall(hr_target_principal, |target_principal| { diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 004fb12419f1..0880b924d380 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -16,7 +16,7 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt, TypingMode}; use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; @@ -593,7 +593,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Typeck only does a "non-const" check since it operates on HIR and cannot distinguish // which path expressions are getting called on and which path expressions are only used // as function pointers. This is required for correctness. - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args); diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 3ac06ae64910..3f977dc4b05a 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -12,7 +12,7 @@ use rustc_middle::mir::CallSource; use rustc_middle::span_bug; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ - self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty, + self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty, TypingMode, suggest_constraining_type_param, }; use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind}; @@ -116,7 +116,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let mut selcx = SelectionContext::new(&infcx); let implsrc = selcx.select(&obligation); diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 547030a18543..e8637ba45cf1 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -114,11 +114,11 @@ impl Qualif for HasMutInterior { ty::TraitRef::new(cx.tcx, freeze_def_id, [ty::GenericArg::from(ty)]), ); - let infcx = cx - .tcx - .infer_ctxt() - .with_opaque_type_inference(cx.body.source.def_id().expect_local()) - .build(); + // FIXME(#132279): This should eventually use the already defined hidden types. + let infcx = cx.tcx.infer_ctxt().build(ty::TypingMode::analysis_in_body( + cx.tcx, + cx.body.source.def_id().expect_local(), + )); let ocx = ObligationCtxt::new(&infcx); ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index a1c773a4b800..d81368e9fcc3 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -9,7 +9,9 @@ use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout, }; -use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance}; +use rustc_middle::ty::{ + self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypingMode, Variance, +}; use rustc_middle::{mir, span_bug}; use rustc_session::Limit; use rustc_span::Span; @@ -325,7 +327,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return true; } // Slow path: spin up an inference context to check if these traits are sufficiently equal. - let infcx = self.tcx.infer_ctxt().build(); + let infcx = self.tcx.infer_ctxt().build(TypingMode::from_param_env(self.param_env)); let ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy_with_span(self.cur_span()); // equate the two trait refs after normalization diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs index 3ea54146fc78..7af977bab4d6 100644 --- a/compiler/rustc_const_eval/src/util/compare_types.rs +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -5,7 +5,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, Variance}; +use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, TypingMode, Variance}; use rustc_trait_selection::traits::ObligationCtxt; /// Returns whether the two types are equal up to subtyping. @@ -45,7 +45,8 @@ pub fn relate_types<'tcx>( } let mut builder = tcx.infer_ctxt().ignoring_regions(); - let infcx = builder.build(); + // FIXME(#132279): This should eventually use the already defined hidden types. + let infcx = builder.build(TypingMode::from_param_env(param_env)); let ocx = ObligationCtxt::new(&infcx); let cause = ObligationCause::dummy(); let src = ocx.normalize(&cause, param_env, src); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 6d04bdf7e48e..f830108a02f4 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -30,6 +30,7 @@ use rustc_trait_selection::traits; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_type_ir::fold::TypeFoldable; use tracing::{debug, instrument}; +use ty::TypingMode; use {rustc_attr as attr, rustc_hir as hir}; use super::compare_impl_item::{check_type_bounds, compare_impl_method, compare_impl_ty}; @@ -276,7 +277,8 @@ fn check_opaque_meets_bounds<'tcx>( }; let param_env = tcx.param_env(defining_use_anchor); - let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build(); + // FIXME(#132279): This should eventually use the already defined hidden types. + let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, defining_use_anchor)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let args = match *origin { @@ -1675,8 +1677,8 @@ pub(super) fn check_coroutine_obligations( // typeck writeback gives us predicates with their regions erased. // As borrowck already has checked lifetimes, we do not need to do it again. .ignoring_regions() - .with_opaque_type_inference(def_id) - .build(); + // FIXME(#132279): This should eventually use the already defined hidden types. + .build(TypingMode::analysis_in_body(tcx, def_id)); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for (predicate, cause) in &typeck_results.coroutine_stalled_predicates { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 9de96b7ba776..db2c44fd29df 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::util::ExplicitSelf; use rustc_middle::ty::{ self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeVisitableExt, Upcast, + TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_span::Span; @@ -228,7 +228,7 @@ fn compare_method_predicate_entailment<'tcx>( let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); debug!(caller_bounds=?param_env.caller_bounds()); - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); // Create obligations for each predicate declared by the impl @@ -516,7 +516,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( ObligationCause::misc(tcx.def_span(impl_m_def_id), impl_m_def_id), ); - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); // Normalize the impl signature with fresh variables for lifetime inference. @@ -1196,7 +1196,7 @@ fn compare_self_type<'tcx>( let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().input(0); let param_env = ty::ParamEnv::reveal_all(); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty); let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty); match ExplicitSelf::determine(self_arg_ty, can_eq_self) { @@ -1801,7 +1801,7 @@ fn compare_const_predicate_entailment<'tcx>( ObligationCause::misc(impl_ct_span, impl_ct_def_id), ); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let impl_ct_own_bounds = impl_ct_predicates.instantiate_own_identity(); @@ -1951,7 +1951,7 @@ fn compare_type_predicate_entailment<'tcx>( let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); debug!(caller_bounds=?param_env.caller_bounds()); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for (predicate, span) in impl_ty_own_bounds { @@ -2036,7 +2036,7 @@ pub(super) fn check_type_bounds<'tcx>( let impl_ty_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id); let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); // A synthetic impl Trait for RPITIT desugaring or assoc type for effects desugaring has no HIR, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 2d6b9813271e..646c104f1f55 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -8,7 +8,7 @@ use rustc_middle::span_bug; use rustc_middle::traits::{ObligationCause, Reveal}; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, + TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_span::Span; use rustc_trait_selection::regions::InferCtxtRegionExt; @@ -132,7 +132,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing); let param_env = normalize_param_env_or_error(tcx, param_env, ObligationCause::dummy()); - let ref infcx = tcx.infer_ctxt().build(); + let ref infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new(infcx); // Normalize the bounds. This has two purposes: diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 97a29b32c015..1c9bbe627fb0 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -9,7 +9,7 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::util::CheckRegions; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode}; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -124,7 +124,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( adt_def_id: LocalDefId, adt_to_impl_args: GenericArgsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let impl_span = tcx.def_span(drop_impl_def_id.to_def_id()); diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 7da2cd93d4e0..0beb1f98d56d 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -4,7 +4,7 @@ use rustc_hir as hir; use rustc_hir::Node; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::span_bug; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_session::config::EntryFnType; use rustc_span::Span; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; @@ -128,7 +128,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { tcx.dcx().emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span }); return; }; - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = traits::ObligationCause::new( return_ty_span, main_diagnostics_def_id, diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index ec5a89ec9d91..e9eea36a0e66 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -85,7 +85,7 @@ use rustc_infer::infer::{self, TyCtxtInferExt as _}; use rustc_infer::traits::ObligationCause; use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::def_id::CRATE_DEF_ID; @@ -530,7 +530,7 @@ fn suggestion_signature<'tcx>( let ty = tcx.type_of(assoc.def_id).instantiate_identity(); let val = tcx .infer_ctxt() - .build() + .build(TypingMode::non_body_analysis()) .err_ctxt() .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty) .unwrap_or_else(|| "value".to_string()); @@ -620,7 +620,7 @@ pub fn check_function_signature<'tcx>( let param_env = ty::ParamEnv::empty(); - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); let actual_sig = tcx.fn_sig(fn_id).instantiate_identity(); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 499e42d31c97..12ed7b89f68b 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; @@ -106,7 +106,7 @@ where F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>) -> Result<(), ErrorGuaranteed>, { let param_env = tcx.param_env(body_def_id); - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env }; @@ -765,7 +765,7 @@ fn test_region_obligations<'tcx>( // Unfortunately, we have to use a new `InferCtxt` each call, because // region constraints get added and solved there and we need to test each // call individually. - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); add_constraints(&infcx); diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index b4f6b5a9dd24..5ff52376837e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -15,7 +15,9 @@ use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::print::PrintTraitRefExt as _; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, suggest_constraining_type_params}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params, +}; use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::misc::{ @@ -213,7 +215,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() let param_env = tcx.param_env(impl_did); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = ObligationCause::misc(span, impl_did); // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw @@ -354,7 +356,7 @@ pub(crate) fn coerce_unsized_info<'tcx>( debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = ObligationCause::misc(span, impl_did); let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>, diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 04770469132b..8a1a887766c7 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -7,7 +7,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, + TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{DefId, LocalDefId}; @@ -302,7 +302,7 @@ fn orphan_check<'tcx>( } // (1) Instantiate all generic params with fresh inference vars. - let infcx = tcx.infer_ctxt().intercrate(true).build(); + let infcx = tcx.infer_ctxt().build(TypingMode::Coherence); let cause = traits::ObligationCause::dummy(); let args = infcx.fresh_args_for_item(cause.span, impl_def_id.to_def_id()); let trait_ref = trait_ref.instantiate(tcx, args); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 3add801cf564..cca52c5142c6 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -34,7 +34,7 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, Span}; @@ -1438,9 +1438,11 @@ fn infer_return_ty_for_fn_sig<'tcx>( Applicability::MachineApplicable, ); recovered_ret_ty = Some(suggestable_ret_ty); - } else if let Some(sugg) = - suggest_impl_trait(&tcx.infer_ctxt().build(), tcx.param_env(def_id), ret_ty) - { + } else if let Some(sugg) = suggest_impl_trait( + &tcx.infer_ctxt().build(TypingMode::non_body_analysis()), + tcx.param_env(def_id), + ret_ty, + ) { diag.span_suggestion( ty.span, "replace with an appropriate return type", diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 0891642f2c88..2d0c3ec28c37 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -39,7 +39,7 @@ use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, - TypeVisitableExt, + TypeVisitableExt, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; @@ -1300,7 +1300,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(infcx) => infcx, None => { assert!(!self_ty.has_infer()); - infcx_ = tcx.infer_ctxt().ignoring_regions().build(); + infcx_ = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); &infcx_ } }; @@ -1492,7 +1492,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { infcx } else { assert!(!qself_ty.has_infer()); - infcx_ = tcx.infer_ctxt().build(); + infcx_ = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); &infcx_ }; diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 2fa4ca680737..5b0165bf993d 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -5,7 +5,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::bug; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_span::def_id::LocalDefId; use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::debug; @@ -68,7 +68,7 @@ fn diagnostic_hir_wf_check<'tcx>( impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - let infcx = self.tcx.infer_ctxt().build(); + let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let tcx_ty = self.icx.lower_ty(ty); diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index a394fc2fbb19..b0c9aed5d855 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -72,7 +72,9 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::traits::specialization_graph::Node; use rustc_middle::ty::trait_def::TraitSpecializationKind; -use rustc_middle::ty::{self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{ + self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt, TypingMode, +}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; @@ -195,7 +197,7 @@ fn get_impl_args( impl1_def_id: LocalDefId, impl2_node: Node, ) -> Result<(GenericArgsRef<'_>, GenericArgsRef<'_>), ErrorGuaranteed> { - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(infcx); let param_env = tcx.param_env(impl1_def_id); let impl1_span = tcx.def_span(impl1_def_id); @@ -409,7 +411,7 @@ fn check_predicates<'tcx>( // Include the well-formed predicates of the type parameters of the impl. for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().instantiate_identity().args { - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let obligations = wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, arg, span) .unwrap(); diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 18e40cfa4287..903be7e732af 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -8,7 +8,7 @@ use rustc_hir::{HirId, HirIdMap}; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_middle::span_bug; use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_span::Span; use rustc_span::def_id::LocalDefIdMap; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -81,7 +81,8 @@ impl<'tcx> TypeckRootCtxt<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner; - let infcx = tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(def_id).build(); + let infcx = + tcx.infer_ctxt().ignoring_regions().build(TypingMode::analysis_in_body(tcx, def_id)); let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner)); TypeckRootCtxt { diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 8c943a961e76..3eda3e9c67e8 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -28,7 +28,7 @@ use relate::lattice::{LatticeOp, LatticeOpKind}; use rustc_middle::bug; use rustc_middle::ty::relate::solver_relating::RelateExt as NextSolverRelate; -use rustc_middle::ty::{Const, ImplSubject}; +use rustc_middle::ty::{Const, ImplSubject, TypingMode}; use super::*; use crate::infer::relate::type_relating::TypeRelating; @@ -67,16 +67,9 @@ impl<'tcx> InferCtxt<'tcx> { /// variables in the same state. This can be used to "branch off" many tests from the same /// common state. pub fn fork(&self) -> Self { - self.fork_with_intercrate(self.intercrate) - } - - /// Forks the inference context, creating a new inference context with the same inference - /// variables in the same state, except possibly changing the intercrate mode. This can be - /// used to "branch off" many tests from the same common state. Used in negative coherence. - pub fn fork_with_intercrate(&self, intercrate: bool) -> Self { Self { tcx: self.tcx, - defining_opaque_types: self.defining_opaque_types, + typing_mode: self.typing_mode, considering_regions: self.considering_regions, skip_leak_check: self.skip_leak_check, inner: self.inner.clone(), @@ -87,11 +80,36 @@ impl<'tcx> InferCtxt<'tcx> { reported_signature_mismatch: self.reported_signature_mismatch.clone(), tainted_by_errors: self.tainted_by_errors.clone(), universe: self.universe.clone(), - intercrate, next_trait_solver: self.next_trait_solver, obligation_inspector: self.obligation_inspector.clone(), } } + + /// Forks the inference context, creating a new inference context with the same inference + /// variables in the same state, except possibly changing the intercrate mode. This can be + /// used to "branch off" many tests from the same common state. Used in negative coherence. + pub fn fork_with_typing_mode(&self, typing_mode: TypingMode<'tcx>) -> Self { + // Unlike `fork`, this invalidates all cache entries as they may depend on the + // typing mode. + let forked = Self { + tcx: self.tcx, + typing_mode, + considering_regions: self.considering_regions, + skip_leak_check: self.skip_leak_check, + inner: self.inner.clone(), + lexical_region_resolutions: self.lexical_region_resolutions.clone(), + selection_cache: Default::default(), + evaluation_cache: Default::default(), + reported_trait_errors: self.reported_trait_errors.clone(), + reported_signature_mismatch: self.reported_signature_mismatch.clone(), + tainted_by_errors: self.tainted_by_errors.clone(), + universe: self.universe.clone(), + next_trait_solver: self.next_trait_solver, + obligation_inspector: self.obligation_inspector.clone(), + }; + forked.inner.borrow_mut().projection_cache().clear(); + forked + } } pub trait ToTrace<'tcx>: Relate> + Copy { diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 90d07964fdac..c9d8ebecef05 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -46,7 +46,7 @@ impl<'tcx> InferCtxt<'tcx> { V: TypeFoldable>, { let (param_env, value) = value.into_parts(); - let param_env = self.tcx.canonical_param_env_cache.get_or_insert( + let canonical_param_env = self.tcx.canonical_param_env_cache.get_or_insert( self.tcx, param_env, query_state, @@ -64,7 +64,7 @@ impl<'tcx> InferCtxt<'tcx> { ); let canonical = Canonicalizer::canonicalize_with_base( - param_env, + canonical_param_env, value, Some(self), self.tcx, @@ -72,7 +72,7 @@ impl<'tcx> InferCtxt<'tcx> { query_state, ) .unchecked_map(|(param_env, value)| param_env.and(value)); - CanonicalQueryInput { canonical, defining_opaque_types: self.defining_opaque_types() } + CanonicalQueryInput { canonical, typing_mode: self.typing_mode(param_env) } } /// Canonicalizes a query *response* `V`. When we canonicalize a diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 0c151a11ad4e..ecda9c6eb000 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -1,7 +1,6 @@ ///! Definition of `InferCtxtLike` from the librarified type layer. -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::DefId; use rustc_middle::traits::ObligationCause; -use rustc_middle::traits::solve::SolverMode; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::relate::combine::PredicateEmittingRelation; @@ -21,11 +20,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.next_trait_solver } - fn solver_mode(&self) -> ty::solve::SolverMode { - match self.intercrate { - true => SolverMode::Coherence, - false => SolverMode::Normal, - } + fn typing_mode( + &self, + param_env_for_debug_assertion: ty::ParamEnv<'tcx>, + ) -> ty::TypingMode<'tcx> { + self.typing_mode(param_env_for_debug_assertion) } fn universe(&self) -> ty::UniverseIndex { @@ -91,10 +90,6 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) } - fn defining_opaque_types(&self) -> &'tcx ty::List { - self.defining_opaque_types() - } - fn next_ty_infer(&self) -> Ty<'tcx> { self.next_ty_var(DUMMY_SP) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index be43cba97f08..fc54d69449f0 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -38,11 +38,12 @@ use rustc_middle::ty::fold::{ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef, - GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, + GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_span::Span; use rustc_span::symbol::Symbol; +use rustc_type_ir::solve::Reveal; use snapshot::undo_log::InferCtxtUndoLogs; use tracing::{debug, instrument}; use type_variable::TypeVariableOrigin; @@ -243,8 +244,9 @@ impl<'tcx> InferCtxtInner<'tcx> { pub struct InferCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, - /// The `DefIds` of the opaque types that may have their hidden types constrained. - defining_opaque_types: &'tcx ty::List, + /// The mode of this inference context, see the struct documentation + /// for more details. + typing_mode: TypingMode<'tcx>, /// Whether this inference context should care about region obligations in /// the root universe. Most notably, this is used during hir typeck as region @@ -296,26 +298,6 @@ pub struct InferCtxt<'tcx> { /// bound. universe: Cell, - /// During coherence we have to assume that other crates may add - /// additional impls which we currently don't know about. - /// - /// To deal with this evaluation, we should be conservative - /// and consider the possibility of impls from outside this crate. - /// This comes up primarily when resolving ambiguity. Imagine - /// there is some trait reference `$0: Bar` where `$0` is an - /// inference variable. If `intercrate` is true, then we can never - /// say for sure that this reference is not implemented, even if - /// there are *no impls at all for `Bar`*, because `$0` could be - /// bound to some type that in a downstream crate that implements - /// `Bar`. - /// - /// Outside of coherence, we set this to false because we are only - /// interested in types that the user could actually have written. - /// In other words, we consider `$0: Bar` to be unimplemented if - /// there is no type that the user could *actually name* that - /// would satisfy it. This avoids crippling inference, basically. - pub intercrate: bool, - next_trait_solver: bool, pub obligation_inspector: Cell>>, @@ -529,11 +511,8 @@ pub struct RegionObligation<'tcx> { /// Used to configure inference contexts before their creation. pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, - defining_opaque_types: &'tcx ty::List, considering_regions: bool, skip_leak_check: bool, - /// Whether we are in coherence mode. - intercrate: bool, /// Whether we should use the new trait solver in the local inference context, /// which affects things like which solver is used in `predicate_may_hold`. next_trait_solver: bool, @@ -544,37 +523,19 @@ impl<'tcx> TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { InferCtxtBuilder { tcx: self, - defining_opaque_types: ty::List::empty(), considering_regions: true, skip_leak_check: false, - intercrate: false, next_trait_solver: self.next_trait_solver_globally(), } } } impl<'tcx> InferCtxtBuilder<'tcx> { - /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types, - /// you need to call this function. Otherwise the opaque type will be treated opaquely. - /// - /// It is only meant to be called in two places, for typeck - /// (via `Inherited::build`) and for the inference context used - /// in mir borrowck. - pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self { - self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor); - self - } - pub fn with_next_trait_solver(mut self, next_trait_solver: bool) -> Self { self.next_trait_solver = next_trait_solver; self } - pub fn intercrate(mut self, intercrate: bool) -> Self { - self.intercrate = intercrate; - self - } - pub fn ignoring_regions(mut self) -> Self { self.considering_regions = false; self @@ -600,24 +561,17 @@ impl<'tcx> InferCtxtBuilder<'tcx> { where T: TypeFoldable>, { - self.defining_opaque_types = input.defining_opaque_types; - let infcx = self.build(); + let infcx = self.build(input.typing_mode); let (value, args) = infcx.instantiate_canonical(span, &input.canonical); (infcx, value, args) } - pub fn build(&mut self) -> InferCtxt<'tcx> { - let InferCtxtBuilder { - tcx, - defining_opaque_types, - considering_regions, - skip_leak_check, - intercrate, - next_trait_solver, - } = *self; + pub fn build(&mut self, typing_mode: TypingMode<'tcx>) -> InferCtxt<'tcx> { + let InferCtxtBuilder { tcx, considering_regions, skip_leak_check, next_trait_solver } = + *self; InferCtxt { tcx, - defining_opaque_types, + typing_mode, considering_regions, skip_leak_check, inner: RefCell::new(InferCtxtInner::new()), @@ -628,7 +582,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> { reported_signature_mismatch: Default::default(), tainted_by_errors: Cell::new(None), universe: Cell::new(ty::UniverseIndex::ROOT), - intercrate, next_trait_solver, obligation_inspector: Cell::new(None), } @@ -659,14 +612,30 @@ impl<'tcx> InferCtxt<'tcx> { self.tcx.dcx().taintable_handle(&self.tainted_by_errors) } - pub fn defining_opaque_types(&self) -> &'tcx ty::List { - self.defining_opaque_types - } - pub fn next_trait_solver(&self) -> bool { self.next_trait_solver } + #[inline(always)] + pub fn typing_mode( + &self, + param_env_for_debug_assertion: ty::ParamEnv<'tcx>, + ) -> TypingMode<'tcx> { + if cfg!(debug_assertions) { + match (param_env_for_debug_assertion.reveal(), self.typing_mode) { + (Reveal::All, TypingMode::PostAnalysis) + | (Reveal::UserFacing, TypingMode::Coherence | TypingMode::Analysis { .. }) => {} + (r, t) => unreachable!("TypingMode x Reveal mismatch: {r:?} {t:?}"), + } + } + self.typing_mode + } + + #[inline(always)] + pub fn typing_mode_unchecked(&self) -> TypingMode<'tcx> { + self.typing_mode + } + pub fn freshen>>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) } @@ -1029,8 +998,12 @@ impl<'tcx> InferCtxt<'tcx> { #[inline(always)] pub fn can_define_opaque_ty(&self, id: impl Into) -> bool { - let Some(id) = id.into().as_local() else { return false }; - self.defining_opaque_types.contains(&id) + match self.typing_mode_unchecked() { + TypingMode::Analysis { defining_opaque_types } => { + id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id)) + } + TypingMode::Coherence | TypingMode::PostAnalysis => false, + } } pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index c38b7114e43e..498d25aea640 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -2,6 +2,7 @@ use hir::def_id::{DefId, LocalDefId}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; +use rustc_middle::bug; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::Goal; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -100,7 +101,7 @@ impl<'tcx> InferCtxt<'tcx> { let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => { let def_id = def_id.expect_local(); - if self.intercrate { + if let ty::TypingMode::Coherence = self.typing_mode(param_env) { // See comment on `insert_hidden_type` for why this is sufficient in coherence return Some(self.register_hidden_type( OpaqueTypeKey { def_id, args }, @@ -519,28 +520,32 @@ impl<'tcx> InferCtxt<'tcx> { // value being folded. In simple cases like `-> impl Foo`, // these are the same span, but not in cases like `-> (impl // Foo, impl Bar)`. - if self.intercrate { - // During intercrate we do not define opaque types but instead always - // force ambiguity unless the hidden type is known to not implement - // our trait. - goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous)) - } else { - let prev = self - .inner - .borrow_mut() - .opaque_types() - .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span }); - if let Some(prev) = prev { - goals.extend( - self.at(&ObligationCause::dummy_with_span(span), param_env) - .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)? - .obligations - .into_iter() - // FIXME: Shuttling between obligations and goals is awkward. - .map(Goal::from), - ); + match self.typing_mode(param_env) { + ty::TypingMode::Coherence => { + // During intercrate we do not define opaque types but instead always + // force ambiguity unless the hidden type is known to not implement + // our trait. + goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous)); } - }; + ty::TypingMode::Analysis { .. } => { + let prev = self + .inner + .borrow_mut() + .opaque_types() + .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span }); + if let Some(prev) = prev { + goals.extend( + self.at(&ObligationCause::dummy_with_span(span), param_env) + .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)? + .obligations + .into_iter() + // FIXME: Shuttling between obligations and goals is awkward. + .map(Goal::from), + ); + } + } + ty::TypingMode::PostAnalysis => bug!("insert hidden type post-analysis"), + } Ok(()) } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 32817dbcb214..4c80bf4e07e8 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -9,6 +9,7 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::visit::MaxUniverse; use rustc_middle::ty::{ self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeVisitable, TypeVisitableExt, + TypingMode, }; use rustc_span::Span; use tracing::{debug, instrument, warn}; @@ -519,7 +520,10 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { // // cc trait-system-refactor-initiative#108 if self.infcx.next_trait_solver() - && !self.infcx.intercrate + && !matches!( + self.infcx.typing_mode_unchecked(), + TypingMode::Coherence + ) && self.in_alias { inner.type_variables().equate(vid, new_var_id); @@ -650,7 +654,10 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { // See the comment for type inference variables // for more details. if self.infcx.next_trait_solver() - && !self.infcx.intercrate + && !matches!( + self.infcx.typing_mode_unchecked(), + TypingMode::Coherence + ) && self.in_alias { variable_table.union(vid, new_var_id); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index dbb8c6675323..77682ea9341b 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -31,7 +31,7 @@ use rustc_middle::bug; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, VariantDef}; use rustc_session::lint::FutureIncompatibilityReason; // hardwired lints from rustc_lint_defs pub use rustc_session::lint::builtin::*; @@ -604,7 +604,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { && cx .tcx .infer_ctxt() - .build() + .build(cx.typing_mode()) .type_implements_trait(iter_trait, [ty], cx.param_env) .must_apply_modulo_regions() { @@ -648,7 +648,9 @@ fn type_implements_negative_copy_modulo_regions<'tcx>( predicate: pred.upcast(tcx), }; - tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation) + tcx.infer_ctxt() + .build(TypingMode::non_body_analysis()) + .predicate_must_hold_modulo_regions(&obligation) } declare_lint! { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 699088914e87..aa7ec2659d08 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -14,11 +14,12 @@ use rustc_feature::Features; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_infer::traits::Reveal; use rustc_middle::bug; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths}; -use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingMode}; use rustc_session::lint::{ BuiltinLintDiag, FutureIncompatibleInfo, Level, Lint, LintBuffer, LintExpectationId, LintId, }; @@ -698,6 +699,15 @@ impl LintContext for EarlyContext<'_> { } impl<'tcx> LateContext<'tcx> { + /// The typing mode of the currently visited node. Use this when + /// building a new `InferCtxt`. + pub fn typing_mode(&self) -> TypingMode<'tcx> { + debug_assert_eq!(self.param_env.reveal(), Reveal::UserFacing); + // FIXME(#132279): In case we're in a body, we should use a typing + // mode which reveals the opaque types defined by that body. + TypingMode::non_body_analysis() + } + /// Gets the type-checking results for the current body, /// or `None` if outside a body. pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> { diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index fcb7a6108c0e..cf68e41243ff 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -166,7 +166,7 @@ fn suggest_question_mark<'tcx>( } let ty = args.type_at(0); - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); let ocx = ObligationCtxt::new(&infcx); let body_def_id = cx.tcx.hir().body_owner_def_id(body_id); diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index cc40b67ab271..026826021c81 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::relate::{ Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys, }; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::FutureIncompatibilityReason; @@ -184,7 +184,7 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) { }), outlives_env: LazyCell::new(|| { let param_env = tcx.param_env(parent_def_id); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let ocx = ObligationCtxt::new(&infcx); let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default(); let implied_bounds = diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 51877e8a0349..cf25ec99e671 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -157,7 +157,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc Some(ty_def) if cx.tcx.is_lang_item(ty_def.did(), LangItem::String), ); - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); let suggest_display = is_str || cx.tcx.get_diagnostic_item(sym::Display).is_some_and(|t| { infcx.type_implements_trait(t, [ty], cx.param_env).may_apply() diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index ffbcf7f808eb..16a1a5a72bc4 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { } let def_id = opaque.def_id.to_def_id(); - let infcx = &cx.tcx.infer_ctxt().build(); + let infcx = &cx.tcx.infer_ctxt().build(cx.typing_mode()); // For every projection predicate in the opaque type's explicit bounds, // check that the type that we're assigning actually satisfies the bounds // of the associated type. diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 564d274bc8b1..57da5b39ba78 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -323,7 +323,7 @@ macro_rules! define_callbacks { // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(target_pointer_width = "64")] const _: () = { - if mem::size_of::>() > 72 { + if mem::size_of::>() > 80 { panic!("{}", concat!( "the query `", stringify!($name), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5ae9c589ec4a..5cbbc80ebfbb 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -54,7 +54,6 @@ use rustc_type_ir::TyKind::*; use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::lang_items::TraitSolverLangItem; pub use rustc_type_ir::lift::Lift; -use rustc_type_ir::solve::SolverMode; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph}; use tracing::{debug, trace}; @@ -170,15 +169,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { tracked.get(self) } - fn with_global_cache( - self, - mode: SolverMode, - f: impl FnOnce(&mut search_graph::GlobalCache) -> R, - ) -> R { - match mode { - SolverMode::Normal => f(&mut *self.new_solver_evaluation_cache.lock()), - SolverMode::Coherence => f(&mut *self.new_solver_coherence_evaluation_cache.lock()), - } + fn with_global_cache(self, f: impl FnOnce(&mut search_graph::GlobalCache) -> R) -> R { + f(&mut *self.new_solver_evaluation_cache.lock()) } fn evaluation_is_concurrent(&self) -> bool { @@ -629,6 +621,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) -> ty::Binder<'tcx, T> { self.anonymize_bound_vars(binder) } + + fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::DefiningOpaqueTypes { + self.opaque_types_defined_by(defining_anchor) + } } macro_rules! bidirectional_lang_item_map { @@ -1334,7 +1330,6 @@ pub struct GlobalCtxt<'tcx> { /// Caches the results of goal evaluation in the new solver. pub new_solver_evaluation_cache: Lock>>, - pub new_solver_coherence_evaluation_cache: Lock>>, pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>, @@ -1561,7 +1556,6 @@ impl<'tcx> TyCtxt<'tcx> { selection_cache: Default::default(), evaluation_cache: Default::default(), new_solver_evaluation_cache: Default::default(), - new_solver_coherence_evaluation_cache: Default::default(), canonical_param_env_cache: Default::default(), data_layout, alloc_map: Lock::new(interpret::AllocMap::new()), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b92fc864b49a..bd32e5837b38 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -100,7 +100,7 @@ pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::{ AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst, - ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, + ParamTy, PolyFnSig, TyKind, TypeAndMut, TypingMode, UpvarArgs, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index d8362ccc0a97..a8327ebc17fe 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -40,6 +40,7 @@ pub type AliasTy<'tcx> = ir::AliasTy>; pub type FnSig<'tcx> = ir::FnSig>; pub type Binder<'tcx, T> = ir::Binder, T>; pub type EarlyBinder<'tcx, T> = ir::EarlyBinder, T>; +pub type TypingMode<'tcx> = ir::TypingMode>; pub trait Article { fn article(&self) -> &'static str; diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 8c20d2e0d3a6..e15ea4d8d8be 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -16,7 +16,7 @@ use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::query::TyCtxtAt; use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir}; -use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -500,7 +500,9 @@ fn construct_fn<'tcx>( ); } - let infcx = tcx.infer_ctxt().build(); + // FIXME(#132279): This should be able to reveal opaque + // types defined during HIR typeck. + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut builder = Builder::new( thir, infcx, @@ -578,7 +580,9 @@ fn construct_const<'a, 'tcx>( _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def), }; - let infcx = tcx.infer_ctxt().build(); + // FIXME(#132279): We likely want to be able to use the hidden types of + // opaques used by this function here. + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut builder = Builder::new(thir, infcx, def, hir_id, span, 0, const_ty, const_ty_span, None); diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 0dfa9168f7c8..c89f526aa175 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -7,7 +7,7 @@ use rustc_infer::traits::Obligation; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir::{FieldPat, Pat, PatKind}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree}; use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_trait_selection::traits::ObligationCause; @@ -36,7 +36,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { id: hir::HirId, span: Span, ) -> Box> { - let infcx = self.tcx.infer_ctxt().build(); + // FIXME(#132279): We likely want to be able to reveal the hidden types + // of opaques defined in this function here. + let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut convert = ConstToPat::new(self, id, span, infcx); convert.to_pat(c, ty) } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index cd2910589777..ab3abc901b40 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -64,7 +64,7 @@ use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{ - self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, + self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::Analysis; @@ -1501,7 +1501,11 @@ fn check_field_tys_sized<'tcx>( return; } - let infcx = tcx.infer_ctxt().ignoring_regions().build(); + // FIXME(#132279): @lcnr believes that we may want to support coroutines + // whose `Sized`-ness relies on the hidden types of opaques defined by the + // parent function. In this case we'd have to be able to reveal only these + // opaques here. + let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); let param_env = tcx.param_env(def_id); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 25e68f44456b..77356723c466 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -12,7 +12,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{ self, CoroutineArgsExt, InstanceKind, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt, - Variance, + TypingMode, Variance, }; use rustc_middle::{bug, span_bug}; use rustc_target::abi::{FIRST_VARIANT, Size}; @@ -606,7 +606,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return true; } - let infcx = self.tcx.infer_ctxt().build(); + let infcx = self.tcx.infer_ctxt().build(TypingMode::from_param_env(self.param_env)); let ocx = ObligationCtxt::new(&infcx); ocx.register_obligation(Obligation::new( self.tcx, diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 4da1e7fa711b..f7fbfed5b8e3 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -1,7 +1,7 @@ use std::ops::Deref; use rustc_type_ir::fold::TypeFoldable; -use rustc_type_ir::solve::{Certainty, Goal, NoSolution, SolverMode}; +use rustc_type_ir::solve::{Certainty, Goal, NoSolution}; use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; pub trait SolverDelegate: Deref::Infcx> + Sized { @@ -15,7 +15,6 @@ pub trait SolverDelegate: Deref::Infcx> + Size fn build_with_canonical( cx: Self::Interner, - solver_mode: SolverMode, canonical: &ty::CanonicalQueryInput, ) -> (Self, V, ty::CanonicalVarValues) where @@ -93,7 +92,6 @@ pub trait SolverDelegate: Deref::Infcx> + Size fn fetch_eligible_assoc_item( &self, - param_env: ::ParamEnv, goal_trait_ref: ty::TraitRef, trait_assoc_def_id: ::DefId, impl_def_id: ::DefId, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index f6a5f20a639e..ebf7372926f8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -8,14 +8,14 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::solve::inspect; use rustc_type_ir::visit::TypeVisitableExt as _; -use rustc_type_ir::{self as ty, Interner, Upcast as _, elaborate}; +use rustc_type_ir::{self as ty, Interner, TypingMode, Upcast as _, elaborate}; use tracing::{debug, instrument}; use crate::delegate::SolverDelegate; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource, - MaybeCause, NoSolution, QueryResult, SolverMode, + MaybeCause, NoSolution, QueryResult, }; /// A candidate is a possible way to prove a goal. @@ -328,11 +328,12 @@ where let mut candidates = vec![]; - if self.solver_mode() == SolverMode::Coherence { + if let TypingMode::Coherence = self.typing_mode(goal.param_env) { if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) { return vec![candidate]; } } + self.assemble_impl_candidates(goal, &mut candidates); self.assemble_builtin_impl_candidates(goal, &mut candidates); @@ -343,8 +344,11 @@ where self.assemble_param_env_candidates(goal, &mut candidates); - if self.solver_mode() == SolverMode::Normal { - self.discard_impls_shadowed_by_env(goal, &mut candidates); + match self.typing_mode(goal.param_env) { + TypingMode::Coherence => {} + TypingMode::Analysis { .. } | TypingMode::PostAnalysis => { + self.discard_impls_shadowed_by_env(goal, &mut candidates); + } } candidates diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index e2fd0dd2a25f..2f50070d4388 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -55,6 +55,7 @@ where &self, goal: Goal, ) -> (Vec, CanonicalInput) { + let param_env_for_debug_assertion = goal.param_env; let opaque_types = self.delegate.clone_opaque_types_for_query_response(); let (goal, opaque_types) = (goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate)); @@ -73,7 +74,7 @@ where ); let query_input = ty::CanonicalQueryInput { canonical, - defining_opaque_types: self.delegate.defining_opaque_types(), + typing_mode: self.typing_mode(param_env_for_debug_assertion), }; (orig_values, query_input) } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 7608253882a2..8685896715e1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -10,7 +10,7 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner}; +use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner, TypingMode}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::{instrument, trace}; @@ -21,7 +21,6 @@ use crate::solve::search_graph::SearchGraph; use crate::solve::{ CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, GoalSource, HasChanged, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, - SolverMode, }; pub(super) mod canonical; @@ -215,8 +214,8 @@ where D: SolverDelegate, I: Interner, { - pub(super) fn solver_mode(&self) -> SolverMode { - self.search_graph.solver_mode() + pub(super) fn typing_mode(&self, param_env_for_debug_assertion: I::ParamEnv) -> TypingMode { + self.delegate.typing_mode(param_env_for_debug_assertion) } pub(super) fn set_is_normalizes_to_goal(&mut self) { @@ -232,7 +231,7 @@ where generate_proof_tree: GenerateProofTree, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R, ) -> (R, Option>) { - let mut search_graph = SearchGraph::new(delegate.solver_mode(), root_depth); + let mut search_graph = SearchGraph::new(root_depth); let mut ecx = EvalCtxt { delegate, @@ -279,7 +278,7 @@ where f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal) -> R, ) -> R { let (ref delegate, input, var_values) = - SolverDelegate::build_with_canonical(cx, search_graph.solver_mode(), &canonical_input); + SolverDelegate::build_with_canonical(cx, &canonical_input); let mut ecx = EvalCtxt { delegate, @@ -942,21 +941,11 @@ where pub(super) fn fetch_eligible_assoc_item( &self, - param_env: I::ParamEnv, goal_trait_ref: ty::TraitRef, trait_assoc_def_id: I::DefId, impl_def_id: I::DefId, ) -> Result, NoSolution> { - self.delegate.fetch_eligible_assoc_item( - param_env, - goal_trait_ref, - trait_assoc_def_id, - impl_def_id, - ) - } - - pub(super) fn can_define_opaque_ty(&self, def_id: I::LocalDefId) -> bool { - self.delegate.defining_opaque_types().contains(&def_id) + self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id) } pub(super) fn insert_hidden_type( diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 7287cdf74bf4..129744b4db7e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -6,7 +6,7 @@ mod weak_types; use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; -use rustc_type_ir::{self as ty, Interner, NormalizesTo, Upcast as _}; +use rustc_type_ir::{self as ty, Interner, NormalizesTo, TypingMode, Upcast as _}; use tracing::instrument; use crate::delegate::SolverDelegate; @@ -15,7 +15,7 @@ use crate::solve::assembly::{self, Candidate}; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, - NoSolution, QueryResult, Reveal, + NoSolution, QueryResult, }; impl EvalCtxt<'_, D> @@ -71,21 +71,21 @@ where Ok(()) } ty::AliasTermKind::OpaqueTy => { - match param_env.reveal() { - // In user-facing mode, paques are only rigid if we may not define it. - Reveal::UserFacing => { + match self.typing_mode(param_env) { + // Opaques are never rigid outside of analysis mode. + TypingMode::Coherence | TypingMode::PostAnalysis => Err(NoSolution), + // During analysis, opaques are only rigid if we may not define it. + TypingMode::Analysis { defining_opaque_types } => { if rigid_alias .def_id .as_local() - .is_some_and(|def_id| self.can_define_opaque_ty(def_id)) + .is_some_and(|def_id| defining_opaque_types.contains(&def_id)) { Err(NoSolution) } else { Ok(()) } } - // Opaques are never rigid in reveal-all mode. - Reveal::All => Err(NoSolution), } } // FIXME(generic_const_exprs): we would need to support generic consts here @@ -252,7 +252,6 @@ where // return ambiguity this would otherwise be incomplete, resulting in // unsoundness during coherence (#105782). let Some(target_item_def_id) = ecx.fetch_eligible_assoc_item( - goal.param_env, goal_trait_ref, goal.predicate.def_id(), impl_def_id, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index f8d51f304f33..d1d701695ab8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -4,12 +4,10 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_type_ir::inherent::*; -use rustc_type_ir::{self as ty, Interner}; +use rustc_type_ir::{self as ty, Interner, TypingMode}; use crate::delegate::SolverDelegate; -use crate::solve::{ - Certainty, EvalCtxt, Goal, NoSolution, QueryResult, Reveal, SolverMode, inspect, -}; +use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, inspect}; impl EvalCtxt<'_, D> where @@ -24,17 +22,27 @@ where let opaque_ty = goal.predicate.alias; let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const"); - match (goal.param_env.reveal(), self.solver_mode()) { - (Reveal::UserFacing, SolverMode::Normal) => { - let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else { + match self.typing_mode(goal.param_env) { + TypingMode::Coherence => { + // An impossible opaque type bound is the only way this goal will fail + // e.g. assigning `impl Copy := NotCopy` + self.add_item_bounds_for_hidden_type( + opaque_ty.def_id, + opaque_ty.args, + goal.param_env, + expected, + ); + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + TypingMode::Analysis { defining_opaque_types } => { + let Some(def_id) = opaque_ty.def_id.as_local() else { return Err(NoSolution); }; - // FIXME: at some point we should call queries without defining - // new opaque types but having the existing opaque type definitions. - // This will require moving this below "Prefer opaques registered already". - if !self.can_define_opaque_ty(opaque_ty_def_id) { + + if !defining_opaque_types.contains(&def_id) { return Err(NoSolution); } + // FIXME: This may have issues when the args contain aliases... match uses_unique_placeholders_ignoring_regions(self.cx(), opaque_ty.args) { Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { @@ -48,8 +56,7 @@ where Ok(()) => {} } // Prefer opaques registered already. - let opaque_type_key = - ty::OpaqueTypeKey { def_id: opaque_ty_def_id, args: opaque_ty.args }; + let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args }; // FIXME: This also unifies the previous hidden type with the expected. // // If that fails, we insert `expected` as a new hidden type instead of @@ -69,7 +76,7 @@ where } ecx.eq(goal.param_env, candidate_ty, expected)?; ecx.add_item_bounds_for_hidden_type( - candidate_key.def_id.into(), + def_id.into(), candidate_key.args, goal.param_env, candidate_ty, @@ -82,25 +89,14 @@ where // FIXME: should we use `inject_hidden_type_unchecked` here? self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?; self.add_item_bounds_for_hidden_type( - opaque_ty.def_id, + def_id.into(), opaque_ty.args, goal.param_env, expected, ); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - (Reveal::UserFacing, SolverMode::Coherence) => { - // An impossible opaque type bound is the only way this goal will fail - // e.g. assigning `impl Copy := NotCopy` - self.add_item_bounds_for_hidden_type( - opaque_ty.def_id, - opaque_ty.args, - goal.param_env, - expected, - ); - self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - } - (Reveal::All, _) => { + TypingMode::PostAnalysis => { // FIXME: Add an assertion that opaque type storage is empty. let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args); self.eq(goal.param_env, expected, actual)?; diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 08cc89d950e2..9b63c6cc68e6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -6,7 +6,7 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::visit::TypeVisitableExt as _; -use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _, elaborate}; +use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate}; use tracing::{instrument, trace}; use crate::delegate::SolverDelegate; @@ -15,7 +15,7 @@ use crate::solve::assembly::{self, Candidate}; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause, - NoSolution, QueryResult, Reveal, SolverMode, + NoSolution, QueryResult, }; impl assembly::GoalKind for TraitPredicate @@ -67,9 +67,9 @@ where let maximal_certainty = match (impl_polarity, goal.predicate.polarity) { // In intercrate mode, this is ambiguous. But outside of intercrate, // it's not a real impl. - (ty::ImplPolarity::Reservation, _) => match ecx.solver_mode() { - SolverMode::Coherence => Certainty::AMBIGUOUS, - SolverMode::Normal => return Err(NoSolution), + (ty::ImplPolarity::Reservation, _) => match ecx.typing_mode(goal.param_env) { + TypingMode::Coherence => Certainty::AMBIGUOUS, + TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Err(NoSolution), }, // Impl matches polarity @@ -167,33 +167,32 @@ where return result; } - // Don't call `type_of` on a local TAIT that's in the defining scope, - // since that may require calling `typeck` on the same item we're + // We only look into opaque types during analysis for opaque types + // outside of their defining scope. Doing so for opaques in the + // defining scope may require calling `typeck` on the same item we're // currently type checking, which will result in a fatal cycle that // ideally we want to avoid, since we can make progress on this goal // via an alias bound or a locally-inferred hidden type instead. - // - // Also, don't call `type_of` on a TAIT in `Reveal::All` mode, since - // we already normalize the self type in - // `assemble_candidates_after_normalizing_self_ty`, and we'd - // just be registering an identical candidate here. - // - // We always return `Err(NoSolution)` here in `SolverMode::Coherence` - // since we'll always register an ambiguous candidate in - // `assemble_candidates_after_normalizing_self_ty` due to normalizing - // the TAIT. if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() { - if matches!(goal.param_env.reveal(), Reveal::All) - || matches!(ecx.solver_mode(), SolverMode::Coherence) - || opaque_ty - .def_id - .as_local() - .is_some_and(|def_id| ecx.can_define_opaque_ty(def_id)) - { - return Err(NoSolution); + match ecx.typing_mode(goal.param_env) { + TypingMode::Coherence | TypingMode::PostAnalysis => { + unreachable!("rigid opaque outside of analysis: {goal:?}"); + } + TypingMode::Analysis { defining_opaque_types } => { + if opaque_ty + .def_id + .as_local() + .is_some_and(|def_id| defining_opaque_types.contains(&def_id)) + { + return Err(NoSolution); + } + } } } + // We want to make sure + debug_assert!(!matches!(ecx.typing_mode(), TypingMode::Coherence)); + ecx.probe_and_evaluate_goal_for_constituent_tys( CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8c4592cbb369..0a2926c04044 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -25,7 +25,7 @@ use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, @@ -2267,7 +2267,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let def_id = hir_id.expect_owner().def_id; let param_env = ty::ParamEnv::empty(); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let span = tcx.def_span(def_id); diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 0b6cf82ca8b4..921a915d05b1 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -2,6 +2,7 @@ use rustc_abi::{HasDataLayout, TargetDataLayout}; use rustc_ast::Attribute; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; +use rustc_middle::infer::canonical::ir::TypingMode; use rustc_middle::span_bug; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; @@ -54,7 +55,7 @@ pub fn ensure_wf<'tcx>( param_env, pred, ); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 5793ac2fc313..c53689b211d2 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -7,13 +7,13 @@ use rustc_infer::infer::canonical::{ Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues, }; use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt}; +use rustc_infer::traits::ObligationCause; use rustc_infer::traits::solve::Goal; -use rustc_infer::traits::{ObligationCause, Reveal}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; -use rustc_type_ir::solve::{Certainty, NoSolution, SolverMode}; -use tracing::trace; +use rustc_type_ir::TypingMode; +use rustc_type_ir::solve::{Certainty, NoSolution}; use crate::traits::specialization_graph; @@ -47,7 +47,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< fn build_with_canonical( interner: TyCtxt<'tcx>, - solver_mode: SolverMode, canonical: &CanonicalQueryInput<'tcx, V>, ) -> (Self, V, CanonicalVarValues<'tcx>) where @@ -56,10 +55,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< let (infcx, value, vars) = interner .infer_ctxt() .with_next_trait_solver(true) - .intercrate(match solver_mode { - SolverMode::Normal => false, - SolverMode::Coherence => true, - }) .build_with_canonical(DUMMY_SP, canonical); (SolverDelegate(infcx), value, vars) } @@ -195,7 +190,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< fn fetch_eligible_assoc_item( &self, - param_env: ty::ParamEnv<'tcx>, goal_trait_ref: ty::TraitRef<'tcx>, trait_assoc_def_id: DefId, impl_def_id: DefId, @@ -211,12 +205,12 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< // and the obligation is monomorphic, otherwise passes such as // transmute checking and polymorphic MIR optimizations could // get a result which isn't correct for all monomorphizations. - if param_env.reveal() == Reveal::All { - let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); - !poly_trait_ref.still_further_specializable() - } else { - trace!(?node_item.item.def_id, "not eligible due to default"); - false + match self.typing_mode_unchecked() { + TypingMode::Coherence | TypingMode::Analysis { .. } => false, + TypingMode::PostAnalysis => { + let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); + !poly_trait_ref.still_further_specializable() + } } }; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 934fe9ec47c0..52ba5621d319 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -10,6 +10,7 @@ use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::{Region, RegionVid}; use tracing::debug; +use ty::TypingMode; use super::*; use crate::errors::UnableToConstructConstantValue; @@ -79,7 +80,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let trait_ref = ty::TraitRef::new(tcx, trait_did, [ty]); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut selcx = SelectionContext::new(&infcx); for polarity in [ty::PredicatePolarity::Positive, ty::PredicatePolarity::Negative] { let result = selcx.select(&Obligation::new( @@ -99,7 +100,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } } - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let mut fresh_preds = FxIndexSet::default(); // Due to the way projections are handled by SelectionContext, we need to run diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index f8fb297e36c4..3cd11d7c8e8d 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -18,7 +18,7 @@ use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; pub use rustc_next_trait_solver::coherence::*; use rustc_next_trait_solver::solve::SolverDelegateEvalExt; use rustc_span::symbol::sym; @@ -195,9 +195,8 @@ fn overlap<'tcx>( let infcx = tcx .infer_ctxt() .skip_leak_check(skip_leak_check.is_yes()) - .intercrate(true) .with_next_trait_solver(tcx.next_trait_solver_in_coherence()) - .build(); + .build(TypingMode::Coherence); let selcx = &mut SelectionContext::new(&infcx); if track_ambiguity_causes.is_yes() { selcx.enable_tracking_intercrate_ambiguity_causes(); @@ -419,7 +418,7 @@ fn impl_intersection_has_negative_obligation( // N.B. We need to unify impl headers *with* intercrate mode, even if proving negative predicates // do not need intercrate mode enabled. - let ref infcx = tcx.infer_ctxt().intercrate(true).with_next_trait_solver(true).build(); + let ref infcx = tcx.infer_ctxt().with_next_trait_solver(true).build(TypingMode::Coherence); let root_universe = infcx.universe(); assert_eq!(root_universe, ty::UniverseIndex::ROOT); @@ -570,7 +569,9 @@ fn try_prove_negated_where_clause<'tcx>( // the *existence* of a negative goal, not the non-existence of a positive goal. // Without this, we over-eagerly register coherence ambiguity candidates when // impl candidates do exist. - let ref infcx = root_infcx.fork_with_intercrate(false); + // FIXME(#132279): `TypingMode::non_body_analysis` is a bit questionable here as it + // would cause us to reveal opaque types to leak their auto traits. + let ref infcx = root_infcx.fork_with_typing_mode(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new(infcx); ocx.register_obligation(Obligation::new( infcx.tcx, @@ -714,7 +715,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { // It is only relevant that a goal is unknowable if it would have otherwise // failed. - let non_intercrate_infcx = infcx.fork_with_intercrate(false); + // FIXME(#132279): Forking with `TypingMode::non_body_analysis` is a bit questionable + // as it would allow us to reveal opaque types, potentially causing unexpected + // cycles. + let non_intercrate_infcx = infcx.fork_with_typing_mode(TypingMode::non_body_analysis()); if non_intercrate_infcx.predicate_may_hold(&Obligation::new( infcx.tcx, ObligationCause::dummy(), diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index a068f25fe35e..bd4e3dd7d8dd 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -14,7 +14,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{ self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, Upcast, + TypeVisitableExt, TypeVisitor, TypingMode, Upcast, }; use rustc_span::Span; use rustc_span::symbol::Symbol; @@ -718,7 +718,7 @@ fn receiver_is_dispatchable<'tcx>( Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate) }; - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); // the receiver is dispatchable iff the obligation holds infcx.predicate_must_hold_modulo_regions(&obligation) } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e3ad21e352a0..29e60e3c428b 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -13,7 +13,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt}; +use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode}; use thin_vec::ThinVec; use tracing::{debug, debug_span, instrument}; @@ -760,7 +760,9 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { stalled_on: &mut Vec, ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { let infcx = self.selcx.infcx; - if obligation.predicate.is_global() && !self.selcx.is_intercrate() { + if obligation.predicate.is_global() + && !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence) + { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. if infcx.predicate_must_hold_considering_regions(obligation) { @@ -813,11 +815,13 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { stalled_on: &mut Vec, ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { let tcx = self.selcx.tcx(); - - if obligation.predicate.is_global() && !self.selcx.is_intercrate() { + let infcx = self.selcx.infcx; + if obligation.predicate.is_global() + && !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence) + { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. - if self.selcx.infcx.predicate_must_hold_considering_regions(obligation) { + if infcx.predicate_must_hold_considering_regions(obligation) { if let Some(key) = ProjectionCacheKey::from_poly_projection_obligation( &mut self.selcx, &project_obligation, @@ -825,8 +829,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { // If `predicate_must_hold_considering_regions` succeeds, then we've // evaluated all sub-obligations. We can therefore mark the 'root' // obligation as complete, and skip evaluating sub-obligations. - self.selcx - .infcx + infcx .inner .borrow_mut() .projection_cache() diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 3e65194577e0..3b17fa6b0328 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; -use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use super::outlives_bounds::InferCtxtExt; use crate::regions::InferCtxtRegionExt; @@ -143,7 +143,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( let mut infringing_inner_tys = vec![]; for inner_ty in inner_tys { // We use an ocx per inner ty for better diagnostics - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); ocx.register_bound( @@ -200,7 +200,7 @@ pub fn all_fields_implement_trait<'tcx>( for variant in adt.variants() { for field in &variant.fields { // Do this per-field to get better error messages. - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); let unnormalized_ty = field.ty(tcx, args); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index f5d9b50359c1..1c84f2171bca 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -34,7 +34,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, Upcast, + self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, TypingMode, + Upcast, }; use rustc_span::Span; use rustc_span::def_id::DefId; @@ -274,7 +275,7 @@ fn do_normalize_predicates<'tcx>( // by wfcheck anyway, so I'm not sure we have to check // them here too, and we will remove this function when // we move over to lazy normalization *anyway*. - let infcx = tcx.infer_ctxt().ignoring_regions().build(); + let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let predicates = ocx.normalize(&cause, elaborated_env, predicates); @@ -475,11 +476,11 @@ pub fn normalize_param_env_or_error<'tcx>( /// Normalizes the predicates and checks whether they hold in an empty environment. If this /// returns true, then either normalize encountered an error or one of the predicates did not -/// hold. Used when creating vtables to check for unsatisfiable methods. +/// hold. Used when creating vtables to check for unsatisfiable methods. This should not be +/// used during analysis. pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec>) -> bool { debug!("impossible_predicates(predicates={:?})", predicates); - - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); let param_env = ty::ParamEnv::reveal_all(); let ocx = ObligationCtxt::new(&infcx); let predicates = ocx.normalize(&ObligationCause::dummy(), param_env, predicates); @@ -568,8 +569,11 @@ fn is_impossible_associated_item( // since that method *may* have some substitutions where the predicates hold. // // This replicates the logic we use in coherence. - let infcx = - tcx.infer_ctxt().ignoring_regions().with_next_trait_solver(true).intercrate(true).build(); + let infcx = tcx + .infer_ctxt() + .ignoring_regions() + .with_next_trait_solver(true) + .build(TypingMode::Coherence); let param_env = ty::ParamEnv::empty(); let fresh_args = infcx.fresh_args_for_item(tcx.def_span(impl_def_id), impl_def_id); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 0803dd74b89b..a75c07c2e8c6 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -334,11 +334,6 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( ) -> Result>, InProgress> { let infcx = selcx.infcx; debug_assert!(!selcx.infcx.next_trait_solver()); - // Don't use the projection cache in intercrate mode - - // the `infcx` may be re-used between intercrate in non-intercrate - // mode, which could lead to using incorrect cache results. - let use_cache = !selcx.is_intercrate(); - let projection_term = infcx.resolve_vars_if_possible(projection_term); let cache_key = ProjectionCacheKey::new(projection_term, param_env); @@ -349,13 +344,8 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( // would not benefit from caching when proving `T: Trait` // bounds. It might be the case that we want two distinct caches, // or else another kind of cache entry. - - let cache_result = if use_cache { - infcx.inner.borrow_mut().projection_cache().try_start(cache_key) - } else { - Ok(()) - }; - match cache_result { + let cache_entry = infcx.inner.borrow_mut().projection_cache().try_start(cache_key); + match cache_entry { Ok(()) => debug!("no cache"), Err(ProjectionCacheEntry::Ambiguous) => { // If we found ambiguity the last time, that means we will continue @@ -378,10 +368,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( // Cache that normalizing this projection resulted in a cycle. This // should ensure that, unless this happens within a snapshot that's // rolled back, fulfillment or evaluation will notice the cycle. - - if use_cache { - infcx.inner.borrow_mut().projection_cache().recur(cache_key); - } + infcx.inner.borrow_mut().projection_cache().recur(cache_key); return Err(InProgress); } Err(ProjectionCacheEntry::Recur) => { @@ -445,26 +432,20 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( let mut deduped = SsoHashSet::with_capacity(result.obligations.len()); result.obligations.retain(|obligation| deduped.insert(obligation.clone())); - if use_cache { - infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); - } + infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); obligations.extend(result.obligations); Ok(Some(result.value)) } Ok(Projected::NoProgress(projected_ty)) => { let result = Normalized { value: projected_ty, obligations: PredicateObligations::new() }; - if use_cache { - infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); - } + infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); // No need to extend `obligations`. Ok(Some(result.value)) } Err(ProjectionError::TooManyCandidates) => { debug!("opt_normalize_projection_type: too many candidates"); - if use_cache { - infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); - } + infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); Ok(None) } Err(ProjectionError::TraitSelectionError(_)) => { @@ -473,10 +454,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( // just return `ty::err` but add the obligation `T : // Trait`, which when processed will cause the error to be // reported later - - if use_cache { - infcx.inner.borrow_mut().projection_cache().error(cache_key); - } + infcx.inner.borrow_mut().projection_cache().error(cache_key); let result = normalize_to_error(selcx, param_env, projection_term, cause, depth); obligations.extend(result.obligations); Ok(Some(result.value)) diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index bb44645a4ce1..9e1a2a3e7d28 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -87,7 +87,6 @@ impl<'tcx> InferCtxt<'tcx> { Ok(result) }) } else { - assert!(!self.intercrate); let c_pred = self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values); self.tcx.at(obligation.cause.span).evaluate_obligation(c_pred) diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index e027586563ec..03fde1d15989 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -16,7 +16,7 @@ use rustc_infer::traits::{ Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError, }; use rustc_middle::ty::fast_reject::DeepRejectCtxt; -use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument, trace}; @@ -790,7 +790,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // // Note that this is only sound as projection candidates of opaque types // are always applicable for auto traits. - } else if self.infcx.intercrate { + } else if let TypingMode::Coherence = + self.infcx.typing_mode(obligation.param_env) + { // We do not emit auto trait candidates for opaque types in coherence. // Doing so can result in weird dependency cycles. candidates.ambiguous = true; @@ -930,7 +932,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Option> { // Don't drop any candidates in intercrate mode, as it's incomplete. // (Not that it matters, since `Unsize` is not a stable trait.) - if self.infcx.intercrate { + // + // FIXME(@lcnr): This should probably only trigger during analysis, + // disabling candidates during codegen is also questionable. + if let TypingMode::Coherence = self.infcx.typing_mode(param_env) { return None; } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 635d3bc99b1a..b1e5e5263151 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2,6 +2,7 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection +use std::assert_matches::assert_matches; use std::cell::{Cell, RefCell}; use std::fmt::{self, Display}; use std::ops::ControlFlow; @@ -28,7 +29,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ self, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, - Upcast, + TypingMode, Upcast, }; use rustc_span::Symbol; use rustc_span::symbol::sym; @@ -222,7 +223,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Enables tracking of intercrate ambiguity causes. See /// the documentation of [`Self::intercrate_ambiguity_causes`] for more. pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) { - assert!(self.is_intercrate()); + assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence); assert!(self.intercrate_ambiguity_causes.is_none()); self.intercrate_ambiguity_causes = Some(FxIndexSet::default()); debug!("selcx: enable_tracking_intercrate_ambiguity_causes"); @@ -234,7 +235,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub fn take_intercrate_ambiguity_causes( &mut self, ) -> FxIndexSet> { - assert!(self.is_intercrate()); + assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence); self.intercrate_ambiguity_causes.take().unwrap_or_default() } @@ -242,10 +243,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.tcx } - pub fn is_intercrate(&self) -> bool { - self.infcx.intercrate - } - /////////////////////////////////////////////////////////////////////////// // Selection // @@ -1029,7 +1026,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: PolyTraitObligation<'tcx>, ) -> Result { - if !self.is_intercrate() + if !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence) && obligation.is_global() && obligation.param_env.caller_bounds().iter().all(|bound| bound.has_param()) { @@ -1312,14 +1309,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option { - // Neither the global nor local cache is aware of intercrate - // mode, so don't do any caching. In particular, we might - // re-use the same `InferCtxt` with both an intercrate - // and non-intercrate `SelectionContext` - if self.is_intercrate() { - return None; - } - let tcx = self.tcx(); if self.can_use_global_caches(param_env) { if let Some(res) = tcx.evaluation_cache.get(&(param_env, trait_pred), tcx) { @@ -1342,14 +1331,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - // Neither the global nor local cache is aware of intercrate - // mode, so don't do any caching. In particular, we might - // re-use the same `InferCtxt` with both an intercrate - // and non-intercrate `SelectionContext` - if self.is_intercrate() { - return; - } - if self.can_use_global_caches(param_env) && !trait_pred.has_infer() { debug!(?trait_pred, ?result, "insert_evaluation_cache global"); // This may overwrite the cache with the same value @@ -1476,13 +1457,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> { - debug!("is_knowable(intercrate={:?})", self.is_intercrate()); - - if !self.is_intercrate() { - return Ok(()); + let obligation = &stack.obligation; + match self.infcx.typing_mode(obligation.param_env) { + TypingMode::Coherence => {} + TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Ok(()), } - let obligation = &stack.obligation; + debug!("is_knowable()"); + let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); // Okay to skip binder because of the nature of the @@ -1502,25 +1484,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return false; } - // Avoid using the global cache during coherence and just rely - // on the local cache. This effectively disables caching - // during coherence. It is really just a simplification to - // avoid us having to fear that coherence results "pollute" - // the master cache. Since coherence executes pretty quickly, - // it's not worth going to more trouble to increase the - // hit-rate, I don't think. - if self.is_intercrate() { - return false; + match self.infcx.typing_mode(param_env) { + // Avoid using the global cache during coherence and just rely + // on the local cache. It is really just a simplification to + // avoid us having to fear that coherence results "pollute" + // the master cache. Since coherence executes pretty quickly, + // it's not worth going to more trouble to increase the + // hit-rate, I don't think. + TypingMode::Coherence => false, + // Avoid using the global cache when we're defining opaque types + // as their hidden type may impact the result of candidate selection. + TypingMode::Analysis { defining_opaque_types } => defining_opaque_types.is_empty(), + // The global cache is only used if there are no opaque types in + // the defining scope or we're outside of analysis. + // + // FIXME(#132279): This is still incorrect as we treat opaque types + // and default associated items differently between these two modes. + TypingMode::PostAnalysis => true, } - - // Avoid using the global cache when we're defining opaque types - // as their hidden type may impact the result of candidate selection. - if !self.infcx.defining_opaque_types().is_empty() { - return false; - } - - // Otherwise, we can use the global cache. - true } fn check_candidate_cache( @@ -1528,13 +1509,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option>> { - // Neither the global nor local cache is aware of intercrate - // mode, so don't do any caching. In particular, we might - // re-use the same `InferCtxt` with both an intercrate - // and non-intercrate `SelectionContext` - if self.is_intercrate() { - return None; - } let tcx = self.tcx(); let pred = cache_fresh_trait_pred.skip_binder(); @@ -1566,13 +1540,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &self, result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>, ) -> bool { - // Neither the global nor local cache is aware of intercrate - // mode, so don't do any caching. In particular, we might - // re-use the same `InferCtxt` with both an intercrate - // and non-intercrate `SelectionContext` - if self.is_intercrate() { - return false; - } match result { Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_infer(), _ => true, @@ -2541,7 +2508,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { })?; nested_obligations.extend(obligations); - if !self.is_intercrate() && impl_trait_header.polarity == ty::ImplPolarity::Reservation { + if impl_trait_header.polarity == ty::ImplPolarity::Reservation + && !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence) + { debug!("reservation impls only apply in intercrate mode"); return Err(()); } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 0e45f7a195f0..5bf3dbcbc327 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -19,7 +19,9 @@ use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::bug; use rustc_middle::query::LocalCrate; use rustc_middle::ty::print::PrintTraitRefExt as _; -use rustc_middle::ty::{self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{ + self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt, TypingMode, +}; use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym}; use specialization_graph::GraphExt; @@ -184,7 +186,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, let penv = tcx.param_env(impl1_def_id); // Create an infcx, taking the predicates of impl1 as assumptions: - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); // Attempt to prove that impl2 applies, given all of the above. fulfill_implication( diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index ed221e2a1835..bb56d6eaf544 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -9,7 +9,8 @@ use rustc_infer::traits::util::PredicateSet; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry, + self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, + VtblEntry, }; use rustc_span::{DUMMY_SP, Span, sym}; use smallvec::{SmallVec, smallvec}; @@ -439,7 +440,7 @@ fn trait_refs_are_compatible<'tcx>( return false; } - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); let param_env = ty::ParamEnv::reveal_all(); let ocx = ObligationCtxt::new(&infcx); let hr_source_principal = diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 111821982465..d8c1c50d79a8 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::traits::CodegenObligationError; -use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{ ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, @@ -30,7 +30,7 @@ pub(crate) fn codegen_select_candidate<'tcx>( // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - let infcx = tcx.infer_ctxt().ignoring_regions().build(); + let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::from_param_env(param_env)); let mut selcx = SelectionContext::new(&infcx); let obligation_cause = ObligationCause::dummy(); diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 3e2794f6489f..d79059a39a1d 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -1,7 +1,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode}; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Normalized, ObligationCause}; use tracing::debug; @@ -22,7 +22,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable> + Par goal: ParamEnvAnd<'tcx, T>, ) -> Result { let ParamEnvAnd { param_env, value } = goal; - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let cause = ObligationCause::dummy(); match infcx.at(&cause, param_env).query_normalize(value) { Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => { diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index 51b908881eb4..c26b41d89600 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -3,7 +3,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_trait_selection::traits; fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { @@ -29,7 +29,7 @@ fn is_item_raw<'tcx>( ) -> bool { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(item, None); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id) } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 9b764133f2c6..e258b6dae0b4 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -6,7 +6,7 @@ use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError}; use rustc_middle::ty::util::AsyncDropGlueMorphology; -use rustc_middle::ty::{self, GenericArgsRef, Instance, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, GenericArgsRef, Instance, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_span::sym; use rustc_trait_selection::traits; use rustc_type_ir::ClosureKind; @@ -130,7 +130,7 @@ fn resolve_associated_item<'tcx>( .unwrap_or_else(|| { bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id); }); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis); let param_env = param_env.with_reveal_all_normalized(tcx); let args = rcvr_args.rebase_onto(tcx, trait_def_id, impl_data.args); let args = translate_args( diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs index 1ead7b731e76..0b4efab1d9c4 100644 --- a/compiler/rustc_ty_utils/src/structural_match.rs +++ b/compiler/rustc_ty_utils/src/structural_match.rs @@ -1,7 +1,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; /// This method returns true if and only if `adt_ty` itself has been marked as @@ -11,7 +11,7 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; /// Note that this does *not* recursively check if the substructure of `adt_ty` /// implements the trait. fn has_structural_eq_impl<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool { - let infcx = &tcx.infer_ctxt().build(); + let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let cause = ObligationCause::dummy(); let ocx = ObligationCtxt::new(infcx); diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 3fb7d87bcc4b..24b2ebc1fbe7 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -8,7 +8,7 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use crate::inherent::*; -use crate::{self as ty, Interner, UniverseIndex}; +use crate::{self as ty, Interner, TypingMode, UniverseIndex}; #[derive_where(Clone; I: Interner, V: Clone)] #[derive_where(Hash; I: Interner, V: Hash)] @@ -19,7 +19,7 @@ use crate::{self as ty, Interner, UniverseIndex}; #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub struct CanonicalQueryInput { pub canonical: Canonical, - pub defining_opaque_types: I::DefiningOpaqueTypes, + pub typing_mode: TypingMode, } /// A "canonicalized" type `V` is one where all free inference diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 7c6a3c65ebfb..22223e4a8900 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -1,9 +1,68 @@ +use derive_where::derive_where; +#[cfg(feature = "nightly")] +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; + use crate::fold::TypeFoldable; +use crate::inherent::*; use crate::relate::RelateResult; use crate::relate::combine::PredicateEmittingRelation; -use crate::solve::SolverMode; +use crate::solve::Reveal; use crate::{self as ty, Interner}; +/// The current typing mode of an inference context. We unfortunately have some +/// slightly different typing rules depending on the current context. See the +/// doc comment for each variant for how and why they are used. +#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub enum TypingMode { + /// When checking whether impls overlap, we check whether any obligations + /// are guaranteed to never hold when unifying the impls. This requires us + /// to be complete: we must never fail to prove something which may actually + /// hold. + /// + /// In this typing mode we bail with ambiguity in case its not knowable + /// whether a trait goal may hold, e.g. because the trait may get implemented + /// in a downstream or sibling crate. + /// + /// We also have to be careful when generalizing aliases inside of higher-ranked + /// types to not unnecessarily constrain any inference variables. + Coherence, + /// Analysis includes type inference, checking that items are well-formed, and + /// pretty much everything else which may emit proper type errors to the user. + /// + /// We only normalize opaque types which may get defined by the current body, + /// which are stored in `defining_opaque_types`. + Analysis { defining_opaque_types: I::DefiningOpaqueTypes }, + /// After analysis, mostly during codegen and MIR optimizations, we're able to + /// reveal all opaque types. + PostAnalysis, +} + +impl TypingMode { + /// Analysis outside of a body does not define any opaque types. + pub fn non_body_analysis() -> TypingMode { + TypingMode::Analysis { defining_opaque_types: Default::default() } + } + + /// While typechecking a body, we need to be able to define the opaque + /// types defined by that body. + pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode { + TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) } + } + + /// FIXME(#132279): Using this function is questionable as the `param_env` + /// does not track `defining_opaque_types` and whether we're in coherence mode. + /// Many uses of this function should also use a not-yet implemented typing mode + /// which reveals already defined opaque types in the future. This function will + /// get completely removed at some point. + pub fn from_param_env(param_env: I::ParamEnv) -> TypingMode { + match param_env.reveal() { + Reveal::UserFacing => TypingMode::non_body_analysis(), + Reveal::All => TypingMode::PostAnalysis, + } + } +} + pub trait InferCtxtLike: Sized { type Interner: Interner; fn cx(&self) -> Self::Interner; @@ -16,7 +75,10 @@ pub trait InferCtxtLike: Sized { true } - fn solver_mode(&self) -> SolverMode; + fn typing_mode( + &self, + param_env_for_debug_assertion: ::ParamEnv, + ) -> TypingMode; fn universe(&self) -> ty::UniverseIndex; fn create_next_universe(&self) -> ty::UniverseIndex; @@ -43,8 +105,6 @@ pub trait InferCtxtLike: Sized { vid: ty::RegionVid, ) -> ::Region; - fn defining_opaque_types(&self) -> ::DefiningOpaqueTypes; - fn next_ty_infer(&self) -> ::Ty; fn next_const_infer(&self) -> ::Const; fn fresh_args_for_item( diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6a8113b38b7b..36ddddccfa25 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -11,9 +11,7 @@ use crate::inherent::*; use crate::ir_print::IrPrint; use crate::lang_items::TraitSolverLangItem; use crate::relate::Relate; -use crate::solve::{ - CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode, -}; +use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, search_graph}; @@ -130,11 +128,7 @@ pub trait Interner: type Clause: Clause; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; - fn with_global_cache( - self, - mode: SolverMode, - f: impl FnOnce(&mut search_graph::GlobalCache) -> R, - ) -> R; + fn with_global_cache(self, f: impl FnOnce(&mut search_graph::GlobalCache) -> R) -> R; fn evaluation_is_concurrent(&self) -> bool; @@ -298,6 +292,11 @@ pub trait Interner: self, binder: ty::Binder, ) -> ty::Binder; + + fn opaque_types_defined_by( + self, + defining_anchor: Self::LocalDefId, + ) -> Self::DefiningOpaqueTypes; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` @@ -414,12 +413,8 @@ impl search_graph::Cx for I { fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, I::DepNodeIndex) { I::with_cached_task(self, task) } - fn with_global_cache( - self, - mode: SolverMode, - f: impl FnOnce(&mut search_graph::GlobalCache) -> R, - ) -> R { - I::with_global_cache(self, mode, f) + fn with_global_cache(self, f: impl FnOnce(&mut search_graph::GlobalCache) -> R) -> R { + I::with_global_cache(self, f) } fn evaluation_is_concurrent(&self) -> bool { self.evaluation_is_concurrent() diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 17a3912730f5..53751f7711a7 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -6,9 +6,9 @@ use super::{ }; use crate::error::TypeError; use crate::inherent::*; -use crate::solve::{Goal, SolverMode}; +use crate::solve::Goal; use crate::visit::TypeVisitableExt as _; -use crate::{self as ty, InferCtxtLike, Interner, Upcast}; +use crate::{self as ty, InferCtxtLike, Interner, TypingMode, Upcast}; pub trait PredicateEmittingRelation::Interner>: TypeRelation @@ -128,19 +128,19 @@ where } (ty::Alias(ty::Opaque, _), _) | (_, ty::Alias(ty::Opaque, _)) => { - match infcx.solver_mode() { - SolverMode::Normal => { - assert!(!infcx.next_trait_solver()); - structurally_relate_tys(relation, a, b) - } + assert!(!infcx.next_trait_solver()); + match infcx.typing_mode(relation.param_env()) { // During coherence, opaque types should be treated as *possibly* - // equal to any other type (except for possibly itinfcx). This is an + // equal to any other type. This is an // extremely heavy hammer, but can be relaxed in a forwards-compatible // way later. - SolverMode::Coherence => { + TypingMode::Coherence => { relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]); Ok(a) } + TypingMode::Analysis { .. } | TypingMode::PostAnalysis => { + structurally_relate_tys(relation, a, b) + } } } diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 3fd2bb61ba58..5010fc09adc3 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -22,7 +22,6 @@ use rustc_index::{Idx, IndexVec}; use tracing::debug; use crate::data_structures::HashMap; -use crate::solve::SolverMode; mod global_cache; use global_cache::CacheData; @@ -48,11 +47,7 @@ pub trait Cx: Copy { fn get_tracked(self, tracked: &Self::Tracked) -> T; fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex); - fn with_global_cache( - self, - mode: SolverMode, - f: impl FnOnce(&mut GlobalCache) -> R, - ) -> R; + fn with_global_cache(self, f: impl FnOnce(&mut GlobalCache) -> R) -> R; fn evaluation_is_concurrent(&self) -> bool; } @@ -358,7 +353,6 @@ struct ProvisionalCacheEntry { } pub struct SearchGraph, X: Cx = ::Cx> { - mode: SolverMode, root_depth: AvailableDepth, /// The stack of goals currently being computed. /// @@ -374,9 +368,8 @@ pub struct SearchGraph, X: Cx = ::Cx> { } impl, X: Cx> SearchGraph { - pub fn new(mode: SolverMode, root_depth: usize) -> SearchGraph { + pub fn new(root_depth: usize) -> SearchGraph { Self { - mode, root_depth: AvailableDepth(root_depth), stack: Default::default(), provisional_cache: Default::default(), @@ -384,10 +377,6 @@ impl, X: Cx> SearchGraph { } } - pub fn solver_mode(&self) -> SolverMode { - self.mode - } - /// Lazily update the stack entry for the parent goal. /// This behavior is shared between actually evaluating goals /// and using existing global cache entries to make sure they @@ -829,7 +818,7 @@ impl, X: Cx> SearchGraph { input: X::Input, available_depth: AvailableDepth, ) -> Option { - cx.with_global_cache(self.mode, |cache| { + cx.with_global_cache(|cache| { cache .get(cx, input, available_depth, |nested_goals| { Self::candidate_is_applicable( @@ -852,7 +841,7 @@ impl, X: Cx> SearchGraph { input: X::Input, available_depth: AvailableDepth, ) -> Option { - cx.with_global_cache(self.mode, |cache| { + cx.with_global_cache(|cache| { let CacheData { result, additional_depth, encountered_overflow, nested_goals } = cache .get(cx, input, available_depth, |nested_goals| { Self::candidate_is_applicable( @@ -1041,7 +1030,7 @@ impl, X: Cx> SearchGraph { ) { let additional_depth = final_entry.reached_depth.as_usize() - self.stack.len(); debug!(?final_entry, ?result, "insert global cache"); - cx.with_global_cache(self.mode, |cache| { + cx.with_global_cache(|cache| { cache.insert( cx, input, diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index b3f8390bbf06..fe4558730513 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -58,19 +58,6 @@ pub enum Reveal { All, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum SolverMode { - /// Ordinary trait solving, using everywhere except for coherence. - Normal, - /// Trait solving during coherence. There are a few notable differences - /// between coherence and ordinary trait solving. - /// - /// Most importantly, trait solving during coherence must not be incomplete, - /// i.e. return `Err(NoSolution)` for goals for which a solution exists. - /// This means that we must not make any guesses or arbitrary choices. - Coherence, -} - pub type CanonicalInput::Predicate> = ty::CanonicalQueryInput>; pub type CanonicalResponse = Canonical>; From ce22ccb55233dbf3d19c8a6796828ef24d6e9095 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 24 Oct 2024 12:00:55 +0200 Subject: [PATCH 10/56] remove outdated debug_assertion --- compiler/rustc_next_trait_solver/src/solve/trait_goals.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 9b63c6cc68e6..e23e475a2a62 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -190,9 +190,6 @@ where } } - // We want to make sure - debug_assert!(!matches!(ecx.typing_mode(), TypingMode::Coherence)); - ecx.probe_and_evaluate_goal_for_constituent_tys( CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, From 4f3a73a42c5571e9985ad18a00b8a9decdd53281 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 24 Oct 2024 10:47:30 +0200 Subject: [PATCH 11/56] update tools --- src/librustdoc/clean/blanket_impl.rs | 4 ++-- src/librustdoc/clean/mod.rs | 6 +++--- src/librustdoc/html/format.rs | 5 ++--- src/tools/clippy/clippy_lints/src/eta_reduction.rs | 5 +++-- .../clippy/clippy_lints/src/functions/must_use.rs | 2 +- src/tools/clippy/clippy_lints/src/future_not_send.rs | 2 +- .../clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +- .../src/needless_borrows_for_generic_args.rs | 2 +- src/tools/clippy/clippy_lints/src/no_effect.rs | 2 +- src/tools/clippy/clippy_lints/src/ptr.rs | 2 +- .../clippy/clippy_lints/src/useless_conversion.rs | 2 +- .../clippy/clippy_utils/src/qualify_min_const_fn.rs | 4 ++-- src/tools/clippy/clippy_utils/src/ty.rs | 10 +++++----- 13 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 1f3cb4a61b89..a6d9676dd84a 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -1,7 +1,7 @@ use rustc_hir as hir; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt}; use rustc_infer::traits; -use rustc_middle::ty::{self, Upcast}; +use rustc_middle::ty::{self, TypingMode, Upcast}; use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -38,7 +38,7 @@ pub(crate) fn synthesize_blanket_impls( if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { continue; } - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id); let impl_ty = ty.instantiate(tcx, args); let param_env = ty::ParamEnv::empty(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ea349f878e0e..87b629078ff8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -45,7 +45,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId}; use rustc_hir_analysis::lower_ty; use rustc_middle::metadata::Reexport; use rustc_middle::middle::resolve_bound_vars as rbv; -use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_span::ExpnKind; use rustc_span::hygiene::{AstPass, MacroKind}; @@ -1863,7 +1863,7 @@ fn normalize<'tcx>( use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; // Try to normalize `::T` to a type - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let normalized = infcx .at(&ObligationCause::dummy(), cx.param_env) .query_normalize(ty) @@ -2399,7 +2399,7 @@ pub(crate) fn clean_variant_def_with_args<'tcx>( use rustc_trait_selection::infer::TyCtxtInferExt; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let kind = match variant.ctor_kind() { Some(CtorKind::Const) => VariantKind::CLike, Some(CtorKind::Fn) => VariantKind::Tuple( diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 8e8e5c6ade8c..47c21d89177b 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -20,8 +20,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_metadata::creader::{CStore, LoadedMacro}; -use rustc_middle::ty; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_span::symbol::kw; use rustc_span::{Symbol, sym}; use rustc_target::spec::abi::Abi; @@ -613,7 +612,7 @@ fn generate_item_def_id_path( // No need to try to infer the actual parent item if it's not an associated item from the `impl` // block. if def_id != original_def_id && matches!(tcx.def_kind(def_id), DefKind::Impl { .. }) { - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); def_id = infcx .at(&ObligationCause::dummy(), tcx.param_env(def_id)) .query_normalize(ty::Binder::dummy(tcx.type_of(def_id).instantiate_identity())) diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index cabc65922582..6ca599ed3611 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -9,7 +9,8 @@ use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Saf use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{ - self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt, TypeckResults, + self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt, + TypeckResults, }; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; @@ -203,7 +204,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc // 'cuz currently nothing changes after deleting this check. local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr) }) { - match cx.tcx.infer_ctxt().build().err_ctxt().type_implements_fn_trait( + match cx.tcx.infer_ctxt().build(cx.typing_mode()).err_ctxt().type_implements_fn_trait( cx.param_env, Binder::bind_with_vars(callee_ty_adjusted, List::empty()), ty::PredicatePolarity::Positive, diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index cfd11e9339fb..c74ba088b78e 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -117,7 +117,7 @@ fn check_needless_must_use( } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { // Ignore async functions unless Future::Output type is a must_use type if sig.header.is_async() { - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); if let Some(future_ty) = infcx.err_ctxt().get_impl_future_output_ty(return_ty(cx, item_id)) && !is_must_use_ty(cx, future_ty) { diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index a4dbe134f365..cf08c16458bd 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { if is_future { let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let cause = traits::ObligationCause::misc(span, fn_def_id); ocx.register_bound(cause, cx.param_env, ret_ty, send_trait); diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index cfa1fdb81372..82549413fa91 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -568,7 +568,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); !cx.tcx .infer_ctxt() - .build() + .build(cx.typing_mode()) .predicate_must_hold_modulo_regions(&obligation) }) { return false; diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index f6db12ed84e8..f7fa31d83aa4 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -278,7 +278,7 @@ fn needless_borrow_count<'tcx>( let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, &args_with_referent_ty[..]); let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate); - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); infcx.predicate_must_hold_modulo_regions(&obligation) }) }; diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 392cfcb813e8..2e5195d459f4 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -160,7 +160,7 @@ impl NoEffect { // Remove `impl Future` to get `T` if cx.tcx.ty_is_opaque_future(ret_ty) && let Some(true_ret_ty) = - cx.tcx.infer_ctxt().build().err_ctxt().get_impl_future_output_ty(ret_ty) + cx.tcx.infer_ctxt().build(cx.typing_mode()).err_ctxt().get_impl_future_output_ty(ret_ty) { ret_ty = true_ret_ty; } diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index f5fcf521b96c..a548c6ef3b1f 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -695,7 +695,7 @@ fn matches_preds<'tcx>( ty: Ty<'tcx>, preds: &'tcx [ty::PolyExistentialPredicate<'tcx>], ) -> bool { - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); preds .iter() .all(|&p| match cx.tcx.instantiate_bound_regions_with_erased(p) { diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index ec3a693d2efe..3b05abc546f4 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -114,7 +114,7 @@ fn into_iter_bound<'tcx>( if !cx .tcx .infer_ctxt() - .build() + .build(cx.typing_mode()) .predicate_must_hold_modulo_regions(&obligation) { return None; diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 46739862de6b..dbadc8432f63 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -17,7 +17,7 @@ use rustc_middle::mir::{ }; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt, TypingMode}; use rustc_span::Span; use rustc_span::symbol::sym; use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext}; @@ -420,7 +420,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx> TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]), ); - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(obligation.param_env)); let mut selcx = SelectionContext::new(&infcx); let Some(impl_src) = selcx.select(&obligation).ok().flatten() else { return false; diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 07c3d0eada00..c618bfe4488c 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -19,7 +19,7 @@ use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, + TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, TypingMode, }; use rustc_span::symbol::Ident; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; @@ -268,7 +268,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>( return false; } - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let args = args .into_iter() .map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into())) @@ -362,7 +362,7 @@ fn is_normalizable_helper<'tcx>( } // prevent recursive loops, false-negative is better than endless loop leading to stack overflow cache.insert(ty, false); - let infcx = cx.tcx.infer_ctxt().build(); + let infcx = cx.tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)); let cause = ObligationCause::dummy(); let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() { match ty.kind() { @@ -1268,7 +1268,7 @@ pub fn make_normalized_projection_with_regions<'tcx>( let cause = ObligationCause::dummy(); match tcx .infer_ctxt() - .build() + .build(TypingMode::from_param_env(param_env)) .at(&cause, param_env) .query_normalize(Ty::new_projection_from_args(tcx, ty.def_id, ty.args)) { @@ -1284,7 +1284,7 @@ pub fn make_normalized_projection_with_regions<'tcx>( pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { let cause = ObligationCause::dummy(); - match tcx.infer_ctxt().build().at(&cause, param_env).query_normalize(ty) { + match tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)).at(&cause, param_env).query_normalize(ty) { Ok(ty) => ty.value, Err(_) => ty, } From 524a22e79057f2db0053bd002262fa88ea1a9947 Mon Sep 17 00:00:00 2001 From: lcnr Date: Tue, 29 Oct 2024 17:07:32 +0100 Subject: [PATCH 12/56] rebase --- compiler/rustc_trait_selection/src/traits/effects.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index bd8c04b76557..60b3357810a6 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -1,8 +1,9 @@ use rustc_hir as hir; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt}; use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation}; +use rustc_middle::span_bug; use rustc_middle::ty::fast_reject::DeepRejectCtxt; -use rustc_middle::{span_bug, ty}; +use rustc_middle::ty::{self, TypingMode}; use rustc_type_ir::solve::NoSolution; use thin_vec::ThinVec; @@ -19,7 +20,7 @@ pub fn evaluate_host_effect_obligation<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &HostEffectObligation<'tcx>, ) -> Result>, EvaluationFailure> { - if selcx.infcx.intercrate { + if matches!(selcx.infcx.typing_mode(obligation.param_env), TypingMode::Coherence) { span_bug!( obligation.cause.span, "should not select host obligation in old solver in intercrate mode" From 0783af89cdda89bf722ce157462821293d5c9a54 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Tue, 29 Oct 2024 18:29:39 +0000 Subject: [PATCH 13/56] Point to Fuchsia team in platform support docs --- src/doc/rustc/src/platform-support/fuchsia.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 0622f4dd564d..489f46e1cb98 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -7,17 +7,9 @@ updatable, and performant. ## Target maintainers -The [Fuchsia team]: +See [`fuchsia.toml`] in the `team` repository for current target maintainers. -- Tyler Mandry ([@tmandry](https://github.com/tmandry)) -- David Koloski ([@djkoloski](https://github.com/djkoloski)) -- Julia Ryan ([@P1n3appl3](https://github.com/P1n3appl3)) -- Erick Tryzelaar ([@erickt](https://github.com/erickt)) - -As the team evolves over time, the specific members listed here may differ from -the members reported by the API. The API should be considered to be -authoritative if this occurs. Instead of pinging individual members, use -`@rustbot ping fuchsia` to contact the team on GitHub. +[`fuchsia.toml`]: https://github.com/rust-lang/team/blob/master/teams/fuchsia.toml ## Table of contents From 4a2e08af22ee97e97b21a1cd75d80a1a2f746a3e Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 21 Aug 2024 23:29:51 -0400 Subject: [PATCH 14/56] Don't lint `irrefutable_let_patterns` on leading patterns if `else if` let-chains. --- .../src/thir/pattern/check_match.rs | 25 +++++++++++++------ .../irrefutable-lets.disallowed.stderr | 20 ++++++++++++++- .../irrefutable-lets.rs | 20 +++++++++++++++ 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index bc1acd51c691..a8ca19b78878 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -79,6 +79,8 @@ enum LetSource { IfLetGuard, LetElse, WhileLet, + Else, + ElseIfLet, } struct MatchVisitor<'p, 'tcx> { @@ -129,15 +131,20 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> { // Give a specific `let_source` for the condition. let let_source = match ex.span.desugaring_kind() { Some(DesugaringKind::WhileLoop) => LetSource::WhileLet, - _ => LetSource::IfLet, + _ => match self.let_source { + LetSource::Else => LetSource::ElseIfLet, + _ => LetSource::IfLet, + }, }; self.with_let_source(let_source, |this| this.visit_expr(&self.thir[cond])); self.with_let_source(LetSource::None, |this| { this.visit_expr(&this.thir[then]); - if let Some(else_) = else_opt { - this.visit_expr(&this.thir[else_]); - } }); + if let Some(else_) = else_opt { + self.with_let_source(LetSource::Else, |this| { + this.visit_expr(&this.thir[else_]) + }); + } return; } ExprKind::Match { scrutinee, scrutinee_hir_id: _, box ref arms, match_source } => { @@ -569,9 +576,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { // and we shouldn't lint. // For let guards inside a match, prefixes might use bindings of the match pattern, // so can't always be moved out. + // For `else if let`, an extra indentation level would be required to move the bindings. // FIXME: Add checking whether the bindings are actually used in the prefix, // and lint if they are not. - if !matches!(self.let_source, LetSource::WhileLet | LetSource::IfLetGuard) { + if !matches!( + self.let_source, + LetSource::WhileLet | LetSource::IfLetGuard | LetSource::ElseIfLet + ) { // Emit the lint let prefix = &chain_refutabilities[..until]; let span_start = prefix[0].unwrap().0; @@ -902,8 +913,8 @@ fn report_irrefutable_let_patterns( } match source { - LetSource::None | LetSource::PlainLet => bug!(), - LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet), + LetSource::None | LetSource::PlainLet | LetSource::Else => bug!(), + LetSource::IfLet | LetSource::ElseIfLet => emit_diag!(IrrefutableLetPatternsIfLet), LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard), LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse), LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet), diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr index be4a52315582..130d0296c5ec 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr @@ -111,5 +111,23 @@ LL | while let Some(ref first) = opt && let second = first && let _third = s = note: these patterns will always match = help: consider moving them into the body -error: aborting due to 12 previous errors +error: trailing irrefutable pattern in let chain + --> $DIR/irrefutable-lets.rs:87:12 + | +LL | && let x = &opt + | ^^^^^^^^^^^^ + | + = note: this pattern will always match + = help: consider moving it into the body + +error: leading irrefutable pattern in let chain + --> $DIR/irrefutable-lets.rs:93:12 + | +LL | if let x = opt.clone().map(|_| 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this pattern will always match + = help: consider moving it outside of the construct + +error: aborting due to 14 previous errors diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs index bd4df337614a..e7d69f89773e 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs @@ -75,4 +75,24 @@ fn main() { && let Range { start: local_start, end: _ } = first && let None = local_start { } + + // No error. An extra nesting level would be required for the `else if`. + if opt == Some(None..None) { + } else if let x = opt.clone().map(|_| 1) + && x == Some(1) + {} + + if opt == Some(None..None) { + } else if opt.is_some() + && let x = &opt + //[disallowed]~^ ERROR trailing irrefutable pattern in let chain + {} + + if opt == Some(None..None) { + } else { + if let x = opt.clone().map(|_| 1) + //[disallowed]~^ ERROR leading irrefutable pattern in let chain + && x == Some(1) + {} + } } From 7086dd83cca1cf694c7bd171efbf262fa8ffb4aa Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 29 Oct 2024 13:37:26 -0700 Subject: [PATCH 15/56] compiler: `rustc_abi::Abi` => `BackendRepr` The initial naming of "Abi" was an awful mistake, conveying wrong ideas about how psABIs worked and even more about what the enum meant. It was only meant to represent the way the value would be described to a codegen backend as it was lowered to that intermediate representation. It was never meant to mean anything about the actual psABI handling! The conflation is because LLVM typically will associate a certain form with a certain ABI, but even that does not hold when the special cases that actually exist arise, plus the IR annotations that modify the ABI. Reframe `rustc_abi::Abi` as the `BackendRepr` of the type, and rename `BackendRepr::Aggregate` as `BackendRepr::Memory`. Unfortunately, due to the persistent misunderstandings, this too is now incorrect: - Scattered ABI-relevant code is entangled with BackendRepr - We do not always pre-compute a correct BackendRepr that reflects how we "actually" want this value to be handled, so we leave the backend interface to also inject various special-cases here - In some cases `BackendRepr::Memory` is a "real" aggregate, but in others it is in fact using memory, and in some cases it is a scalar! Our rustc-to-backend lowering code handles this sort of thing right now. That will eventually be addressed by lifting duplicated lowering code to either rustc_codegen_ssa or rustc_target as appropriate. --- compiler/rustc_abi/src/callconv.rs | 16 +-- compiler/rustc_abi/src/layout.rs | 104 ++++++++-------- compiler/rustc_abi/src/layout/ty.rs | 12 +- compiler/rustc_abi/src/lib.rs | 112 +++++++++++------- compiler/rustc_codegen_llvm/src/abi.rs | 10 +- compiler/rustc_codegen_llvm/src/asm.rs | 93 ++++++++------- compiler/rustc_codegen_llvm/src/builder.rs | 4 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 13 +- compiler/rustc_codegen_llvm/src/type_of.rs | 37 +++--- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- .../rustc_codegen_ssa/src/mir/constant.rs | 4 +- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 4 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 39 +++--- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 10 +- .../rustc_codegen_ssa/src/traits/builder.rs | 4 +- .../src/const_eval/dummy_machine.rs | 2 +- .../src/const_eval/eval_queries.rs | 6 +- .../src/const_eval/valtrees.rs | 6 +- .../rustc_const_eval/src/interpret/call.rs | 4 +- .../rustc_const_eval/src/interpret/cast.rs | 2 +- .../src/interpret/discriminant.rs | 2 +- .../src/interpret/intrinsics.rs | 2 +- .../rustc_const_eval/src/interpret/operand.rs | 53 +++++---- .../src/interpret/operator.rs | 12 +- .../rustc_const_eval/src/interpret/place.rs | 12 +- .../src/interpret/validity.rs | 23 ++-- .../src/util/check_validity_requirement.rs | 14 +-- compiler/rustc_lint/src/builtin.rs | 6 +- compiler/rustc_lint/src/foreign_modules.rs | 2 +- compiler/rustc_lint/src/types.rs | 6 +- compiler/rustc_middle/src/ty/layout.rs | 7 +- .../src/build/expr/as_rvalue.rs | 4 +- .../rustc_mir_dataflow/src/value_analysis.rs | 2 +- .../src/dataflow_const_prop.rs | 12 +- compiler/rustc_mir_transform/src/gvn.rs | 19 +-- .../src/known_panics_lint.rs | 10 +- compiler/rustc_passes/src/layout_test.rs | 6 +- .../rustc_smir/src/rustc_smir/convert/abi.rs | 14 +-- .../rustc_target/src/callconv/loongarch.rs | 18 +-- compiler/rustc_target/src/callconv/mips64.rs | 8 +- compiler/rustc_target/src/callconv/mod.rs | 29 +++-- compiler/rustc_target/src/callconv/riscv.rs | 18 +-- compiler/rustc_target/src/callconv/sparc64.rs | 8 +- compiler/rustc_target/src/callconv/x86.rs | 18 +-- compiler/rustc_target/src/callconv/x86_64.rs | 14 ++- .../rustc_target/src/callconv/x86_win64.rs | 27 +++-- compiler/rustc_target/src/callconv/xtensa.rs | 6 +- .../src/traits/dyn_compatibility.rs | 10 +- compiler/rustc_ty_utils/src/abi.rs | 14 +-- compiler/rustc_ty_utils/src/layout.rs | 43 ++++--- .../rustc_ty_utils/src/layout/invariant.rs | 42 +++---- 51 files changed, 517 insertions(+), 428 deletions(-) diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index 872cae59a4e0..ee63e46e88c1 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -6,9 +6,9 @@ mod abi { #[cfg(feature = "nightly")] use rustc_macros::HashStable_Generic; -#[cfg(feature = "nightly")] -use crate::{Abi, FieldsShape, TyAbiInterface, TyAndLayout}; use crate::{Align, HasDataLayout, Size}; +#[cfg(feature = "nightly")] +use crate::{BackendRepr, FieldsShape, TyAbiInterface, TyAndLayout}; #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -128,11 +128,11 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { where Ty: TyAbiInterface<'a, C> + Copy, { - match self.abi { - Abi::Uninhabited => Err(Heterogeneous), + match self.backend_repr { + BackendRepr::Uninhabited => Err(Heterogeneous), // The primitive for this algorithm. - Abi::Scalar(scalar) => { + BackendRepr::Scalar(scalar) => { let kind = match scalar.primitive() { abi::Int(..) | abi::Pointer(_) => RegKind::Integer, abi::Float(_) => RegKind::Float, @@ -140,7 +140,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) } - Abi::Vector { .. } => { + BackendRepr::Vector { .. } => { assert!(!self.is_zst()); Ok(HomogeneousAggregate::Homogeneous(Reg { kind: RegKind::Vector, @@ -148,7 +148,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { })) } - Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => { + BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => { // Helper for computing `homogeneous_aggregate`, allowing a custom // starting offset (used below for handling variants). let from_fields_at = @@ -246,7 +246,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ok(result) } } - Abi::Aggregate { sized: false } => Err(Heterogeneous), + BackendRepr::Memory { sized: false } => Err(Heterogeneous), } } } diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 86de39b8f975..e6d66f608dae 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -6,7 +6,7 @@ use rustc_index::Idx; use tracing::debug; use crate::{ - Abi, AbiAndPrefAlign, Align, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, + AbiAndPrefAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer, LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, }; @@ -125,7 +125,7 @@ impl LayoutCalculator { offsets: [Size::ZERO, b_offset].into(), memory_index: [0, 1].into(), }, - abi: Abi::ScalarPair(a, b), + backend_repr: BackendRepr::ScalarPair(a, b), largest_niche, align, size, @@ -216,7 +216,7 @@ impl LayoutCalculator { LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, - abi: Abi::Uninhabited, + backend_repr: BackendRepr::Uninhabited, largest_niche: None, align: dl.i8_align, size: Size::ZERO, @@ -331,7 +331,7 @@ impl LayoutCalculator { if let Ok(common) = common_non_zst_abi_and_align { // Discard valid range information and allow undef - let field_abi = field.abi.to_union(); + let field_abi = field.backend_repr.to_union(); if let Some((common_abi, common_align)) = common { if common_abi != field_abi { @@ -340,7 +340,7 @@ impl LayoutCalculator { } else { // Fields with the same non-Aggregate ABI should also // have the same alignment - if !matches!(common_abi, Abi::Aggregate { .. }) { + if !matches!(common_abi, BackendRepr::Memory { .. }) { assert_eq!( common_align, field.align.abi, "non-Aggregate field with matching ABI but differing alignment" @@ -369,11 +369,11 @@ impl LayoutCalculator { // If all non-ZST fields have the same ABI, we may forward that ABI // for the union as a whole, unless otherwise inhibited. let abi = match common_non_zst_abi_and_align { - Err(AbiMismatch) | Ok(None) => Abi::Aggregate { sized: true }, + Err(AbiMismatch) | Ok(None) => BackendRepr::Memory { sized: true }, Ok(Some((abi, _))) => { if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) { // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt - Abi::Aggregate { sized: true } + BackendRepr::Memory { sized: true } } else { abi } @@ -387,7 +387,7 @@ impl LayoutCalculator { Ok(LayoutData { variants: Variants::Single { index: only_variant_idx }, fields: FieldsShape::Union(union_field_count), - abi, + backend_repr: abi, largest_niche: None, align, size: size.align_to(align.abi), @@ -434,23 +434,23 @@ impl LayoutCalculator { // Already doesn't have any niches Scalar::Union { .. } => {} }; - match &mut st.abi { - Abi::Uninhabited => {} - Abi::Scalar(scalar) => hide_niches(scalar), - Abi::ScalarPair(a, b) => { + match &mut st.backend_repr { + BackendRepr::Uninhabited => {} + BackendRepr::Scalar(scalar) => hide_niches(scalar), + BackendRepr::ScalarPair(a, b) => { hide_niches(a); hide_niches(b); } - Abi::Vector { element, count: _ } => hide_niches(element), - Abi::Aggregate { sized: _ } => {} + BackendRepr::Vector { element, count: _ } => hide_niches(element), + BackendRepr::Memory { sized: _ } => {} } st.largest_niche = None; return Ok(st); } let (start, end) = scalar_valid_range; - match st.abi { - Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { + match st.backend_repr { + BackendRepr::Scalar(ref mut scalar) | BackendRepr::ScalarPair(ref mut scalar, _) => { // Enlarging validity ranges would result in missed // optimizations, *not* wrongly assuming the inner // value is valid. e.g. unions already enlarge validity ranges, @@ -607,8 +607,8 @@ impl LayoutCalculator { } // It can't be a Scalar or ScalarPair because the offset isn't 0. - if !layout.abi.is_uninhabited() { - layout.abi = Abi::Aggregate { sized: true }; + if !layout.is_uninhabited() { + layout.backend_repr = BackendRepr::Memory { sized: true }; } layout.size += this_offset; @@ -627,26 +627,26 @@ impl LayoutCalculator { let same_size = size == variant_layouts[largest_variant_index].size; let same_align = align == variant_layouts[largest_variant_index].align; - let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) { - Abi::Uninhabited + let abi = if variant_layouts.iter().all(|v| v.is_uninhabited()) { + BackendRepr::Uninhabited } else if same_size && same_align && others_zst { - match variant_layouts[largest_variant_index].abi { + match variant_layouts[largest_variant_index].backend_repr { // When the total alignment and size match, we can use the // same ABI as the scalar variant with the reserved niche. - Abi::Scalar(_) => Abi::Scalar(niche_scalar), - Abi::ScalarPair(first, second) => { + BackendRepr::Scalar(_) => BackendRepr::Scalar(niche_scalar), + BackendRepr::ScalarPair(first, second) => { // Only the niche is guaranteed to be initialised, // so use union layouts for the other primitive. if niche_offset == Size::ZERO { - Abi::ScalarPair(niche_scalar, second.to_union()) + BackendRepr::ScalarPair(niche_scalar, second.to_union()) } else { - Abi::ScalarPair(first.to_union(), niche_scalar) + BackendRepr::ScalarPair(first.to_union(), niche_scalar) } } - _ => Abi::Aggregate { sized: true }, + _ => BackendRepr::Memory { sized: true }, } } else { - Abi::Aggregate { sized: true } + BackendRepr::Memory { sized: true } }; let layout = LayoutData { @@ -664,7 +664,7 @@ impl LayoutCalculator { offsets: [niche_offset].into(), memory_index: [0].into(), }, - abi, + backend_repr: abi, largest_niche, size, align, @@ -833,14 +833,14 @@ impl LayoutCalculator { end: (max as u128 & tag_mask), }, }; - let mut abi = Abi::Aggregate { sized: true }; + let mut abi = BackendRepr::Memory { sized: true }; - if layout_variants.iter().all(|v| v.abi.is_uninhabited()) { - abi = Abi::Uninhabited; + if layout_variants.iter().all(|v| v.is_uninhabited()) { + abi = BackendRepr::Uninhabited; } else if tag.size(dl) == size { // Make sure we only use scalar layout when the enum is entirely its // own tag (i.e. it has no padding nor any non-ZST variant fields). - abi = Abi::Scalar(tag); + abi = BackendRepr::Scalar(tag); } else { // Try to use a ScalarPair for all tagged enums. // That's possible only if we can find a common primitive type for all variants. @@ -864,8 +864,8 @@ impl LayoutCalculator { break; } }; - let prim = match field.abi { - Abi::Scalar(scalar) => { + let prim = match field.backend_repr { + BackendRepr::Scalar(scalar) => { common_prim_initialized_in_all_variants &= matches!(scalar, Scalar::Initialized { .. }); scalar.primitive() @@ -934,7 +934,7 @@ impl LayoutCalculator { { // We can use `ScalarPair` only when it matches our // already computed layout (including `#[repr(C)]`). - abi = pair.abi; + abi = pair.backend_repr; } } } @@ -942,12 +942,14 @@ impl LayoutCalculator { // If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the // variants to ensure they are consistent. This is because a downcast is // semantically a NOP, and thus should not affect layout. - if matches!(abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + if matches!(abi, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) { for variant in &mut layout_variants { // We only do this for variants with fields; the others are not accessed anyway. // Also do not overwrite any already existing "clever" ABIs. - if variant.fields.count() > 0 && matches!(variant.abi, Abi::Aggregate { .. }) { - variant.abi = abi; + if variant.fields.count() > 0 + && matches!(variant.backend_repr, BackendRepr::Memory { .. }) + { + variant.backend_repr = abi; // Also need to bump up the size and alignment, so that the entire value fits // in here. variant.size = cmp::max(variant.size, size); @@ -970,7 +972,7 @@ impl LayoutCalculator { memory_index: [0].into(), }, largest_niche, - abi, + backend_repr: abi, align, size, max_repr_align, @@ -1252,7 +1254,7 @@ impl LayoutCalculator { } let mut layout_of_single_non_zst_field = None; let sized = unsized_field.is_none(); - let mut abi = Abi::Aggregate { sized }; + let mut abi = BackendRepr::Memory { sized }; let optimize_abi = !repr.inhibit_newtype_abi_optimization(); @@ -1270,16 +1272,16 @@ impl LayoutCalculator { // Field fills the struct and it has a scalar or scalar pair ABI. if offsets[i].bytes() == 0 && align.abi == field.align.abi && size == field.size { - match field.abi { + match field.backend_repr { // For plain scalars, or vectors of them, we can't unpack // newtypes for `#[repr(C)]`, as that affects C ABIs. - Abi::Scalar(_) | Abi::Vector { .. } if optimize_abi => { - abi = field.abi; + BackendRepr::Scalar(_) | BackendRepr::Vector { .. } if optimize_abi => { + abi = field.backend_repr; } // But scalar pairs are Rust-specific and get // treated as aggregates by C ABIs anyway. - Abi::ScalarPair(..) => { - abi = field.abi; + BackendRepr::ScalarPair(..) => { + abi = field.backend_repr; } _ => {} } @@ -1288,8 +1290,8 @@ impl LayoutCalculator { // Two non-ZST fields, and they're both scalars. (Some((i, a)), Some((j, b)), None) => { - match (a.abi, b.abi) { - (Abi::Scalar(a), Abi::Scalar(b)) => { + match (a.backend_repr, b.backend_repr) { + (BackendRepr::Scalar(a), BackendRepr::Scalar(b)) => { // Order by the memory placement, not source order. let ((i, a), (j, b)) = if offsets[i] < offsets[j] { ((i, a), (j, b)) @@ -1315,7 +1317,7 @@ impl LayoutCalculator { { // We can use `ScalarPair` only when it matches our // already computed layout (including `#[repr(C)]`). - abi = pair.abi; + abi = pair.backend_repr; } } _ => {} @@ -1325,8 +1327,8 @@ impl LayoutCalculator { _ => {} } } - if fields.iter().any(|f| f.abi.is_uninhabited()) { - abi = Abi::Uninhabited; + if fields.iter().any(|f| f.is_uninhabited()) { + abi = BackendRepr::Uninhabited; } let unadjusted_abi_align = if repr.transparent() { @@ -1344,7 +1346,7 @@ impl LayoutCalculator { Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets, memory_index }, - abi, + backend_repr: abi, largest_niche, align, size, diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index e029e1426b21..062447ea03f0 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -83,8 +83,8 @@ impl<'a> Layout<'a> { &self.0.0.variants } - pub fn abi(self) -> Abi { - self.0.0.abi + pub fn backend_repr(self) -> BackendRepr { + self.0.0.backend_repr } pub fn largest_niche(self) -> Option { @@ -114,7 +114,7 @@ impl<'a> Layout<'a> { pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool { self.size() == data_layout.pointer_size && self.align().abi == data_layout.pointer_align.abi - && matches!(self.abi(), Abi::Scalar(Scalar::Initialized { .. })) + && matches!(self.backend_repr(), BackendRepr::Scalar(Scalar::Initialized { .. })) } } @@ -196,9 +196,9 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty: TyAbiInterface<'a, C>, C: HasDataLayout, { - match self.abi { - Abi::Scalar(scalar) => matches!(scalar.primitive(), Float(F32 | F64)), - Abi::Aggregate { .. } => { + match self.backend_repr { + BackendRepr::Scalar(scalar) => matches!(scalar.primitive(), Float(F32 | F64)), + BackendRepr::Memory { .. } => { if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { self.field(cx, 0).is_single_fp_element(cx) } else { diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 41922aee6487..fac1122c4dfc 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1344,11 +1344,19 @@ impl AddressSpace { pub const DATA: Self = AddressSpace(0); } -/// Describes how values of the type are passed by target ABIs, -/// in terms of categories of C types there are ABI rules for. +/// The way we represent values to the backend +/// +/// Previously this was conflated with the "ABI" a type is given, as in the platform-specific ABI. +/// In reality, this implies little about that, but is mostly used to describe the syntactic form +/// emitted for the backend, as most backends handle SSA values and blobs of memory differently. +/// The psABI may need consideration in doing so, but this enum does not constitute a promise for +/// how the value will be lowered to the calling convention, in itself. +/// +/// Generally, a codegen backend will prefer to handle smaller values as a scalar or short vector, +/// and larger values will usually prefer to be represented as memory. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] -pub enum Abi { +pub enum BackendRepr { Uninhabited, Scalar(Scalar), ScalarPair(Scalar, Scalar), @@ -1356,19 +1364,23 @@ pub enum Abi { element: Scalar, count: u64, }, - Aggregate { + // FIXME: I sometimes use memory, sometimes use an IR aggregate! + Memory { /// If true, the size is exact, otherwise it's only a lower bound. sized: bool, }, } -impl Abi { +impl BackendRepr { /// Returns `true` if the layout corresponds to an unsized type. #[inline] pub fn is_unsized(&self) -> bool { match *self { - Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, - Abi::Aggregate { sized } => !sized, + BackendRepr::Uninhabited + | BackendRepr::Scalar(_) + | BackendRepr::ScalarPair(..) + | BackendRepr::Vector { .. } => false, + BackendRepr::Memory { sized } => !sized, } } @@ -1381,7 +1393,7 @@ impl Abi { #[inline] pub fn is_signed(&self) -> bool { match self { - Abi::Scalar(scal) => match scal.primitive() { + BackendRepr::Scalar(scal) => match scal.primitive() { Primitive::Int(_, signed) => signed, _ => false, }, @@ -1392,61 +1404,67 @@ impl Abi { /// Returns `true` if this is an uninhabited type #[inline] pub fn is_uninhabited(&self) -> bool { - matches!(*self, Abi::Uninhabited) + matches!(*self, BackendRepr::Uninhabited) } /// Returns `true` if this is a scalar type #[inline] pub fn is_scalar(&self) -> bool { - matches!(*self, Abi::Scalar(_)) + matches!(*self, BackendRepr::Scalar(_)) } /// Returns `true` if this is a bool #[inline] pub fn is_bool(&self) -> bool { - matches!(*self, Abi::Scalar(s) if s.is_bool()) + matches!(*self, BackendRepr::Scalar(s) if s.is_bool()) } /// Returns the fixed alignment of this ABI, if any is mandated. pub fn inherent_align(&self, cx: &C) -> Option { Some(match *self { - Abi::Scalar(s) => s.align(cx), - Abi::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)), - Abi::Vector { element, count } => { + BackendRepr::Scalar(s) => s.align(cx), + BackendRepr::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)), + BackendRepr::Vector { element, count } => { cx.data_layout().vector_align(element.size(cx) * count) } - Abi::Uninhabited | Abi::Aggregate { .. } => return None, + BackendRepr::Uninhabited | BackendRepr::Memory { .. } => return None, }) } /// Returns the fixed size of this ABI, if any is mandated. pub fn inherent_size(&self, cx: &C) -> Option { Some(match *self { - Abi::Scalar(s) => { + BackendRepr::Scalar(s) => { // No padding in scalars. s.size(cx) } - Abi::ScalarPair(s1, s2) => { + BackendRepr::ScalarPair(s1, s2) => { // May have some padding between the pair. let field2_offset = s1.size(cx).align_to(s2.align(cx).abi); (field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi) } - Abi::Vector { element, count } => { + BackendRepr::Vector { element, count } => { // No padding in vectors, except possibly for trailing padding // to make the size a multiple of align (e.g. for vectors of size 3). (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi) } - Abi::Uninhabited | Abi::Aggregate { .. } => return None, + BackendRepr::Uninhabited | BackendRepr::Memory { .. } => return None, }) } /// Discard validity range information and allow undef. pub fn to_union(&self) -> Self { match *self { - Abi::Scalar(s) => Abi::Scalar(s.to_union()), - Abi::ScalarPair(s1, s2) => Abi::ScalarPair(s1.to_union(), s2.to_union()), - Abi::Vector { element, count } => Abi::Vector { element: element.to_union(), count }, - Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true }, + BackendRepr::Scalar(s) => BackendRepr::Scalar(s.to_union()), + BackendRepr::ScalarPair(s1, s2) => { + BackendRepr::ScalarPair(s1.to_union(), s2.to_union()) + } + BackendRepr::Vector { element, count } => { + BackendRepr::Vector { element: element.to_union(), count } + } + BackendRepr::Uninhabited | BackendRepr::Memory { .. } => { + BackendRepr::Memory { sized: true } + } } } @@ -1454,12 +1472,12 @@ impl Abi { match (self, other) { // Scalar, Vector, ScalarPair have `Scalar` in them where we ignore validity ranges. // We do *not* ignore the sign since it matters for some ABIs (e.g. s390x). - (Abi::Scalar(l), Abi::Scalar(r)) => l.primitive() == r.primitive(), + (BackendRepr::Scalar(l), BackendRepr::Scalar(r)) => l.primitive() == r.primitive(), ( - Abi::Vector { element: element_l, count: count_l }, - Abi::Vector { element: element_r, count: count_r }, + BackendRepr::Vector { element: element_l, count: count_l }, + BackendRepr::Vector { element: element_r, count: count_r }, ) => element_l.primitive() == element_r.primitive() && count_l == count_r, - (Abi::ScalarPair(l1, l2), Abi::ScalarPair(r1, r2)) => { + (BackendRepr::ScalarPair(l1, l2), BackendRepr::ScalarPair(r1, r2)) => { l1.primitive() == r1.primitive() && l2.primitive() == r2.primitive() } // Everything else must be strictly identical. @@ -1616,14 +1634,14 @@ pub struct LayoutData { /// must be taken into account. pub variants: Variants, - /// The `abi` defines how this data is passed between functions, and it defines - /// value restrictions via `valid_range`. + /// The `backend_repr` defines how this data will be represented to the codegen backend, + /// and encodes value restrictions via `valid_range`. /// /// Note that this is entirely orthogonal to the recursive structure defined by /// `variants` and `fields`; for example, `ManuallyDrop>` has - /// `Abi::ScalarPair`! So, even with non-`Aggregate` `abi`, `fields` and `variants` + /// `IrForm::ScalarPair`! So, even with non-`Memory` `backend_repr`, `fields` and `variants` /// have to be taken into account to find all fields of this layout. - pub abi: Abi, + pub backend_repr: BackendRepr, /// The leaf scalar with the largest number of invalid values /// (i.e. outside of its `valid_range`), if it exists. @@ -1646,15 +1664,15 @@ pub struct LayoutData { impl LayoutData { /// Returns `true` if this is an aggregate type (including a ScalarPair!) pub fn is_aggregate(&self) -> bool { - match self.abi { - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false, - Abi::ScalarPair(..) | Abi::Aggregate { .. } => true, + match self.backend_repr { + BackendRepr::Uninhabited | BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => false, + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true, } } /// Returns `true` if this is an uninhabited type pub fn is_uninhabited(&self) -> bool { - self.abi.is_uninhabited() + self.backend_repr.is_uninhabited() } pub fn scalar(cx: &C, scalar: Scalar) -> Self { @@ -1664,7 +1682,7 @@ impl LayoutData { LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, - abi: Abi::Scalar(scalar), + backend_repr: BackendRepr::Scalar(scalar), largest_niche, size, align, @@ -1686,7 +1704,7 @@ where let LayoutData { size, align, - abi, + backend_repr, fields, largest_niche, variants, @@ -1696,7 +1714,7 @@ where f.debug_struct("Layout") .field("size", size) .field("align", align) - .field("abi", abi) + .field("abi", backend_repr) .field("fields", fields) .field("largest_niche", largest_niche) .field("variants", variants) @@ -1732,12 +1750,12 @@ impl LayoutData { /// Returns `true` if the layout corresponds to an unsized type. #[inline] pub fn is_unsized(&self) -> bool { - self.abi.is_unsized() + self.backend_repr.is_unsized() } #[inline] pub fn is_sized(&self) -> bool { - self.abi.is_sized() + self.backend_repr.is_sized() } /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1). @@ -1750,10 +1768,12 @@ impl LayoutData { /// Note that this does *not* imply that the type is irrelevant for layout! It can still have /// non-trivial alignment constraints. You probably want to use `is_1zst` instead. pub fn is_zst(&self) -> bool { - match self.abi { - Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, - Abi::Uninhabited => self.size.bytes() == 0, - Abi::Aggregate { sized } => sized && self.size.bytes() == 0, + match self.backend_repr { + BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) | BackendRepr::Vector { .. } => { + false + } + BackendRepr::Uninhabited => self.size.bytes() == 0, + BackendRepr::Memory { sized } => sized && self.size.bytes() == 0, } } @@ -1768,8 +1788,8 @@ impl LayoutData { // 2nd point is quite hard to check though. self.size == other.size && self.is_sized() == other.is_sized() - && self.abi.eq_up_to_validity(&other.abi) - && self.abi.is_bool() == other.abi.is_bool() + && self.backend_repr.eq_up_to_validity(&other.backend_repr) + && self.backend_repr.is_bool() == other.backend_repr.is_bool() && self.align.abi == other.align.abi && self.max_repr_align == other.max_repr_align && self.unadjusted_abi_align == other.unadjusted_abi_align diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 8a1ee48c43ca..855ca0106119 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -458,7 +458,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { match &self.ret.mode { PassMode::Direct(attrs) => { attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); - if let abi::Abi::Scalar(scalar) = self.ret.layout.abi { + if let abi::BackendRepr::Scalar(scalar) = self.ret.layout.backend_repr { apply_range_attr(llvm::AttributePlace::ReturnValue, scalar); } } @@ -495,7 +495,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } PassMode::Direct(attrs) => { let i = apply(attrs); - if let abi::Abi::Scalar(scalar) = arg.layout.abi { + if let abi::BackendRepr::Scalar(scalar) = arg.layout.backend_repr { apply_range_attr(llvm::AttributePlace::Argument(i), scalar); } } @@ -510,7 +510,9 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Pair(a, b) => { let i = apply(a); let ii = apply(b); - if let abi::Abi::ScalarPair(scalar_a, scalar_b) = arg.layout.abi { + if let abi::BackendRepr::ScalarPair(scalar_a, scalar_b) = + arg.layout.backend_repr + { apply_range_attr(llvm::AttributePlace::Argument(i), scalar_a); apply_range_attr(llvm::AttributePlace::Argument(ii), scalar_b); } @@ -570,7 +572,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } if bx.cx.sess().opts.optimize != config::OptLevel::No && llvm_util::get_version() < (19, 0, 0) - && let abi::Abi::Scalar(scalar) = self.ret.layout.abi + && let abi::BackendRepr::Scalar(scalar) = self.ret.layout.backend_repr && matches!(scalar.primitive(), Int(..)) // If the value is a boolean, the range is 0..2 and that ultimately // become 0..0 when the type becomes i1, which would be rejected diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 3c30822a2e2f..53758967552d 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -880,8 +880,8 @@ fn llvm_fixup_input<'ll, 'tcx>( ) -> &'ll Value { use InlineAsmRegClass::*; let dl = &bx.tcx.data_layout; - match (reg, layout.abi) { - (AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { + match (reg, layout.backend_repr) { + (AArch64(AArch64InlineAsmRegClass::vreg), BackendRepr::Scalar(s)) => { if let Primitive::Int(Integer::I8, _) = s.primitive() { let vec_ty = bx.cx.type_vector(bx.cx.type_i8(), 8); bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0)) @@ -889,7 +889,7 @@ fn llvm_fixup_input<'ll, 'tcx>( value } } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Scalar(s)) if s.primitive() != Primitive::Float(Float::F128) => { let elem_ty = llvm_asm_scalar_type(bx.cx, s); @@ -902,7 +902,7 @@ fn llvm_fixup_input<'ll, 'tcx>( } bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0)) } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Vector { element, count }) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Vector { element, count }) if layout.size.bytes() == 8 => { let elem_ty = llvm_asm_scalar_type(bx.cx, element); @@ -910,14 +910,14 @@ fn llvm_fixup_input<'ll, 'tcx>( let indices: Vec<_> = (0..count * 2).map(|x| bx.const_i32(x as i32)).collect(); bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices)) } - (X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) + (X86(X86InlineAsmRegClass::reg_abcd), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F64) => { bx.bitcast(value, bx.cx.type_i64()) } ( X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), - Abi::Vector { .. }, + BackendRepr::Vector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, bx.cx.type_vector(bx.cx.type_f64(), 8)), ( X86( @@ -925,7 +925,7 @@ fn llvm_fixup_input<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) if bx.sess().asm_arch == Some(InlineAsmArch::X86) && s.primitive() == Primitive::Float(Float::F128) => { @@ -937,7 +937,7 @@ fn llvm_fixup_input<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) if s.primitive() == Primitive::Float(Float::F16) => { let value = bx.insert_element( bx.const_undef(bx.type_vector(bx.type_f16(), 8)), @@ -952,11 +952,14 @@ fn llvm_fixup_input<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Vector { element, count: count @ (8 | 16) }, + BackendRepr::Vector { element, count: count @ (8 | 16) }, ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) } - (Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s)) => { + ( + Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), + BackendRepr::Scalar(s), + ) => { if let Primitive::Int(Integer::I32, _) = s.primitive() { bx.bitcast(value, bx.cx.type_f32()) } else { @@ -969,7 +972,7 @@ fn llvm_fixup_input<'ll, 'tcx>( | ArmInlineAsmRegClass::dreg_low8 | ArmInlineAsmRegClass::dreg_low16, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) => { if let Primitive::Int(Integer::I64, _) = s.primitive() { bx.bitcast(value, bx.cx.type_f64()) @@ -986,11 +989,11 @@ fn llvm_fixup_input<'ll, 'tcx>( | ArmInlineAsmRegClass::qreg_low4 | ArmInlineAsmRegClass::qreg_low8, ), - Abi::Vector { element, count: count @ (4 | 8) }, + BackendRepr::Vector { element, count: count @ (4 | 8) }, ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) } - (Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { + (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()), @@ -999,7 +1002,7 @@ fn llvm_fixup_input<'ll, 'tcx>( _ => value, } } - (RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + (RiscV(RiscVInlineAsmRegClass::freg), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F16) && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) => { @@ -1022,15 +1025,15 @@ fn llvm_fixup_output<'ll, 'tcx>( instance: Instance<'_>, ) -> &'ll Value { use InlineAsmRegClass::*; - match (reg, layout.abi) { - (AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { + match (reg, layout.backend_repr) { + (AArch64(AArch64InlineAsmRegClass::vreg), BackendRepr::Scalar(s)) => { if let Primitive::Int(Integer::I8, _) = s.primitive() { bx.extract_element(value, bx.const_i32(0)) } else { value } } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Scalar(s)) if s.primitive() != Primitive::Float(Float::F128) => { value = bx.extract_element(value, bx.const_i32(0)); @@ -1039,7 +1042,7 @@ fn llvm_fixup_output<'ll, 'tcx>( } value } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Vector { element, count }) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Vector { element, count }) if layout.size.bytes() == 8 => { let elem_ty = llvm_asm_scalar_type(bx.cx, element); @@ -1047,14 +1050,14 @@ fn llvm_fixup_output<'ll, 'tcx>( let indices: Vec<_> = (0..count).map(|x| bx.const_i32(x as i32)).collect(); bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices)) } - (X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) + (X86(X86InlineAsmRegClass::reg_abcd), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F64) => { bx.bitcast(value, bx.cx.type_f64()) } ( X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), - Abi::Vector { .. }, + BackendRepr::Vector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, layout.llvm_type(bx.cx)), ( X86( @@ -1062,7 +1065,7 @@ fn llvm_fixup_output<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) if bx.sess().asm_arch == Some(InlineAsmArch::X86) && s.primitive() == Primitive::Float(Float::F128) => { @@ -1074,7 +1077,7 @@ fn llvm_fixup_output<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) if s.primitive() == Primitive::Float(Float::F16) => { let value = bx.bitcast(value, bx.type_vector(bx.type_f16(), 8)); bx.extract_element(value, bx.const_usize(0)) @@ -1085,11 +1088,14 @@ fn llvm_fixup_output<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Vector { element, count: count @ (8 | 16) }, + BackendRepr::Vector { element, count: count @ (8 | 16) }, ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) } - (Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s)) => { + ( + Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), + BackendRepr::Scalar(s), + ) => { if let Primitive::Int(Integer::I32, _) = s.primitive() { bx.bitcast(value, bx.cx.type_i32()) } else { @@ -1102,7 +1108,7 @@ fn llvm_fixup_output<'ll, 'tcx>( | ArmInlineAsmRegClass::dreg_low8 | ArmInlineAsmRegClass::dreg_low16, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) => { if let Primitive::Int(Integer::I64, _) = s.primitive() { bx.bitcast(value, bx.cx.type_i64()) @@ -1119,11 +1125,11 @@ fn llvm_fixup_output<'ll, 'tcx>( | ArmInlineAsmRegClass::qreg_low4 | ArmInlineAsmRegClass::qreg_low8, ), - Abi::Vector { element, count: count @ (4 | 8) }, + BackendRepr::Vector { element, count: count @ (4 | 8) }, ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) } - (Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { + (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()), @@ -1133,7 +1139,7 @@ fn llvm_fixup_output<'ll, 'tcx>( _ => value, } } - (RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + (RiscV(RiscVInlineAsmRegClass::freg), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F16) && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) => { @@ -1153,35 +1159,35 @@ fn llvm_fixup_output_type<'ll, 'tcx>( instance: Instance<'_>, ) -> &'ll Type { use InlineAsmRegClass::*; - match (reg, layout.abi) { - (AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { + match (reg, layout.backend_repr) { + (AArch64(AArch64InlineAsmRegClass::vreg), BackendRepr::Scalar(s)) => { if let Primitive::Int(Integer::I8, _) = s.primitive() { cx.type_vector(cx.type_i8(), 8) } else { layout.llvm_type(cx) } } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Scalar(s)) if s.primitive() != Primitive::Float(Float::F128) => { let elem_ty = llvm_asm_scalar_type(cx, s); let count = 16 / layout.size.bytes(); cx.type_vector(elem_ty, count) } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Vector { element, count }) + (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Vector { element, count }) if layout.size.bytes() == 8 => { let elem_ty = llvm_asm_scalar_type(cx, element); cx.type_vector(elem_ty, count * 2) } - (X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) + (X86(X86InlineAsmRegClass::reg_abcd), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F64) => { cx.type_i64() } ( X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), - Abi::Vector { .. }, + BackendRepr::Vector { .. }, ) if layout.size.bytes() == 64 => cx.type_vector(cx.type_f64(), 8), ( X86( @@ -1189,7 +1195,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) if cx.sess().asm_arch == Some(InlineAsmArch::X86) && s.primitive() == Primitive::Float(Float::F128) => { @@ -1201,7 +1207,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) if s.primitive() == Primitive::Float(Float::F16) => cx.type_vector(cx.type_i16(), 8), ( X86( @@ -1209,11 +1215,14 @@ fn llvm_fixup_output_type<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - Abi::Vector { element, count: count @ (8 | 16) }, + BackendRepr::Vector { element, count: count @ (8 | 16) }, ) if element.primitive() == Primitive::Float(Float::F16) => { cx.type_vector(cx.type_i16(), count) } - (Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s)) => { + ( + Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), + BackendRepr::Scalar(s), + ) => { if let Primitive::Int(Integer::I32, _) = s.primitive() { cx.type_f32() } else { @@ -1226,7 +1235,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( | ArmInlineAsmRegClass::dreg_low8 | ArmInlineAsmRegClass::dreg_low16, ), - Abi::Scalar(s), + BackendRepr::Scalar(s), ) => { if let Primitive::Int(Integer::I64, _) = s.primitive() { cx.type_f64() @@ -1243,11 +1252,11 @@ fn llvm_fixup_output_type<'ll, 'tcx>( | ArmInlineAsmRegClass::qreg_low4 | ArmInlineAsmRegClass::qreg_low8, ), - Abi::Vector { element, count: count @ (4 | 8) }, + BackendRepr::Vector { element, count: count @ (4 | 8) }, ) if element.primitive() == Primitive::Float(Float::F16) => { cx.type_vector(cx.type_i16(), count) } - (Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => { + (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(), @@ -1256,7 +1265,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( _ => layout.llvm_type(cx), } } - (RiscV(RiscVInlineAsmRegClass::freg), Abi::Scalar(s)) + (RiscV(RiscVInlineAsmRegClass::freg), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F16) && !any_target_feature_enabled(cx, instance, &[sym::zfhmin, sym::zfh]) => { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 8702532c36ee..8e87869f9461 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -545,13 +545,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } let llval = const_llval.unwrap_or_else(|| { let load = self.load(llty, place.val.llval, place.val.align); - if let abi::Abi::Scalar(scalar) = place.layout.abi { + if let abi::BackendRepr::Scalar(scalar) = place.layout.backend_repr { scalar_load_metadata(self, load, scalar, place.layout, Size::ZERO); } load }); OperandValue::Immediate(self.to_immediate(llval, place.layout)) - } else if let abi::Abi::ScalarPair(a, b) = place.layout.abi { + } else if let abi::BackendRepr::ScalarPair(a, b) = place.layout.backend_repr { let b_offset = a.size(self).align_to(b.align(self).abi); let mut load = |i, scalar: abi::Scalar, layout, align, offset| { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index d04b52576194..c77e00aed9ac 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -258,8 +258,8 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.call_intrinsic("llvm.va_copy", &[args[0].immediate(), args[1].immediate()]) } sym::va_arg => { - match fn_abi.ret.layout.abi { - abi::Abi::Scalar(scalar) => { + match fn_abi.ret.layout.backend_repr { + abi::BackendRepr::Scalar(scalar) => { match scalar.primitive() { Primitive::Int(..) => { if self.cx().size_of(ret_ty).bytes() < 4 { @@ -436,13 +436,13 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } sym::raw_eq => { - use abi::Abi::*; + use abi::BackendRepr::*; let tp_ty = fn_args.type_at(0); let layout = self.layout_of(tp_ty).layout; - let use_integer_compare = match layout.abi() { + let use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, Uninhabited | Vector { .. } => false, - Aggregate { .. } => { + Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), // so we re-use that same threshold here. @@ -549,7 +549,8 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } let llret_ty = if ret_ty.is_simd() - && let abi::Abi::Aggregate { .. } = self.layout_of(ret_ty).layout.abi + && let abi::BackendRepr::Memory { .. } = + self.layout_of(ret_ty).layout.backend_repr { let (size, elem_ty) = ret_ty.simd_size_and_type(self.tcx()); let elem_ll_ty = match elem_ty.kind() { diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 6be4c3f034f1..2b05e24a7bab 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -1,7 +1,7 @@ use std::fmt::Write; use rustc_abi::Primitive::{Float, Int, Pointer}; -use rustc_abi::{Abi, Align, FieldsShape, Scalar, Size, Variants}; +use rustc_abi::{Align, BackendRepr, FieldsShape, Scalar, Size, Variants}; use rustc_codegen_ssa::traits::*; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; @@ -17,13 +17,13 @@ fn uncached_llvm_type<'a, 'tcx>( layout: TyAndLayout<'tcx>, defer: &mut Option<(&'a Type, TyAndLayout<'tcx>)>, ) -> &'a Type { - match layout.abi { - Abi::Scalar(_) => bug!("handled elsewhere"), - Abi::Vector { element, count } => { + match layout.backend_repr { + BackendRepr::Scalar(_) => bug!("handled elsewhere"), + BackendRepr::Vector { element, count } => { let element = layout.scalar_llvm_type_at(cx, element); return cx.type_vector(element, count); } - Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalarPair(..) => {} + BackendRepr::Uninhabited | BackendRepr::Memory { .. } | BackendRepr::ScalarPair(..) => {} } let name = match layout.ty.kind() { @@ -170,16 +170,21 @@ pub(crate) trait LayoutLlvmExt<'tcx> { impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { fn is_llvm_immediate(&self) -> bool { - match self.abi { - Abi::Scalar(_) | Abi::Vector { .. } => true, - Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false, + match self.backend_repr { + BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => true, + BackendRepr::ScalarPair(..) | BackendRepr::Uninhabited | BackendRepr::Memory { .. } => { + false + } } } fn is_llvm_scalar_pair(&self) -> bool { - match self.abi { - Abi::ScalarPair(..) => true, - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false, + match self.backend_repr { + BackendRepr::ScalarPair(..) => true, + BackendRepr::Uninhabited + | BackendRepr::Scalar(_) + | BackendRepr::Vector { .. } + | BackendRepr::Memory { .. } => false, } } @@ -198,7 +203,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // This must produce the same result for `repr(transparent)` wrappers as for the inner type! // In other words, this should generally not look at the type at all, but only at the // layout. - if let Abi::Scalar(scalar) = self.abi { + if let BackendRepr::Scalar(scalar) = self.backend_repr { // Use a different cache for scalars because pointers to DSTs // can be either wide or thin (data pointers of wide pointers). if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { @@ -248,13 +253,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { } fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { - match self.abi { - Abi::Scalar(scalar) => { + match self.backend_repr { + BackendRepr::Scalar(scalar) => { if scalar.is_bool() { return cx.type_i1(); } } - Abi::ScalarPair(..) => { + BackendRepr::ScalarPair(..) => { // An immediate pair always contains just the two elements, without any padding // filler, as it should never be stored to memory. return cx.type_struct( @@ -287,7 +292,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // This must produce the same result for `repr(transparent)` wrappers as for the inner type! // In other words, this should generally not look at the type at all, but only at the // layout. - let Abi::ScalarPair(a, b) = self.abi else { + let BackendRepr::ScalarPair(a, b) = self.backend_repr else { bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self); }; let scalar = [a, b][index]; diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index a17a127f0149..283740fa6643 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1532,7 +1532,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // the load would just produce `OperandValue::Ref` instead // of the `OperandValue::Immediate` we need for the call. llval = bx.load(bx.backend_type(arg.layout), llval, align); - if let abi::Abi::Scalar(scalar) = arg.layout.abi { + if let abi::BackendRepr::Scalar(scalar) = arg.layout.backend_repr { if scalar.is_bool() { bx.range_metadata(llval, WrappingRange { start: 0, end: 1 }); } diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 15f45b226f5e..54b9c9cc89f5 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -1,8 +1,8 @@ +use rustc_abi::BackendRepr; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, mir, span_bug}; -use rustc_target::abi::Abi; use super::FunctionCx; use crate::errors; @@ -86,7 +86,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .map(|field| { if let Some(prim) = field.try_to_scalar() { let layout = bx.layout_of(field_ty); - let Abi::Scalar(scalar) = layout.abi else { + let BackendRepr::Scalar(scalar) = layout.backend_repr else { bug!("from_const: invalid ByVal layout: {:#?}", layout); }; bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout)) diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 146f55f95c21..21d20475408b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -2,6 +2,7 @@ use std::collections::hash_map::Entry; use std::marker::PhantomData; use std::ops::Range; +use rustc_abi::{BackendRepr, FieldIdx, FieldsShape, Size, VariantIdx}; use rustc_data_structures::fx::FxHashMap; use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -11,7 +12,6 @@ use rustc_middle::{bug, mir, ty}; use rustc_session::config::DebugInfo; use rustc_span::symbol::{Symbol, kw}; use rustc_span::{BytePos, Span, hygiene}; -use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx}; use super::operand::{OperandRef, OperandValue}; use super::place::{PlaceRef, PlaceValue}; @@ -510,7 +510,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // be marked as a `LocalVariable` for MSVC debuggers to visualize // their data correctly. (See #81894 & #88625) let var_ty_layout = self.cx.layout_of(var_ty); - if let Abi::ScalarPair(_, _) = var_ty_layout.abi { + if let BackendRepr::ScalarPair(_, _) = var_ty_layout.backend_repr { VariableKind::LocalVariable } else { VariableKind::ArgumentVariable(arg_index) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 88ceff327d0a..19101ec2d1ba 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -4,7 +4,7 @@ use std::fmt; use arrayvec::ArrayVec; use either::Either; use rustc_abi as abi; -use rustc_abi::{Abi, Align, Size}; +use rustc_abi::{Align, BackendRepr, Size}; use rustc_middle::bug; use rustc_middle::mir::interpret::{Pointer, Scalar, alloc_range}; use rustc_middle::mir::{self, ConstValue}; @@ -163,7 +163,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let val = match val { ConstValue::Scalar(x) => { - let Abi::Scalar(scalar) = layout.abi else { + let BackendRepr::Scalar(scalar) = layout.backend_repr else { bug!("from_const: invalid ByVal layout: {:#?}", layout); }; let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); @@ -171,7 +171,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } ConstValue::ZeroSized => return OperandRef::zero_sized(layout), ConstValue::Slice { data, meta } => { - let Abi::ScalarPair(a_scalar, _) = layout.abi else { + let BackendRepr::ScalarPair(a_scalar, _) = layout.backend_repr else { bug!("from_const: invalid ScalarPair layout: {:#?}", layout); }; let a = Scalar::from_pointer( @@ -221,14 +221,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { // case where some of the bytes are initialized and others are not. So, we need an extra // check that walks over the type of `mplace` to make sure it is truly correct to treat this // like a `Scalar` (or `ScalarPair`). - match layout.abi { - Abi::Scalar(s @ abi::Scalar::Initialized { .. }) => { + match layout.backend_repr { + BackendRepr::Scalar(s @ abi::Scalar::Initialized { .. }) => { let size = s.size(bx); assert_eq!(size, layout.size, "abi::Scalar size does not match layout size"); let val = read_scalar(offset, size, s, bx.immediate_backend_type(layout)); OperandRef { val: OperandValue::Immediate(val), layout } } - Abi::ScalarPair( + BackendRepr::ScalarPair( a @ abi::Scalar::Initialized { .. }, b @ abi::Scalar::Initialized { .. }, ) => { @@ -322,7 +322,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { llval: V, layout: TyAndLayout<'tcx>, ) -> Self { - let val = if let Abi::ScalarPair(..) = layout.abi { + let val = if let BackendRepr::ScalarPair(..) = layout.backend_repr { debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout); // Deconstruct the immediate aggregate. @@ -343,7 +343,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let field = self.layout.field(bx.cx(), i); let offset = self.layout.fields.offset(i); - let mut val = match (self.val, self.layout.abi) { + let mut val = match (self.val, self.layout.backend_repr) { // If the field is ZST, it has no data. _ if field.is_zst() => OperandValue::ZeroSized, @@ -356,7 +356,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } // Extract a scalar component from a pair. - (OperandValue::Pair(a_llval, b_llval), Abi::ScalarPair(a, b)) => { + (OperandValue::Pair(a_llval, b_llval), BackendRepr::ScalarPair(a, b)) => { if offset.bytes() == 0 { assert_eq!(field.size, a.size(bx.cx())); OperandValue::Immediate(a_llval) @@ -368,30 +368,30 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } // `#[repr(simd)]` types are also immediate. - (OperandValue::Immediate(llval), Abi::Vector { .. }) => { + (OperandValue::Immediate(llval), BackendRepr::Vector { .. }) => { OperandValue::Immediate(bx.extract_element(llval, bx.cx().const_usize(i as u64))) } _ => bug!("OperandRef::extract_field({:?}): not applicable", self), }; - match (&mut val, field.abi) { + match (&mut val, field.backend_repr) { (OperandValue::ZeroSized, _) => {} ( OperandValue::Immediate(llval), - Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. }, + BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) | BackendRepr::Vector { .. }, ) => { // Bools in union fields needs to be truncated. *llval = bx.to_immediate(*llval, field); } - (OperandValue::Pair(a, b), Abi::ScalarPair(a_abi, b_abi)) => { + (OperandValue::Pair(a, b), BackendRepr::ScalarPair(a_abi, b_abi)) => { // Bools in union fields needs to be truncated. *a = bx.to_immediate_scalar(*a, a_abi); *b = bx.to_immediate_scalar(*b, b_abi); } // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]); - (OperandValue::Immediate(llval), Abi::Aggregate { sized: true }) => { - assert_matches!(self.layout.abi, Abi::Vector { .. }); + (OperandValue::Immediate(llval), BackendRepr::Memory { sized: true }) => { + assert_matches!(self.layout.backend_repr, BackendRepr::Vector { .. }); let llfield_ty = bx.cx().backend_type(field); @@ -400,7 +400,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { bx.store(*llval, llptr, field.align.abi); *llval = bx.load(llfield_ty, llptr, field.align.abi); } - (OperandValue::Immediate(_), Abi::Uninhabited | Abi::Aggregate { sized: false }) => { + ( + OperandValue::Immediate(_), + BackendRepr::Uninhabited | BackendRepr::Memory { sized: false }, + ) => { bug!() } (OperandValue::Pair(..), _) => bug!(), @@ -494,7 +497,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { bx.store_with_flags(val, dest.val.llval, dest.val.align, flags); } OperandValue::Pair(a, b) => { - let Abi::ScalarPair(a_scalar, b_scalar) = dest.layout.abi else { + let BackendRepr::ScalarPair(a_scalar, b_scalar) = dest.layout.backend_repr else { bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout); }; let b_offset = a_scalar.size(bx).align_to(b_scalar.align(bx).abi); @@ -645,7 +648,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // However, some SIMD types do not actually use the vector ABI // (in particular, packed SIMD types do not). Ensure we exclude those. let layout = bx.layout_of(constant_ty); - if let Abi::Vector { .. } = layout.abi { + if let BackendRepr::Vector { .. } = layout.backend_repr { let (llval, ty) = self.immediate_const_vector(bx, constant); return OperandRef { val: OperandValue::Immediate(llval), diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 6e8c193cd758..86cf0f9614d3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -1136,17 +1136,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValueKind::ZeroSized } else if self.cx.is_backend_immediate(layout) { assert!(!self.cx.is_backend_scalar_pair(layout)); - OperandValueKind::Immediate(match layout.abi { - abi::Abi::Scalar(s) => s, - abi::Abi::Vector { element, .. } => element, + OperandValueKind::Immediate(match layout.backend_repr { + abi::BackendRepr::Scalar(s) => s, + abi::BackendRepr::Vector { element, .. } => element, x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"), }) } else if self.cx.is_backend_scalar_pair(layout) { - let abi::Abi::ScalarPair(s1, s2) = layout.abi else { + let abi::BackendRepr::ScalarPair(s1, s2) = layout.backend_repr else { span_bug!( self.mir.span, "Couldn't translate {:?} as backend scalar pair", - layout.abi, + layout.backend_repr, ); }; OperandValueKind::Pair(s1, s2) diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 50a517141469..768a0439ab51 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -1,13 +1,13 @@ use std::assert_matches::assert_matches; use std::ops::Deref; +use rustc_abi::{Align, BackendRepr, Scalar, Size, WrappingRange}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::{Instance, Ty}; use rustc_session::config::OptLevel; use rustc_span::Span; use rustc_target::abi::call::FnAbi; -use rustc_target::abi::{Abi, Align, Scalar, Size, WrappingRange}; use super::abi::AbiBuilderMethods; use super::asm::AsmBuilderMethods; @@ -162,7 +162,7 @@ pub trait BuilderMethods<'a, 'tcx>: fn from_immediate(&mut self, val: Self::Value) -> Self::Value; fn to_immediate(&mut self, val: Self::Value, layout: TyAndLayout<'_>) -> Self::Value { - if let Abi::Scalar(scalar) = layout.abi { + if let BackendRepr::Scalar(scalar) = layout.backend_repr { self.to_immediate_scalar(val, scalar) } else { val diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index 743924faa21d..bc2661c4fc71 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -131,7 +131,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { interp_ok(match bin_op { Eq | Ne | Lt | Le | Gt | Ge => { // Types can differ, e.g. fn ptrs with different `for`. - assert_eq!(left.layout.abi, right.layout.abi); + assert_eq!(left.layout.backend_repr, right.layout.backend_repr); let size = ecx.pointer_size(); // Just compare the bits. ScalarPairs are compared lexicographically. // We thus always compare pairs and simply fill scalars up with 0. diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 7319c251bbd9..81b9d73b9528 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -1,6 +1,7 @@ use std::sync::atomic::Ordering::Relaxed; use either::{Left, Right}; +use rustc_abi::{self as abi, BackendRepr}; use rustc_hir::def::DefKind; use rustc_middle::bug; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo}; @@ -12,7 +13,6 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; use rustc_span::{DUMMY_SP, Span}; -use rustc_target::abi::{self, Abi}; use tracing::{debug, instrument, trace}; use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine}; @@ -174,8 +174,8 @@ pub(super) fn op_to_const<'tcx>( // type (it's used throughout the compiler and having it work just on literals is not enough) // and we want it to be fast (i.e., don't go to an `Allocation` and reconstruct the `Scalar` // from its byte-serialized form). - let force_as_immediate = match op.layout.abi { - Abi::Scalar(abi::Scalar::Initialized { .. }) => true, + let force_as_immediate = match op.layout.backend_repr { + BackendRepr::Scalar(abi::Scalar::Initialized { .. }) => true, // We don't *force* `ConstValue::Slice` for `ScalarPair`. This has the advantage that if the // input `op` is a place, then turning it into a `ConstValue` and back into a `OpTy` will // not have to generate any duplicate allocations (we preserve the original `AllocId` in diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 9e80e666ba91..ea88b2ed22e2 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,10 +1,10 @@ +use rustc_abi::{BackendRepr, VariantIdx}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::DUMMY_SP; -use rustc_target::abi::{Abi, VariantIdx}; use tracing::{debug, instrument, trace}; use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const}; @@ -117,7 +117,7 @@ fn const_to_valtree_inner<'tcx>( let val = ecx.read_immediate(place).unwrap(); // We could allow wide raw pointers where both sides are integers in the future, // but for now we reject them. - if matches!(val.layout.abi, Abi::ScalarPair(..)) { + if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) { return Err(ValTreeCreationError::NonSupportedType(ty)); } let val = val.to_scalar(); @@ -311,7 +311,7 @@ pub fn valtree_to_const_value<'tcx>( // Fast path to avoid some allocations. return mir::ConstValue::ZeroSized; } - if layout.abi.is_scalar() + if layout.backend_repr.is_scalar() && (matches!(ty.kind(), ty::Tuple(_)) || matches!(ty.kind(), ty::Adt(def, _) if def.is_struct())) { diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 85d99900c6cc..1915bf75c95a 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -172,8 +172,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // must be compatible. So we just accept everything with Pointer ABI as compatible, // even if this will accept some code that is not stably guaranteed to work. // This also handles function pointers. - let thin_pointer = |layout: TyAndLayout<'tcx>| match layout.abi { - abi::Abi::Scalar(s) => match s.primitive() { + let thin_pointer = |layout: TyAndLayout<'tcx>| match layout.backend_repr { + abi::BackendRepr::Scalar(s) => match s.primitive() { abi::Primitive::Pointer(addr_space) => Some(addr_space), _ => None, }, diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 64b15611316f..60d5e904bd9a 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -274,7 +274,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { cast_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Scalar> { // Let's make sure v is sign-extended *if* it has a signed type. - let signed = src_layout.abi.is_signed(); // Also asserts that abi is `Scalar`. + let signed = src_layout.backend_repr.is_signed(); // Also asserts that abi is `Scalar`. let v = match src_layout.ty.kind() { Uint(_) | RawPtr(..) | FnPtr(..) => scalar.to_uint(src_layout.size)?, diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index feed08606799..bb4ac9556ea8 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -112,7 +112,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Read tag and sanity-check `tag_layout`. let tag_val = self.read_immediate(&self.project_field(op, tag_field)?)?; assert_eq!(tag_layout.size, tag_val.layout.size); - assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed()); + assert_eq!(tag_layout.backend_repr.is_signed(), tag_val.layout.backend_repr.is_signed()); trace!("tag value: {}", tag_val); // Figure out which discriminant and variant this corresponds to. diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 6148123bdfeb..80e14ee887cb 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -563,7 +563,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.binary_op(mir_op.wrapping_to_overflowing().unwrap(), l, r)?.to_scalar_pair(); interp_ok(if overflowed.to_bool()? { let size = l.layout.size; - if l.layout.abi.is_signed() { + if l.layout.backend_repr.is_signed() { // For signed ints the saturated value depends on the sign of the first // term since the sign of the second term can be inferred from this and // the fact that the operation has overflowed (if either is 0 no diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index cd5e2aeca855..43ae98e74b00 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -5,7 +5,7 @@ use std::assert_matches::assert_matches; use either::{Either, Left, Right}; use rustc_abi as abi; -use rustc_abi::{Abi, HasDataLayout, Size}; +use rustc_abi::{BackendRepr, HasDataLayout, Size}; use rustc_hir::def::Namespace; use rustc_middle::mir::interpret::ScalarSizeMismatch; use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutOf, TyAndLayout}; @@ -114,9 +114,9 @@ impl Immediate { } /// Assert that this immediate is a valid value for the given ABI. - pub fn assert_matches_abi(self, abi: Abi, msg: &str, cx: &impl HasDataLayout) { + pub fn assert_matches_abi(self, abi: BackendRepr, msg: &str, cx: &impl HasDataLayout) { match (self, abi) { - (Immediate::Scalar(scalar), Abi::Scalar(s)) => { + (Immediate::Scalar(scalar), BackendRepr::Scalar(s)) => { assert_eq!(scalar.size(), s.size(cx), "{msg}: scalar value has wrong size"); if !matches!(s.primitive(), abi::Primitive::Pointer(..)) { // This is not a pointer, it should not carry provenance. @@ -126,7 +126,7 @@ impl Immediate { ); } } - (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => { + (Immediate::ScalarPair(a_val, b_val), BackendRepr::ScalarPair(a, b)) => { assert_eq!( a_val.size(), a.size(cx), @@ -244,7 +244,7 @@ impl<'tcx, Prov: Provenance> std::ops::Deref for ImmTy<'tcx, Prov> { impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_scalar(val: Scalar, layout: TyAndLayout<'tcx>) -> Self { - debug_assert!(layout.abi.is_scalar(), "`ImmTy::from_scalar` on non-scalar layout"); + debug_assert!(layout.backend_repr.is_scalar(), "`ImmTy::from_scalar` on non-scalar layout"); debug_assert_eq!(val.size(), layout.size); ImmTy { imm: val.into(), layout } } @@ -252,7 +252,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_scalar_pair(a: Scalar, b: Scalar, layout: TyAndLayout<'tcx>) -> Self { debug_assert!( - matches!(layout.abi, Abi::ScalarPair(..)), + matches!(layout.backend_repr, BackendRepr::ScalarPair(..)), "`ImmTy::from_scalar_pair` on non-scalar-pair layout" ); let imm = Immediate::ScalarPair(a, b); @@ -263,9 +263,9 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { pub fn from_immediate(imm: Immediate, layout: TyAndLayout<'tcx>) -> Self { // Without a `cx` we cannot call `assert_matches_abi`. debug_assert!( - match (imm, layout.abi) { - (Immediate::Scalar(..), Abi::Scalar(..)) => true, - (Immediate::ScalarPair(..), Abi::ScalarPair(..)) => true, + match (imm, layout.backend_repr) { + (Immediate::Scalar(..), BackendRepr::Scalar(..)) => true, + (Immediate::ScalarPair(..), BackendRepr::ScalarPair(..)) => true, (Immediate::Uninit, _) if layout.is_sized() => true, _ => false, }, @@ -356,7 +356,11 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { fn offset_(&self, offset: Size, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self { // Verify that the input matches its type. if cfg!(debug_assertions) { - self.assert_matches_abi(self.layout.abi, "invalid input to Immediate::offset", cx); + self.assert_matches_abi( + self.layout.backend_repr, + "invalid input to Immediate::offset", + cx, + ); } // `ImmTy` have already been checked to be in-bounds, so we can just check directly if this // remains in-bounds. This cannot actually be violated since projections are type-checked @@ -370,19 +374,19 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { ); // This makes several assumptions about what layouts we will encounter; we match what // codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`). - let inner_val: Immediate<_> = match (**self, self.layout.abi) { + let inner_val: Immediate<_> = match (**self, self.layout.backend_repr) { // If the entire value is uninit, then so is the field (can happen in ConstProp). (Immediate::Uninit, _) => Immediate::Uninit, // If the field is uninhabited, we can forget the data (can happen in ConstProp). // `enum S { A(!), B, C }` is an example of an enum with Scalar layout that // has an `Uninhabited` variant, which means this case is possible. - _ if layout.abi.is_uninhabited() => Immediate::Uninit, + _ if layout.is_uninhabited() => Immediate::Uninit, // the field contains no information, can be left uninit // (Scalar/ScalarPair can contain even aligned ZST, not just 1-ZST) _ if layout.is_zst() => Immediate::Uninit, // some fieldless enum variants can have non-zero size but still `Aggregate` ABI... try // to detect those here and also give them no data - _ if matches!(layout.abi, Abi::Aggregate { .. }) + _ if matches!(layout.backend_repr, BackendRepr::Memory { .. }) && matches!(layout.variants, abi::Variants::Single { .. }) && matches!(&layout.fields, abi::FieldsShape::Arbitrary { offsets, .. } if offsets.len() == 0) => { @@ -394,7 +398,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { **self } // extract fields from types with `ScalarPair` ABI - (Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => { + (Immediate::ScalarPair(a_val, b_val), BackendRepr::ScalarPair(a, b)) => { Immediate::from(if offset.bytes() == 0 { a_val } else { @@ -411,7 +415,11 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { ), }; // Ensure the new layout matches the new value. - inner_val.assert_matches_abi(layout.abi, "invalid field type in Immediate::offset", cx); + inner_val.assert_matches_abi( + layout.backend_repr, + "invalid field type in Immediate::offset", + cx, + ); ImmTy::from_immediate(inner_val, layout) } @@ -567,8 +575,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // case where some of the bytes are initialized and others are not. So, we need an extra // check that walks over the type of `mplace` to make sure it is truly correct to treat this // like a `Scalar` (or `ScalarPair`). - interp_ok(match mplace.layout.abi { - Abi::Scalar(abi::Scalar::Initialized { value: s, .. }) => { + interp_ok(match mplace.layout.backend_repr { + BackendRepr::Scalar(abi::Scalar::Initialized { value: s, .. }) => { let size = s.size(self); assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size"); let scalar = alloc.read_scalar( @@ -577,7 +585,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { )?; Some(ImmTy::from_scalar(scalar, mplace.layout)) } - Abi::ScalarPair( + BackendRepr::ScalarPair( abi::Scalar::Initialized { value: a, .. }, abi::Scalar::Initialized { value: b, .. }, ) => { @@ -637,9 +645,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { op: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { if !matches!( - op.layout().abi, - Abi::Scalar(abi::Scalar::Initialized { .. }) - | Abi::ScalarPair(abi::Scalar::Initialized { .. }, abi::Scalar::Initialized { .. }) + op.layout().backend_repr, + BackendRepr::Scalar(abi::Scalar::Initialized { .. }) + | BackendRepr::ScalarPair( + abi::Scalar::Initialized { .. }, + abi::Scalar::Initialized { .. } + ) ) { span_bug!(self.cur_span(), "primitive read not possible for type: {}", op.layout().ty); } diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 380db9074812..cf280e0c1aeb 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -114,7 +114,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let l_bits = left.layout.size.bits(); // Compute the equivalent shift modulo `size` that is in the range `0..size`. (This is // the one MIR operator that does *not* directly map to a single LLVM operation.) - let (shift_amount, overflow) = if right.layout.abi.is_signed() { + let (shift_amount, overflow) = if right.layout.backend_repr.is_signed() { let shift_amount = r_signed(); let rem = shift_amount.rem_euclid(l_bits.into()); // `rem` is guaranteed positive, so the `unwrap` cannot fail @@ -126,7 +126,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; let shift_amount = u32::try_from(shift_amount).unwrap(); // we brought this in the range `0..size` so this will always fit // Compute the shifted result. - let result = if left.layout.abi.is_signed() { + let result = if left.layout.backend_repr.is_signed() { let l = l_signed(); let result = match bin_op { Shl | ShlUnchecked => l.checked_shl(shift_amount).unwrap(), @@ -147,7 +147,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if overflow && let Some(intrinsic) = throw_ub_on_overflow { throw_ub!(ShiftOverflow { intrinsic, - shift_amount: if right.layout.abi.is_signed() { + shift_amount: if right.layout.backend_repr.is_signed() { Either::Right(r_signed()) } else { Either::Left(r_unsigned()) @@ -171,7 +171,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let size = left.layout.size; // Operations that need special treatment for signed integers - if left.layout.abi.is_signed() { + if left.layout.backend_repr.is_signed() { let op: Option bool> = match bin_op { Lt => Some(i128::lt), Le => Some(i128::le), @@ -250,7 +250,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { BitXor => ImmTy::from_uint(l ^ r, left.layout), _ => { - assert!(!left.layout.abi.is_signed()); + assert!(!left.layout.backend_repr.is_signed()); let op: fn(u128, u128) -> (u128, bool) = match bin_op { Add | AddUnchecked | AddWithOverflow => u128::overflowing_add, Sub | SubUnchecked | SubWithOverflow => u128::overflowing_sub, @@ -332,7 +332,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } let offset_bytes = val.to_target_isize(self)?; - if !right.layout.abi.is_signed() && offset_bytes < 0 { + if !right.layout.backend_repr.is_signed() && offset_bytes < 0 { // We were supposed to do an unsigned offset but the result is negative -- this // can only mean that the cast wrapped around. throw_ub!(PointerArithOverflow) diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 81b926a1b65f..139a1db60e03 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -5,11 +5,11 @@ use std::assert_matches::assert_matches; use either::{Either, Left, Right}; +use rustc_abi::{Align, BackendRepr, HasDataLayout, Size}; use rustc_ast::Mutability; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::{bug, mir, span_bug}; -use rustc_target::abi::{Abi, Align, HasDataLayout, Size}; use tracing::{instrument, trace}; use super::{ @@ -659,7 +659,7 @@ where // Unfortunately this is too expensive to do in release builds. if cfg!(debug_assertions) { src.assert_matches_abi( - local_layout.abi, + local_layout.backend_repr, "invalid immediate for given destination place", self, ); @@ -683,7 +683,11 @@ where ) -> InterpResult<'tcx> { // We use the sizes from `value` below. // Ensure that matches the type of the place it is written to. - value.assert_matches_abi(layout.abi, "invalid immediate for given destination place", self); + value.assert_matches_abi( + layout.backend_repr, + "invalid immediate for given destination place", + self, + ); // Note that it is really important that the type here is the right one, and matches the // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here // to handle padding properly, which is only correct if we never look at this data with the @@ -700,7 +704,7 @@ where alloc.write_scalar(alloc_range(Size::ZERO, scalar.size()), scalar) } Immediate::ScalarPair(a_val, b_val) => { - let Abi::ScalarPair(a, b) = layout.abi else { + let BackendRepr::ScalarPair(a, b) = layout.backend_repr else { span_bug!( self.cur_span(), "write_immediate_to_mplace: invalid ScalarPair layout: {:#?}", diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 8b5bb1332e79..cd2c1ef36132 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -11,6 +11,10 @@ use std::num::NonZero; use either::{Left, Right}; use hir::def::DefKind; +use rustc_abi::{ + BackendRepr, FieldIdx, FieldsShape, Scalar as ScalarAbi, Size, VariantIdx, Variants, + WrappingRange, +}; use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; @@ -23,9 +27,6 @@ use rustc_middle::mir::interpret::{ use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::{Symbol, sym}; -use rustc_target::abi::{ - Abi, FieldIdx, FieldsShape, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange, -}; use tracing::trace; use super::machine::AllocMap; @@ -422,7 +423,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // Reset provenance: ensure slice tail metadata does not preserve provenance, // and ensure all pointers do not preserve partial provenance. if self.reset_provenance_and_padding { - if matches!(imm.layout.abi, Abi::Scalar(..)) { + if matches!(imm.layout.backend_repr, BackendRepr::Scalar(..)) { // A thin pointer. If it has provenance, we don't have to do anything. // If it does not, ensure we clear the provenance in memory. if matches!(imm.to_scalar(), Scalar::Int(..)) { @@ -981,7 +982,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { let elem = layout.field(cx, 0); // Fast-path for large arrays of simple types that do not contain any padding. - if elem.abi.is_scalar() { + if elem.backend_repr.is_scalar() { out.add_range(base_offset, elem.size * count); } else { for idx in 0..count { @@ -1299,19 +1300,19 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // FIXME: We could avoid some redundant checks here. For newtypes wrapping // scalars, we do the same check on every "level" (e.g., first we check // MyNewtype and then the scalar in there). - match val.layout.abi { - Abi::Uninhabited => { + match val.layout.backend_repr { + BackendRepr::Uninhabited => { let ty = val.layout.ty; throw_validation_failure!(self.path, UninhabitedVal { ty }); } - Abi::Scalar(scalar_layout) => { + BackendRepr::Scalar(scalar_layout) => { if !scalar_layout.is_uninit_valid() { // There is something to check here. let scalar = self.read_scalar(val, ExpectedKind::InitScalar)?; self.visit_scalar(scalar, scalar_layout)?; } } - Abi::ScalarPair(a_layout, b_layout) => { + BackendRepr::ScalarPair(a_layout, b_layout) => { // We can only proceed if *both* scalars need to be initialized. // FIXME: find a way to also check ScalarPair when one side can be uninit but // the other must be init. @@ -1322,12 +1323,12 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, self.visit_scalar(b, b_layout)?; } } - Abi::Vector { .. } => { + BackendRepr::Vector { .. } => { // No checks here, we assume layout computation gets this right. // (This is harder to check since Miri does not represent these as `Immediate`. We // also cannot use field projections since this might be a newtype around a vector.) } - Abi::Aggregate { .. } => { + BackendRepr::Memory { .. } => { // Nothing to do. } } diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 7a8b976dfc4e..f743525f3599 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -1,9 +1,9 @@ +use rustc_abi::{BackendRepr, FieldsShape, Scalar, Variants}; use rustc_middle::bug; use rustc_middle::ty::layout::{ HasTyCtxt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement, }; use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; -use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants}; use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeMachine}; use crate::interpret::{InterpCx, MemoryKind}; @@ -111,12 +111,12 @@ fn check_validity_requirement_lax<'tcx>( }; // Check the ABI. - let valid = match this.abi { - Abi::Uninhabited => false, // definitely UB - Abi::Scalar(s) => scalar_allows_raw_init(s), - Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), - Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s), - Abi::Aggregate { .. } => true, // Fields are checked below. + let valid = match this.backend_repr { + BackendRepr::Uninhabited => false, // definitely UB + BackendRepr::Scalar(s) => scalar_allows_raw_init(s), + BackendRepr::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2), + BackendRepr::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s), + BackendRepr::Memory { .. } => true, // Fields are checked below. }; if !valid { // This is definitely not okay. diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index dbb8c6675323..6400685101b5 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -16,6 +16,7 @@ use std::fmt::Write; use ast::token::TokenKind; +use rustc_abi::BackendRepr; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; @@ -40,7 +41,6 @@ use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{BytePos, InnerSpan, Span}; -use rustc_target::abi::Abi; use rustc_target::asm::InlineAsmArch; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; @@ -2466,7 +2466,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { // Check if this ADT has a constrained layout (like `NonNull` and friends). if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty)) { - if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &layout.abi { + if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) = + &layout.backend_repr + { let range = scalar.valid_range(cx); let msg = if !range.contains(0) { "must be non-null" diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index abe4e3e78ee7..394ea798d3e5 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -217,7 +217,7 @@ fn structurally_same_type<'tcx>( // `extern` blocks cannot be generic, so we'll always get a layout here. let a_layout = tcx.layout_of(param_env.and(a)).unwrap(); let b_layout = tcx.layout_of(param_env.and(b)).unwrap(); - assert_eq!(a_layout.abi, b_layout.abi); + assert_eq!(a_layout.backend_repr, b_layout.backend_repr); assert_eq!(a_layout.size, b_layout.size); assert_eq!(a_layout.align, b_layout.align); } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 0751d35cb9c3..88878a018e7a 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,6 +1,7 @@ use std::iter; use std::ops::ControlFlow; +use rustc_abi::{BackendRepr, TagEncoding, Variants, WrappingRange}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagMessage; use rustc_hir::{Expr, ExprKind}; @@ -13,7 +14,6 @@ use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol, source_map}; -use rustc_target::abi::{Abi, TagEncoding, Variants, WrappingRange}; use rustc_target::spec::abi::Abi as SpecAbi; use tracing::debug; use {rustc_ast as ast, rustc_hir as hir}; @@ -776,8 +776,8 @@ pub(crate) fn repr_nullable_ptr<'tcx>( bug!("should be able to compute the layout of non-polymorphic type"); } - let field_ty_abi = &field_ty_layout.ok()?.abi; - if let Abi::Scalar(field_ty_scalar) = field_ty_abi { + let field_ty_abi = &field_ty_layout.ok()?.backend_repr; + if let BackendRepr::Scalar(field_ty_scalar) = field_ty_abi { match field_ty_scalar.valid_range(&tcx) { WrappingRange { start: 0, end } if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 2c7a3ffd04c8..0560ffe058a3 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -4,8 +4,9 @@ use std::{cmp, fmt}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ - Abi, AddressSpace, Align, FieldsShape, HasDataLayout, Integer, LayoutCalculator, LayoutData, - PointeeInfo, PointerKind, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, Variants, + AddressSpace, Align, BackendRepr, FieldsShape, HasDataLayout, Integer, LayoutCalculator, + LayoutData, PointeeInfo, PointerKind, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, + Variants, }; use rustc_error_messages::DiagMessage; use rustc_errors::{ @@ -757,7 +758,7 @@ where Some(fields) => FieldsShape::Union(fields), None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() }, }, - abi: Abi::Uninhabited, + backend_repr: BackendRepr::Uninhabited, largest_niche: None, align: tcx.data_layout.i8_align, size: Size::ZERO, diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index fd949a533845..2357dd734905 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, Ty, UpvarArgs}; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span}; -use rustc_target::abi::{Abi, FieldIdx, Primitive}; +use rustc_target::abi::{BackendRepr, FieldIdx, Primitive}; use tracing::debug; use crate::build::expr::as_place::PlaceBase; @@ -207,7 +207,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); let (op, ty) = (Operand::Move(discr), discr_ty); - if let Abi::Scalar(scalar) = layout.unwrap().abi + if let BackendRepr::Scalar(scalar) = layout.unwrap().backend_repr && !scalar.is_always_valid(&this.tcx) && let Primitive::Int(int_width, _signed) = scalar.primitive() { diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index f7d4a082779b..80151b8ba2de 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -858,7 +858,7 @@ impl<'tcx> Map<'tcx> { // Allocate a value slot if it doesn't have one, and the user requested one. assert!(place_info.value_index.is_none()); if let Ok(layout) = tcx.layout_of(param_env.and(place_info.ty)) - && layout.abi.is_scalar() + && layout.backend_repr.is_scalar() { place_info.value_index = Some(self.value_count.into()); self.value_count += 1; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 002216f50f2d..ca24d0d7e70e 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -2,6 +2,7 @@ //! //! Currently, this pass only propagates scalar values. +use rustc_abi::{BackendRepr, FIRST_VARIANT, FieldIdx, Size, VariantIdx}; use rustc_const_eval::const_eval::{DummyMachine, throw_machine_stop_str}; use rustc_const_eval::interpret::{ ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable, interp_ok, @@ -20,7 +21,6 @@ use rustc_mir_dataflow::value_analysis::{ }; use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor}; use rustc_span::DUMMY_SP; -use rustc_target::abi::{Abi, FIRST_VARIANT, FieldIdx, Size, VariantIdx}; use tracing::{debug, debug_span, instrument}; // These constants are somewhat random guesses and have not been optimized. @@ -457,7 +457,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { // a pair and sometimes not. But as a hack we always return a pair // and just make the 2nd component `Bottom` when it does not exist. Some(val) => { - if matches!(val.layout.abi, Abi::ScalarPair(..)) { + if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) { let (val, overflow) = val.to_scalar_pair(); (FlatSet::Elem(val), FlatSet::Elem(overflow)) } else { @@ -470,7 +470,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { // Exactly one side is known, attempt some algebraic simplifications. (FlatSet::Elem(const_arg), _) | (_, FlatSet::Elem(const_arg)) => { let layout = const_arg.layout; - if !matches!(layout.abi, rustc_target::abi::Abi::Scalar(..)) { + if !matches!(layout.backend_repr, rustc_target::abi::BackendRepr::Scalar(..)) { return (FlatSet::Top, FlatSet::Top); } @@ -589,13 +589,13 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { } let place = map.find(place.as_ref())?; - if layout.abi.is_scalar() + if layout.backend_repr.is_scalar() && let Some(value) = propagatable_scalar(place, state, map) { return Some(Const::Val(ConstValue::Scalar(value), ty)); } - if matches!(layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + if matches!(layout.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) { let alloc_id = ecx .intern_with_temp_alloc(layout, |ecx, dest| { try_write_constant(ecx, dest, place, ty, state, map) @@ -641,7 +641,7 @@ fn try_write_constant<'tcx>( } // Fast path for scalars. - if layout.abi.is_scalar() + if layout.backend_repr.is_scalar() && let Some(value) = propagatable_scalar(place, state, map) { return ecx.write_immediate(Immediate::Scalar(value), dest); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 79c62372df02..8a646d8cbfef 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -85,6 +85,7 @@ use std::borrow::Cow; use either::Either; +use rustc_abi::{self as abi, BackendRepr, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx}; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, Scalar, @@ -103,7 +104,6 @@ use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; -use rustc_target::abi::{self, Abi, FIRST_VARIANT, FieldIdx, Primitive, Size, VariantIdx}; use smallvec::SmallVec; use tracing::{debug, instrument, trace}; @@ -427,7 +427,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { }; let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); ImmTy::from_immediate(ptr_imm, ty).into() - } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + } else if matches!( + ty.backend_repr, + BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..) + ) { let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; let variant_dest = if let Some(variant) = variant { self.ecx.project_downcast(&dest, variant).discard_err()? @@ -573,12 +576,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // limited transmutes: it only works between types with the same layout, and // cannot transmute pointers to integers. if value.as_mplace_or_imm().is_right() { - let can_transmute = match (value.layout.abi, to.abi) { - (Abi::Scalar(s1), Abi::Scalar(s2)) => { + let can_transmute = match (value.layout.backend_repr, to.backend_repr) { + (BackendRepr::Scalar(s1), BackendRepr::Scalar(s2)) => { s1.size(&self.ecx) == s2.size(&self.ecx) && !matches!(s1.primitive(), Primitive::Pointer(..)) } - (Abi::ScalarPair(a1, b1), Abi::ScalarPair(a2, b2)) => { + (BackendRepr::ScalarPair(a1, b1), BackendRepr::ScalarPair(a2, b2)) => { a1.size(&self.ecx) == a2.size(&self.ecx) && b1.size(&self.ecx) == b2.size(&self.ecx) && // The alignment of the second component determines its offset, so that also needs to match. @@ -1241,7 +1244,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let as_bits = |value| { let constant = self.evaluated[value].as_ref()?; - if layout.abi.is_scalar() { + if layout.backend_repr.is_scalar() { let scalar = self.ecx.read_scalar(constant).discard_err()?; scalar.to_bits(constant.layout.size).discard_err() } else { @@ -1497,12 +1500,12 @@ fn op_to_prop_const<'tcx>( // Do not synthetize too large constants. Codegen will just memcpy them, which we'd like to // avoid. - if !matches!(op.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + if !matches!(op.layout.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) { return None; } // If this constant has scalar ABI, return it as a `ConstValue::Scalar`. - if let Abi::Scalar(abi::Scalar::Initialized { .. }) = op.layout.abi + if let BackendRepr::Scalar(abi::Scalar::Initialized { .. }) = op.layout.backend_repr && let Some(scalar) = ecx.read_scalar(op).discard_err() { if !scalar.try_to_scalar_int().is_ok() { diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 08923748eb27..0604665642ab 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -4,6 +4,7 @@ use std::fmt::Debug; +use rustc_abi::{BackendRepr, FieldIdx, HasDataLayout, Size, TargetDataLayout, VariantIdx}; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error, interp_ok, @@ -19,7 +20,6 @@ use rustc_middle::mir::*; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::{self, ConstInt, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; -use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, VariantIdx}; use tracing::{debug, instrument, trace}; use crate::errors::{AssertLint, AssertLintKind}; @@ -557,7 +557,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?; let val = self.use_ecx(|this| this.ecx.binary_op(bin_op, &left, &right))?; - if matches!(val.layout.abi, Abi::ScalarPair(..)) { + if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) { // FIXME `Value` should properly support pairs in `Immediate`... but currently // it does not. let (val, overflow) = val.to_pair(&self.ecx); @@ -651,9 +651,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let to = self.ecx.layout_of(to).ok()?; // `offset` for immediates only supports scalar/scalar-pair ABIs, // so bail out if the target is not one. - match (value.layout.abi, to.abi) { - (Abi::Scalar(..), Abi::Scalar(..)) => {} - (Abi::ScalarPair(..), Abi::ScalarPair(..)) => {} + match (value.layout.backend_repr, to.backend_repr) { + (BackendRepr::Scalar(..), BackendRepr::Scalar(..)) => {} + (BackendRepr::ScalarPair(..), BackendRepr::ScalarPair(..)) => {} _ => return None, } diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 0b6cf82ca8b4..7260c12f2784 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -81,8 +81,12 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { let meta_items = attr.meta_item_list().unwrap_or_default(); for meta_item in meta_items { match meta_item.name_or_empty() { + // FIXME: this never was about ABI and now this dump arg is confusing sym::abi => { - tcx.dcx().emit_err(LayoutAbi { span, abi: format!("{:?}", ty_layout.abi) }); + tcx.dcx().emit_err(LayoutAbi { + span, + abi: format!("{:?}", ty_layout.backend_repr), + }); } sym::align => { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 410bf0f40f46..af24fd23f50b 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -56,7 +56,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::LayoutData Stable<'tcx> for rustc_abi::TagEncoding { } } -impl<'tcx> Stable<'tcx> for rustc_abi::Abi { +impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr { type T = ValueAbi; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match *self { - rustc_abi::Abi::Uninhabited => ValueAbi::Uninhabited, - rustc_abi::Abi::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables)), - rustc_abi::Abi::ScalarPair(first, second) => { + rustc_abi::BackendRepr::Uninhabited => ValueAbi::Uninhabited, + rustc_abi::BackendRepr::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables)), + rustc_abi::BackendRepr::ScalarPair(first, second) => { ValueAbi::ScalarPair(first.stable(tables), second.stable(tables)) } - rustc_abi::Abi::Vector { element, count } => { + rustc_abi::BackendRepr::Vector { element, count } => { ValueAbi::Vector { element: element.stable(tables), count } } - rustc_abi::Abi::Aggregate { sized } => ValueAbi::Aggregate { sized }, + rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized }, } } } diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index ffec76370d02..d1234c3cc91d 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -1,5 +1,7 @@ use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; -use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; +use crate::abi::{ + self, BackendRepr, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout, +}; use crate::spec::HasTargetSpec; use crate::spec::abi::Abi as SpecAbi; @@ -21,8 +23,8 @@ enum FloatConv { struct CannotUseFpConv; fn is_loongarch_aggregate(arg: &ArgAbi<'_, Ty>) -> bool { - match arg.layout.abi { - Abi::Vector { .. } => true, + match arg.layout.backend_repr { + BackendRepr::Vector { .. } => true, _ => arg.layout.is_aggregate(), } } @@ -38,8 +40,8 @@ fn should_use_fp_conv_helper<'a, Ty, C>( where Ty: TyAbiInterface<'a, C> + Copy, { - match arg_layout.abi { - Abi::Scalar(scalar) => match scalar.primitive() { + match arg_layout.backend_repr { + BackendRepr::Scalar(scalar) => match scalar.primitive() { abi::Int(..) | abi::Pointer(_) => { if arg_layout.size.bits() > xlen { return Err(CannotUseFpConv); @@ -77,8 +79,8 @@ where } } }, - Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv), - Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields { + BackendRepr::Vector { .. } | BackendRepr::Uninhabited => return Err(CannotUseFpConv), + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") } @@ -311,7 +313,7 @@ fn classify_arg<'a, Ty, C>( } fn extend_integer_width(arg: &mut ArgAbi<'_, Ty>, xlen: u64) { - if let Abi::Scalar(scalar) = arg.layout.abi { + if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr { if let abi::Int(i, _) = scalar.primitive() { // 32-bit integers are always sign-extended if i.size().bits() == 32 && xlen > 32 { diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs index 2c3258c8d42d..5bdf4c2ad77f 100644 --- a/compiler/rustc_target/src/callconv/mips64.rs +++ b/compiler/rustc_target/src/callconv/mips64.rs @@ -5,7 +5,7 @@ use crate::abi::{self, HasDataLayout, Size, TyAbiInterface}; fn extend_integer_width_mips(arg: &mut ArgAbi<'_, Ty>, bits: u64) { // Always sign extend u32 values on 64-bit mips - if let abi::Abi::Scalar(scalar) = arg.layout.abi { + if let abi::BackendRepr::Scalar(scalar) = arg.layout.backend_repr { if let abi::Int(i, signed) = scalar.primitive() { if !signed && i.size().bits() == 32 { if let PassMode::Direct(ref mut attrs) = arg.mode { @@ -24,8 +24,8 @@ where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { - match ret.layout.field(cx, i).abi { - abi::Abi::Scalar(scalar) => match scalar.primitive() { + match ret.layout.field(cx, i).backend_repr { + abi::BackendRepr::Scalar(scalar) => match scalar.primitive() { abi::Float(abi::F32) => Some(Reg::f32()), abi::Float(abi::F64) => Some(Reg::f64()), _ => None, @@ -109,7 +109,7 @@ where let offset = arg.layout.fields.offset(i); // We only care about aligned doubles - if let abi::Abi::Scalar(scalar) = field.abi { + if let abi::BackendRepr::Scalar(scalar) = field.backend_repr { if scalar.primitive() == abi::Float(abi::F64) { if offset.is_aligned(dl.f64_align.abi) { // Insert enough integers to cover [last_offset, offset) diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 25b001b57e8a..8c3df9c426b0 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -6,7 +6,8 @@ use rustc_macros::HashStable_Generic; use rustc_span::Symbol; use crate::abi::{ - self, Abi, AddressSpace, Align, HasDataLayout, Pointer, Size, TyAbiInterface, TyAndLayout, + self, AddressSpace, Align, BackendRepr, HasDataLayout, Pointer, Size, TyAbiInterface, + TyAndLayout, }; use crate::spec::abi::Abi as SpecAbi; use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi}; @@ -350,15 +351,17 @@ impl<'a, Ty> ArgAbi<'a, Ty> { layout: TyAndLayout<'a, Ty>, scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, abi::Scalar, Size) -> ArgAttributes, ) -> Self { - let mode = match layout.abi { - Abi::Uninhabited => PassMode::Ignore, - Abi::Scalar(scalar) => PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)), - Abi::ScalarPair(a, b) => PassMode::Pair( + let mode = match layout.backend_repr { + BackendRepr::Uninhabited => PassMode::Ignore, + BackendRepr::Scalar(scalar) => { + PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)) + } + BackendRepr::ScalarPair(a, b) => PassMode::Pair( scalar_attrs(&layout, a, Size::ZERO), scalar_attrs(&layout, b, a.size(cx).align_to(b.align(cx).abi)), ), - Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()), - Abi::Aggregate { .. } => Self::indirect_pass_mode(&layout), + BackendRepr::Vector { .. } => PassMode::Direct(ArgAttributes::new()), + BackendRepr::Memory { .. } => Self::indirect_pass_mode(&layout), }; ArgAbi { layout, mode } } @@ -460,7 +463,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { pub fn extend_integer_width_to(&mut self, bits: u64) { // Only integers have signedness - if let Abi::Scalar(scalar) = self.layout.abi { + if let BackendRepr::Scalar(scalar) = self.layout.backend_repr { if let abi::Int(i, signed) = scalar.primitive() { if i.size().bits() < bits { if let PassMode::Direct(ref mut attrs) = self.mode { @@ -512,7 +515,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { // That elevates any type difference to an ABI difference since we just use the // full Rust type as the LLVM argument/return type. if matches!(self.mode, PassMode::Direct(..)) - && matches!(self.layout.abi, Abi::Aggregate { .. }) + && matches!(self.layout.backend_repr, BackendRepr::Memory { .. }) { // For aggregates in `Direct` mode to be compatible, the types need to be equal. self.layout.ty == other.layout.ty @@ -791,8 +794,8 @@ impl<'a, Ty> FnAbi<'a, Ty> { continue; } - match arg.layout.abi { - Abi::Aggregate { .. } => {} + match arg.layout.backend_repr { + BackendRepr::Memory { .. } => {} // This is a fun case! The gist of what this is doing is // that we want callers and callees to always agree on the @@ -813,7 +816,9 @@ impl<'a, Ty> FnAbi<'a, Ty> { // Note that the intrinsic ABI is exempt here as // that's how we connect up to LLVM and it's unstable // anyway, we control all calls to it in libstd. - Abi::Vector { .. } if abi != SpecAbi::RustIntrinsic && spec.simd_types_indirect => { + BackendRepr::Vector { .. } + if abi != SpecAbi::RustIntrinsic && spec.simd_types_indirect => + { arg.make_indirect(); continue; } diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index f96169e6a618..c0298edb5ab7 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -4,8 +4,10 @@ // Reference: Clang RISC-V ELF psABI lowering code // https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773 +use rustc_abi::{BackendRepr, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; + +use crate::abi; use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; -use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; use crate::spec::HasTargetSpec; use crate::spec::abi::Abi as SpecAbi; @@ -27,8 +29,8 @@ enum FloatConv { struct CannotUseFpConv; fn is_riscv_aggregate(arg: &ArgAbi<'_, Ty>) -> bool { - match arg.layout.abi { - Abi::Vector { .. } => true, + match arg.layout.backend_repr { + BackendRepr::Vector { .. } => true, _ => arg.layout.is_aggregate(), } } @@ -44,8 +46,8 @@ fn should_use_fp_conv_helper<'a, Ty, C>( where Ty: TyAbiInterface<'a, C> + Copy, { - match arg_layout.abi { - Abi::Scalar(scalar) => match scalar.primitive() { + match arg_layout.backend_repr { + BackendRepr::Scalar(scalar) => match scalar.primitive() { abi::Int(..) | abi::Pointer(_) => { if arg_layout.size.bits() > xlen { return Err(CannotUseFpConv); @@ -83,8 +85,8 @@ where } } }, - Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv), - Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields { + BackendRepr::Vector { .. } | BackendRepr::Uninhabited => return Err(CannotUseFpConv), + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") } @@ -317,7 +319,7 @@ fn classify_arg<'a, Ty, C>( } fn extend_integer_width(arg: &mut ArgAbi<'_, Ty>, xlen: u64) { - if let Abi::Scalar(scalar) = arg.layout.abi { + if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr { if let abi::Int(i, _) = scalar.primitive() { // 32-bit integers are always sign-extended if i.size().bits() == 32 && xlen > 32 { diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index 835353f76fc9..313d8730399b 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -109,11 +109,11 @@ where return data; } - match layout.abi { - abi::Abi::Scalar(scalar) => { + match layout.backend_repr { + abi::BackendRepr::Scalar(scalar) => { data = arg_scalar(cx, &scalar, offset, data); } - abi::Abi::Aggregate { .. } => { + abi::BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { if offset < layout.fields.offset(i) { offset = layout.fields.offset(i); @@ -122,7 +122,7 @@ where } } _ => { - if let abi::Abi::ScalarPair(scalar1, scalar2) = &layout.abi { + if let abi::BackendRepr::ScalarPair(scalar1, scalar2) = &layout.backend_repr { data = arg_scalar_pair(cx, scalar1, scalar2, offset, data); } } diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index e907beecb381..a5af975d4d24 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -1,6 +1,6 @@ use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind}; use crate::abi::{ - Abi, AddressSpace, Align, Float, HasDataLayout, Pointer, TyAbiInterface, TyAndLayout, + AddressSpace, Align, BackendRepr, Float, HasDataLayout, Pointer, TyAbiInterface, TyAndLayout, }; use crate::spec::HasTargetSpec; use crate::spec::abi::Abi as SpecAbi; @@ -105,10 +105,12 @@ where where Ty: TyAbiInterface<'a, C> + Copy, { - match layout.abi { - Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) => false, - Abi::Vector { .. } => true, - Abi::Aggregate { .. } => { + match layout.backend_repr { + BackendRepr::Uninhabited + | BackendRepr::Scalar(_) + | BackendRepr::ScalarPair(..) => false, + BackendRepr::Vector { .. } => true, + BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { if contains_vector(cx, layout.field(cx, i)) { return true; @@ -223,9 +225,9 @@ where // Intrinsics themselves are not actual "real" functions, so theres no need to change their ABIs. && abi != SpecAbi::RustIntrinsic { - let has_float = match fn_abi.ret.layout.abi { - Abi::Scalar(s) => matches!(s.primitive(), Float(_)), - Abi::ScalarPair(s1, s2) => { + let has_float = match fn_abi.ret.layout.backend_repr { + BackendRepr::Scalar(s) => matches!(s.primitive(), Float(_)), + BackendRepr::ScalarPair(s1, s2) => { matches!(s1.primitive(), Float(_)) || matches!(s2.primitive(), Float(_)) } _ => false, // anyway not passed via registers on x86 diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index 9910e623ac9b..bd101b23ea16 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -1,8 +1,10 @@ // The classification code for the x86_64 ABI is taken from the clay language // https://github.com/jckarter/clay/blob/db0bd2702ab0b6e48965cd85f8859bbd5f60e48e/compiler/externals.cpp +use rustc_abi::{BackendRepr, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; + +use crate::abi; use crate::abi::call::{ArgAbi, CastTarget, FnAbi, Reg, RegKind}; -use crate::abi::{self, Abi, HasDataLayout, Size, TyAbiInterface, TyAndLayout}; /// Classification of "eightbyte" components. // N.B., the order of the variants is from general to specific, @@ -46,17 +48,17 @@ where return Ok(()); } - let mut c = match layout.abi { - Abi::Uninhabited => return Ok(()), + let mut c = match layout.backend_repr { + BackendRepr::Uninhabited => return Ok(()), - Abi::Scalar(scalar) => match scalar.primitive() { + BackendRepr::Scalar(scalar) => match scalar.primitive() { abi::Int(..) | abi::Pointer(_) => Class::Int, abi::Float(_) => Class::Sse, }, - Abi::Vector { .. } => Class::Sse, + BackendRepr::Vector { .. } => Class::Sse, - Abi::ScalarPair(..) | Abi::Aggregate { .. } => { + BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { let field_off = off + layout.fields.offset(i); classify(cx, layout.field(cx, i), cls, field_off)?; diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs index e5a20b248e43..83d94cb11baf 100644 --- a/compiler/rustc_target/src/callconv/x86_win64.rs +++ b/compiler/rustc_target/src/callconv/x86_win64.rs @@ -1,25 +1,28 @@ +use rustc_abi::{BackendRepr, Float, Primitive}; + use crate::abi::call::{ArgAbi, FnAbi, Reg}; -use crate::abi::{Abi, Float, Primitive}; use crate::spec::HasTargetSpec; // Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing pub(crate) fn compute_abi_info(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) { let fixup = |a: &mut ArgAbi<'_, Ty>| { - match a.layout.abi { - Abi::Uninhabited | Abi::Aggregate { sized: false } => {} - Abi::ScalarPair(..) | Abi::Aggregate { sized: true } => match a.layout.size.bits() { - 8 => a.cast_to(Reg::i8()), - 16 => a.cast_to(Reg::i16()), - 32 => a.cast_to(Reg::i32()), - 64 => a.cast_to(Reg::i64()), - _ => a.make_indirect(), - }, - Abi::Vector { .. } => { + match a.layout.backend_repr { + BackendRepr::Uninhabited | BackendRepr::Memory { sized: false } => {} + BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => { + match a.layout.size.bits() { + 8 => a.cast_to(Reg::i8()), + 16 => a.cast_to(Reg::i16()), + 32 => a.cast_to(Reg::i32()), + 64 => a.cast_to(Reg::i64()), + _ => a.make_indirect(), + } + } + BackendRepr::Vector { .. } => { // FIXME(eddyb) there should be a size cap here // (probably what clang calls "illegal vectors"). } - Abi::Scalar(scalar) => { + BackendRepr::Scalar(scalar) => { // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up // with what LLVM expects. if a.layout.size.bytes() > 8 diff --git a/compiler/rustc_target/src/callconv/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs index e1728b08a396..9d313d165003 100644 --- a/compiler/rustc_target/src/callconv/xtensa.rs +++ b/compiler/rustc_target/src/callconv/xtensa.rs @@ -6,7 +6,7 @@ //! Section 2.3 from the Xtensa programmers guide. use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform}; -use crate::abi::{Abi, HasDataLayout, Size, TyAbiInterface}; +use crate::abi::{BackendRepr, HasDataLayout, Size, TyAbiInterface}; use crate::spec::HasTargetSpec; const NUM_ARG_GPRS: u64 = 6; @@ -114,8 +114,8 @@ where } fn is_xtensa_aggregate<'a, Ty>(arg: &ArgAbi<'a, Ty>) -> bool { - match arg.layout.abi { - Abi::Vector { .. } => true, + match arg.layout.backend_repr { + BackendRepr::Vector { .. } => true, _ => arg.layout.is_aggregate(), } } diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index a068f25fe35e..3ddf023cf97d 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{ }; use rustc_span::Span; use rustc_span::symbol::Symbol; -use rustc_target::abi::Abi; +use rustc_target::abi::BackendRepr; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -523,8 +523,8 @@ fn check_receiver_correct<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: // e.g., `Rc<()>` let unit_receiver_ty = receiver_for_self_ty(tcx, receiver_ty, tcx.types.unit, method_def_id); - match tcx.layout_of(param_env.and(unit_receiver_ty)).map(|l| l.abi) { - Ok(Abi::Scalar(..)) => (), + match tcx.layout_of(param_env.and(unit_receiver_ty)).map(|l| l.backend_repr) { + Ok(BackendRepr::Scalar(..)) => (), abi => { tcx.dcx().span_delayed_bug( tcx.def_span(method_def_id), @@ -538,8 +538,8 @@ fn check_receiver_correct<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: // e.g., `Rc` let trait_object_receiver = receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method_def_id); - match tcx.layout_of(param_env.and(trait_object_receiver)).map(|l| l.abi) { - Ok(Abi::ScalarPair(..)) => (), + match tcx.layout_of(param_env.and(trait_object_receiver)).map(|l| l.backend_repr) { + Ok(BackendRepr::ScalarPair(..)) => (), abi => { tcx.dcx().span_delayed_bug( tcx.def_span(method_def_id), diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 48149a08de88..722ef5f45698 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -1,7 +1,7 @@ use std::iter; use rustc_abi::Primitive::Pointer; -use rustc_abi::{Abi, PointerKind, Scalar, Size}; +use rustc_abi::{BackendRepr, PointerKind, Scalar, Size}; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_middle::bug; @@ -469,7 +469,7 @@ fn fn_abi_sanity_check<'tcx>( // careful. Scalar/ScalarPair is fine, since backends will generally use // `layout.abi` and ignore everything else. We should just reject `Aggregate` // entirely here, but some targets need to be fixed first. - if matches!(arg.layout.abi, Abi::Aggregate { .. }) { + if matches!(arg.layout.backend_repr, BackendRepr::Memory { .. }) { // For an unsized type we'd only pass the sized prefix, so there is no universe // in which we ever want to allow this. assert!( @@ -500,7 +500,7 @@ fn fn_abi_sanity_check<'tcx>( // Similar to `Direct`, we need to make sure that backends use `layout.abi` and // ignore the rest of the layout. assert!( - matches!(arg.layout.abi, Abi::ScalarPair(..)), + matches!(arg.layout.backend_repr, BackendRepr::ScalarPair(..)), "PassMode::Pair for type {}", arg.layout.ty ); @@ -658,9 +658,9 @@ fn fn_abi_adjust_for_abi<'tcx>( fn unadjust<'tcx>(arg: &mut ArgAbi<'tcx, Ty<'tcx>>) { // This still uses `PassMode::Pair` for ScalarPair types. That's unlikely to be intended, // but who knows what breaks if we change this now. - if matches!(arg.layout.abi, Abi::Aggregate { .. }) { + if matches!(arg.layout.backend_repr, BackendRepr::Memory { .. }) { assert!( - arg.layout.abi.is_sized(), + arg.layout.backend_repr.is_sized(), "'unadjusted' ABI does not support unsized arguments" ); } @@ -731,8 +731,8 @@ fn make_thin_self_ptr<'tcx>( // FIXME (mikeyhew) change this to use &own if it is ever added to the language Ty::new_mut_ptr(tcx, layout.ty) } else { - match layout.abi { - Abi::ScalarPair(..) | Abi::Scalar(..) => (), + match layout.backend_repr { + BackendRepr::ScalarPair(..) | BackendRepr::Scalar(..) => (), _ => bug!("receiver type has unsupported layout: {:?}", layout), } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 94b80e2694d8..5ca7afe24539 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -5,8 +5,9 @@ use hir::def_id::DefId; use rustc_abi::Integer::{I8, I32}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ - Abi, AbiAndPrefAlign, AddressSpace, Align, FieldsShape, HasDataLayout, LayoutCalculatorError, - LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange, + AbiAndPrefAlign, AddressSpace, Align, BackendRepr, FieldsShape, HasDataLayout, + LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, + Variants, WrappingRange, }; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; @@ -173,7 +174,9 @@ fn layout_of_uncached<'tcx>( let mut layout = LayoutData::clone(&layout.0); match *pat { ty::PatternKind::Range { start, end, include_end } => { - if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &mut layout.abi { + if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) = + &mut layout.backend_repr + { if let Some(start) = start { scalar.valid_range_mut().start = start .try_to_bits(tcx, param_env) @@ -275,7 +278,7 @@ fn layout_of_uncached<'tcx>( return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr))); } - let Abi::Scalar(metadata) = metadata_layout.abi else { + let BackendRepr::Scalar(metadata) = metadata_layout.backend_repr else { return Err(error(cx, LayoutError::Unknown(pointee))); }; @@ -330,9 +333,9 @@ fn layout_of_uncached<'tcx>( .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?; let abi = if count != 0 && ty.is_privately_uninhabited(tcx, param_env) { - Abi::Uninhabited + BackendRepr::Uninhabited } else { - Abi::Aggregate { sized: true } + BackendRepr::Memory { sized: true } }; let largest_niche = if count != 0 { element.largest_niche } else { None }; @@ -340,7 +343,7 @@ fn layout_of_uncached<'tcx>( tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: element.size, count }, - abi, + backend_repr: abi, largest_niche, align: element.align, size, @@ -353,7 +356,7 @@ fn layout_of_uncached<'tcx>( tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: element.size, count: 0 }, - abi: Abi::Aggregate { sized: false }, + backend_repr: BackendRepr::Memory { sized: false }, largest_niche: None, align: element.align, size: Size::ZERO, @@ -364,7 +367,7 @@ fn layout_of_uncached<'tcx>( ty::Str => tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, - abi: Abi::Aggregate { sized: false }, + backend_repr: BackendRepr::Memory { sized: false }, largest_niche: None, align: dl.i8_align, size: Size::ZERO, @@ -384,8 +387,8 @@ fn layout_of_uncached<'tcx>( &ReprOptions::default(), StructKind::AlwaysSized, )?; - match unit.abi { - Abi::Aggregate { ref mut sized } => *sized = false, + match unit.backend_repr { + BackendRepr::Memory { ref mut sized } => *sized = false, _ => bug!(), } tcx.mk_layout(unit) @@ -500,7 +503,7 @@ fn layout_of_uncached<'tcx>( // Compute the ABI of the element type: let e_ly = cx.layout_of(e_ty)?; - let Abi::Scalar(e_abi) = e_ly.abi else { + let BackendRepr::Scalar(e_abi) = e_ly.backend_repr else { // This error isn't caught in typeck, e.g., if // the element type of the vector is generic. tcx.dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty }); @@ -516,12 +519,12 @@ fn layout_of_uncached<'tcx>( // Non-power-of-two vectors have padding up to the next power-of-two. // If we're a packed repr, remove the padding while keeping the alignment as close // to a vector as possible. - (Abi::Aggregate { sized: true }, AbiAndPrefAlign { + (BackendRepr::Memory { sized: true }, AbiAndPrefAlign { abi: Align::max_for_offset(size), pref: dl.vector_align(size).pref, }) } else { - (Abi::Vector { element: e_abi, count: e_len }, dl.vector_align(size)) + (BackendRepr::Vector { element: e_abi, count: e_len }, dl.vector_align(size)) }; let size = size.align_to(align.abi); @@ -535,7 +538,7 @@ fn layout_of_uncached<'tcx>( tcx.mk_layout(LayoutData { variants: Variants::Single { index: FIRST_VARIANT }, fields, - abi, + backend_repr: abi, largest_niche: e_ly.largest_niche, size, align, @@ -985,10 +988,12 @@ fn coroutine_layout<'tcx>( size = size.align_to(align.abi); - let abi = if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi.is_uninhabited()) { - Abi::Uninhabited + let abi = if prefix.backend_repr.is_uninhabited() + || variants.iter().all(|v| v.backend_repr.is_uninhabited()) + { + BackendRepr::Uninhabited } else { - Abi::Aggregate { sized: true } + BackendRepr::Memory { sized: true } }; let layout = tcx.mk_layout(LayoutData { @@ -999,7 +1004,7 @@ fn coroutine_layout<'tcx>( variants, }, fields: outer_fields, - abi, + backend_repr: abi, // Suppress niches inside coroutines. If the niche is inside a field that is aliased (due to // self-referentiality), getting the discriminant can cause aliasing violations. // `UnsafeCell` blocks niches for the same reason, but we don't yet have `UnsafePinned` that diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 3db5a4f1805c..f43feb552b28 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -66,12 +66,12 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) { // Verify the ABI mandated alignment and size. - let align = layout.abi.inherent_align(cx).map(|align| align.abi); - let size = layout.abi.inherent_size(cx); + let align = layout.backend_repr.inherent_align(cx).map(|align| align.abi); + let size = layout.backend_repr.inherent_size(cx); let Some((align, size)) = align.zip(size) else { assert_matches!( - layout.layout.abi(), - Abi::Uninhabited | Abi::Aggregate { .. }, + layout.layout.backend_repr(), + BackendRepr::Uninhabited | BackendRepr::Memory { .. }, "ABI unexpectedly missing alignment and/or size in {layout:#?}" ); return; @@ -88,12 +88,12 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa ); // Verify per-ABI invariants - match layout.layout.abi() { - Abi::Scalar(_) => { + match layout.layout.backend_repr() { + BackendRepr::Scalar(_) => { // Check that this matches the underlying field. let inner = skip_newtypes(cx, layout); assert!( - matches!(inner.layout.abi(), Abi::Scalar(_)), + matches!(inner.layout.backend_repr(), BackendRepr::Scalar(_)), "`Scalar` type {} is newtype around non-`Scalar` type {}", layout.ty, inner.ty @@ -132,7 +132,7 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa "`Scalar` field with bad align in {inner:#?}", ); assert!( - matches!(field.abi, Abi::Scalar(_)), + matches!(field.backend_repr, BackendRepr::Scalar(_)), "`Scalar` field with bad ABI in {inner:#?}", ); } @@ -141,11 +141,11 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa } } } - Abi::ScalarPair(scalar1, scalar2) => { + BackendRepr::ScalarPair(scalar1, scalar2) => { // Check that the underlying pair of fields matches. let inner = skip_newtypes(cx, layout); assert!( - matches!(inner.layout.abi(), Abi::ScalarPair(..)), + matches!(inner.layout.backend_repr(), BackendRepr::ScalarPair(..)), "`ScalarPair` type {} is newtype around non-`ScalarPair` type {}", layout.ty, inner.ty @@ -208,8 +208,8 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa "`ScalarPair` first field with bad align in {inner:#?}", ); assert_matches!( - field1.abi, - Abi::Scalar(_), + field1.backend_repr, + BackendRepr::Scalar(_), "`ScalarPair` first field with bad ABI in {inner:#?}", ); let field2_offset = size1.align_to(align2); @@ -226,16 +226,16 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa "`ScalarPair` second field with bad align in {inner:#?}", ); assert_matches!( - field2.abi, - Abi::Scalar(_), + field2.backend_repr, + BackendRepr::Scalar(_), "`ScalarPair` second field with bad ABI in {inner:#?}", ); } - Abi::Vector { element, .. } => { + BackendRepr::Vector { element, .. } => { assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`. // FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair. } - Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check. + BackendRepr::Uninhabited | BackendRepr::Memory { .. } => {} // Nothing to check. } } @@ -274,13 +274,13 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa // The top-level ABI and the ABI of the variants should be coherent. let scalar_coherent = |s1: Scalar, s2: Scalar| s1.size(cx) == s2.size(cx) && s1.align(cx) == s2.align(cx); - let abi_coherent = match (layout.abi, variant.abi) { - (Abi::Scalar(s1), Abi::Scalar(s2)) => scalar_coherent(s1, s2), - (Abi::ScalarPair(a1, b1), Abi::ScalarPair(a2, b2)) => { + let abi_coherent = match (layout.backend_repr, variant.backend_repr) { + (BackendRepr::Scalar(s1), BackendRepr::Scalar(s2)) => scalar_coherent(s1, s2), + (BackendRepr::ScalarPair(a1, b1), BackendRepr::ScalarPair(a2, b2)) => { scalar_coherent(a1, a2) && scalar_coherent(b1, b2) } - (Abi::Uninhabited, _) => true, - (Abi::Aggregate { .. }, _) => true, + (BackendRepr::Uninhabited, _) => true, + (BackendRepr::Memory { .. }, _) => true, _ => false, }; if !abi_coherent { From 6d5d8b5071d4982d0886379f4e557556cc761469 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 29 Oct 2024 13:37:59 -0700 Subject: [PATCH 16/56] cg_clif: `rustc_abi::Abi` => `BackendRepr` --- .../rustc_codegen_cranelift/src/abi/mod.rs | 2 +- .../src/abi/pass_mode.rs | 28 ++++----- compiler/rustc_codegen_cranelift/src/base.rs | 8 +-- .../src/discriminant.rs | 4 +- .../src/intrinsics/mod.rs | 10 ++-- compiler/rustc_codegen_cranelift/src/lib.rs | 2 +- .../src/value_and_place.rs | 57 +++++++++++-------- .../rustc_codegen_cranelift/src/vtable.rs | 4 +- 8 files changed, 62 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 892ec3e95855..089b09d06aef 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -193,7 +193,7 @@ fn make_local_place<'tcx>( ); } let place = if is_ssa { - if let rustc_target::abi::Abi::ScalarPair(_, _) = layout.abi { + if let BackendRepr::ScalarPair(_, _) = layout.backend_repr { CPlace::new_var_pair(fx, local, layout) } else { CPlace::new_var(fx, local, layout) diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 38c322b5e045..ad0a13dc7e57 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -78,19 +78,19 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]> { match self.mode { PassMode::Ignore => smallvec![], - PassMode::Direct(attrs) => match self.layout.abi { - Abi::Scalar(scalar) => smallvec![apply_arg_attrs_to_abi_param( + PassMode::Direct(attrs) => match self.layout.backend_repr { + BackendRepr::Scalar(scalar) => smallvec![apply_arg_attrs_to_abi_param( AbiParam::new(scalar_to_clif_type(tcx, scalar)), attrs )], - Abi::Vector { .. } => { + BackendRepr::Vector { .. } => { let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout); smallvec![AbiParam::new(vector_ty)] } - _ => unreachable!("{:?}", self.layout.abi), + _ => unreachable!("{:?}", self.layout.backend_repr), }, - PassMode::Pair(attrs_a, attrs_b) => match self.layout.abi { - Abi::ScalarPair(a, b) => { + PassMode::Pair(attrs_a, attrs_b) => match self.layout.backend_repr { + BackendRepr::ScalarPair(a, b) => { let a = scalar_to_clif_type(tcx, a); let b = scalar_to_clif_type(tcx, b); smallvec![ @@ -98,7 +98,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { apply_arg_attrs_to_abi_param(AbiParam::new(b), attrs_b), ] } - _ => unreachable!("{:?}", self.layout.abi), + _ => unreachable!("{:?}", self.layout.backend_repr), }, PassMode::Cast { ref cast, pad_i32 } => { assert!(!pad_i32, "padding support not yet implemented"); @@ -130,23 +130,23 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option, Vec) { match self.mode { PassMode::Ignore => (None, vec![]), - PassMode::Direct(_) => match self.layout.abi { - Abi::Scalar(scalar) => { + PassMode::Direct(_) => match self.layout.backend_repr { + BackendRepr::Scalar(scalar) => { (None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))]) } - Abi::Vector { .. } => { + BackendRepr::Vector { .. } => { let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout); (None, vec![AbiParam::new(vector_ty)]) } - _ => unreachable!("{:?}", self.layout.abi), + _ => unreachable!("{:?}", self.layout.backend_repr), }, - PassMode::Pair(_, _) => match self.layout.abi { - Abi::ScalarPair(a, b) => { + PassMode::Pair(_, _) => match self.layout.backend_repr { + BackendRepr::ScalarPair(a, b) => { let a = scalar_to_clif_type(tcx, a); let b = scalar_to_clif_type(tcx, b); (None, vec![AbiParam::new(a), AbiParam::new(b)]) } - _ => unreachable!("{:?}", self.layout.abi), + _ => unreachable!("{:?}", self.layout.backend_repr), }, PassMode::Cast { ref cast, .. } => { (None, cast_target_to_abi_params(cast).into_iter().collect()) diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index a681e6d9f3cd..99e39971b747 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -290,7 +290,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { let arg_uninhabited = fx .mir .args_iter() - .any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).abi.is_uninhabited()); + .any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).is_uninhabited()); if arg_uninhabited { fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]); fx.bcx.switch_to_block(fx.block_map[START_BLOCK]); @@ -644,9 +644,9 @@ fn codegen_stmt<'tcx>( _ => unreachable!("un op Neg for {:?}", layout.ty), } } - UnOp::PtrMetadata => match layout.abi { - Abi::Scalar(_) => CValue::zst(dest_layout), - Abi::ScalarPair(_, _) => { + UnOp::PtrMetadata => match layout.backend_repr { + BackendRepr::Scalar(_) => CValue::zst(dest_layout), + BackendRepr::ScalarPair(_, _) => { CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout) } _ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"), diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index d462dcd63a92..45794a426658 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -14,7 +14,7 @@ pub(crate) fn codegen_set_discriminant<'tcx>( variant_index: VariantIdx, ) { let layout = place.layout(); - if layout.for_variant(fx, variant_index).abi.is_uninhabited() { + if layout.for_variant(fx, variant_index).is_uninhabited() { return; } match layout.variants { @@ -80,7 +80,7 @@ pub(crate) fn codegen_get_discriminant<'tcx>( ) { let layout = value.layout(); - if layout.abi.is_uninhabited() { + if layout.is_uninhabited() { return; } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 35f0ccff3f99..aae6794891d7 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -51,8 +51,8 @@ fn report_atomic_type_validation_error<'tcx>( } pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Type { - let (element, count) = match layout.abi { - Abi::Vector { element, count } => (element, count), + let (element, count) = match layout.backend_repr { + BackendRepr::Vector { element, count } => (element, count), _ => unreachable!(), }; @@ -505,7 +505,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = fx.layout_of(generic_args.type_at(0)); // Note: Can't use is_unsized here as truly unsized types need to take the fixed size // branch - let meta = if let Abi::ScalarPair(_, _) = ptr.layout().abi { + let meta = if let BackendRepr::ScalarPair(_, _) = ptr.layout().backend_repr { Some(ptr.load_scalar_pair(fx).1) } else { None @@ -519,7 +519,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = fx.layout_of(generic_args.type_at(0)); // Note: Can't use is_unsized here as truly unsized types need to take the fixed size // branch - let meta = if let Abi::ScalarPair(_, _) = ptr.layout().abi { + let meta = if let BackendRepr::ScalarPair(_, _) = ptr.layout().backend_repr { Some(ptr.load_scalar_pair(fx).1) } else { None @@ -693,7 +693,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = fx.layout_of(ty); let msg_str = with_no_visible_paths!({ with_no_trimmed_paths!({ - if layout.abi.is_uninhabited() { + if layout.is_uninhabited() { // Use this error even for the other intrinsics as it is more precise. format!("attempted to instantiate uninhabited type `{}`", ty) } else if intrinsic == sym::assert_zero_valid { diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index b6f9ce8fc298..602b1b982002 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -92,6 +92,7 @@ mod prelude { StackSlotData, StackSlotKind, TrapCode, Type, Value, types, }; pub(crate) use cranelift_module::{self, DataDescription, FuncId, Linkage, Module}; + pub(crate) use rustc_abi::{BackendRepr, FIRST_VARIANT, FieldIdx, Scalar, Size, VariantIdx}; pub(crate) use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE}; pub(crate) use rustc_index::Idx; @@ -101,7 +102,6 @@ mod prelude { self, FloatTy, Instance, InstanceKind, IntTy, ParamEnv, Ty, TyCtxt, UintTy, }; pub(crate) use rustc_span::Span; - pub(crate) use rustc_target::abi::{Abi, FIRST_VARIANT, FieldIdx, Scalar, Size, VariantIdx}; pub(crate) use crate::abi::*; pub(crate) use crate::base::{codegen_operand, codegen_place}; diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index fd77502224e4..900d7e69714e 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -131,8 +131,8 @@ impl<'tcx> CValue<'tcx> { match self.0 { CValueInner::ByRef(ptr, None) => { - let (a_scalar, b_scalar) = match self.1.abi { - Abi::ScalarPair(a, b) => (a, b), + let (a_scalar, b_scalar) = match self.1.backend_repr { + BackendRepr::ScalarPair(a, b) => (a, b), _ => unreachable!("dyn_star_force_data_on_stack({:?})", self), }; let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); @@ -164,15 +164,15 @@ impl<'tcx> CValue<'tcx> { } } - /// Load a value with layout.abi of scalar + /// Load a value with layout.backend_repr of scalar #[track_caller] pub(crate) fn load_scalar(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> Value { let layout = self.1; match self.0 { CValueInner::ByRef(ptr, None) => { - let clif_ty = match layout.abi { - Abi::Scalar(scalar) => scalar_to_clif_type(fx.tcx, scalar), - Abi::Vector { element, count } => scalar_to_clif_type(fx.tcx, element) + let clif_ty = match layout.backend_repr { + BackendRepr::Scalar(scalar) => scalar_to_clif_type(fx.tcx, scalar), + BackendRepr::Vector { element, count } => scalar_to_clif_type(fx.tcx, element) .by(u32::try_from(count).unwrap()) .unwrap(), _ => unreachable!("{:?}", layout.ty), @@ -187,14 +187,14 @@ impl<'tcx> CValue<'tcx> { } } - /// Load a value pair with layout.abi of scalar pair + /// Load a value pair with layout.backend_repr of scalar pair #[track_caller] pub(crate) fn load_scalar_pair(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> (Value, Value) { let layout = self.1; match self.0 { CValueInner::ByRef(ptr, None) => { - let (a_scalar, b_scalar) = match layout.abi { - Abi::ScalarPair(a, b) => (a, b), + let (a_scalar, b_scalar) = match layout.backend_repr { + BackendRepr::ScalarPair(a, b) => (a, b), _ => unreachable!("load_scalar_pair({:?})", self), }; let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); @@ -222,8 +222,8 @@ impl<'tcx> CValue<'tcx> { let layout = self.1; match self.0 { CValueInner::ByVal(_) => unreachable!(), - CValueInner::ByValPair(val1, val2) => match layout.abi { - Abi::ScalarPair(_, _) => { + CValueInner::ByValPair(val1, val2) => match layout.backend_repr { + BackendRepr::ScalarPair(_, _) => { let val = match field.as_u32() { 0 => val1, 1 => val2, @@ -232,7 +232,7 @@ impl<'tcx> CValue<'tcx> { let field_layout = layout.field(&*fx, usize::from(field)); CValue::by_val(val, field_layout) } - _ => unreachable!("value_field for ByValPair with abi {:?}", layout.abi), + _ => unreachable!("value_field for ByValPair with abi {:?}", layout.backend_repr), }, CValueInner::ByRef(ptr, None) => { let (field_ptr, field_layout) = codegen_field(fx, ptr, None, layout, field); @@ -360,7 +360,7 @@ impl<'tcx> CValue<'tcx> { pub(crate) fn cast_pointer_to(self, layout: TyAndLayout<'tcx>) -> Self { assert!(matches!(self.layout().ty.kind(), ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..))); assert!(matches!(layout.ty.kind(), ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..))); - assert_eq!(self.layout().abi, layout.abi); + assert_eq!(self.layout().backend_repr, layout.backend_repr); CValue(self.0, layout) } } @@ -609,8 +609,8 @@ impl<'tcx> CPlace<'tcx> { let dst_layout = self.layout(); match self.inner { CPlaceInner::Var(_local, var) => { - let data = match from.1.abi { - Abi::Scalar(_) => CValue(from.0, dst_layout).load_scalar(fx), + let data = match from.1.backend_repr { + BackendRepr::Scalar(_) => CValue(from.0, dst_layout).load_scalar(fx), _ => { let (ptr, meta) = from.force_stack(fx); assert!(meta.is_none()); @@ -621,8 +621,10 @@ impl<'tcx> CPlace<'tcx> { transmute_scalar(fx, var, data, dst_ty); } CPlaceInner::VarPair(_local, var1, var2) => { - let (data1, data2) = match from.1.abi { - Abi::ScalarPair(_, _) => CValue(from.0, dst_layout).load_scalar_pair(fx), + let (data1, data2) = match from.1.backend_repr { + BackendRepr::ScalarPair(_, _) => { + CValue(from.0, dst_layout).load_scalar_pair(fx) + } _ => { let (ptr, meta) = from.force_stack(fx); assert!(meta.is_none()); @@ -635,7 +637,9 @@ impl<'tcx> CPlace<'tcx> { } CPlaceInner::Addr(_, Some(_)) => bug!("Can't write value to unsized place {:?}", self), CPlaceInner::Addr(to_ptr, None) => { - if dst_layout.size == Size::ZERO || dst_layout.abi == Abi::Uninhabited { + if dst_layout.size == Size::ZERO + || dst_layout.backend_repr == BackendRepr::Uninhabited + { return; } @@ -646,23 +650,28 @@ impl<'tcx> CPlace<'tcx> { CValueInner::ByVal(val) => { to_ptr.store(fx, val, flags); } - CValueInner::ByValPair(val1, val2) => match from.layout().abi { - Abi::ScalarPair(a_scalar, b_scalar) => { + CValueInner::ByValPair(val1, val2) => match from.layout().backend_repr { + BackendRepr::ScalarPair(a_scalar, b_scalar) => { let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); to_ptr.store(fx, val1, flags); to_ptr.offset(fx, b_offset).store(fx, val2, flags); } - _ => bug!("Non ScalarPair abi {:?} for ByValPair CValue", dst_layout.abi), + _ => { + bug!( + "Non ScalarPair repr {:?} for ByValPair CValue", + dst_layout.backend_repr + ) + } }, CValueInner::ByRef(from_ptr, None) => { - match from.layout().abi { - Abi::Scalar(_) => { + match from.layout().backend_repr { + BackendRepr::Scalar(_) => { let val = from.load_scalar(fx); to_ptr.store(fx, val, flags); return; } - Abi::ScalarPair(a_scalar, b_scalar) => { + BackendRepr::ScalarPair(a_scalar, b_scalar) => { let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); let (val1, val2) = from.load_scalar_pair(fx); diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 14c607ccad7d..82b6178be9dc 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -47,7 +47,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( idx: usize, ) -> (Pointer, Value) { let (ptr, vtable) = 'block: { - if let Abi::Scalar(_) = arg.layout().abi { + if let BackendRepr::Scalar(_) = arg.layout().backend_repr { while !arg.layout().ty.is_unsafe_ptr() && !arg.layout().ty.is_ref() { let (idx, _) = arg .layout() @@ -68,7 +68,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( } } - if let Abi::ScalarPair(_, _) = arg.layout().abi { + if let BackendRepr::ScalarPair(_, _) = arg.layout().backend_repr { let (ptr, vtable) = arg.load_scalar_pair(fx); (Pointer::new(ptr), vtable) } else { From 03492099014ce0cd9c105b3e0995f3ecc966b3d8 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 29 Oct 2024 13:38:09 -0700 Subject: [PATCH 17/56] cg_gcc: `rustc_abi::Abi` => `BackendRepr` --- compiler/rustc_codegen_gcc/src/builder.rs | 4 +- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 6 +-- compiler/rustc_codegen_gcc/src/type_of.rs | 37 +++++++++++-------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 7c52cba096b4..e6ae7cf174d0 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1016,11 +1016,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { OperandValue::Ref(place.val) } else if place.layout.is_gcc_immediate() { let load = self.load(place.layout.gcc_type(self), place.val.llval, place.val.align); - if let abi::Abi::Scalar(ref scalar) = place.layout.abi { + if let abi::BackendRepr::Scalar(ref scalar) = place.layout.backend_repr { scalar_load_metadata(self, load, scalar); } OperandValue::Immediate(self.to_immediate(load, place.layout)) - } else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi { + } else if let abi::BackendRepr::ScalarPair(ref a, ref b) = place.layout.backend_repr { let b_offset = a.size(self).align_to(b.align(self).abi); let mut load = |i, scalar: &abi::Scalar, align| { diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 972d66321403..b0298a35cb08 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -294,13 +294,13 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } sym::raw_eq => { - use rustc_target::abi::Abi::*; + use rustc_abi::BackendRepr::*; let tp_ty = fn_args.type_at(0); let layout = self.layout_of(tp_ty).layout; - let _use_integer_compare = match layout.abi() { + let _use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, Uninhabited | Vector { .. } => false, - Aggregate { .. } => { + Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), // so we re-use that same threshold here. diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index db874afe1ab9..0efdf36da485 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -3,7 +3,7 @@ use std::fmt::Write; use gccjit::{Struct, Type}; use rustc_abi as abi; use rustc_abi::Primitive::*; -use rustc_abi::{Abi, FieldsShape, Integer, PointeeInfo, Size, Variants}; +use rustc_abi::{BackendRepr, FieldsShape, Integer, PointeeInfo, Size, Variants}; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, DerivedTypeCodegenMethods, LayoutTypeCodegenMethods, }; @@ -60,9 +60,9 @@ fn uncached_gcc_type<'gcc, 'tcx>( layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>, ) -> Type<'gcc> { - match layout.abi { - Abi::Scalar(_) => bug!("handled elsewhere"), - Abi::Vector { ref element, count } => { + match layout.backend_repr { + BackendRepr::Scalar(_) => bug!("handled elsewhere"), + BackendRepr::Vector { ref element, count } => { let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO); let element = // NOTE: gcc doesn't allow pointer types in vectors. @@ -74,7 +74,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( }; return cx.context.new_vector_type(element, count); } - Abi::ScalarPair(..) => { + BackendRepr::ScalarPair(..) => { return cx.type_struct( &[ layout.scalar_pair_element_gcc_type(cx, 0), @@ -83,7 +83,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( false, ); } - Abi::Uninhabited | Abi::Aggregate { .. } => {} + BackendRepr::Uninhabited | BackendRepr::Memory { .. } => {} } let name = match *layout.ty.kind() { @@ -176,16 +176,21 @@ pub trait LayoutGccExt<'tcx> { impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_immediate(&self) -> bool { - match self.abi { - Abi::Scalar(_) | Abi::Vector { .. } => true, - Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false, + match self.backend_repr { + BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => true, + BackendRepr::ScalarPair(..) | BackendRepr::Uninhabited | BackendRepr::Memory { .. } => { + false + } } } fn is_gcc_scalar_pair(&self) -> bool { - match self.abi { - Abi::ScalarPair(..) => true, - Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false, + match self.backend_repr { + BackendRepr::ScalarPair(..) => true, + BackendRepr::Uninhabited + | BackendRepr::Scalar(_) + | BackendRepr::Vector { .. } + | BackendRepr::Memory { .. } => false, } } @@ -205,7 +210,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { // This must produce the same result for `repr(transparent)` wrappers as for the inner type! // In other words, this should generally not look at the type at all, but only at the // layout. - if let Abi::Scalar(ref scalar) = self.abi { + if let BackendRepr::Scalar(ref scalar) = self.backend_repr { // Use a different cache for scalars because pointers to DSTs // can be either wide or thin (data pointers of wide pointers). if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) { @@ -261,7 +266,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { } fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { - if let Abi::Scalar(ref scalar) = self.abi { + if let BackendRepr::Scalar(ref scalar) = self.backend_repr { if scalar.is_bool() { return cx.type_i1(); } @@ -299,8 +304,8 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { // This must produce the same result for `repr(transparent)` wrappers as for the inner type! // In other words, this should generally not look at the type at all, but only at the // layout. - let (a, b) = match self.abi { - Abi::ScalarPair(ref a, ref b) => (a, b), + let (a, b) = match self.backend_repr { + BackendRepr::ScalarPair(ref a, ref b) => (a, b), _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self), }; let scalar = [a, b][index]; From 3059ed8fa6ad148fe2a67303114da7a5f2bba43c Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 29 Oct 2024 13:38:16 -0700 Subject: [PATCH 18/56] miri: `rustc_abi::Abi` => `BackendRepr` --- src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs | 7 +++++-- src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs | 7 +++++-- src/tools/miri/src/helpers.rs | 8 ++++++-- src/tools/miri/src/lib.rs | 1 + src/tools/miri/src/operator.rs | 2 +- src/tools/miri/src/shims/native_lib.rs | 4 ++-- 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index fdc7a675fb71..47fe41d9ecdd 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -9,11 +9,11 @@ use std::cell::RefCell; use std::fmt::Write; use std::{cmp, mem}; +use rustc_abi::{BackendRepr, Size}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::{Mutability, RetagKind}; use rustc_middle::ty::layout::HasParamEnv; use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::{Abi, Size}; use self::diagnostics::{RetagCause, RetagInfo}; pub use self::item::{Item, Permission}; @@ -972,7 +972,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { RetagFields::OnlyScalar => { // Matching `ArgAbi::new` at the time of writing, only fields of // `Scalar` and `ScalarPair` ABI are considered. - matches!(place.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) + matches!( + place.layout.backend_repr, + BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..) + ) } }; if recurse { diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index acfb76030f5f..40467aa4bc1b 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -1,8 +1,8 @@ +use rustc_abi::{BackendRepr, Size}; use rustc_middle::mir::{Mutability, RetagKind}; use rustc_middle::ty::layout::HasParamEnv; use rustc_middle::ty::{self, Ty}; use rustc_span::def_id::DefId; -use rustc_target::abi::{Abi, Size}; use crate::borrow_tracker::{GlobalState, GlobalStateInner, ProtectorKind}; use crate::concurrency::data_race::NaReadType; @@ -495,7 +495,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { RetagFields::OnlyScalar => { // Matching `ArgAbi::new` at the time of writing, only fields of // `Scalar` and `ScalarPair` ABI are considered. - matches!(place.layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) + matches!( + place.layout.backend_repr, + BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..) + ) } }; if recurse { diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index d35cbf242f5d..17f664da8538 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -349,8 +349,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { i: impl Into, dest: &impl Writeable<'tcx, Provenance>, ) -> InterpResult<'tcx> { - assert!(dest.layout().abi.is_scalar(), "write_int on non-scalar type {}", dest.layout().ty); - let val = if dest.layout().abi.is_signed() { + assert!( + dest.layout().backend_repr.is_scalar(), + "write_int on non-scalar type {}", + dest.layout().ty + ); + let val = if dest.layout().backend_repr.is_signed() { Scalar::from_int(i, dest.layout().size) } else { // `unwrap` can only fail here if `i` is negative diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 938d1ca319e0..f903ccbc25a7 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -55,6 +55,7 @@ extern crate either; extern crate tracing; // The rustc crates we need +extern crate rustc_abi; extern crate rustc_apfloat; extern crate rustc_ast; extern crate rustc_attr; diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index 8e06f4258d61..608e23fc1108 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -23,7 +23,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(match bin_op { Eq | Ne | Lt | Le | Gt | Ge => { - assert_eq!(left.layout.abi, right.layout.abi); // types can differ, e.g. fn ptrs with different `for` + assert_eq!(left.layout.backend_repr, right.layout.backend_repr); // types can differ, e.g. fn ptrs with different `for` let size = this.pointer_size(); // Just compare the bits. ScalarPairs are compared lexicographically. // We thus always compare pairs and simply fill scalars up with 0. diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index 3f282017bb79..525bcd381d52 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -5,7 +5,7 @@ use libffi::high::call as ffi; use libffi::low::CodePtr; use rustc_middle::ty::{self as ty, IntTy, UintTy}; use rustc_span::Symbol; -use rustc_target::abi::{Abi, HasDataLayout}; +use rustc_abi::{BackendRepr, HasDataLayout}; use crate::*; @@ -149,7 +149,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Get the function arguments, and convert them to `libffi`-compatible form. let mut libffi_args = Vec::::with_capacity(args.len()); for arg in args.iter() { - if !matches!(arg.layout.abi, Abi::Scalar(_)) { + if !matches!(arg.layout.backend_repr, BackendRepr::Scalar(_)) { throw_unsup_format!("only scalar argument types are support for native calls") } libffi_args.push(imm_to_carg(this.read_immediate(arg)?, this)?); From 11f9217a3391baf7bc9bfac2d3fee115438c983b Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 29 Oct 2024 13:38:30 -0700 Subject: [PATCH 19/56] rust-analyzer: `rustc_abi::Abi` => `BackendRepr` --- .../rust-analyzer/crates/hir-ty/src/layout.rs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index 9f4cc98993e2..c5fa20bc8acb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -6,7 +6,7 @@ use base_db::ra_salsa::Cycle; use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use hir_def::{ layout::{ - Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutData, + BackendRepr, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutData, Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange, }, LocalFieldId, StructId, @@ -168,7 +168,7 @@ fn layout_of_simd_ty( // Compute the ABI of the element type: let e_ly = db.layout_of_ty(e_ty, env)?; - let Abi::Scalar(e_abi) = e_ly.abi else { + let BackendRepr::Scalar(e_abi) = e_ly.backend_repr else { return Err(LayoutError::Unknown); }; @@ -190,7 +190,7 @@ fn layout_of_simd_ty( Ok(Arc::new(Layout { variants: Variants::Single { index: struct_variant_idx() }, fields, - abi: Abi::Vector { element: e_abi, count: e_len }, + backend_repr: BackendRepr::Vector { element: e_abi, count: e_len }, largest_niche: e_ly.largest_niche, size, align, @@ -294,10 +294,10 @@ pub fn layout_of_ty_query( .checked_mul(count, dl) .ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?; - let abi = if count != 0 && matches!(element.abi, Abi::Uninhabited) { - Abi::Uninhabited + let backend_repr = if count != 0 && matches!(element.backend_repr, BackendRepr::Uninhabited) { + BackendRepr::Uninhabited } else { - Abi::Aggregate { sized: true } + BackendRepr::Memory { sized: true } }; let largest_niche = if count != 0 { element.largest_niche } else { None }; @@ -305,7 +305,7 @@ pub fn layout_of_ty_query( Layout { variants: Variants::Single { index: struct_variant_idx() }, fields: FieldsShape::Array { stride: element.size, count }, - abi, + backend_repr, largest_niche, align: element.align, size, @@ -318,7 +318,7 @@ pub fn layout_of_ty_query( Layout { variants: Variants::Single { index: struct_variant_idx() }, fields: FieldsShape::Array { stride: element.size, count: 0 }, - abi: Abi::Aggregate { sized: false }, + backend_repr: BackendRepr::Memory { sized: false }, largest_niche: None, align: element.align, size: Size::ZERO, @@ -329,7 +329,7 @@ pub fn layout_of_ty_query( TyKind::Str => Layout { variants: Variants::Single { index: struct_variant_idx() }, fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, - abi: Abi::Aggregate { sized: false }, + backend_repr: BackendRepr::Memory { sized: false }, largest_niche: None, align: dl.i8_align, size: Size::ZERO, @@ -379,8 +379,8 @@ pub fn layout_of_ty_query( TyKind::Never => cx.calc.layout_of_never_type(), TyKind::Dyn(_) | TyKind::Foreign(_) => { let mut unit = layout_of_unit(&cx)?; - match &mut unit.abi { - Abi::Aggregate { sized } => *sized = false, + match &mut unit.backend_repr { + BackendRepr::Memory { sized } => *sized = false, _ => return Err(LayoutError::Unknown), } unit From e54c177118a5150b819c8a84054504ab8e1e7748 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Oct 2024 08:45:46 +1100 Subject: [PATCH 20/56] Remove `Analysis::into_engine`. This is a standard pattern: ``` MyAnalysis.into_engine(tcx, body).iterate_to_fixpoint() ``` `into_engine` and `iterate_to_fixpoint` are always called in pairs, but sometimes with a builder-style `pass_name` call between them. But a builder-style interface is overkill here. This has been bugging me a for a while. This commit: - Merges `Engine::new` and `Engine::iterate_to_fixpoint`. This removes the need for `Engine` to have fields, leaving it as a trivial type that the next commit will remove. - Renames `Analysis::into_engine` as `Analysis::iterate_to_fixpoint`, gives it an extra argument for the optional pass name, and makes it call `Engine::iterate_to_fixpoint` instead of `Engine::new`. This turns the pattern from above into this: ``` MyAnalysis.iterate_to_fixpoint(tcx, body, None) ``` which is shorter at every call site, and there's less plumbing required to support it. --- compiler/rustc_borrowck/src/lib.rs | 31 ++++++------ .../src/check_consts/check.rs | 12 ++--- .../src/framework/engine.rs | 47 +++++-------------- .../rustc_mir_dataflow/src/framework/mod.rs | 33 +++++++------ compiler/rustc_mir_dataflow/src/rustc_peek.rs | 15 +++--- compiler/rustc_mir_transform/src/coroutine.rs | 15 ++---- .../src/dataflow_const_prop.rs | 2 +- .../src/dead_store_elimination.rs | 3 +- compiler/rustc_mir_transform/src/dest_prop.rs | 5 +- .../src/elaborate_drops.rs | 8 +--- compiler/rustc_mir_transform/src/lint.rs | 6 +-- compiler/rustc_mir_transform/src/ref_prop.rs | 3 +- .../src/remove_uninit_drops.rs | 4 +- .../clippy_utils/src/mir/possible_borrower.rs | 4 +- 14 files changed, 72 insertions(+), 116 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 698fdafc9361..3e43d28eb5c9 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -193,9 +193,7 @@ fn do_mir_borrowck<'tcx>( .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true))); let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, Some("borrowck")) .into_results_cursor(body); let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure(); @@ -243,18 +241,21 @@ fn do_mir_borrowck<'tcx>( // usage significantly on some benchmarks. drop(flow_inits); - let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint(); - let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint(); - let flow_ever_inits = EverInitializedPlaces::new(body, &move_data) - .into_engine(tcx, body) - .pass_name("borrowck") - .iterate_to_fixpoint(); + let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set).iterate_to_fixpoint( + tcx, + body, + Some("borrowck"), + ); + let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint( + tcx, + body, + Some("borrowck"), + ); + let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint( + tcx, + body, + Some("borrowck"), + ); let movable_coroutine = // The first argument is the coroutine type passed by value diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 463a66d4e2e4..4d6f6715b9de 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -63,8 +63,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let ConstCx { tcx, body, .. } = *ccx; FlowSensitiveAnalysis::new(NeedsDrop, ccx) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); @@ -93,8 +92,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let ConstCx { tcx, body, .. } = *ccx; FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); @@ -123,8 +121,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { let ConstCx { tcx, body, .. } = *ccx; FlowSensitiveAnalysis::new(HasMutInterior, ccx) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body) }); @@ -239,8 +236,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { let always_live_locals = &always_storage_live_locals(&ccx.body); let mut maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals)) - .into_engine(ccx.tcx, &ccx.body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(ccx.tcx, &ccx.body, None) .into_results_cursor(&ccx.body); // And then check all `Return` in the MIR, and if a local is "maybe live" at a diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index cbd1083d037d..44fda84ce03e 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -71,25 +71,21 @@ where } /// A solver for dataflow problems. -pub struct Engine<'mir, 'tcx, A> -where - A: Analysis<'tcx>, -{ - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - entry_sets: IndexVec, - pass_name: Option<&'static str>, - analysis: A, -} +pub struct Engine; -impl<'mir, 'tcx, A, D> Engine<'mir, 'tcx, A> -where - A: Analysis<'tcx, Domain = D>, - D: Clone + JoinSemiLattice, -{ +impl Engine { /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer /// function. - pub(crate) fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, analysis: A) -> Self { + pub(crate) fn iterate_to_fixpoint<'mir, 'tcx, A>( + tcx: TyCtxt<'tcx>, + body: &'mir mir::Body<'tcx>, + mut analysis: A, + pass_name: Option<&'static str>, + ) -> Results<'tcx, A> + where + A: Analysis<'tcx>, + A::Domain: DebugWithContext + Clone + JoinSemiLattice, + { let mut entry_sets = IndexVec::from_fn_n(|_| analysis.bottom_value(body), body.basic_blocks.len()); analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); @@ -99,25 +95,6 @@ where bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); } - Engine { analysis, tcx, body, pass_name: None, entry_sets } - } - - /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis. - /// - /// Some analyses are run multiple times in the compilation pipeline. Give them a `pass_name` - /// to differentiate them. Otherwise, only the results for the latest run will be saved. - pub fn pass_name(mut self, name: &'static str) -> Self { - self.pass_name = Some(name); - self - } - - /// Computes the fixpoint for this dataflow problem and returns it. - pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> - where - A::Domain: DebugWithContext, - { - let Engine { mut analysis, body, mut entry_sets, tcx, pass_name } = self; - let mut dirty_queue: WorkQueue = WorkQueue::with_none(body.basic_blocks.len()); if A::Direction::IS_FORWARD { diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 959f1ea53409..5ad05921b4fd 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -7,18 +7,17 @@ //! //! The `impls` module contains several examples of dataflow analyses. //! -//! Create an `Engine` for your analysis using the `into_engine` method on the `Analysis` trait, -//! then call `iterate_to_fixpoint`. From there, you can use a `ResultsCursor` to inspect the -//! fixpoint solution to your dataflow problem, or implement the `ResultsVisitor` interface and use -//! `visit_results`. The following example uses the `ResultsCursor` approach. +//! Then call `iterate_to_fixpoint` on your type that impls `Analysis` to get a `Results`. From +//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem, +//! or implement the `ResultsVisitor` interface and use `visit_results`. The following example uses +//! the `ResultsCursor` approach. //! //! ```ignore (cross-crate-imports) -//! use rustc_const_eval::dataflow::Analysis; // Makes `into_engine` available. +//! use rustc_const_eval::dataflow::Analysis; // Makes `iterate_to_fixpoint` available. //! //! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) { //! let analysis = MyAnalysis::new() -//! .into_engine(tcx, body) -//! .iterate_to_fixpoint() +//! .iterate_to_fixpoint(tcx, body, None) //! .into_results_cursor(body); //! //! // Print the dataflow state *after* each statement in the start block. @@ -39,6 +38,8 @@ use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet}; use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges}; use rustc_middle::ty::TyCtxt; +use super::fmt::DebugWithContext; + mod cursor; mod direction; mod engine; @@ -223,26 +224,30 @@ pub trait Analysis<'tcx> { /* Extension methods */ - /// Creates an `Engine` to find the fixpoint for this dataflow problem. + /// Finds the fixpoint for this dataflow problem. /// /// You shouldn't need to override this. Its purpose is to enable method chaining like so: /// /// ```ignore (cross-crate-imports) /// let results = MyAnalysis::new(tcx, body) - /// .into_engine(tcx, body, def_id) - /// .iterate_to_fixpoint() + /// .iterate_to_fixpoint(tcx, body, None) /// .into_results_cursor(body); /// ``` - #[inline] - fn into_engine<'mir>( + /// You can optionally add a `pass_name` to the graphviz output for this particular run of a + /// dataflow analysis. Some analyses are run multiple times in the compilation pipeline. + /// Without a `pass_name` to differentiates them, only the results for the latest run will be + /// saved. + fn iterate_to_fixpoint<'mir>( self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, - ) -> Engine<'mir, 'tcx, Self> + pass_name: Option<&'static str>, + ) -> Results<'tcx, Self> where Self: Sized, + Self::Domain: DebugWithContext, { - Engine::new(tcx, body, self) + Engine::iterate_to_fixpoint(tcx, body, self, pass_name) } } diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 5727517bd612..99d0ccde1052 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -43,31 +43,28 @@ pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let move_data = MoveData::gather_moves(body, tcx, |_| true); if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() { - let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .iterate_to_fixpoint(); + let flow_inits = + MaybeInitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(tcx, body, None); sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body)); } if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() { let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .iterate_to_fixpoint(); + .iterate_to_fixpoint(tcx, body, None); sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body)); } if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() { - let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data) - .into_engine(tcx, body) - .iterate_to_fixpoint(); + let flow_def_inits = + DefinitelyInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(tcx, body, None); sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body)); } if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() { - let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint(); + let flow_liveness = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None); sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body)); } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 0a413d68020d..859b257174ab 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -666,14 +666,13 @@ fn locals_live_across_suspend_points<'tcx>( // Calculate when MIR locals have live storage. This gives us an upper bound of their // lifetimes. let mut storage_live = MaybeStorageLive::new(std::borrow::Cow::Borrowed(always_live_locals)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); // Calculate the MIR locals which have been previously // borrowed (even if they are still active). let borrowed_locals_results = - MaybeBorrowedLocals.into_engine(tcx, body).pass_name("coroutine").iterate_to_fixpoint(); + MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")); let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body); @@ -681,16 +680,12 @@ fn locals_live_across_suspend_points<'tcx>( // for. let mut requires_storage_cursor = MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); // Calculate the liveness of MIR locals ignoring borrows. - let mut liveness = MaybeLiveLocals - .into_engine(tcx, body) - .pass_name("coroutine") - .iterate_to_fixpoint() - .into_results_cursor(body); + let mut liveness = + MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")).into_results_cursor(body); let mut storage_liveness_map = IndexVec::from_elem(None, &body.basic_blocks); let mut live_locals_at_suspension_points = Vec::new(); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 002216f50f2d..07263460733c 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -59,7 +59,7 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { // Perform the actual dataflow analysis. let analysis = ConstAnalysis::new(tcx, body, map); let mut results = debug_span!("analyze") - .in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint()); + .in_scope(|| analysis.wrap().iterate_to_fixpoint(tcx, body, None)); // Collect results and patch the body afterwards. let mut visitor = Collector::new(tcx, &body.local_decls); diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index edffe6ce78f6..2898f82e25c3 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -37,8 +37,7 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { always_live.union(&borrowed_locals); let mut live = MaybeTransitiveLiveLocals::new(&always_live) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); // For blocks with a call terminator, if an argument copy can be turned into a move, diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index ad83c0295bae..beeab0d4a666 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -169,10 +169,7 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation { let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body); - let live = MaybeLiveLocals - .into_engine(tcx, body) - .pass_name("MaybeLiveLocals-DestinationPropagation") - .iterate_to_fixpoint(); + let live = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("MaybeLiveLocals-DestProp")); let points = DenseLocationMap::new(body); let mut live = save_as_intervals(&points, body, live); diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 30e1ac05e039..58e1db194380 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -64,18 +64,14 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops { let mut inits = MaybeInitializedPlaces::new(tcx, body, &env.move_data) .skipping_unreachable_unwind() - .into_engine(tcx, body) - .pass_name("elaborate_drops") - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, Some("elaborate_drops")) .into_results_cursor(body); let dead_unwinds = compute_dead_unwinds(body, &mut inits); let uninits = MaybeUninitializedPlaces::new(tcx, body, &env.move_data) .mark_inactive_variants_as_uninit() .skipping_unreachable_unwind(dead_unwinds) - .into_engine(tcx, body) - .pass_name("elaborate_drops") - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, Some("elaborate_drops")) .into_results_cursor(body); let drop_flags = IndexVec::from_elem(None, &env.move_data.move_paths); diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs index 23733994a8b4..d8ff1cfc90b5 100644 --- a/compiler/rustc_mir_transform/src/lint.rs +++ b/compiler/rustc_mir_transform/src/lint.rs @@ -17,13 +17,11 @@ pub(super) fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String let always_live_locals = &always_storage_live_locals(body); let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); let maybe_storage_dead = MaybeStorageDead::new(Cow::Borrowed(always_live_locals)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); let mut lint = Lint { diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index 53e53d9d5ba8..b11b503e8d43 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -126,8 +126,7 @@ fn compute_replacement<'tcx>( // Compute `MaybeStorageDead` dataflow to check that we only replace when the pointee is // definitely live. let mut maybe_dead = MaybeStorageDead::new(Cow::Owned(always_live_locals)) - .into_engine(tcx, body) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); // Map for each local to the pointee. diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index 09969a4c7cc7..55dd96100b0a 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -22,9 +22,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops { let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, param_env)); let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) - .into_engine(tcx, body) - .pass_name("remove_uninit_drops") - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, Some("remove_uninit_drops")) .into_results_cursor(body); let mut to_remove = vec![]; diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs index a00196c4b511..6b3078f52aff 100644 --- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs +++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs @@ -185,9 +185,7 @@ impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { vis.into_map(cx) }; let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len()))) - .into_engine(cx.tcx, mir) - .pass_name("redundant_clone") - .iterate_to_fixpoint() + .iterate_to_fixpoint(cx.tcx, mir, Some("redundant_clone")) .into_results_cursor(mir); let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin); vis.visit_body(mir); From d78e7bbeff6006feef9c04140c1e6bf67bdbef00 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Oct 2024 09:34:37 +1100 Subject: [PATCH 21/56] Remove `Engine`. It's no longer needed. `Engine::iterate_to_fixpoint` can be inlined into `Analysis::iterate_to_fixpoint` and removed. The commit also renames `engine.rs` as `results.rs`. --- .../rustc_mir_dataflow/src/framework/mod.rs | 78 +++++++++++++-- .../src/framework/{engine.rs => results.rs} | 98 +------------------ compiler/rustc_mir_dataflow/src/lib.rs | 6 +- 3 files changed, 80 insertions(+), 102 deletions(-) rename compiler/rustc_mir_dataflow/src/framework/{engine.rs => results.rs} (66%) diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 5ad05921b4fd..8f81da8bb049 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -33,25 +33,29 @@ use std::cmp::Ordering; -use rustc_index::Idx; +use rustc_data_structures::work_queue::WorkQueue; use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet}; -use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges}; +use rustc_index::{Idx, IndexVec}; +use rustc_middle::bug; +use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal}; use rustc_middle::ty::TyCtxt; +use tracing::error; +use self::results::write_graphviz_results; use super::fmt::DebugWithContext; mod cursor; mod direction; -mod engine; pub mod fmt; pub mod graphviz; pub mod lattice; +mod results; mod visitor; pub use self::cursor::ResultsCursor; pub use self::direction::{Backward, Direction, Forward}; -pub use self::engine::{Engine, Results}; pub use self::lattice::{JoinSemiLattice, MaybeReachable}; +pub use self::results::Results; pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results}; /// Analysis domains are all bitsets of various kinds. This trait holds @@ -238,7 +242,7 @@ pub trait Analysis<'tcx> { /// Without a `pass_name` to differentiates them, only the results for the latest run will be /// saved. fn iterate_to_fixpoint<'mir>( - self, + mut self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, pass_name: Option<&'static str>, @@ -247,7 +251,69 @@ pub trait Analysis<'tcx> { Self: Sized, Self::Domain: DebugWithContext, { - Engine::iterate_to_fixpoint(tcx, body, self, pass_name) + let mut entry_sets = + IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len()); + self.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); + + if Self::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != self.bottom_value(body) { + bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); + } + + let mut dirty_queue: WorkQueue = WorkQueue::with_none(body.basic_blocks.len()); + + if Self::Direction::IS_FORWARD { + for (bb, _) in traversal::reverse_postorder(body) { + dirty_queue.insert(bb); + } + } else { + // Reverse post-order on the reverse CFG may generate a better iteration order for + // backward dataflow analyses, but probably not enough to matter. + for (bb, _) in traversal::postorder(body) { + dirty_queue.insert(bb); + } + } + + // `state` is not actually used between iterations; + // this is just an optimization to avoid reallocating + // every iteration. + let mut state = self.bottom_value(body); + while let Some(bb) = dirty_queue.pop() { + let bb_data = &body[bb]; + + // Set the state to the entry state of the block. + // This is equivalent to `state = entry_sets[bb].clone()`, + // but it saves an allocation, thus improving compile times. + state.clone_from(&entry_sets[bb]); + + // Apply the block transfer function, using the cached one if it exists. + let edges = Self::Direction::apply_effects_in_block(&mut self, &mut state, bb, bb_data); + + Self::Direction::join_state_into_successors_of( + &mut self, + body, + &mut state, + bb, + edges, + |target: BasicBlock, state: &Self::Domain| { + let set_changed = entry_sets[target].join(state); + if set_changed { + dirty_queue.insert(target); + } + }, + ); + } + + let results = Results { analysis: self, entry_sets }; + + if tcx.sess.opts.unstable_opts.dump_mir_dataflow { + let (res, results) = write_graphviz_results(tcx, body, results, pass_name); + if let Err(e) = res { + error!("Failed to write graphviz dataflow results: {}", e); + } + results + } else { + results + } } } diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs similarity index 66% rename from compiler/rustc_mir_dataflow/src/framework/engine.rs rename to compiler/rustc_mir_dataflow/src/framework/results.rs index 44fda84ce03e..366fcbf33ba3 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/results.rs @@ -1,23 +1,19 @@ -//! A solver for dataflow problems. +//! Dataflow analysis results. use std::ffi::OsString; use std::path::PathBuf; -use rustc_data_structures::work_queue::WorkQueue; use rustc_hir::def_id::DefId; use rustc_index::IndexVec; -use rustc_middle::bug; use rustc_middle::mir::{self, BasicBlock, create_dump_file, dump_enabled, traversal}; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_span::symbol::{Symbol, sym}; -use tracing::{debug, error}; +use tracing::debug; use {rustc_ast as ast, rustc_graphviz as dot}; use super::fmt::DebugWithContext; -use super::{ - Analysis, Direction, JoinSemiLattice, ResultsCursor, ResultsVisitor, graphviz, visit_results, -}; +use super::{Analysis, ResultsCursor, ResultsVisitor, graphviz, visit_results}; use crate::errors::{ DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter, }; @@ -65,101 +61,17 @@ where body: &'mir mir::Body<'tcx>, vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>, ) { - let blocks = mir::traversal::reachable(body); + let blocks = traversal::reachable(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) } } -/// A solver for dataflow problems. -pub struct Engine; - -impl Engine { - /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer - /// function. - pub(crate) fn iterate_to_fixpoint<'mir, 'tcx, A>( - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - mut analysis: A, - pass_name: Option<&'static str>, - ) -> Results<'tcx, A> - where - A: Analysis<'tcx>, - A::Domain: DebugWithContext + Clone + JoinSemiLattice, - { - let mut entry_sets = - IndexVec::from_fn_n(|_| analysis.bottom_value(body), body.basic_blocks.len()); - analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); - - if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != analysis.bottom_value(body) - { - bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); - } - - let mut dirty_queue: WorkQueue = WorkQueue::with_none(body.basic_blocks.len()); - - if A::Direction::IS_FORWARD { - for (bb, _) in traversal::reverse_postorder(body) { - dirty_queue.insert(bb); - } - } else { - // Reverse post-order on the reverse CFG may generate a better iteration order for - // backward dataflow analyses, but probably not enough to matter. - for (bb, _) in traversal::postorder(body) { - dirty_queue.insert(bb); - } - } - - // `state` is not actually used between iterations; - // this is just an optimization to avoid reallocating - // every iteration. - let mut state = analysis.bottom_value(body); - while let Some(bb) = dirty_queue.pop() { - let bb_data = &body[bb]; - - // Set the state to the entry state of the block. - // This is equivalent to `state = entry_sets[bb].clone()`, - // but it saves an allocation, thus improving compile times. - state.clone_from(&entry_sets[bb]); - - // Apply the block transfer function, using the cached one if it exists. - let edges = - A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data); - - A::Direction::join_state_into_successors_of( - &mut analysis, - body, - &mut state, - bb, - edges, - |target: BasicBlock, state: &A::Domain| { - let set_changed = entry_sets[target].join(state); - if set_changed { - dirty_queue.insert(target); - } - }, - ); - } - - let results = Results { analysis, entry_sets }; - - if tcx.sess.opts.unstable_opts.dump_mir_dataflow { - let (res, results) = write_graphviz_results(tcx, body, results, pass_name); - if let Err(e) = res { - error!("Failed to write graphviz dataflow results: {}", e); - } - results - } else { - results - } - } -} - // Graphviz /// Writes a DOT file containing the results of a dataflow analysis if the user requested it via /// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are /// the same. -fn write_graphviz_results<'tcx, A>( +pub(super) fn write_graphviz_results<'tcx, A>( tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, results: Results<'tcx, A>, diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index b284f0308f97..b404e3bfb72c 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -18,9 +18,9 @@ pub use self::drop_flag_effects::{ move_path_children_matching, on_all_children_bits, on_lookup_result_bits, }; pub use self::framework::{ - Analysis, Backward, Direction, Engine, Forward, GenKill, JoinSemiLattice, MaybeReachable, - Results, ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, - lattice, visit_results, + Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results, + ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice, + visit_results, }; use self::move_paths::MoveData; From d942113fdb05a2577aec048090e904b5b486f1dc Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 25 Sep 2024 16:23:46 -0700 Subject: [PATCH 22/56] Fix directives for lint-non-snake-case-crate This test fails on targets without unwinding because the proc macro was compiled as the target, not the host. Some targets were explicitly disabled to pass CI, but these directives are more general. Fixes Fuchsia tests. --- .../lint-non-snake-case-crate.cdylib_.stderr | 4 ++-- .../lint-non-snake-case-crate.dylib_.stderr | 4 ++-- .../lint-non-snake-case-crate.lib_.stderr | 4 ++-- .../lint-non-snake-case-crate.proc_macro_.stderr | 4 ++-- .../lint-non-snake-case-crate.rlib_.stderr | 4 ++-- .../non-snake-case/lint-non-snake-case-crate.rs | 15 +++++++++++---- .../lint-non-snake-case-crate.staticlib_.stderr | 4 ++-- 7 files changed, 23 insertions(+), 16 deletions(-) diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr index 140d72b97421..1192b690e29c 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:29:18 + --> $DIR/lint-non-snake-case-crate.rs:36:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:31:9 + --> $DIR/lint-non-snake-case-crate.rs:38:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr index 140d72b97421..1192b690e29c 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:29:18 + --> $DIR/lint-non-snake-case-crate.rs:36:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:31:9 + --> $DIR/lint-non-snake-case-crate.rs:38:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr index 140d72b97421..1192b690e29c 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:29:18 + --> $DIR/lint-non-snake-case-crate.rs:36:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:31:9 + --> $DIR/lint-non-snake-case-crate.rs:38:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr index 140d72b97421..1192b690e29c 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:29:18 + --> $DIR/lint-non-snake-case-crate.rs:36:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:31:9 + --> $DIR/lint-non-snake-case-crate.rs:38:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr index 140d72b97421..1192b690e29c 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:29:18 + --> $DIR/lint-non-snake-case-crate.rs:36:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:31:9 + --> $DIR/lint-non-snake-case-crate.rs:38:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs index 097b246c1650..6f701cd27c62 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs @@ -10,10 +10,17 @@ // But should fire on non-binary crates. -//@[cdylib_] ignore-musl (dylibs are not supported) -//@[dylib_] ignore-musl (dylibs are not supported) -//@[dylib_] ignore-wasm (dylib is not supported) -//@[proc_macro_] ignore-wasm (dylib is not supported) +// FIXME(#132309): dylib crate type is not supported on wasm; we need a proper +// supports-crate-type directive. Also, needs-dynamic-linking should rule out +// musl since it supports neither dylibs nor cdylibs. +//@[dylib_] ignore-wasm +//@[dylib_] ignore-musl +//@[cdylib_] ignore-musl + +//@[dylib_] needs-dynamic-linking +//@[cdylib_] needs-dynamic-linking +//@[proc_macro_] force-host +//@[proc_macro_] no-prefer-dynamic //@[cdylib_] compile-flags: --crate-type=cdylib //@[dylib_] compile-flags: --crate-type=dylib diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr index 140d72b97421..1192b690e29c 100644 --- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr +++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr @@ -1,11 +1,11 @@ error: crate `NonSnakeCase` should have a snake case name - --> $DIR/lint-non-snake-case-crate.rs:29:18 + --> $DIR/lint-non-snake-case-crate.rs:36:18 | LL | #![crate_name = "NonSnakeCase"] | ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case` | note: the lint level is defined here - --> $DIR/lint-non-snake-case-crate.rs:31:9 + --> $DIR/lint-non-snake-case-crate.rs:38:9 | LL | #![deny(non_snake_case)] | ^^^^^^^^^^^^^^ From 65ff2a6ad71de45c848a622d86b6c74092e1b734 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 30 Oct 2024 10:02:46 +1100 Subject: [PATCH 23/56] Consistently use safe wrapper function `set_section` --- compiler/rustc_codegen_llvm/src/back/lto.rs | 3 ++- compiler/rustc_codegen_llvm/src/back/write.rs | 16 +++++++--------- compiler/rustc_codegen_llvm/src/base.rs | 6 ++---- compiler/rustc_codegen_llvm/src/context.rs | 2 +- compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 6 ++++-- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 02149e176eab..48beb9be2b2a 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -165,13 +165,14 @@ fn get_bitcode_slice_from_object_data<'a>( // We drop the "__LLVM," prefix here because on Apple platforms there's a notion of "segment // name" which in the public API for sections gets treated as part of the section name, but // internally in MachOObjectFile.cpp gets treated separately. - let section_name = bitcode_section_name(cgcx).trim_start_matches("__LLVM,"); + let section_name = bitcode_section_name(cgcx).to_str().unwrap().trim_start_matches("__LLVM,"); let mut len = 0; let data = unsafe { llvm::LLVMRustGetSliceFromObjectDataByName( obj.as_ptr(), obj.len(), section_name.as_ptr(), + section_name.len(), &mut len, ) }; diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index e68ba96f14f9..bfa9e8b82a03 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1,4 +1,4 @@ -use std::ffi::CString; +use std::ffi::{CStr, CString}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -958,14 +958,13 @@ fn target_is_aix(cgcx: &CodegenContext) -> bool { cgcx.opts.target_triple.triple().contains("-aix") } -//FIXME use c string literals here too -pub(crate) fn bitcode_section_name(cgcx: &CodegenContext) -> &'static str { +pub(crate) fn bitcode_section_name(cgcx: &CodegenContext) -> &'static CStr { if target_is_apple(cgcx) { - "__LLVM,__bitcode\0" + c"__LLVM,__bitcode" } else if target_is_aix(cgcx) { - ".ipa\0" + c".ipa" } else { - ".llvmbc\0" + c".llvmbc" } } @@ -1042,8 +1041,7 @@ unsafe fn embed_bitcode( ); llvm::LLVMSetInitializer(llglobal, llconst); - let section = bitcode_section_name(cgcx); - llvm::LLVMSetSection(llglobal, section.as_c_char_ptr()); + llvm::set_section(llglobal, bitcode_section_name(cgcx)); llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::LLVMSetGlobalConstant(llglobal, llvm::True); @@ -1061,7 +1059,7 @@ unsafe fn embed_bitcode( } else { c".llvmcmd" }; - llvm::LLVMSetSection(llglobal, section.as_ptr()); + llvm::set_section(llglobal, section); llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); } else { // We need custom section flags, so emit module-level inline assembly. diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 0ba8d82406a8..327938947949 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -145,10 +145,8 @@ pub(crate) fn compile_codegen_unit( pub(crate) fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) { let Some(sect) = attrs.link_section else { return }; - unsafe { - let buf = SmallCStr::new(sect.as_str()); - llvm::LLVMSetSection(llval, buf.as_ptr()); - } + let buf = SmallCStr::new(sect.as_str()); + llvm::set_section(llval, &buf); } pub(crate) fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage { diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index f33da42d63e8..9778ff4918c0 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -565,7 +565,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr()); llvm::LLVMSetInitializer(g, array); llvm::set_linkage(g, llvm::Linkage::AppendingLinkage); - llvm::LLVMSetSection(g, c"llvm.metadata".as_ptr()); + llvm::set_section(g, c"llvm.metadata"); } } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 7947c9c8c8ef..aef8642f1998 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -72,7 +72,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( let section_var = cx .define_global(section_var_name, llvm_type) .unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name)); - llvm::LLVMSetSection(section_var, c".debug_gdb_scripts".as_ptr()); + llvm::set_section(section_var, c".debug_gdb_scripts"); llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 888d41d47266..c0ca7e510250 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2416,6 +2416,7 @@ unsafe extern "C" { data: *const u8, len: usize, name: *const u8, + name_len: usize, out_len: &mut usize, ) -> *const u8; diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 20bf32d731e1..3e906f89c15c 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1559,8 +1559,10 @@ extern "C" LLVMModuleRef LLVMRustParseBitcodeForLTO(LLVMContextRef Context, extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data, size_t len, const char *name, + size_t name_len, size_t *out_len) { *out_len = 0; + auto Name = StringRef(name, name_len); auto Data = StringRef(data, len); auto Buffer = MemoryBufferRef(Data, ""); // The id is unused. file_magic Type = identify_magic(Buffer.getBuffer()); @@ -1571,8 +1573,8 @@ extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data, return nullptr; } for (const object::SectionRef &Sec : (*ObjFileOrError)->sections()) { - Expected Name = Sec.getName(); - if (Name && *Name == name) { + Expected SecName = Sec.getName(); + if (SecName && *SecName == Name) { Expected SectionOrError = Sec.getContents(); if (!SectionOrError) { LLVMRustSetLastError(toString(SectionOrError.takeError()).c_str()); From 744eb2f9372dfe9c4de9faeac27c986fb5c5fb10 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Oct 2024 13:12:03 +1100 Subject: [PATCH 24/56] Rename `BlockFormatter::results` as `BlockFormatter::cursor`. Because it's a `ResultsCursor`, not a `Results`. I find this easier to read and understand. --- .../src/framework/graphviz.rs | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 96a70f4fa5b0..58bec4b8bb21 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -96,13 +96,13 @@ where // the value with `None`, move it into the results cursor, move it // back out, and return it to the refcell wrapped in `Some`. let mut fmt = BlockFormatter { - results: results.take().unwrap().into_results_cursor(self.body), + cursor: results.take().unwrap().into_results_cursor(self.body), style: self.style, bg: Background::Light, }; fmt.write_node_label(&mut label, *block).unwrap(); - Some(fmt.results.into_results()) + Some(fmt.cursor.into_results()) }); dot::LabelText::html(String::from_utf8(label).unwrap()) } @@ -155,7 +155,7 @@ struct BlockFormatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { - results: ResultsCursor<'mir, 'tcx, A>, + cursor: ResultsCursor<'mir, 'tcx, A>, bg: Background, style: OutputStyle, } @@ -219,8 +219,8 @@ where // C: State at start of block self.bg = Background::Light; - self.results.seek_to_block_start(block); - let block_start_state = self.results.get().clone(); + self.cursor.seek_to_block_start(block); + let block_start_state = self.cursor.get().clone(); self.write_row_with_full_state(w, "", "(on start)")?; // D + E: Statement and terminator transfer functions @@ -228,12 +228,12 @@ where // F: State at end of block - let terminator = self.results.body()[block].terminator(); + let terminator = self.cursor.body()[block].terminator(); // Write the full dataflow state immediately after the terminator if it differs from the // state at block entry. - self.results.seek_to_block_end(block); - if self.results.get() != &block_start_state || A::Direction::IS_BACKWARD { + self.cursor.seek_to_block_end(block); + if self.cursor.get() != &block_start_state || A::Direction::IS_BACKWARD { let after_terminator_name = match terminator.kind { mir::TerminatorKind::Call { target: Some(_), .. } => "(on unwind)", _ => "(on end)", @@ -250,8 +250,8 @@ where match terminator.kind { mir::TerminatorKind::Call { destination, .. } => { self.write_row(w, "", "(on successful return)", |this, w, fmt| { - let state_on_unwind = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { + let state_on_unwind = this.cursor.get().clone(); + this.cursor.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect( state, block, @@ -265,9 +265,9 @@ where colspan = this.style.num_state_columns(), fmt = fmt, diff = diff_pretty( - this.results.get(), + this.cursor.get(), &state_on_unwind, - this.results.analysis() + this.cursor.analysis() ), ) })?; @@ -275,8 +275,8 @@ where mir::TerminatorKind::Yield { resume, resume_arg, .. } => { self.write_row(w, "", "(on yield resume)", |this, w, fmt| { - let state_on_coroutine_drop = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { + let state_on_coroutine_drop = this.cursor.get().clone(); + this.cursor.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect( state, resume, @@ -290,9 +290,9 @@ where colspan = this.style.num_state_columns(), fmt = fmt, diff = diff_pretty( - this.results.get(), + this.cursor.get(), &state_on_coroutine_drop, - this.results.analysis() + this.cursor.analysis() ), ) })?; @@ -302,8 +302,8 @@ where if !targets.is_empty() => { self.write_row(w, "", "(on successful return)", |this, w, fmt| { - let state_on_unwind = this.results.get().clone(); - this.results.apply_custom_effect(|analysis, state| { + let state_on_unwind = this.cursor.get().clone(); + this.cursor.apply_custom_effect(|analysis, state| { analysis.apply_call_return_effect( state, block, @@ -317,9 +317,9 @@ where colspan = this.style.num_state_columns(), fmt = fmt, diff = diff_pretty( - this.results.get(), + this.cursor.get(), &state_on_unwind, - this.results.analysis() + this.cursor.analysis() ), ) })?; @@ -407,9 +407,9 @@ where block: BasicBlock, ) -> io::Result<()> { let diffs = StateDiffCollector::run( - self.results.body(), + self.cursor.body(), block, - self.results.mut_results(), + self.cursor.mut_results(), self.style, ); @@ -420,7 +420,7 @@ where if A::Direction::IS_FORWARD { it.next().unwrap() } else { it.next_back().unwrap() } }; - for (i, statement) in self.results.body()[block].statements.iter().enumerate() { + for (i, statement) in self.cursor.body()[block].statements.iter().enumerate() { let statement_str = format!("{statement:?}"); let index_str = format!("{i}"); @@ -442,7 +442,7 @@ where assert!(diffs_after.is_empty()); assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty)); - let terminator = self.results.body()[block].terminator(); + let terminator = self.cursor.body()[block].terminator(); let mut terminator_str = String::new(); terminator.kind.fmt_head(&mut terminator_str).unwrap(); @@ -492,8 +492,8 @@ where mir: &str, ) -> io::Result<()> { self.write_row(w, i, mir, |this, w, fmt| { - let state = this.results.get(); - let analysis = this.results.analysis(); + let state = this.cursor.get(); + let analysis = this.cursor.analysis(); // FIXME: The full state vector can be quite long. It would be nice to split on commas // and use some text wrapping algorithm. From a8ce44f7d9921f4ae1e620016c22f2a0ac6d8753 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Oct 2024 13:12:25 +1100 Subject: [PATCH 25/56] Simplify `graphviz::Formatter`. `Formatter` currently has a `RefCell>` field. This is so the `Results` can be temporarily taken and put into a `ResultsCursor` that is used by `BlockFormatter`, and then put back, which is messy. This commit changes `Formatter` to have a `RefCell` and `BlockFormatter` to have a `&mut ResultsCursor`, which greatly simplifies the code at the `Formatter`/`BlockFormatter` interaction point in `Formatter::node_label`. It also means we construct a `ResultsCursor` once per `Formatter`, instead of once per `node_label` call. The commit also: - documents the reason for the `RefCell`; - adds a `Formatter::body` method, replacing the `Formatter::body` field. --- .../src/framework/graphviz.rs | 53 +++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 58bec4b8bb21..5785964de21f 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -32,8 +32,11 @@ pub(crate) struct Formatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { - body: &'mir Body<'tcx>, - results: RefCell>>, + // The `RefCell` is used because `::node_label` + // takes `&self`, but it needs to modify the cursor. This is also the + // reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has + // the operations that involve the mutation, i.e. within the `borrow_mut`. + cursor: RefCell>, style: OutputStyle, reachable: BitSet, } @@ -48,11 +51,15 @@ where style: OutputStyle, ) -> Self { let reachable = mir::traversal::reachable_as_bitset(body); - Formatter { body, results: Some(results).into(), style, reachable } + Formatter { cursor: results.into_results_cursor(body).into(), style, reachable } + } + + fn body(&self) -> &'mir Body<'tcx> { + self.cursor.borrow().body() } pub(crate) fn into_results(self) -> Results<'tcx, A> { - self.results.into_inner().unwrap() + self.cursor.into_inner().into_results() } } @@ -81,7 +88,7 @@ where type Edge = CfgEdge; fn graph_id(&self) -> dot::Id<'_> { - let name = graphviz_safe_def_name(self.body.source.def_id()); + let name = graphviz_safe_def_name(self.body().source.def_id()); dot::Id::new(format!("graph_for_def_id_{name}")).unwrap() } @@ -91,19 +98,11 @@ where fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { let mut label = Vec::new(); - self.results.replace_with(|results| { - // `Formatter::result` is a `RefCell>` so we can replace - // the value with `None`, move it into the results cursor, move it - // back out, and return it to the refcell wrapped in `Some`. - let mut fmt = BlockFormatter { - cursor: results.take().unwrap().into_results_cursor(self.body), - style: self.style, - bg: Background::Light, - }; + let mut cursor = self.cursor.borrow_mut(); + let mut fmt = + BlockFormatter { cursor: &mut cursor, style: self.style, bg: Background::Light }; + fmt.write_node_label(&mut label, *block).unwrap(); - fmt.write_node_label(&mut label, *block).unwrap(); - Some(fmt.cursor.into_results()) - }); dot::LabelText::html(String::from_utf8(label).unwrap()) } @@ -112,12 +111,12 @@ where } fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> { - let label = &self.body[e.source].terminator().kind.fmt_successor_labels()[e.index]; + let label = &self.body()[e.source].terminator().kind.fmt_successor_labels()[e.index]; dot::LabelText::label(label.clone()) } } -impl<'mir, 'tcx, A> dot::GraphWalk<'mir> for Formatter<'mir, 'tcx, A> +impl<'tcx, A> dot::GraphWalk<'_> for Formatter<'_, 'tcx, A> where A: Analysis<'tcx>, { @@ -125,7 +124,7 @@ where type Edge = CfgEdge; fn nodes(&self) -> dot::Nodes<'_, Self::Node> { - self.body + self.body() .basic_blocks .indices() .filter(|&idx| self.reachable.contains(idx)) @@ -134,10 +133,10 @@ where } fn edges(&self) -> dot::Edges<'_, Self::Edge> { - self.body - .basic_blocks + let body = self.body(); + body.basic_blocks .indices() - .flat_map(|bb| dataflow_successors(self.body, bb)) + .flat_map(|bb| dataflow_successors(body, bb)) .collect::>() .into() } @@ -147,20 +146,20 @@ where } fn target(&self, edge: &Self::Edge) -> Self::Node { - self.body[edge.source].terminator().successors().nth(edge.index).unwrap() + self.body()[edge.source].terminator().successors().nth(edge.index).unwrap() } } -struct BlockFormatter<'mir, 'tcx, A> +struct BlockFormatter<'a, 'mir, 'tcx, A> where A: Analysis<'tcx>, { - cursor: ResultsCursor<'mir, 'tcx, A>, + cursor: &'a mut ResultsCursor<'mir, 'tcx, A>, bg: Background, style: OutputStyle, } -impl<'mir, 'tcx, A> BlockFormatter<'mir, 'tcx, A> +impl<'tcx, A> BlockFormatter<'_, '_, 'tcx, A> where A: Analysis<'tcx>, A::Domain: DebugWithContext, From d921be92a459b41f0ba2d5b97e32397902f37294 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Oct 2024 13:21:32 +1100 Subject: [PATCH 26/56] Return label from `write_node_label`. Instead of appending an empty label. Because it's conceptually simpler. --- .../rustc_mir_dataflow/src/framework/graphviz.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 5785964de21f..bac75b972f9b 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -97,11 +97,10 @@ where } fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { - let mut label = Vec::new(); let mut cursor = self.cursor.borrow_mut(); let mut fmt = BlockFormatter { cursor: &mut cursor, style: self.style, bg: Background::Light }; - fmt.write_node_label(&mut label, *block).unwrap(); + let label = fmt.write_node_label(*block).unwrap(); dot::LabelText::html(String::from_utf8(label).unwrap()) } @@ -172,7 +171,9 @@ where bg } - fn write_node_label(&mut self, w: &mut impl io::Write, block: BasicBlock) -> io::Result<()> { + fn write_node_label(&mut self, block: BasicBlock) -> io::Result> { + use std::io::Write; + // Sample output: // +-+-----------------------------------------------+ // A | bb4 | @@ -199,6 +200,9 @@ where // attributes. Make sure to test the output before trying to remove the redundancy. // Notably, `align` was found to have no effect when applied only to . + let mut v = vec![]; + let w = &mut v; + let table_fmt = concat!( " border=\"1\"", " cellborder=\"1\"", @@ -327,7 +331,9 @@ where _ => {} }; - write!(w, "
") + write!(w, "")?; + + Ok(v) } fn write_block_header_simple( From c3071590ab70f016380fe16030057e84b76e59eb Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 28 Oct 2024 17:25:40 +1100 Subject: [PATCH 27/56] Clean up FFI calls for operand bundles --- compiler/rustc_codegen_llvm/src/allocator.rs | 3 +- compiler/rustc_codegen_llvm/src/builder.rs | 23 ++--- compiler/rustc_codegen_llvm/src/common.rs | 8 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 91 ++++++++++--------- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 38 +++++--- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 80 +++------------- 6 files changed, 104 insertions(+), 139 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index a2e6c7eb8561..149ded28356b 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -154,7 +154,7 @@ fn create_wrapper_function( .enumerate() .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint)) .collect::>(); - let ret = llvm::LLVMRustBuildCall( + let ret = llvm::LLVMBuildCallWithOperandBundles( llbuilder, ty, callee, @@ -162,6 +162,7 @@ fn create_wrapper_function( args.len() as c_uint, [].as_ptr(), 0 as c_uint, + c"".as_ptr(), ); llvm::LLVMSetTailCall(ret, True); if output.is_some() { diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 8702532c36ee..f8eb3e0c982c 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -239,7 +239,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let args = self.check_call("invoke", llty, llfn, args); let funclet_bundle = funclet.map(|funclet| funclet.bundle()); - let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw); let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); if let Some(funclet_bundle) = funclet_bundle { bundles.push(funclet_bundle); @@ -250,13 +249,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); - if let Some(kcfi_bundle) = kcfi_bundle { + if let Some(kcfi_bundle) = kcfi_bundle.as_deref() { bundles.push(kcfi_bundle); } let invoke = unsafe { - llvm::LLVMRustBuildInvoke( + llvm::LLVMBuildInvokeWithOperandBundles( self.llbuilder, llty, llfn, @@ -1179,7 +1177,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let args = self.check_call("call", llty, llfn, args); let funclet_bundle = funclet.map(|funclet| funclet.bundle()); - let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw); let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); if let Some(funclet_bundle) = funclet_bundle { bundles.push(funclet_bundle); @@ -1190,13 +1187,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); - if let Some(kcfi_bundle) = kcfi_bundle { + if let Some(kcfi_bundle) = kcfi_bundle.as_deref() { bundles.push(kcfi_bundle); } let call = unsafe { - llvm::LLVMRustBuildCall( + llvm::LLVMBuildCallWithOperandBundles( self.llbuilder, llty, llfn, @@ -1204,6 +1200,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { args.len() as c_uint, bundles.as_ptr(), bundles.len() as c_uint, + c"".as_ptr(), ) }; if let Some(fn_abi) = fn_abi { @@ -1509,7 +1506,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { let args = self.check_call("callbr", llty, llfn, args); let funclet_bundle = funclet.map(|funclet| funclet.bundle()); - let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw); let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); if let Some(funclet_bundle) = funclet_bundle { bundles.push(funclet_bundle); @@ -1520,13 +1516,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw); - if let Some(kcfi_bundle) = kcfi_bundle { + if let Some(kcfi_bundle) = kcfi_bundle.as_deref() { bundles.push(kcfi_bundle); } let callbr = unsafe { - llvm::LLVMRustBuildCallBr( + llvm::LLVMBuildCallBr( self.llbuilder, llty, llfn, @@ -1601,7 +1596,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, instance: Option>, llfn: &'ll Value, - ) -> Option> { + ) -> Option> { let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) }; let kcfi_bundle = if self.tcx.sess.is_sanitizer_kcfi_enabled() && let Some(fn_abi) = fn_abi @@ -1627,7 +1622,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { kcfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; - Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)])) + Some(llvm::OperandBundleOwned::new("kcfi", &[self.const_u32(kcfi_typeid)])) } else { None }; diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 29adc616ee20..8852dec7d9ff 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -17,7 +17,7 @@ use tracing::debug; use crate::consts::const_alloc_to_llvm; pub(crate) use crate::context::CodegenCx; -use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, OperandBundleDef, True}; +use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, True}; use crate::type_::Type; use crate::value::Value; @@ -63,19 +63,19 @@ use crate::value::Value; /// the `OperandBundleDef` value created for MSVC landing pads. pub(crate) struct Funclet<'ll> { cleanuppad: &'ll Value, - operand: OperandBundleDef<'ll>, + operand: llvm::OperandBundleOwned<'ll>, } impl<'ll> Funclet<'ll> { pub(crate) fn new(cleanuppad: &'ll Value) -> Self { - Funclet { cleanuppad, operand: OperandBundleDef::new("funclet", &[cleanuppad]) } + Funclet { cleanuppad, operand: llvm::OperandBundleOwned::new("funclet", &[cleanuppad]) } } pub(crate) fn cleanuppad(&self) -> &'ll Value { self.cleanuppad } - pub(crate) fn bundle(&self) -> &OperandBundleDef<'ll> { + pub(crate) fn bundle(&self) -> &llvm::OperandBundle<'ll> { &self.operand } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 888d41d47266..d67f76b51a23 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -3,6 +3,7 @@ use std::fmt::Debug; use std::marker::PhantomData; +use std::ptr; use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t}; use rustc_macros::TryFromU32; @@ -708,8 +709,9 @@ unsafe extern "C" { } #[repr(C)] pub struct RustArchiveMember<'a>(InvariantOpaque<'a>); +/// Opaque pointee of `LLVMOperandBundleRef`. #[repr(C)] -pub struct OperandBundleDef<'a>(InvariantOpaque<'a>); +pub(crate) struct OperandBundle<'a>(InvariantOpaque<'a>); #[repr(C)] pub struct Linker<'a>(InvariantOpaque<'a>); @@ -1538,6 +1540,50 @@ unsafe extern "C" { pub fn LLVMGetOrInsertComdat(M: &Module, Name: *const c_char) -> &Comdat; pub fn LLVMSetComdat(V: &Value, C: &Comdat); + + pub(crate) fn LLVMCreateOperandBundle( + Tag: *const c_char, + TagLen: size_t, + Args: *const &'_ Value, + NumArgs: c_uint, + ) -> *mut OperandBundle<'_>; + pub(crate) fn LLVMDisposeOperandBundle(Bundle: ptr::NonNull>); + + pub(crate) fn LLVMBuildCallWithOperandBundles<'a>( + B: &Builder<'a>, + Ty: &'a Type, + Fn: &'a Value, + Args: *const &'a Value, + NumArgs: c_uint, + Bundles: *const &OperandBundle<'a>, + NumBundles: c_uint, + Name: *const c_char, + ) -> &'a Value; + pub(crate) fn LLVMBuildInvokeWithOperandBundles<'a>( + B: &Builder<'a>, + Ty: &'a Type, + Fn: &'a Value, + Args: *const &'a Value, + NumArgs: c_uint, + Then: &'a BasicBlock, + Catch: &'a BasicBlock, + Bundles: *const &OperandBundle<'a>, + NumBundles: c_uint, + Name: *const c_char, + ) -> &'a Value; + pub(crate) fn LLVMBuildCallBr<'a>( + B: &Builder<'a>, + Ty: &'a Type, + Fn: &'a Value, + DefaultDest: &'a BasicBlock, + IndirectDests: *const &'a BasicBlock, + NumIndirectDests: c_uint, + Args: *const &'a Value, + NumArgs: c_uint, + Bundles: *const &OperandBundle<'a>, + NumBundles: c_uint, + Name: *const c_char, + ) -> &'a Value; } #[link(name = "llvm-wrapper", kind = "static")] @@ -1623,47 +1669,11 @@ unsafe extern "C" { AttrsLen: size_t, ); - pub fn LLVMRustBuildInvoke<'a>( - B: &Builder<'a>, - Ty: &'a Type, - Fn: &'a Value, - Args: *const &'a Value, - NumArgs: c_uint, - Then: &'a BasicBlock, - Catch: &'a BasicBlock, - OpBundles: *const &OperandBundleDef<'a>, - NumOpBundles: c_uint, - Name: *const c_char, - ) -> &'a Value; - - pub fn LLVMRustBuildCallBr<'a>( - B: &Builder<'a>, - Ty: &'a Type, - Fn: &'a Value, - DefaultDest: &'a BasicBlock, - IndirectDests: *const &'a BasicBlock, - NumIndirectDests: c_uint, - Args: *const &'a Value, - NumArgs: c_uint, - OpBundles: *const &OperandBundleDef<'a>, - NumOpBundles: c_uint, - Name: *const c_char, - ) -> &'a Value; - pub fn LLVMRustSetFastMath(Instr: &Value); pub fn LLVMRustSetAlgebraicMath(Instr: &Value); pub fn LLVMRustSetAllowReassoc(Instr: &Value); // Miscellaneous instructions - pub fn LLVMRustBuildCall<'a>( - B: &Builder<'a>, - Ty: &'a Type, - Fn: &'a Value, - Args: *const &'a Value, - NumArgs: c_uint, - OpBundles: *const &OperandBundleDef<'a>, - NumOpBundles: c_uint, - ) -> &'a Value; pub fn LLVMRustBuildMemCpy<'a>( B: &Builder<'a>, Dst: &'a Value, @@ -2357,13 +2367,6 @@ unsafe extern "C" { pub fn LLVMRustSetDataLayoutFromTargetMachine<'a>(M: &'a Module, TM: &'a TargetMachine); - pub fn LLVMRustBuildOperandBundleDef( - Name: *const c_char, - Inputs: *const &'_ Value, - NumInputs: c_uint, - ) -> &mut OperandBundleDef<'_>; - pub fn LLVMRustFreeOperandBundleDef<'a>(Bundle: &'a mut OperandBundleDef<'a>); - pub fn LLVMRustPositionBuilderAtStart<'a>(B: &Builder<'a>, BB: &'a BasicBlock); pub fn LLVMRustSetModulePICLevel(M: &Module); diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index acd425bbb8e7..00a5cd3b8595 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -2,11 +2,12 @@ use std::cell::RefCell; use std::ffi::{CStr, CString}; +use std::ops::Deref; +use std::ptr; use std::str::FromStr; use std::string::FromUtf8Error; use libc::c_uint; -use rustc_data_structures::small_c_str::SmallCStr; use rustc_llvm::RustString; use rustc_target::abi::{Align, Size, WrappingRange}; @@ -331,28 +332,43 @@ pub fn last_error() -> Option { } } -pub struct OperandBundleDef<'a> { - pub raw: &'a mut ffi::OperandBundleDef<'a>, +/// Owns an [`OperandBundle`], and will dispose of it when dropped. +pub(crate) struct OperandBundleOwned<'a> { + raw: ptr::NonNull>, } -impl<'a> OperandBundleDef<'a> { - pub fn new(name: &str, vals: &[&'a Value]) -> Self { - let name = SmallCStr::new(name); - let def = unsafe { - LLVMRustBuildOperandBundleDef(name.as_ptr(), vals.as_ptr(), vals.len() as c_uint) +impl<'a> OperandBundleOwned<'a> { + pub(crate) fn new(name: &str, vals: &[&'a Value]) -> Self { + let raw = unsafe { + LLVMCreateOperandBundle( + name.as_c_char_ptr(), + name.len(), + vals.as_ptr(), + vals.len() as c_uint, + ) }; - OperandBundleDef { raw: def } + OperandBundleOwned { raw: ptr::NonNull::new(raw).unwrap() } } } -impl Drop for OperandBundleDef<'_> { +impl Drop for OperandBundleOwned<'_> { fn drop(&mut self) { unsafe { - LLVMRustFreeOperandBundleDef(&mut *(self.raw as *mut _)); + LLVMDisposeOperandBundle(self.raw); } } } +impl<'a> Deref for OperandBundleOwned<'a> { + type Target = OperandBundle<'a>; + + fn deref(&self) -> &Self::Target { + // SAFETY: The returned reference is opaque and can only used for FFI. + // It is valid for as long as `&self` is. + unsafe { self.raw.as_ref() } + } +} + pub(crate) fn add_module_flag_u32( module: &Module, merge_behavior: ModuleFlagMergeBehavior, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index b3dab6d512e4..645b4082be5d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1537,38 +1537,6 @@ LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, RustStringRef MessageOut, return true; } -extern "C" OperandBundleDef *LLVMRustBuildOperandBundleDef(const char *Name, - LLVMValueRef *Inputs, - unsigned NumInputs) { - return new OperandBundleDef(Name, - ArrayRef(unwrap(Inputs), NumInputs)); -} - -extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) { - delete Bundle; -} - -// OpBundlesIndirect is an array of pointers (*not* a pointer to an array). -extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, - LLVMValueRef Fn, LLVMValueRef *Args, - unsigned NumArgs, - OperandBundleDef **OpBundlesIndirect, - unsigned NumOpBundles) { - Value *Callee = unwrap(Fn); - FunctionType *FTy = unwrap(Ty); - - // FIXME: Is there a way around this? - SmallVector OpBundles; - OpBundles.reserve(NumOpBundles); - for (unsigned i = 0; i < NumOpBundles; ++i) { - OpBundles.push_back(*OpBundlesIndirect[i]); - } - - return wrap(unwrap(B)->CreateCall(FTy, Callee, - ArrayRef(unwrap(Args), NumArgs), - ArrayRef(OpBundles))); -} - extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, LLVMValueRef Src, unsigned SrcAlign, @@ -1596,37 +1564,18 @@ extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B, LLVMValueRef Dst, MaybeAlign(DstAlign), IsVolatile)); } -// OpBundlesIndirect is an array of pointers (*not* a pointer to an array). +// Polyfill for `LLVMBuildCallBr`, which was added in LLVM 19. +// +// FIXME: Remove when Rust's minimum supported LLVM version reaches 19. +#if LLVM_VERSION_LT(19, 0) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OperandBundleDef, LLVMOperandBundleRef) + extern "C" LLVMValueRef -LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, - LLVMValueRef *Args, unsigned NumArgs, - LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, - OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles, - const char *Name) { - Value *Callee = unwrap(Fn); - FunctionType *FTy = unwrap(Ty); - - // FIXME: Is there a way around this? - SmallVector OpBundles; - OpBundles.reserve(NumOpBundles); - for (unsigned i = 0; i < NumOpBundles; ++i) { - OpBundles.push_back(*OpBundlesIndirect[i]); - } - - return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch), - ArrayRef(unwrap(Args), NumArgs), - ArrayRef(OpBundles), - Name)); -} - -// OpBundlesIndirect is an array of pointers (*not* a pointer to an array). -extern "C" LLVMValueRef -LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, - LLVMBasicBlockRef DefaultDest, - LLVMBasicBlockRef *IndirectDests, unsigned NumIndirectDests, - LLVMValueRef *Args, unsigned NumArgs, - OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles, - const char *Name) { +LLVMBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, + LLVMBasicBlockRef DefaultDest, LLVMBasicBlockRef *IndirectDests, + unsigned NumIndirectDests, LLVMValueRef *Args, unsigned NumArgs, + LLVMOperandBundleRef *Bundles, unsigned NumBundles, + const char *Name) { Value *Callee = unwrap(Fn); FunctionType *FTy = unwrap(Ty); @@ -1639,9 +1588,9 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, // FIXME: Is there a way around this? SmallVector OpBundles; - OpBundles.reserve(NumOpBundles); - for (unsigned i = 0; i < NumOpBundles; ++i) { - OpBundles.push_back(*OpBundlesIndirect[i]); + OpBundles.reserve(NumBundles); + for (unsigned i = 0; i < NumBundles; ++i) { + OpBundles.push_back(*unwrap(Bundles[i])); } return wrap( @@ -1650,6 +1599,7 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn, ArrayRef(unwrap(Args), NumArgs), ArrayRef(OpBundles), Name)); } +#endif extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B, LLVMBasicBlockRef BB) { From e419b3d1ec234d428a00c9d6a8527ec4f6dc7e1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:10:05 +0800 Subject: [PATCH 28/56] compiletest: improve robustness of LLVM version handling --- Cargo.lock | 1 + src/tools/compiletest/Cargo.toml | 1 + src/tools/compiletest/src/common.rs | 3 +- src/tools/compiletest/src/header.rs | 112 ++++++++++++++-------- src/tools/compiletest/src/header/tests.rs | 78 ++++++++++++--- src/tools/compiletest/src/lib.rs | 2 +- src/tools/compiletest/src/tests.rs | 13 --- 7 files changed, 140 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 22b3e8280d62..fc16ccf0a679 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -720,6 +720,7 @@ dependencies = [ "miropt-test-tools", "regex", "rustfix", + "semver", "serde", "serde_json", "tracing", diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index b6a89dd49e61..cef6b525a7bc 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -18,6 +18,7 @@ build_helper = { path = "../build_helper" } tracing = "0.1" tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } regex = "1.0" +semver = { version = "1.0.23", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" rustfix = "0.8.1" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 69ac4644941d..e82b88eef798 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -7,6 +7,7 @@ use std::sync::OnceLock; use std::{fmt, iter}; use build_helper::git::GitConfig; +use semver::Version; use serde::de::{Deserialize, Deserializer, Error as _}; use test::{ColorConfig, OutputFormat}; @@ -298,7 +299,7 @@ pub struct Config { pub lldb_version: Option, /// Version of LLVM - pub llvm_version: Option, + pub llvm_version: Option, /// Is LLVM a system LLVM pub system_llvm: bool, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index a3bf36c0e908..bfcdd747eb44 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -6,6 +6,7 @@ use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process::Command; +use semver::Version; use tracing::*; use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; @@ -1113,26 +1114,39 @@ fn parse_normalize_rule(header: &str) -> Option<(String, String)> { Some((regex, replacement)) } -pub fn extract_llvm_version(version: &str) -> Option { - let pat = |c: char| !c.is_ascii_digit() && c != '.'; - let version_without_suffix = match version.find(pat) { - Some(pos) => &version[..pos], +/// Given an llvm version string that looks like `1.2.3-rc1`, extract as semver. Note that this +/// accepts more than just strict `semver` syntax (as in `major.minor.patch`); this permits omitting +/// minor and patch version components so users can write e.g. `//@ min-llvm-version: 19` instead of +/// having to write `//@ min-llvm-version: 19.0.0`. +/// +/// Currently panics if the input string is malformed, though we really should not use panic as an +/// error handling strategy. +/// +/// FIXME(jieyouxu): improve error handling +pub fn extract_llvm_version(version: &str) -> Version { + // The version substring we're interested in usually looks like the `1.2.3`, without any of the + // fancy suffix like `-rc1` or `meow`. + let version = version.trim(); + let uninterested = |c: char| !c.is_ascii_digit() && c != '.'; + let version_without_suffix = match version.split_once(uninterested) { + Some((prefix, _suffix)) => prefix, None => version, }; - let components: Vec = version_without_suffix + + let components: Vec = version_without_suffix .split('.') - .map(|s| s.parse().expect("Malformed version component")) + .map(|s| s.parse().expect("llvm version component should consist of only digits")) .collect(); - let version = match *components { - [a] => a * 10_000, - [a, b] => a * 10_000 + b * 100, - [a, b, c] => a * 10_000 + b * 100 + c, - _ => panic!("Malformed version"), - }; - Some(version) + + match &components[..] { + [major] => Version::new(*major, 0, 0), + [major, minor] => Version::new(*major, *minor, 0), + [major, minor, patch] => Version::new(*major, *minor, *patch), + _ => panic!("malformed llvm version string, expected only 1-3 components: {version}"), + } } -pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option { +pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option { let output = Command::new(binary_path).arg("--version").output().ok()?; if !output.status.success() { return None; @@ -1140,7 +1154,7 @@ pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option { let version = String::from_utf8(output.stdout).ok()?; for line in version.lines() { if let Some(version) = line.split("LLVM version ").nth(1) { - return extract_llvm_version(version); + return Some(extract_llvm_version(version)); } } None @@ -1247,15 +1261,17 @@ pub fn llvm_has_libzstd(config: &Config) -> bool { false } -/// Takes a directive of the form `" [- ]"`, -/// returns the numeric representation of `` and `` as -/// tuple: `( as u32, as u32)`. +/// Takes a directive of the form `" [- ]"`, returns the numeric representation +/// of `` and `` as tuple: `(, )`. /// -/// If the `` part is omitted, the second component of the tuple -/// is the same as ``. -fn extract_version_range(line: &str, parse: F) -> Option<(u32, u32)> +/// If the `` part is omitted, the second component of the tuple is the same as +/// ``. +fn extract_version_range<'a, F, VersionTy: Clone>( + line: &'a str, + parse: F, +) -> Option<(VersionTy, VersionTy)> where - F: Fn(&str) -> Option, + F: Fn(&'a str) -> Option, { let mut splits = line.splitn(2, "- ").map(str::trim); let min = splits.next().unwrap(); @@ -1273,7 +1289,7 @@ where let max = match max { Some("") => return None, Some(max) => parse(max)?, - _ => min, + _ => min.clone(), }; Some((min, max)) @@ -1489,43 +1505,55 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision { }; } } - if let Some(actual_version) = config.llvm_version { - if let Some(rest) = line.strip_prefix("min-llvm-version:").map(str::trim) { - let min_version = extract_llvm_version(rest).unwrap(); - // Ignore if actual version is smaller the minimum required - // version - if actual_version < min_version { + if let Some(actual_version) = &config.llvm_version { + // Note that these `min` versions will check for not just major versions. + + if let Some(version_string) = config.parse_name_value_directive(line, "min-llvm-version") { + let min_version = extract_llvm_version(&version_string); + // Ignore if actual version is smaller than the minimum required version. + if *actual_version < min_version { return IgnoreDecision::Ignore { - reason: format!("ignored when the LLVM version is older than {rest}"), + reason: format!( + "ignored when the LLVM version {actual_version} is older than {min_version}" + ), }; } - } else if let Some(rest) = line.strip_prefix("min-system-llvm-version:").map(str::trim) { - let min_version = extract_llvm_version(rest).unwrap(); + } else if let Some(version_string) = + config.parse_name_value_directive(line, "min-system-llvm-version") + { + let min_version = extract_llvm_version(&version_string); // Ignore if using system LLVM and actual version // is smaller the minimum required version - if config.system_llvm && actual_version < min_version { + if config.system_llvm && *actual_version < min_version { return IgnoreDecision::Ignore { - reason: format!("ignored when the system LLVM version is older than {rest}"), + reason: format!( + "ignored when the system LLVM version {actual_version} is older than {min_version}" + ), }; } - } else if let Some(rest) = line.strip_prefix("ignore-llvm-version:").map(str::trim) { + } else if let Some(version_range) = + config.parse_name_value_directive(line, "ignore-llvm-version") + { // Syntax is: "ignore-llvm-version: [- ]" let (v_min, v_max) = - extract_version_range(rest, extract_llvm_version).unwrap_or_else(|| { - panic!("couldn't parse version range: {:?}", rest); - }); + extract_version_range(&version_range, |s| Some(extract_llvm_version(s))) + .unwrap_or_else(|| { + panic!("couldn't parse version range: \"{version_range}\""); + }); if v_max < v_min { - panic!("Malformed LLVM version range: max < min") + panic!("malformed LLVM version range where {v_max} < {v_min}") } // Ignore if version lies inside of range. - if actual_version >= v_min && actual_version <= v_max { + if *actual_version >= v_min && *actual_version <= v_max { if v_min == v_max { return IgnoreDecision::Ignore { - reason: format!("ignored when the LLVM version is {rest}"), + reason: format!("ignored when the LLVM version is {actual_version}"), }; } else { return IgnoreDecision::Ignore { - reason: format!("ignored when the LLVM version is between {rest}"), + reason: format!( + "ignored when the LLVM version is between {v_min} and {v_max}" + ), }; } } diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index c3c9496c4d2d..2e6effcab986 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -1,9 +1,13 @@ use std::io::Read; use std::path::Path; -use super::iter_header; +use semver::Version; + +use super::{ + EarlyProps, HeadersCache, extract_llvm_version, extract_version_range, iter_header, + parse_normalize_rule, +}; use crate::common::{Config, Debugger, Mode}; -use crate::header::{EarlyProps, HeadersCache, parse_normalize_rule}; fn make_test_description( config: &Config, @@ -408,18 +412,66 @@ fn channel() { } #[test] -fn test_extract_version_range() { - use super::{extract_llvm_version, extract_version_range}; +fn test_extract_llvm_version() { + // Note: officially, semver *requires* that versions at the minimum have all three + // `major.minor.patch` numbers, though for test-writer's convenience we allow omitting the minor + // and patch numbers (which will be stubbed out as 0). + assert_eq!(extract_llvm_version("0"), Version::new(0, 0, 0)); + assert_eq!(extract_llvm_version("0.0"), Version::new(0, 0, 0)); + assert_eq!(extract_llvm_version("0.0.0"), Version::new(0, 0, 0)); + assert_eq!(extract_llvm_version("1"), Version::new(1, 0, 0)); + assert_eq!(extract_llvm_version("1.2"), Version::new(1, 2, 0)); + assert_eq!(extract_llvm_version("1.2.3"), Version::new(1, 2, 3)); + assert_eq!(extract_llvm_version("4.5.6git"), Version::new(4, 5, 6)); + assert_eq!(extract_llvm_version("4.5.6-rc1"), Version::new(4, 5, 6)); + assert_eq!(extract_llvm_version("123.456.789-rc1"), Version::new(123, 456, 789)); + assert_eq!(extract_llvm_version("8.1.2-rust"), Version::new(8, 1, 2)); + assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Version::new(9, 0, 1)); + assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Version::new(9, 3, 1)); + assert_eq!(extract_llvm_version("10.0.0-rust"), Version::new(10, 0, 0)); + assert_eq!(extract_llvm_version("11.1.0"), Version::new(11, 1, 0)); + assert_eq!(extract_llvm_version("12.0.0libcxx"), Version::new(12, 0, 0)); + assert_eq!(extract_llvm_version("12.0.0-rc3"), Version::new(12, 0, 0)); + assert_eq!(extract_llvm_version("13.0.0git"), Version::new(13, 0, 0)); +} - assert_eq!(extract_version_range("1.2.3 - 4.5.6", extract_llvm_version), Some((10203, 40506))); - assert_eq!(extract_version_range("0 - 4.5.6", extract_llvm_version), Some((0, 40506))); - assert_eq!(extract_version_range("1.2.3 -", extract_llvm_version), None); - assert_eq!(extract_version_range("1.2.3 - ", extract_llvm_version), None); - assert_eq!(extract_version_range("- 4.5.6", extract_llvm_version), None); - assert_eq!(extract_version_range("-", extract_llvm_version), None); - assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None); - assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None); - assert_eq!(extract_version_range("0 -", extract_llvm_version), None); +#[test] +#[should_panic] +fn test_llvm_version_invalid_components() { + extract_llvm_version("4.x.6"); +} + +#[test] +#[should_panic] +fn test_llvm_version_invalid_prefix() { + extract_llvm_version("meow4.5.6"); +} + +#[test] +#[should_panic] +fn test_llvm_version_too_many_components() { + extract_llvm_version("4.5.6.7"); +} + +#[test] +fn test_extract_version_range() { + let wrapped_extract = |s: &str| Some(extract_llvm_version(s)); + + assert_eq!( + extract_version_range("1.2.3 - 4.5.6", wrapped_extract), + Some((Version::new(1, 2, 3), Version::new(4, 5, 6))) + ); + assert_eq!( + extract_version_range("0 - 4.5.6", wrapped_extract), + Some((Version::new(0, 0, 0), Version::new(4, 5, 6))) + ); + assert_eq!(extract_version_range("1.2.3 -", wrapped_extract), None); + assert_eq!(extract_version_range("1.2.3 - ", wrapped_extract), None); + assert_eq!(extract_version_range("- 4.5.6", wrapped_extract), None); + assert_eq!(extract_version_range("-", wrapped_extract), None); + assert_eq!(extract_version_range(" - 4.5.6", wrapped_extract), None); + assert_eq!(extract_version_range(" - 4.5.6", wrapped_extract), None); + assert_eq!(extract_version_range("0 -", wrapped_extract), None); } #[test] diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 490df3132285..ccf8057bf5c5 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -228,7 +228,7 @@ pub fn parse_config(args: Vec) -> Config { Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), }; let llvm_version = - matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else( + matches.opt_str("llvm-version").as_deref().map(header::extract_llvm_version).or_else( || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), ); diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs index 680579c59aec..fec746904ded 100644 --- a/src/tools/compiletest/src/tests.rs +++ b/src/tools/compiletest/src/tests.rs @@ -1,7 +1,6 @@ use std::ffi::OsString; use crate::debuggers::{extract_gdb_version, extract_lldb_version}; -use crate::header::extract_llvm_version; use crate::is_test; #[test] @@ -67,15 +66,3 @@ fn is_test_test() { assert!(!is_test(&OsString::from("#a_dog_gif"))); assert!(!is_test(&OsString::from("~a_temp_file"))); } - -#[test] -fn test_extract_llvm_version() { - assert_eq!(extract_llvm_version("8.1.2-rust"), Some(80102)); - assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Some(90001)); - assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Some(90301)); - assert_eq!(extract_llvm_version("10.0.0-rust"), Some(100000)); - assert_eq!(extract_llvm_version("11.1.0"), Some(110100)); - assert_eq!(extract_llvm_version("12.0.0libcxx"), Some(120000)); - assert_eq!(extract_llvm_version("12.0.0-rc3"), Some(120000)); - assert_eq!(extract_llvm_version("13.0.0git"), Some(130000)); -} From 0b9d1eb889e8ceaea6af4f614e747b746a68822e Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 29 Oct 2024 23:22:36 -0700 Subject: [PATCH 29/56] tests: cross-compile multi-platform ZST ABI tests This allows them to be blessed, regardless of platform. --- ...nux.stderr => c-zst.aarch64-darwin.stderr} | 0 tests/ui/abi/c-zst.rs | 74 ++++++++++++++----- ...other.stderr => c-zst.x86_64-linux.stderr} | 0 tests/ui/abi/win64-zst.rs | 23 ++++-- ...r.stderr => win64-zst.x86_64-linux.stderr} | 0 ...rr => win64-zst.x86_64-windows-gnu.stderr} | 0 6 files changed, 73 insertions(+), 24 deletions(-) rename tests/ui/abi/{c-zst.other-linux.stderr => c-zst.aarch64-darwin.stderr} (100%) rename tests/ui/abi/{c-zst.other.stderr => c-zst.x86_64-linux.stderr} (100%) rename tests/ui/abi/{win64-zst.other.stderr => win64-zst.x86_64-linux.stderr} (100%) rename tests/ui/abi/{win64-zst.windows-gnu.stderr => win64-zst.x86_64-windows-gnu.stderr} (100%) diff --git a/tests/ui/abi/c-zst.other-linux.stderr b/tests/ui/abi/c-zst.aarch64-darwin.stderr similarity index 100% rename from tests/ui/abi/c-zst.other-linux.stderr rename to tests/ui/abi/c-zst.aarch64-darwin.stderr diff --git a/tests/ui/abi/c-zst.rs b/tests/ui/abi/c-zst.rs index 0cfd653b37e8..69ebefa09acb 100644 --- a/tests/ui/abi/c-zst.rs +++ b/tests/ui/abi/c-zst.rs @@ -1,27 +1,63 @@ -//@ revisions: other other-linux x86_64-pc-windows-gnu s390x-linux sparc64-linux powerpc-linux //@ normalize-stderr-test: "(abi|pref|unadjusted_abi_align): Align\([1-8] bytes\)" -> "$1: $$SOME_ALIGN" -// ZSTs are only not ignored when the target_env is "gnu", "musl" or "uclibc". However, Rust does -// not currently support any other target_env on these architectures. +/*! +C doesn't have zero-sized types... except it does. -// Ignore the ZST revisions -//@[other] ignore-x86_64-pc-windows-gnu -//@[other] ignore-linux -//@[other-linux] only-linux -//@[other-linux] ignore-s390x -//@[other-linux] ignore-sparc64 -//@[other-linux] ignore-powerpc +Standard C doesn't, but some C compilers, like GCC, implement ZSTs as a compiler extension. +This historically has wound up interacting with processor-specific ABIs in fairly ad-hoc ways. +e.g. despite being "zero-sized", sometimes C compilers decide ZSTs consume registers. -// Pass the ZST indirectly revisions -//@[x86_64-pc-windows-gnu] only-x86_64-pc-windows-gnu -//@[s390x-linux] only-s390x -//@[s390x-linux] only-linux -//@[sparc64-linux] only-sparc64 -//@[sparc64-linux] only-linux -//@[powerpc-linux] only-powerpc -//@[powerpc-linux] only-linux +That means these two function signatures may not be compatible: -#![feature(rustc_attrs)] +``` +extern "C" fn((), i32, i32); +extern "C" fn(i32, (), i32); +``` +*/ + +/* + * ZST IN "C" IS ZERO-SIZED + */ + +//@ revisions: aarch64-darwin +//@[aarch64-darwin] compile-flags: --target aarch64-apple-darwin +//@[aarch64-darwin] needs-llvm-components: aarch64 + +//@ revisions: x86_64-linux +//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64-linux] needs-llvm-components: x86 + + +/* + * ZST IN "C" IS PASS-BY-POINTER + */ + +// according to the SRV4 ABI, an aggregate is always passed in registers, +// and it so happens the GCC extension for ZSTs considers them as structs. +//@ revisions: powerpc-linux +//@[powerpc-linux] compile-flags: --target powerpc-unknown-linux-gnu +//@[powerpc-linux] needs-llvm-components: powerpc + +//@ revisions: s390x-linux +//@[s390x-linux] compile-flags: --target s390x-unknown-linux-gnu +//@[s390x-linux] needs-llvm-components: systemz + +//@ revisions: sparc64-linux +//@[sparc64-linux] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64-linux] needs-llvm-components: sparc + +// The Win64 ABI uses slightly different handling for power-of-2 sizes in the ABI, +// so GCC decided that ZSTs are pass-by-pointer, as `0.is_power_of_two() == false` +//@ revisions: x86_64-pc-windows-gnu +//@[x86_64-pc-windows-gnu] compile-flags: --target x86_64-pc-windows-gnu +//@[x86_64-pc-windows-gnu] needs-llvm-components: x86 + + +#![feature(lang_items, no_core, rustc_attrs)] +#![no_core] #![crate_type = "lib"] +#[lang = "sized"] +trait Sized {} + #[rustc_abi(debug)] extern "C" fn pass_zst(_: ()) {} //~ ERROR: fn_abi diff --git a/tests/ui/abi/c-zst.other.stderr b/tests/ui/abi/c-zst.x86_64-linux.stderr similarity index 100% rename from tests/ui/abi/c-zst.other.stderr rename to tests/ui/abi/c-zst.x86_64-linux.stderr diff --git a/tests/ui/abi/win64-zst.rs b/tests/ui/abi/win64-zst.rs index cae32795e16e..a2f7d19eb459 100644 --- a/tests/ui/abi/win64-zst.rs +++ b/tests/ui/abi/win64-zst.rs @@ -1,11 +1,24 @@ -//@ only-x86_64 -//@ revisions: other windows-gnu //@ normalize-stderr-test: "(abi|pref|unadjusted_abi_align): Align\([1-8] bytes\)" -> "$1: $$SOME_ALIGN" -//@[other] ignore-windows-gnu -//@[windows-gnu] only-windows-gnu +//@ only-x86_64 -#![feature(rustc_attrs)] +//@ revisions: x86_64-linux +//@[x86_64-linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86_64-linux] needs-llvm-components: x86 + +//@ revisions: x86_64-windows-gnu +//@[x86_64-windows-gnu] compile-flags: --target x86_64-pc-windows-gnu +//@[x86_64-windows-gnu] needs-llvm-components: x86 + +//@ revisions: x86_64-windows-msvc +//@[x86_64-windows-msvc] compile-flags: --target x86_64-pc-windows-msvc +//@[x86_64-windows-msvc] needs-llvm-components: x86 + +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] #![crate_type = "lib"] +#[lang = "sized"] +trait Sized {} + #[rustc_abi(debug)] extern "win64" fn pass_zst(_: ()) {} //~ ERROR: fn_abi diff --git a/tests/ui/abi/win64-zst.other.stderr b/tests/ui/abi/win64-zst.x86_64-linux.stderr similarity index 100% rename from tests/ui/abi/win64-zst.other.stderr rename to tests/ui/abi/win64-zst.x86_64-linux.stderr diff --git a/tests/ui/abi/win64-zst.windows-gnu.stderr b/tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr similarity index 100% rename from tests/ui/abi/win64-zst.windows-gnu.stderr rename to tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr From 083a362dd113da1217f7eed0e48baa2c584ac641 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Tue, 29 Oct 2024 23:21:20 -0700 Subject: [PATCH 30/56] tests: Bless `rustc_abi::Abi::Aggregate` => `::Memory` --- tests/ui/abi/c-zst.aarch64-darwin.stderr | 6 +- tests/ui/abi/c-zst.powerpc-linux.stderr | 6 +- tests/ui/abi/c-zst.s390x-linux.stderr | 6 +- tests/ui/abi/c-zst.sparc64-linux.stderr | 6 +- tests/ui/abi/c-zst.x86_64-linux.stderr | 6 +- .../ui/abi/c-zst.x86_64-pc-windows-gnu.stderr | 6 +- tests/ui/abi/debug.stderr | 24 +++---- tests/ui/abi/sysv64-zst.stderr | 4 +- tests/ui/abi/win64-zst.x86_64-linux.stderr | 6 +- .../abi/win64-zst.x86_64-windows-gnu.stderr | 6 +- .../abi/win64-zst.x86_64-windows-msvc.stderr | 67 +++++++++++++++++++ tests/ui/layout/debug.stderr | 20 +++--- tests/ui/layout/enum-scalar-pair-int-ptr.rs | 2 +- .../ui/layout/enum-scalar-pair-int-ptr.stderr | 2 +- tests/ui/layout/hexagon-enum.stderr | 10 +-- ...-scalarpair-payload-might-be-uninit.stderr | 10 +-- .../issue-96185-overaligned-enum.stderr | 10 +-- tests/ui/layout/struct.rs | 2 +- tests/ui/layout/struct.stderr | 2 +- tests/ui/layout/thumb-enum.stderr | 10 +-- .../layout/zero-sized-array-enum-niche.stderr | 26 +++---- ...-variants.aarch64-unknown-linux-gnu.stderr | 4 +- ...-c-dead-variants.armebv7r-none-eabi.stderr | 4 +- ...-dead-variants.i686-pc-windows-msvc.stderr | 4 +- ...d-variants.x86_64-unknown-linux-gnu.stderr | 4 +- tests/ui/repr/repr-c-int-dead-variants.stderr | 4 +- .../type/pattern_types/range_patterns.stderr | 4 +- 27 files changed, 164 insertions(+), 97 deletions(-) create mode 100644 tests/ui/abi/win64-zst.x86_64-windows-msvc.stderr diff --git a/tests/ui/abi/c-zst.aarch64-darwin.stderr b/tests/ui/abi/c-zst.aarch64-darwin.stderr index 5a656e6ea66e..7d384bc875f9 100644 --- a/tests/ui/abi/c-zst.aarch64-darwin.stderr +++ b/tests/ui/abi/c-zst.aarch64-darwin.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -36,7 +36,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -58,7 +58,7 @@ error: fn_abi_of(pass_zst) = FnAbi { conv: C, can_unwind: false, } - --> $DIR/c-zst.rs:27:1 + --> $DIR/c-zst.rs:63:1 | LL | extern "C" fn pass_zst(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr index ba9738050d87..7980710bab67 100644 --- a/tests/ui/abi/c-zst.powerpc-linux.stderr +++ b/tests/ui/abi/c-zst.powerpc-linux.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -47,7 +47,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -69,7 +69,7 @@ error: fn_abi_of(pass_zst) = FnAbi { conv: C, can_unwind: false, } - --> $DIR/c-zst.rs:27:1 + --> $DIR/c-zst.rs:63:1 | LL | extern "C" fn pass_zst(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr index ba9738050d87..7980710bab67 100644 --- a/tests/ui/abi/c-zst.s390x-linux.stderr +++ b/tests/ui/abi/c-zst.s390x-linux.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -47,7 +47,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -69,7 +69,7 @@ error: fn_abi_of(pass_zst) = FnAbi { conv: C, can_unwind: false, } - --> $DIR/c-zst.rs:27:1 + --> $DIR/c-zst.rs:63:1 | LL | extern "C" fn pass_zst(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr index ba9738050d87..7980710bab67 100644 --- a/tests/ui/abi/c-zst.sparc64-linux.stderr +++ b/tests/ui/abi/c-zst.sparc64-linux.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -47,7 +47,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -69,7 +69,7 @@ error: fn_abi_of(pass_zst) = FnAbi { conv: C, can_unwind: false, } - --> $DIR/c-zst.rs:27:1 + --> $DIR/c-zst.rs:63:1 | LL | extern "C" fn pass_zst(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/c-zst.x86_64-linux.stderr b/tests/ui/abi/c-zst.x86_64-linux.stderr index 5a656e6ea66e..7d384bc875f9 100644 --- a/tests/ui/abi/c-zst.x86_64-linux.stderr +++ b/tests/ui/abi/c-zst.x86_64-linux.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -36,7 +36,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -58,7 +58,7 @@ error: fn_abi_of(pass_zst) = FnAbi { conv: C, can_unwind: false, } - --> $DIR/c-zst.rs:27:1 + --> $DIR/c-zst.rs:63:1 | LL | extern "C" fn pass_zst(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr index ba9738050d87..7980710bab67 100644 --- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr +++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -47,7 +47,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -69,7 +69,7 @@ error: fn_abi_of(pass_zst) = FnAbi { conv: C, can_unwind: false, } - --> $DIR/c-zst.rs:27:1 + --> $DIR/c-zst.rs:63:1 | LL | extern "C" fn pass_zst(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr index 7365839da89d..aa51c42c58dc 100644 --- a/tests/ui/abi/debug.stderr +++ b/tests/ui/abi/debug.stderr @@ -235,7 +235,7 @@ error: fn_abi_of(test_generic) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -317,7 +317,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -387,7 +387,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -426,7 +426,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Array { @@ -464,7 +464,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -497,7 +497,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Array { @@ -535,7 +535,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -610,7 +610,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -680,7 +680,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -756,7 +756,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -826,7 +826,7 @@ error: ABIs are not compatible abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -929,7 +929,7 @@ error: fn_abi_of(assoc_test) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/abi/sysv64-zst.stderr b/tests/ui/abi/sysv64-zst.stderr index 8b0b84dfa069..8e1791e27d27 100644 --- a/tests/ui/abi/sysv64-zst.stderr +++ b/tests/ui/abi/sysv64-zst.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -36,7 +36,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/abi/win64-zst.x86_64-linux.stderr b/tests/ui/abi/win64-zst.x86_64-linux.stderr index 15db141cb574..76d90670eb1d 100644 --- a/tests/ui/abi/win64-zst.x86_64-linux.stderr +++ b/tests/ui/abi/win64-zst.x86_64-linux.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -36,7 +36,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -58,7 +58,7 @@ error: fn_abi_of(pass_zst) = FnAbi { conv: X86_64Win64, can_unwind: false, } - --> $DIR/win64-zst.rs:11:1 + --> $DIR/win64-zst.rs:24:1 | LL | extern "win64" fn pass_zst(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr b/tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr index 7773e0aa2b57..7ee90e247441 100644 --- a/tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr +++ b/tests/ui/abi/win64-zst.x86_64-windows-gnu.stderr @@ -9,7 +9,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -47,7 +47,7 @@ error: fn_abi_of(pass_zst) = FnAbi { abi: $SOME_ALIGN, pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -69,7 +69,7 @@ error: fn_abi_of(pass_zst) = FnAbi { conv: X86_64Win64, can_unwind: false, } - --> $DIR/win64-zst.rs:11:1 + --> $DIR/win64-zst.rs:24:1 | LL | extern "win64" fn pass_zst(_: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/win64-zst.x86_64-windows-msvc.stderr b/tests/ui/abi/win64-zst.x86_64-windows-msvc.stderr new file mode 100644 index 000000000000..76d90670eb1d --- /dev/null +++ b/tests/ui/abi/win64-zst.x86_64-windows-msvc.stderr @@ -0,0 +1,67 @@ +error: fn_abi_of(pass_zst) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Ignore, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: $SOME_ALIGN, + pref: $SOME_ALIGN, + }, + abi: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: X86_64Win64, + can_unwind: false, + } + --> $DIR/win64-zst.rs:24:1 + | +LL | extern "win64" fn pass_zst(_: ()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index c9715a8e1463..bd31665dac1f 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -10,7 +10,7 @@ error: layout_of(E) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -48,7 +48,7 @@ error: layout_of(E) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -150,7 +150,7 @@ error: layout_of(U) = Layout { abi: Align(4 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Union( @@ -337,7 +337,7 @@ error: layout_of(V) = Layout { abi: Align(2 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Union( @@ -361,7 +361,7 @@ error: layout_of(W) = Layout { abi: Align(2 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Union( @@ -385,7 +385,7 @@ error: layout_of(Y) = Layout { abi: Align(2 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Union( @@ -409,7 +409,7 @@ error: layout_of(P1) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Union( @@ -433,7 +433,7 @@ error: layout_of(P2) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Union( @@ -457,7 +457,7 @@ error: layout_of(P3) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Union( @@ -481,7 +481,7 @@ error: layout_of(P4) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Union( diff --git a/tests/ui/layout/enum-scalar-pair-int-ptr.rs b/tests/ui/layout/enum-scalar-pair-int-ptr.rs index 885cc3e37dfd..ebb3fdb1514c 100644 --- a/tests/ui/layout/enum-scalar-pair-int-ptr.rs +++ b/tests/ui/layout/enum-scalar-pair-int-ptr.rs @@ -18,7 +18,7 @@ enum ScalarPairPointerWithInt { //~ERROR: abi: ScalarPair // of a different size. (Assumes that no target has 8 bit pointers, which // feels pretty safe.) #[rustc_layout(abi)] -enum NotScalarPairPointerWithSmallerInt { //~ERROR: abi: Aggregate +enum NotScalarPairPointerWithSmallerInt { //~ERROR: abi: Memory A(u8), B(Box<()>), } diff --git a/tests/ui/layout/enum-scalar-pair-int-ptr.stderr b/tests/ui/layout/enum-scalar-pair-int-ptr.stderr index b25eda628cd6..357c8182ebd6 100644 --- a/tests/ui/layout/enum-scalar-pair-int-ptr.stderr +++ b/tests/ui/layout/enum-scalar-pair-int-ptr.stderr @@ -4,7 +4,7 @@ error: abi: ScalarPair(Initialized { value: Int(I?, false), valid_range: $VALID_ LL | enum ScalarPairPointerWithInt { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: abi: Aggregate { sized: true } +error: abi: Memory { sized: true } --> $DIR/enum-scalar-pair-int-ptr.rs:21:1 | LL | enum NotScalarPairPointerWithSmallerInt { diff --git a/tests/ui/layout/hexagon-enum.stderr b/tests/ui/layout/hexagon-enum.stderr index a2ad4a1ab58a..59fe667923f1 100644 --- a/tests/ui/layout/hexagon-enum.stderr +++ b/tests/ui/layout/hexagon-enum.stderr @@ -48,7 +48,7 @@ error: layout_of(A) = Layout { abi: Align(1 bytes), pref: Align(1 bytes), }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -122,7 +122,7 @@ error: layout_of(B) = Layout { abi: Align(1 bytes), pref: Align(1 bytes), }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -196,7 +196,7 @@ error: layout_of(C) = Layout { abi: Align(2 bytes), pref: Align(2 bytes), }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -270,7 +270,7 @@ error: layout_of(P) = Layout { abi: Align(4 bytes), pref: Align(4 bytes), }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -344,7 +344,7 @@ error: layout_of(T) = Layout { abi: Align(4 bytes), pref: Align(4 bytes), }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr index d3ba1a295b1b..ca041fb539b9 100644 --- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr +++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr @@ -90,7 +90,7 @@ error: layout_of(MissingPayloadField) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -489,7 +489,7 @@ error: layout_of(NicheFirst) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -509,7 +509,7 @@ error: layout_of(NicheFirst) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -641,7 +641,7 @@ error: layout_of(NicheSecond) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -661,7 +661,7 @@ error: layout_of(NicheSecond) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/layout/issue-96185-overaligned-enum.stderr b/tests/ui/layout/issue-96185-overaligned-enum.stderr index c539eb453d91..bc40a2aa482e 100644 --- a/tests/ui/layout/issue-96185-overaligned-enum.stderr +++ b/tests/ui/layout/issue-96185-overaligned-enum.stderr @@ -4,7 +4,7 @@ error: layout_of(Aligned1) = Layout { abi: Align(8 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -42,7 +42,7 @@ error: layout_of(Aligned1) = Layout { abi: Align(8 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -64,7 +64,7 @@ error: layout_of(Aligned1) = Layout { abi: Align(8 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -142,7 +142,7 @@ error: layout_of(Aligned2) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -164,7 +164,7 @@ error: layout_of(Aligned2) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/layout/struct.rs b/tests/ui/layout/struct.rs index d072d123b0d4..309624e667cc 100644 --- a/tests/ui/layout/struct.rs +++ b/tests/ui/layout/struct.rs @@ -6,7 +6,7 @@ #![crate_type = "lib"] #[rustc_layout(abi)] -struct AlignedZstPreventsScalar(i16, [i32; 0]); //~ERROR: abi: Aggregate +struct AlignedZstPreventsScalar(i16, [i32; 0]); //~ERROR: abi: Memory #[rustc_layout(abi)] struct AlignedZstButStillScalar(i32, [i16; 0]); //~ERROR: abi: Scalar diff --git a/tests/ui/layout/struct.stderr b/tests/ui/layout/struct.stderr index b61c9a99cce6..7bc9af61ed48 100644 --- a/tests/ui/layout/struct.stderr +++ b/tests/ui/layout/struct.stderr @@ -1,4 +1,4 @@ -error: abi: Aggregate { sized: true } +error: abi: Memory { sized: true } --> $DIR/struct.rs:9:1 | LL | struct AlignedZstPreventsScalar(i16, [i32; 0]); diff --git a/tests/ui/layout/thumb-enum.stderr b/tests/ui/layout/thumb-enum.stderr index 6f6ab4982067..bf043af586b1 100644 --- a/tests/ui/layout/thumb-enum.stderr +++ b/tests/ui/layout/thumb-enum.stderr @@ -48,7 +48,7 @@ error: layout_of(A) = Layout { abi: Align(1 bytes), pref: Align(4 bytes), }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -122,7 +122,7 @@ error: layout_of(B) = Layout { abi: Align(1 bytes), pref: Align(4 bytes), }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -196,7 +196,7 @@ error: layout_of(C) = Layout { abi: Align(2 bytes), pref: Align(4 bytes), }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -270,7 +270,7 @@ error: layout_of(P) = Layout { abi: Align(4 bytes), pref: Align(4 bytes), }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -344,7 +344,7 @@ error: layout_of(T) = Layout { abi: Align(4 bytes), pref: Align(4 bytes), }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index ee34cfdfb0db..d61408098df7 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -4,7 +4,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -42,7 +42,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -66,7 +66,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -109,7 +109,7 @@ error: layout_of(MultipleAlignments) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -147,7 +147,7 @@ error: layout_of(MultipleAlignments) = Layout { abi: Align(2 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -171,7 +171,7 @@ error: layout_of(MultipleAlignments) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -195,7 +195,7 @@ error: layout_of(MultipleAlignments) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -238,7 +238,7 @@ error: layout_of(Result<[u32; 0], Packed>>) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -276,7 +276,7 @@ error: layout_of(Result<[u32; 0], Packed>>) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -300,7 +300,7 @@ error: layout_of(Result<[u32; 0], Packed>>) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -343,7 +343,7 @@ error: layout_of(Result<[u32; 0], Packed>) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -385,7 +385,7 @@ error: layout_of(Result<[u32; 0], Packed>) = Layout { abi: Align(4 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -409,7 +409,7 @@ error: layout_of(Result<[u32; 0], Packed>) = Layout { abi: Align(1 bytes), pref: $PREF_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr index e2e57fe0e731..64a0cb7f31a1 100644 --- a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr +++ b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr @@ -190,7 +190,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -254,7 +254,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr index 6ecdab1cc140..5c4daa6d5197 100644 --- a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr +++ b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr @@ -190,7 +190,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -254,7 +254,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr index e2e57fe0e731..64a0cb7f31a1 100644 --- a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr +++ b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr @@ -190,7 +190,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -254,7 +254,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr index e2e57fe0e731..64a0cb7f31a1 100644 --- a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr +++ b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr @@ -190,7 +190,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -254,7 +254,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/repr/repr-c-int-dead-variants.stderr b/tests/ui/repr/repr-c-int-dead-variants.stderr index f7df576df248..75005a64523a 100644 --- a/tests/ui/repr/repr-c-int-dead-variants.stderr +++ b/tests/ui/repr/repr-c-int-dead-variants.stderr @@ -190,7 +190,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -254,7 +254,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { abi: Align(8 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr index 8465e1b7ff27..7bd0d826cab7 100644 --- a/tests/ui/type/pattern_types/range_patterns.stderr +++ b/tests/ui/type/pattern_types/range_patterns.stderr @@ -124,7 +124,7 @@ error: layout_of(Option<(u32) is 1..=>) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { @@ -232,7 +232,7 @@ error: layout_of(Option>) = Layout { abi: Align(1 bytes), pref: $SOME_ALIGN, }, - abi: Aggregate { + abi: Memory { sized: true, }, fields: Arbitrary { From 6d8d79595e93c74a545d60b181febc0e351851db Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Mon, 2 Sep 2024 12:52:39 +0000 Subject: [PATCH 31/56] Reject generic self types. The RFC for arbitrary self types v2 declares that we should reject "generic" self types. This commit does so. The definition of "generic" was unclear in the RFC, but has been explored in https://github.com/rust-lang/rust/issues/129147 and the conclusion is that "generic" means any `self` type which is a type parameter defined on the method itself, or references to such a type. This approach was chosen because other definitions of "generic" don't work. Specifically, * we can't filter out generic type _arguments_, because that would filter out Rc and all the other types of smart pointer we want to support; * we can't filter out all type params, because Self itself is a type param, and because existing Rust code depends on other type params declared on the type (as opposed to the method). This PR decides to make a new error code for this case, instead of reusing the existing E0307 error. This makes the code a bit more complex, but it seems we have an opportunity to provide specific diagnostics for this case so we should do so. This PR filters out generic self types whether or not the 'arbitrary self types' feature is enabled. However, it's believed that it can't have any effect on code which uses stable Rust, since there are no stable traits which can be used to indicate a valid generic receiver type, and thus it would have been impossible to write code which could trigger this new error case. It is however possible that this could break existing code which uses either of the unstable `arbitrary_self_types` or `receiver_trait` features. This breakage is intentional; as we move arbitrary self types towards stabilization we don't want to continue to support generic such types. This PR adds lots of extra tests to arbitrary-self-from-method-substs. Most of these are ways to trigger a "type mismatch" error which https://github.com/rust-lang/rust/blob/9b82580c7347f800c2550e6719e4218a60a80b28/compiler/rustc_hir_typeck/src/method/confirm.rs#L519 hopes can be minimized by filtering out generics in this way. We remove a FIXME from confirm.rs suggesting that we make this change. It's still possible to cause type mismatch errors, and a subsequent PR may be able to improve diagnostics in this area, but it's harder to cause these errors without contrived uses of the turbofish. This is a part of the arbitrary self types v2 project, https://github.com/rust-lang/rfcs/pull/3519 https://github.com/rust-lang/rust/issues/44874 r? @wesleywiser --- .../src/error_codes/E0801.md | 51 +++++ compiler/rustc_error_codes/src/lib.rs | 1 + compiler/rustc_hir_analysis/messages.ftl | 6 + .../rustc_hir_analysis/src/check/wfcheck.rs | 86 +++++++-- compiler/rustc_hir_analysis/src/errors.rs | 10 + .../rustc_hir_typeck/src/method/confirm.rs | 3 - src/tools/tidy/src/issues.txt | 1 - .../arbitrary-self-from-method-substs-ice.rs | 2 +- ...bitrary-self-from-method-substs-ice.stderr | 10 +- ...ary-self-from-method-substs.default.stderr | 162 +++++++++++++++- ...ary-self-from-method-substs.feature.stderr | 176 +++++++++++++++++- .../self/arbitrary-self-from-method-substs.rs | 94 +++++++++- tests/ui/type-alias-impl-trait/issue-57700.rs | 21 --- .../type-alias-impl-trait/issue-57700.stderr | 8 - 14 files changed, 570 insertions(+), 61 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0801.md delete mode 100644 tests/ui/type-alias-impl-trait/issue-57700.rs delete mode 100644 tests/ui/type-alias-impl-trait/issue-57700.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0801.md b/compiler/rustc_error_codes/src/error_codes/E0801.md new file mode 100644 index 000000000000..c89feb9b3080 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0801.md @@ -0,0 +1,51 @@ +The `self` parameter in a method has an invalid generic "receiver type". + +Erroneous code example: + +```compile_fail,E0801 +struct Foo; + +impl Foo { + fn foo>(self: R) {} +} +``` + +or alternatively, + +```compile_fail,E0801 +struct Foo; + +impl Foo { + fn foo(self: impl std::ops::Deref) {} +} +``` + +Methods take a special first parameter, termed `self`. It's normal to +use `self`, `&self` or `&mut self`, which are syntactic sugar for +`self: Self`, `self: &Self`, and `self: &mut Self` respectively. +But it's also possible to use more sophisticated types of `self` +parameter, for instance `std::rc::Rc`. The set of allowable +`Self` types is extensible using the nightly feature +[Arbitrary self types][AST]. +This will extend the valid set of `Self` types to anything which implements +`std::ops::Deref`, for example `Rc`, `Box`, or +your own smart pointers that do the same. + +However, even with that feature, the `self` type must be concrete. +Generic `self` types are not permitted. Specifically, a `self` type will +be rejected if it is a type parameter defined on the method. + +These are OK: + +``` +struct Foo; + +impl Foo { + fn foo(self) {} + fn foo2(self: std::rc::Rc) {} // or some other similar + // smart pointer if you enable arbitrary self types and + // the pointer implements Deref +} +``` + +[AST]: https://doc.rust-lang.org/unstable-book/language-features/arbitrary-self-types.html diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 27a34d6003db..29f3277d3997 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -540,6 +540,7 @@ E0797: 0797, E0798: 0798, E0799: 0799, E0800: 0800, +E0801: 0801, ); ) } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 7191c7240614..38b11aa40179 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -234,6 +234,12 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a .help = consider moving this inherent impl into the crate defining the type if possible .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items +hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}` + .note = type of `self` must not be a method generic parameter type + +hir_analysis_invalid_generic_receiver_ty_help = + use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + hir_analysis_invalid_receiver_ty = invalid `self` parameter type: `{$receiver_ty}` .note = type of `self` must be `Self` or a type that dereferences to it diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 12ed7b89f68b..5bc320b12b0a 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2,13 +2,14 @@ use std::cell::LazyCell; use std::ops::{ControlFlow, Deref}; use hir::intravisit::{self, Visitor}; +use itertools::Itertools; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; -use rustc_hir::ItemKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lang_items::LangItem; +use rustc_hir::{GenericParamKind, ItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_macros::LintDiagnostic; @@ -378,7 +379,7 @@ fn check_trait_item<'tcx>( _ => (None, trait_item.span), }; check_dyn_incompatible_self_trait_by_name(tcx, trait_item); - let mut res = check_associated_item(tcx, def_id, span, method_sig); + let mut res = check_associated_item(tcx, def_id, span, method_sig, None); if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) { for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) { @@ -387,6 +388,7 @@ fn check_trait_item<'tcx>( assoc_ty_def_id.expect_local(), tcx.def_span(assoc_ty_def_id), None, + None, )); } } @@ -904,8 +906,13 @@ fn check_impl_item<'tcx>( hir::ImplItemKind::Type(ty) if ty.span != DUMMY_SP => (None, ty.span), _ => (None, impl_item.span), }; - - check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig) + check_associated_item( + tcx, + impl_item.owner_id.def_id, + span, + method_sig, + Some(impl_item.generics), + ) } fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ErrorGuaranteed> { @@ -1038,6 +1045,7 @@ fn check_associated_item( item_id: LocalDefId, span: Span, sig_if_method: Option<&hir::FnSig<'_>>, + generics: Option<&hir::Generics<'_>>, ) -> Result<(), ErrorGuaranteed> { let loc = Some(WellFormedLoc::Ty(item_id)); enter_wf_checking_ctxt(tcx, span, item_id, |wfcx| { @@ -1070,7 +1078,7 @@ fn check_associated_item( hir_sig.decl, item.def_id.expect_local(), ); - check_method_receiver(wfcx, hir_sig, item, self_ty) + check_method_receiver(wfcx, hir_sig, item, self_ty, generics) } ty::AssocKind::Type => { if let ty::AssocItemContainer::TraitContainer = item.container { @@ -1692,6 +1700,7 @@ fn check_method_receiver<'tcx>( fn_sig: &hir::FnSig<'_>, method: ty::AssocItem, self_ty: Ty<'tcx>, + generics: Option<&hir::Generics<'_>>, ) -> Result<(), ErrorGuaranteed> { let tcx = wfcx.tcx(); @@ -1726,7 +1735,9 @@ fn check_method_receiver<'tcx>( None }; - if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level) { + let receiver_validity = + receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level, generics); + if let Err(receiver_validity_err) = receiver_validity { return Err(match arbitrary_self_types_level { // Wherever possible, emit a message advising folks that the features // `arbitrary_self_types` or `arbitrary_self_types_pointers` might @@ -1737,7 +1748,9 @@ fn check_method_receiver<'tcx>( receiver_ty, self_ty, Some(ArbitrarySelfTypesLevel::Basic), - ) => + generics, + ) + .is_ok() => { // Report error; would have worked with `arbitrary_self_types`. feature_err( @@ -1759,7 +1772,9 @@ fn check_method_receiver<'tcx>( receiver_ty, self_ty, Some(ArbitrarySelfTypesLevel::WithPointers), - ) => + generics, + ) + .is_ok() => { // Report error; would have worked with `arbitrary_self_types_pointers`. feature_err( @@ -1777,13 +1792,53 @@ fn check_method_receiver<'tcx>( _ => // Report error; would not have worked with `arbitrary_self_types[_pointers]`. { - tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }) + match receiver_validity_err { + ReceiverValidityError::DoesNotDeref => { + tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }) + } + ReceiverValidityError::MethodGenericParamUsed => { + tcx.dcx().emit_err(errors::InvalidGenericReceiverTy { span, receiver_ty }) + } + } } }); } Ok(()) } +/// Error cases which may be returned from `receiver_is_valid`. These error +/// cases are generated in this function as they may be unearthed as we explore +/// the `autoderef` chain, but they're converted to diagnostics in the caller. +enum ReceiverValidityError { + /// The self type does not get to the receiver type by following the + /// autoderef chain. + DoesNotDeref, + /// A type was found which is a method type parameter, and that's not allowed. + MethodGenericParamUsed, +} + +/// Confirms that a type is not a type parameter referring to one of the +/// method's type params. +fn confirm_type_is_not_a_method_generic_param( + ty: Ty<'_>, + method_generics: Option<&hir::Generics<'_>>, +) -> Result<(), ReceiverValidityError> { + if let ty::Param(param) = ty.kind() { + if let Some(generics) = method_generics { + if generics + .params + .iter() + .filter(|g| matches!(g.kind, GenericParamKind::Type { .. })) + .map(|g| g.name.ident().name) + .contains(¶m.name) + { + return Err(ReceiverValidityError::MethodGenericParamUsed); + } + } + } + Ok(()) +} + /// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If /// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly /// through a `*const/mut T` raw pointer if `arbitrary_self_types_pointers` is also enabled. @@ -1799,7 +1854,8 @@ fn receiver_is_valid<'tcx>( receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, arbitrary_self_types_enabled: Option, -) -> bool { + generics: Option<&hir::Generics<'_>>, +) -> Result<(), ReceiverValidityError> { let infcx = wfcx.infcx; let tcx = wfcx.tcx(); let cause = @@ -1811,9 +1867,11 @@ fn receiver_is_valid<'tcx>( ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?; if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } }) { - return true; + return Ok(()); } + confirm_type_is_not_a_method_generic_param(receiver_ty, generics)?; + let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty); // The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`. @@ -1830,6 +1888,8 @@ fn receiver_is_valid<'tcx>( potential_self_ty, self_ty ); + confirm_type_is_not_a_method_generic_param(potential_self_ty, generics)?; + // Check if the self type unifies. If it does, then commit the result // since it may have region side-effects. if let Ok(()) = wfcx.infcx.commit_if_ok(|_| { @@ -1838,7 +1898,7 @@ fn receiver_is_valid<'tcx>( if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } }) { wfcx.register_obligations(autoderef.into_obligations()); - return true; + return Ok(()); } // Without `feature(arbitrary_self_types)`, we require that each step in the @@ -1865,7 +1925,7 @@ fn receiver_is_valid<'tcx>( } debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); - false + Err(ReceiverValidityError::DoesNotDeref) } fn receiver_is_implemented<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 7fa9dfe346d7..a92a5e4278c5 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1623,6 +1623,16 @@ pub(crate) struct InvalidReceiverTy<'tcx> { pub receiver_ty: Ty<'tcx>, } +#[derive(Diagnostic)] +#[diag(hir_analysis_invalid_generic_receiver_ty, code = E0801)] +#[note] +#[help(hir_analysis_invalid_generic_receiver_ty_help)] +pub(crate) struct InvalidGenericReceiverTy<'tcx> { + #[primary_span] + pub span: Span, + pub receiver_ty: Ty<'tcx>, +} + #[derive(Diagnostic)] #[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)] #[note] diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index f2b55d3aa4e1..92b504d10bc0 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -533,9 +533,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.register_predicates(obligations); } Err(terr) => { - // FIXME(arbitrary_self_types): We probably should limit the - // situations where this can occur by adding additional restrictions - // to the feature, like the self type can't reference method args. if self.tcx.features().arbitrary_self_types() { self.err_ctxt() .report_mismatched_types( diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 94f8d23c1586..932a58788e04 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -4102,7 +4102,6 @@ ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs ui/type-alias-impl-trait/issue-57611-trait-alias.rs -ui/type-alias-impl-trait/issue-57700.rs ui/type-alias-impl-trait/issue-57807-associated-type.rs ui/type-alias-impl-trait/issue-57961.rs ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs index a544c8ea0d15..d121a194be6b 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs @@ -8,7 +8,7 @@ use std::ops::Deref; struct Foo(u32); impl Foo { const fn get>(self: R) -> u32 { - //~^ ERROR: `R` cannot be used as the type of `self` + //~^ ERROR invalid generic `self` parameter type //~| ERROR destructor of `R` cannot be evaluated at compile-time self.0 //~^ ERROR cannot call non-const fn `::deref` in constant function diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr index 6ae60e7af47d..7252b5890fdb 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr @@ -15,18 +15,16 @@ LL | const fn get>(self: R) -> u32 { LL | } | - value is dropped here -error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature +error[E0801]: invalid generic `self` parameter type: `R` --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49 | LL | const fn get>(self: R) -> u32 { | ^ | - = note: see issue #44874 for more information - = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) error: aborting due to 3 previous errors -Some errors have detailed explanations: E0015, E0493, E0658. +Some errors have detailed explanations: E0015, E0493, E0801. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr index 4cc69666b887..5dc3a0b02347 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr @@ -1,14 +1,168 @@ -error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature - --> $DIR/arbitrary-self-from-method-substs.rs:8:43 +error[E0801]: invalid generic `self` parameter type: `R` + --> $DIR/arbitrary-self-from-method-substs.rs:9:43 | LL | fn get>(self: R) -> u32 { | ^ | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&R` + --> $DIR/arbitrary-self-from-method-substs.rs:13:44 + | +LL | fn get1>(self: &R) -> u32 { + | ^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&mut R` + --> $DIR/arbitrary-self-from-method-substs.rs:17:44 + | +LL | fn get2>(self: &mut R) -> u32 { + | ^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `Rc` + --> $DIR/arbitrary-self-from-method-substs.rs:21:44 + | +LL | fn get3>(self: std::rc::Rc) -> u32 { + | ^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&Rc` + --> $DIR/arbitrary-self-from-method-substs.rs:25:44 + | +LL | fn get4>(self: &std::rc::Rc) -> u32 { + | ^^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `Rc<&R>` + --> $DIR/arbitrary-self-from-method-substs.rs:29:44 + | +LL | fn get5>(self: std::rc::Rc<&R>) -> u32 { + | ^^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0658]: `::Receiver` cannot be used as the type of `self` without the `arbitrary_self_types` feature + --> $DIR/arbitrary-self-from-method-substs.rs:33:37 + | +LL | fn get6(self: FR::Receiver, other: FR) -> u32 { + | ^^^^^^^^^^^^ + | = note: see issue #44874 for more information = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) -error: aborting due to 1 previous error +error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature + --> $DIR/arbitrary-self-from-method-substs.rs:61:18 + | +LL | fn get(self: R) {} + | ^ + | + = note: see issue #44874 for more information + = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) -For more information about this error, try `rustc --explain E0658`. +error[E0271]: type mismatch resolving `::Receiver == Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:92:9 + | +LL | foo.get6(Silly); + | ^^^^ type mismatch resolving `::Receiver == Foo` + | +note: expected this to be `Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:71:21 + | +LL | type Receiver = std::rc::Rc; + | ^^^^^^^^^^^^^^^^ + = note: expected struct `Foo` + found struct `Rc` + +error[E0271]: type mismatch resolving `::Receiver == &Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:96:9 + | +LL | foo.get6(Silly); + | ^^^^ type mismatch resolving `::Receiver == &Foo` + | +note: expected this to be `&Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:71:21 + | +LL | type Receiver = std::rc::Rc; + | ^^^^^^^^^^^^^^^^ + = note: expected reference `&Foo` + found struct `Rc` + +error[E0599]: the method `get` exists for struct `Rc>`, but its trait bounds were not satisfied + --> $DIR/arbitrary-self-from-method-substs.rs:100:7 + | +LL | struct Bar(std::marker::PhantomData); + | ------------- doesn't satisfy `Bar<_>: Deref` +... +LL | t.get(); + | ^^^ method cannot be called on `Rc>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>` + `<&Rc> as Deref>::Target = Bar<&Rc>>` + `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>` + `<&mut Rc> as Deref>::Target = Bar<&mut Rc>>` + `> as Deref>::Target = Bar>>` + `Bar<_>: Deref` + --> $DIR/arbitrary-self-from-method-substs.rs:60:9 + | +LL | impl> Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ + | | | + | | unsatisfied trait bound introduced here + | unsatisfied trait bound introduced here +note: the trait `Deref` must be implemented + --> $SRC_DIR/core/src/ops/deref.rs:LL:COL + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `get`, perhaps you need to implement it: + candidate #1: `SliceIndex` + +error[E0599]: the method `get` exists for reference `&Rc>`, but its trait bounds were not satisfied + --> $DIR/arbitrary-self-from-method-substs.rs:108:7 + | +LL | struct Bar(std::marker::PhantomData); + | ------------- doesn't satisfy `Bar<_>: Deref` +... +LL | t.get(); + | ^^^ method cannot be called on `&Rc>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `<&&Rc> as Deref>::Target = Bar<&&Rc>>` + `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>` + `<&Rc> as Deref>::Target = Bar<&Rc>>` + `<&mut &Rc> as Deref>::Target = Bar<&mut &Rc>>` + `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>` + `<&mut Rc> as Deref>::Target = Bar<&mut Rc>>` + `> as Deref>::Target = Bar>>` + `Bar<_>: Deref` + --> $DIR/arbitrary-self-from-method-substs.rs:60:9 + | +LL | impl> Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ + | | | + | | unsatisfied trait bound introduced here + | unsatisfied trait bound introduced here +note: the trait `Deref` must be implemented + --> $SRC_DIR/core/src/ops/deref.rs:LL:COL + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `get`, perhaps you need to implement it: + candidate #1: `SliceIndex` + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0271, E0599, E0658, E0801. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr b/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr index 44e553f1a06c..6e864f44aa34 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr @@ -1,9 +1,179 @@ +error[E0801]: invalid generic `self` parameter type: `R` + --> $DIR/arbitrary-self-from-method-substs.rs:9:43 + | +LL | fn get>(self: R) -> u32 { + | ^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&R` + --> $DIR/arbitrary-self-from-method-substs.rs:13:44 + | +LL | fn get1>(self: &R) -> u32 { + | ^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&mut R` + --> $DIR/arbitrary-self-from-method-substs.rs:17:44 + | +LL | fn get2>(self: &mut R) -> u32 { + | ^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `Rc` + --> $DIR/arbitrary-self-from-method-substs.rs:21:44 + | +LL | fn get3>(self: std::rc::Rc) -> u32 { + | ^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `&Rc` + --> $DIR/arbitrary-self-from-method-substs.rs:25:44 + | +LL | fn get4>(self: &std::rc::Rc) -> u32 { + | ^^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + +error[E0801]: invalid generic `self` parameter type: `Rc<&R>` + --> $DIR/arbitrary-self-from-method-substs.rs:29:44 + | +LL | fn get5>(self: std::rc::Rc<&R>) -> u32 { + | ^^^^^^^^^^^^^^^ + | + = note: type of `self` must not be a method generic parameter type + = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one of the previous types except `Self`) + error[E0308]: mismatched types - --> $DIR/arbitrary-self-from-method-substs.rs:16:5 + --> $DIR/arbitrary-self-from-method-substs.rs:76:5 | LL | foo.get::<&Foo>(); | ^^^ expected `&Foo`, found `Foo` -error: aborting due to 1 previous error +error[E0308]: mismatched types + --> $DIR/arbitrary-self-from-method-substs.rs:78:5 + | +LL | foo.get::>(); + | ^^^ expected `Rc`, found `Foo` + | + = note: expected struct `Rc` + found struct `Foo` -For more information about this error, try `rustc --explain E0308`. +error[E0308]: mismatched types + --> $DIR/arbitrary-self-from-method-substs.rs:84:5 + | +LL | smart_ptr.get::>(); + | ^^^^^^^^^ expected `SmartPtr2<'_, Foo>`, found `SmartPtr<'_, Foo>` + | + = note: expected struct `SmartPtr2<'_, Foo>` + found struct `SmartPtr<'_, Foo>` + +error[E0308]: mismatched types + --> $DIR/arbitrary-self-from-method-substs.rs:86:5 + | +LL | smart_ptr.get::<&Foo>(); + | ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>` + | + = note: expected reference `&Foo` + found struct `SmartPtr<'_, Foo, >` + +error[E0271]: type mismatch resolving `::Receiver == Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:92:9 + | +LL | foo.get6(Silly); + | ^^^^ type mismatch resolving `::Receiver == Foo` + | +note: expected this to be `Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:71:21 + | +LL | type Receiver = std::rc::Rc; + | ^^^^^^^^^^^^^^^^ + = note: expected struct `Foo` + found struct `Rc` + +error[E0271]: type mismatch resolving `::Receiver == &Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:96:9 + | +LL | foo.get6(Silly); + | ^^^^ type mismatch resolving `::Receiver == &Foo` + | +note: expected this to be `&Foo` + --> $DIR/arbitrary-self-from-method-substs.rs:71:21 + | +LL | type Receiver = std::rc::Rc; + | ^^^^^^^^^^^^^^^^ + = note: expected reference `&Foo` + found struct `Rc` + +error[E0599]: the method `get` exists for struct `Rc>`, but its trait bounds were not satisfied + --> $DIR/arbitrary-self-from-method-substs.rs:100:7 + | +LL | struct Bar(std::marker::PhantomData); + | ------------- doesn't satisfy `Bar<_>: Deref` +... +LL | t.get(); + | ^^^ method cannot be called on `Rc>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>` + `<&Rc> as Deref>::Target = Bar<&Rc>>` + `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>` + `<&mut Rc> as Deref>::Target = Bar<&mut Rc>>` + `> as Deref>::Target = Bar>>` + `Bar<_>: Deref` + --> $DIR/arbitrary-self-from-method-substs.rs:60:9 + | +LL | impl> Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ + | | | + | | unsatisfied trait bound introduced here + | unsatisfied trait bound introduced here +note: the trait `Deref` must be implemented + --> $SRC_DIR/core/src/ops/deref.rs:LL:COL + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `get`, perhaps you need to implement it: + candidate #1: `SliceIndex` + +error[E0599]: the method `get` exists for reference `&Rc>`, but its trait bounds were not satisfied + --> $DIR/arbitrary-self-from-method-substs.rs:108:7 + | +LL | struct Bar(std::marker::PhantomData); + | ------------- doesn't satisfy `Bar<_>: Deref` +... +LL | t.get(); + | ^^^ method cannot be called on `&Rc>` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `<&&Rc> as Deref>::Target = Bar<&&Rc>>` + `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>` + `<&Rc> as Deref>::Target = Bar<&Rc>>` + `<&mut &Rc> as Deref>::Target = Bar<&mut &Rc>>` + `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>` + `<&mut Rc> as Deref>::Target = Bar<&mut Rc>>` + `> as Deref>::Target = Bar>>` + `Bar<_>: Deref` + --> $DIR/arbitrary-self-from-method-substs.rs:60:9 + | +LL | impl> Bar { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ + | | | + | | unsatisfied trait bound introduced here + | unsatisfied trait bound introduced here +note: the trait `Deref` must be implemented + --> $SRC_DIR/core/src/ops/deref.rs:LL:COL + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `get`, perhaps you need to implement it: + candidate #1: `SliceIndex` + +error: aborting due to 14 previous errors + +Some errors have detailed explanations: E0271, E0308, E0599, E0801. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/self/arbitrary-self-from-method-substs.rs b/tests/ui/self/arbitrary-self-from-method-substs.rs index 99977ed9b8c5..f2d658596151 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs.rs +++ b/tests/ui/self/arbitrary-self-from-method-substs.rs @@ -2,17 +2,109 @@ #![cfg_attr(feature, feature(arbitrary_self_types))] use std::ops::Deref; +use std::marker::PhantomData; struct Foo(u32); impl Foo { fn get>(self: R) -> u32 { - //[default]~^ ERROR: `R` cannot be used as the type of `self` + //~^ ERROR: invalid generic `self` parameter type self.0 } + fn get1>(self: &R) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get2>(self: &mut R) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get3>(self: std::rc::Rc) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get4>(self: &std::rc::Rc) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get5>(self: std::rc::Rc<&R>) -> u32 { + //~^ ERROR: invalid generic `self` parameter type + self.0 + } + fn get6(self: FR::Receiver, other: FR) -> u32 { + //[default]~^ ERROR: `::Receiver` cannot be used as the type of `self` + 42 + } +} + + +struct SmartPtr<'a, T: ?Sized>(&'a T); + +impl<'a, T: ?Sized> Deref for SmartPtr<'a, T> { + type Target = T; + fn deref(&self) -> &Self::Target { + unimplemented!() + } +} + +struct SmartPtr2<'a, T: ?Sized>(&'a T); + +impl<'a, T: ?Sized> Deref for SmartPtr2<'a, T> { + type Target = T; + fn deref(&self) -> &Self::Target { + unimplemented!() + } +} + +struct Bar(std::marker::PhantomData); + +impl> Bar { + fn get(self: R) {} + //[default]~^ ERROR: `R` cannot be used as the type of `self` +} + +trait FindReceiver { + type Receiver: Deref; +} + +struct Silly; +impl FindReceiver for Silly { + type Receiver = std::rc::Rc; } fn main() { let mut foo = Foo(1); foo.get::<&Foo>(); //[feature]~^ ERROR mismatched types + foo.get::>(); + //[feature]~^ ERROR mismatched types + + let smart_ptr = SmartPtr(&foo); + let smart_ptr2 = SmartPtr2(&foo); + smart_ptr.get(); // this compiles + smart_ptr.get::>(); + //[feature]~^ ERROR mismatched types + smart_ptr.get::<&Foo>(); + //[feature]~^ ERROR mismatched types + + let mut foo = Foo(1); + // This test is slightly contrived in an attempt to generate a mismatched types + // error for the self type below, without using the turbofish. + foo.get6(Silly); + //~^ ERROR type mismatch + let mut foo = Foo(1); + let foo = &foo; + foo.get6(Silly); + //~^ ERROR type mismatch + + let t = std::rc::Rc::new(Bar(std::marker::PhantomData)); + t.get(); + //~^ ERROR its trait bounds were not satisfied + let t = &t; + // This is a further attempt at triggering 'type mismatch' errors + // from arbitrary self types without resorting to the turbofish. + // Ideally, here, t is Thing> while we're going to call + // it with a &t method receiver. However, this doesn't work since that + // type of t becomes recursive and trait bounds can't be satisfied. + t.get(); + //~^ ERROR its trait bounds were not satisfied } diff --git a/tests/ui/type-alias-impl-trait/issue-57700.rs b/tests/ui/type-alias-impl-trait/issue-57700.rs deleted file mode 100644 index 8746545ecc9e..000000000000 --- a/tests/ui/type-alias-impl-trait/issue-57700.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![feature(arbitrary_self_types)] -#![feature(impl_trait_in_assoc_type)] - -use std::ops::Deref; - -trait Foo { - type Bar: Foo; - - fn foo(self: impl Deref) -> Self::Bar; -} - -impl Foo for C { - type Bar = impl Foo; - - fn foo(self: impl Deref) -> Self::Bar { - self - //~^ Error type parameter `impl Deref` is part of concrete type but not used in parameter list for the `impl Trait` type alias - } -} - -fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-57700.stderr b/tests/ui/type-alias-impl-trait/issue-57700.stderr deleted file mode 100644 index 7efb05f40b07..000000000000 --- a/tests/ui/type-alias-impl-trait/issue-57700.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: type parameter `impl Deref` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-57700.rs:16:9 - | -LL | self - | ^^^^ - -error: aborting due to 1 previous error - From 86af0f9b7eccf3f8807cc0205a46d67ce31d9cf7 Mon Sep 17 00:00:00 2001 From: Adrian Taylor Date: Thu, 24 Oct 2024 16:25:02 +0000 Subject: [PATCH 32/56] Switch to comparing indices instead of names. --- .../rustc_hir_analysis/src/check/wfcheck.rs | 39 ++++++------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 5bc320b12b0a..b20fa49eadb8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2,14 +2,13 @@ use std::cell::LazyCell; use std::ops::{ControlFlow, Deref}; use hir::intravisit::{self, Visitor}; -use itertools::Itertools; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; +use rustc_hir::ItemKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lang_items::LangItem; -use rustc_hir::{GenericParamKind, ItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_macros::LintDiagnostic; @@ -379,7 +378,7 @@ fn check_trait_item<'tcx>( _ => (None, trait_item.span), }; check_dyn_incompatible_self_trait_by_name(tcx, trait_item); - let mut res = check_associated_item(tcx, def_id, span, method_sig, None); + let mut res = check_associated_item(tcx, def_id, span, method_sig); if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) { for &assoc_ty_def_id in tcx.associated_types_for_impl_traits_in_associated_fn(def_id) { @@ -388,7 +387,6 @@ fn check_trait_item<'tcx>( assoc_ty_def_id.expect_local(), tcx.def_span(assoc_ty_def_id), None, - None, )); } } @@ -906,13 +904,7 @@ fn check_impl_item<'tcx>( hir::ImplItemKind::Type(ty) if ty.span != DUMMY_SP => (None, ty.span), _ => (None, impl_item.span), }; - check_associated_item( - tcx, - impl_item.owner_id.def_id, - span, - method_sig, - Some(impl_item.generics), - ) + check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig) } fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ErrorGuaranteed> { @@ -1045,7 +1037,6 @@ fn check_associated_item( item_id: LocalDefId, span: Span, sig_if_method: Option<&hir::FnSig<'_>>, - generics: Option<&hir::Generics<'_>>, ) -> Result<(), ErrorGuaranteed> { let loc = Some(WellFormedLoc::Ty(item_id)); enter_wf_checking_ctxt(tcx, span, item_id, |wfcx| { @@ -1078,7 +1069,7 @@ fn check_associated_item( hir_sig.decl, item.def_id.expect_local(), ); - check_method_receiver(wfcx, hir_sig, item, self_ty, generics) + check_method_receiver(wfcx, hir_sig, item, self_ty) } ty::AssocKind::Type => { if let ty::AssocItemContainer::TraitContainer = item.container { @@ -1700,7 +1691,6 @@ fn check_method_receiver<'tcx>( fn_sig: &hir::FnSig<'_>, method: ty::AssocItem, self_ty: Ty<'tcx>, - generics: Option<&hir::Generics<'_>>, ) -> Result<(), ErrorGuaranteed> { let tcx = wfcx.tcx(); @@ -1734,6 +1724,7 @@ fn check_method_receiver<'tcx>( } else { None }; + let generics = tcx.generics_of(method.def_id); let receiver_validity = receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level, generics); @@ -1821,19 +1812,11 @@ enum ReceiverValidityError { /// method's type params. fn confirm_type_is_not_a_method_generic_param( ty: Ty<'_>, - method_generics: Option<&hir::Generics<'_>>, + method_generics: &ty::Generics, ) -> Result<(), ReceiverValidityError> { if let ty::Param(param) = ty.kind() { - if let Some(generics) = method_generics { - if generics - .params - .iter() - .filter(|g| matches!(g.kind, GenericParamKind::Type { .. })) - .map(|g| g.name.ident().name) - .contains(¶m.name) - { - return Err(ReceiverValidityError::MethodGenericParamUsed); - } + if (param.index as usize) >= method_generics.parent_count { + return Err(ReceiverValidityError::MethodGenericParamUsed); } } Ok(()) @@ -1854,7 +1837,7 @@ fn receiver_is_valid<'tcx>( receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, arbitrary_self_types_enabled: Option, - generics: Option<&hir::Generics<'_>>, + method_generics: &ty::Generics, ) -> Result<(), ReceiverValidityError> { let infcx = wfcx.infcx; let tcx = wfcx.tcx(); @@ -1870,7 +1853,7 @@ fn receiver_is_valid<'tcx>( return Ok(()); } - confirm_type_is_not_a_method_generic_param(receiver_ty, generics)?; + confirm_type_is_not_a_method_generic_param(receiver_ty, method_generics)?; let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty); @@ -1888,7 +1871,7 @@ fn receiver_is_valid<'tcx>( potential_self_ty, self_ty ); - confirm_type_is_not_a_method_generic_param(potential_self_ty, generics)?; + confirm_type_is_not_a_method_generic_param(potential_self_ty, method_generics)?; // Check if the self type unifies. If it does, then commit the result // since it may have region side-effects. From a43a37c706890aa6d7e1a01a021e8e5b3d6341b8 Mon Sep 17 00:00:00 2001 From: Henry Jiang Date: Wed, 30 Oct 2024 09:17:44 -0400 Subject: [PATCH 33/56] fix libc call from i8 to u8 --- compiler/rustc_session/src/filesearch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 4aae2649843b..b3e3381d986b 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -84,7 +84,7 @@ fn current_dll_path() -> Result { loop { if libc::loadquery( libc::L_GETINFO, - buffer.as_mut_ptr() as *mut i8, + buffer.as_mut_ptr() as *mut u8, (std::mem::size_of::() * buffer.len()) as u32, ) >= 0 { From 0900a1bd8037bc2042eb926b129123e942f00d33 Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 30 Oct 2024 13:29:05 +0000 Subject: [PATCH 34/56] the unvacationer --- triagebot.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 6fa92b4af054..7f4def6a11ba 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -966,7 +966,6 @@ cc = ["@kobzol"] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ - "BoxyUwU", "fmease", "jyn514", "oli-obk", From b6e1214ac041f1edeb3d40f87924ec752619a564 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 20 Aug 2024 00:48:43 +0000 Subject: [PATCH 35/56] Remap impl-trait lifetimes on HIR instead of AST lowering. --- compiler/rustc_ast_lowering/src/lib.rs | 255 +----------- .../src/diagnostics/region_name.rs | 2 +- compiler/rustc_hir/src/hir.rs | 15 +- compiler/rustc_hir/src/intravisit.rs | 7 +- compiler/rustc_hir_analysis/src/collect.rs | 2 +- .../src/collect/generics_of.rs | 15 + .../src/collect/predicates_of.rs | 7 - .../src/collect/resolve_bound_vars.rs | 377 +++++++++++++----- .../src/hir_ty_lowering/mod.rs | 94 +++-- compiler/rustc_hir_pretty/src/lib.rs | 2 - .../src/opaque_hidden_inferred_bound.rs | 2 +- .../src/middle/resolve_bound_vars.rs | 4 +- compiler/rustc_middle/src/query/mod.rs | 17 + compiler/rustc_middle/src/ty/context.rs | 12 +- compiler/rustc_middle/src/ty/sty.rs | 1 + compiler/rustc_resolve/src/late.rs | 40 +- .../nice_region_error/static_impl_trait.rs | 2 +- .../src/error_reporting/infer/region.rs | 16 - .../src/error_reporting/traits/suggestions.rs | 6 +- compiler/rustc_ty_utils/src/assoc.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- .../clippy/clippy_lints/src/lifetimes.rs | 9 - .../clippy_lints/src/manual_async_fn.rs | 82 ++-- .../clippy/clippy_utils/src/hir_utils.rs | 5 +- src/tools/clippy/tests/ui/issue_4266.stderr | 2 +- tests/ui/impl-trait/in-trait/variance.rs | 6 +- tests/ui/impl-trait/in-trait/variance.stderr | 6 +- .../precise-capturing/capturing-implicit.rs | 5 +- .../capturing-implicit.stderr | 14 +- .../bound-lifetime-through-dyn-trait.rs | 3 + .../bound-lifetime-through-dyn-trait.stderr | 46 ++- .../escaping-bound-var.rs | 1 + .../escaping-bound-var.stderr | 14 +- tests/ui/type-alias-impl-trait/variance.rs | 16 +- .../ui/type-alias-impl-trait/variance.stderr | 16 +- 35 files changed, 508 insertions(+), 597 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index dc9c6b765d0e..e1ee3d0af491 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -45,16 +45,14 @@ use rustc_ast::ptr::P; use rustc_ast::{self as ast, *}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; +use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::{ - self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, MissingLifetimeKind, - ParamName, TraitCandidate, + self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, ParamName, TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -83,7 +81,6 @@ mod expr; mod format; mod index; mod item; -mod lifetime_collector; mod pat; mod path; @@ -149,12 +146,6 @@ struct LoweringContext<'a, 'hir> { allow_async_iterator: Lrc<[Symbol]>, allow_for_await: Lrc<[Symbol]>, allow_async_fn_traits: Lrc<[Symbol]>, - - /// Mapping from generics `def_id`s to TAIT generics `def_id`s. - /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic - /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this - /// field from the original parameter 'a to the new parameter 'a1. - generics_def_id_map: Vec>, } impl<'a, 'hir> LoweringContext<'a, 'hir> { @@ -199,7 +190,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller` // interact with `gen`/`async gen` blocks allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), - generics_def_id_map: Default::default(), } } @@ -528,54 +518,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name /// resolver (if any). - fn orig_opt_local_def_id(&self, node: NodeId) -> Option { - self.resolver.node_id_to_def_id.get(&node).copied() - } - - /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name - /// resolver (if any), after applying any remapping from `get_remapped_def_id`. - /// - /// For example, in a function like `fn foo<'a>(x: &'a u32)`, - /// invoking with the id from the `ast::Lifetime` node found inside - /// the `&'a u32` type would return the `LocalDefId` of the - /// `'a` parameter declared on `foo`. - /// - /// This function also applies remapping from `get_remapped_def_id`. - /// These are used when synthesizing opaque types from `-> impl Trait` return types and so forth. - /// For example, in a function like `fn foo<'a>() -> impl Debug + 'a`, - /// we would create an opaque type `type FooReturn<'a1> = impl Debug + 'a1`. - /// When lowering the `Debug + 'a` bounds, we add a remapping to map `'a` to `'a1`. fn opt_local_def_id(&self, node: NodeId) -> Option { - self.orig_opt_local_def_id(node).map(|local_def_id| self.get_remapped_def_id(local_def_id)) + self.resolver.node_id_to_def_id.get(&node).copied() } fn local_def_id(&self, node: NodeId) -> LocalDefId { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) } - /// Get the previously recorded `to` local def id given the `from` local def id, obtained using - /// `generics_def_id_map` field. - fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId { - // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we - // push new mappings, so we first need to get the latest (innermost) mappings, hence `iter().rev()`. - // - // Consider: - // - // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}` - // - // We would end with a generics_def_id_map like: - // - // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]` - // - // for the opaque type generated on `impl Sized + 'b`, we want the result to be: impl_sized#'b. - // So, if we were trying to find first from the start (outermost) would give the wrong result, impl_trait#'b. - self.generics_def_id_map - .iter() - .rev() - .find_map(|map| map.get(&local_def_id).copied()) - .unwrap_or(local_def_id) - } - /// Freshen the `LoweringContext` and ready it to lower a nested item. /// The lowered item is registered into `self.children`. /// @@ -647,27 +597,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { result } - /// Installs the remapping `remap` in scope while `f` is being executed. - /// This causes references to the `LocalDefId` keys to be changed to - /// refer to the values instead. - /// - /// The remapping is used when one piece of AST expands to multiple - /// pieces of HIR. For example, the function `fn foo<'a>(...) -> impl Debug + 'a`, - /// expands to both a function definition (`foo`) and a TAIT for the return value, - /// both of which have a lifetime parameter `'a`. The remapping allows us to - /// rewrite the `'a` in the return value to refer to the - /// `'a` declared on the TAIT, instead of the function. - fn with_remapping( - &mut self, - remap: LocalDefIdMap, - f: impl FnOnce(&mut Self) -> R, - ) -> R { - self.generics_def_id_map.push(remap); - let res = f(self); - self.generics_def_id_map.pop(); - res - } - fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> { let attrs = std::mem::take(&mut self.attrs); let mut bodies = std::mem::take(&mut self.bodies); @@ -1499,27 +1428,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // frequently opened issues show. let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); - // Whether this opaque always captures lifetimes in scope. - // Right now, this is all RPITIT and TAITs, and when `lifetime_capture_rules_2024` - // is enabled. We don't check the span of the edition, since this is done - // on a per-opaque basis to account for nested opaques. - let always_capture_in_scope = match origin { - _ if self.tcx.features().lifetime_capture_rules_2024() => true, - hir::OpaqueTyOrigin::TyAlias { .. } => true, - hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(), - hir::OpaqueTyOrigin::AsyncFn { .. } => { - unreachable!("should be using `lower_coroutine_fn_ret_ty`") - } - }; - let captured_lifetimes_to_duplicate = lifetime_collector::lifetimes_for_opaque( - self.resolver, - always_capture_in_scope, - opaque_ty_node_id, - bounds, - span, - ); - debug!(?captured_lifetimes_to_duplicate); - // Feature gate for RPITIT + use<..> match origin { rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => { @@ -1542,22 +1450,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => {} } - self.lower_opaque_inner( - opaque_ty_node_id, - origin, - captured_lifetimes_to_duplicate, - span, - opaque_ty_span, - |this| this.lower_param_bounds(bounds, itctx), - ) + self.lower_opaque_inner(opaque_ty_node_id, origin, opaque_ty_span, |this| { + this.lower_param_bounds(bounds, itctx) + }) } fn lower_opaque_inner( &mut self, opaque_ty_node_id: NodeId, origin: hir::OpaqueTyOrigin, - captured_lifetimes_to_duplicate: FxIndexSet, - span: Span, opaque_ty_span: Span, lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], ) -> hir::TyKind<'hir> { @@ -1565,145 +1466,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_hir_id = self.lower_node_id(opaque_ty_node_id); debug!(?opaque_ty_def_id, ?opaque_ty_hir_id); - // Map from captured (old) lifetime to synthetic (new) lifetime. - // Used to resolve lifetimes in the bounds of the opaque. - let mut captured_to_synthesized_mapping = LocalDefIdMap::default(); - // List of (early-bound) synthetic lifetimes that are owned by the opaque. - // This is used to create the `hir::Generics` owned by the opaque. - let mut synthesized_lifetime_definitions = vec![]; - // Pairs of lifetime arg (that resolves to the captured lifetime) - // and the def-id of the (early-bound) synthetic lifetime definition. - // This is used both to create generics for the `TyKind::OpaqueDef` that - // we return, and also as a captured lifetime mapping for RPITITs. - let mut synthesized_lifetime_args = vec![]; - - for lifetime in captured_lifetimes_to_duplicate { - let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error); - let (old_def_id, missing_kind) = match res { - LifetimeRes::Param { param: old_def_id, binder: _ } => (old_def_id, None), - - LifetimeRes::Fresh { param, kind, .. } => { - debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); - if let Some(old_def_id) = self.orig_opt_local_def_id(param) { - (old_def_id, Some(kind)) - } else { - self.dcx() - .span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime"); - continue; - } - } - - // Opaques do not capture `'static` - LifetimeRes::Static { .. } | LifetimeRes::Error => { - continue; - } - - res => { - let bug_msg = format!( - "Unexpected lifetime resolution {:?} for {:?} at {:?}", - res, lifetime.ident, lifetime.ident.span - ); - span_bug!(lifetime.ident.span, "{}", bug_msg); - } - }; - - if captured_to_synthesized_mapping.get(&old_def_id).is_none() { - // Create a new lifetime parameter local to the opaque. - let duplicated_lifetime_node_id = self.next_node_id(); - let duplicated_lifetime_def_id = self.create_def( - opaque_ty_def_id, - duplicated_lifetime_node_id, - lifetime.ident.name, - DefKind::LifetimeParam, - self.lower_span(lifetime.ident.span), - ); - captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id); - // FIXME: Instead of doing this, we could move this whole loop - // into the `with_hir_id_owner`, then just directly construct - // the `hir::GenericParam` here. - synthesized_lifetime_definitions.push(( - duplicated_lifetime_node_id, - duplicated_lifetime_def_id, - self.lower_ident(lifetime.ident), - missing_kind, - )); - - // Now make an arg that we can use for the generic params of the opaque tykind. - let id = self.next_node_id(); - let lifetime_arg = self.new_named_lifetime_with_res(id, lifetime.ident, res); - let duplicated_lifetime_def_id = self.local_def_id(duplicated_lifetime_node_id); - synthesized_lifetime_args.push((lifetime_arg, duplicated_lifetime_def_id)) - } - } - let opaque_ty_def = self.with_def_id_parent(opaque_ty_def_id, |this| { - // Install the remapping from old to new (if any). This makes sure that - // any lifetimes that would have resolved to the def-id of captured - // lifetimes are remapped to the new *synthetic* lifetimes of the opaque. - let bounds = this - .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this)); - - let generic_params = - this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map( - |&(new_node_id, new_def_id, ident, missing_kind)| { - let hir_id = this.lower_node_id(new_node_id); - let (name, kind) = if ident.name == kw::UnderscoreLifetime { - ( - hir::ParamName::Fresh, - hir::LifetimeParamKind::Elided( - missing_kind.unwrap_or(MissingLifetimeKind::Underscore), - ), - ) - } else { - (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) - }; - - hir::GenericParam { - hir_id, - def_id: new_def_id, - name, - span: ident.span, - pure_wrt_drop: false, - kind: hir::GenericParamKind::Lifetime { kind }, - colon_span: None, - source: hir::GenericParamSource::Generics, - } - }, - )); - debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params); - - let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args); - - trace!("registering opaque type with id {:#?}", opaque_ty_def_id); + let bounds = lower_item_bounds(this); let opaque_ty_def = hir::OpaqueTy { hir_id: opaque_ty_hir_id, def_id: opaque_ty_def_id, - generics: this.arena.alloc(hir::Generics { - params: generic_params, - predicates: &[], - has_where_clause_predicates: false, - where_clause_span: this.lower_span(span), - span: this.lower_span(span), - }), bounds, origin, - lifetime_mapping, span: this.lower_span(opaque_ty_span), }; this.arena.alloc(opaque_ty_def) }); - let generic_args = self.arena.alloc_from_iter( - synthesized_lifetime_args - .iter() - .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)), - ); - - // Create the `Foo<...>` reference itself. Note that the `type - // Foo = impl Trait` is, internally, created as a child of the - // async fn, so the *type parameters* are inherited. It's - // only the lifetime parameters that we must supply. - hir::TyKind::OpaqueDef(opaque_ty_def, generic_args) + hir::TyKind::OpaqueDef(opaque_ty_def) } fn lower_precise_capturing_args( @@ -1885,13 +1660,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, allowed_features); - let captured_lifetimes = self - .resolver - .extra_lifetime_params(opaque_ty_node_id) - .into_iter() - .map(|(ident, id, _)| Lifetime { id, ident }) - .collect(); - let in_trait_or_impl = match fn_kind { FnDeclKind::Trait => Some(hir::RpitContext::Trait), FnDeclKind::Impl => Some(hir::RpitContext::TraitImpl), @@ -1902,8 +1670,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_ref = self.lower_opaque_inner( opaque_ty_node_id, hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl }, - captured_lifetimes, - span, opaque_ty_span, |this| { let bound = this.lower_coroutine_fn_output_type_to_bound( @@ -2000,10 +1766,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { res: LifetimeRes, ) -> &'hir hir::Lifetime { let res = match res { - LifetimeRes::Param { param, .. } => { - let param = self.get_remapped_def_id(param); - hir::LifetimeName::Param(param) - } + LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param), LifetimeRes::Fresh { param, .. } => { let param = self.local_def_id(param); hir::LifetimeName::Param(param) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index b4b8373ac974..6ca7251295dd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -830,7 +830,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { /// /// [`OpaqueDef`]: hir::TyKind::OpaqueDef fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { - let hir::TyKind::OpaqueDef(opaque_ty, _) = hir_ty.kind else { + let hir::TyKind::OpaqueDef(opaque_ty) = hir_ty.kind else { span_bug!( hir_ty.span, "lowered return type of async fn is not OpaqueDef: {:?}", diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1c268c8bbe06..2cfe10503ac5 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2627,7 +2627,6 @@ impl<'hir> Ty<'hir> { } TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty), TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(), - TyKind::OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args), TyKind::Path(QPath::TypeRelative(ty, segment)) => { ty.is_suggestable_infer_ty() || are_suggestable_generic_args(segment.args().args) } @@ -2746,19 +2745,8 @@ pub struct BareFnTy<'hir> { pub struct OpaqueTy<'hir> { pub hir_id: HirId, pub def_id: LocalDefId, - pub generics: &'hir Generics<'hir>, pub bounds: GenericBounds<'hir>, pub origin: OpaqueTyOrigin, - /// Return-position impl traits (and async futures) must "reify" any late-bound - /// lifetimes that are captured from the function signature they originate from. - /// - /// This is done by generating a new early-bound lifetime parameter local to the - /// opaque which is instantiated in the function signature with the late-bound - /// lifetime. - /// - /// This mapping associated a captured lifetime (first parameter) with the new - /// early-bound lifetime that was generated for the opaque. - pub lifetime_mapping: &'hir [(&'hir Lifetime, LocalDefId)], pub span: Span, } @@ -2866,7 +2854,7 @@ pub enum TyKind<'hir> { /// possibly parameters) that are actually bound on the `impl Trait`. /// /// The last parameter specifies whether this opaque appears in a trait definition. - OpaqueDef(&'hir OpaqueTy<'hir>, &'hir [GenericArg<'hir>]), + OpaqueDef(&'hir OpaqueTy<'hir>), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax), @@ -3991,7 +3979,6 @@ impl<'hir> Node<'hir> { | Node::TraitItem(TraitItem { generics, .. }) | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), Node::Item(item) => item.kind.generics(), - Node::OpaqueTy(opaque) => Some(opaque.generics), _ => None, } } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 322f8e2a517c..a453af3f7fd3 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -896,9 +896,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul TyKind::Path(ref qpath) => { try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span)); } - TyKind::OpaqueDef(opaque, lifetimes) => { + TyKind::OpaqueDef(opaque) => { try_visit!(visitor.visit_opaque_ty(opaque)); - walk_list!(visitor, visit_generic_arg, lifetimes); } TyKind::Array(ref ty, ref length) => { try_visit!(visitor.visit_ty(ty)); @@ -1188,10 +1187,8 @@ pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>( } pub fn walk_opaque_ty<'v, V: Visitor<'v>>(visitor: &mut V, opaque: &'v OpaqueTy<'v>) -> V::Result { - let &OpaqueTy { hir_id, def_id: _, generics, bounds, origin: _, lifetime_mapping: _, span: _ } = - opaque; + let &OpaqueTy { hir_id, def_id: _, bounds, origin: _, span: _ } = opaque; try_visit!(visitor.visit_id(hir_id)); - try_visit!(walk_generics(visitor, generics)); walk_list!(visitor, visit_param_bound, bounds); V::Result::output() } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index cca52c5142c6..c41117d213f2 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1302,7 +1302,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { } } -#[instrument(level = "debug", skip(tcx))] +#[instrument(level = "debug", skip(tcx), ret)] fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFnSig<'_>> { use rustc_hir::Node::*; use rustc_hir::*; diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 3eec0e126657..c31bff28fd34 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -426,6 +426,21 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { }); } + if let Node::OpaqueTy(&hir::OpaqueTy { .. }) = node { + assert!(own_params.is_empty()); + + let lifetimes = tcx.opaque_captured_lifetimes(def_id); + debug!(?lifetimes); + + own_params.extend(lifetimes.iter().map(|&(_, param)| ty::GenericParamDef { + name: tcx.item_name(param.to_def_id()), + index: next_index(), + def_id: param.to_def_id(), + pure_wrt_drop: false, + kind: ty::GenericParamDefKind::Lifetime, + })) + } + let param_def_id_to_index = own_params.iter().map(|param| (param.def_id, param.index)).collect(); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 644ff0c667c6..0b0180538550 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -329,13 +329,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // We create bi-directional Outlives predicates between the original // and the duplicated parameter, to ensure that they do not get out of sync. if let Node::OpaqueTy(..) = node { - let opaque_ty_node = tcx.parent_hir_node(hir_id); - let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes), .. }) = opaque_ty_node - else { - bug!("unexpected {opaque_ty_node:?}") - }; - debug!(?lifetimes); - compute_bidirectional_outlives_predicates(tcx, &generics.own_params, &mut predicates); debug!(?predicates); } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index f7daef3e80c9..675e033e9499 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -6,12 +6,14 @@ //! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file //! is also responsible for assigning their semantics to implicit lifetimes in trait objects. -use core::ops::ControlFlow; +use std::cell::RefCell; use std::fmt; +use std::ops::ControlFlow; use rustc_ast::visit::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; +use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{self, Visitor}; @@ -25,7 +27,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; -use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_span::symbol::{Ident, sym}; use tracing::{debug, debug_span, instrument}; @@ -80,6 +82,9 @@ struct NamedVarMap { // - trait refs // - bound types (like `T` in `for<'a> T<'a>: Foo`) late_bound_vars: ItemLocalMap>, + + // List captured variables for each opaque type. + opaque_captured_lifetimes: LocalDefIdMap>, } struct BoundVarContext<'a, 'tcx> { @@ -147,6 +152,20 @@ enum Scope<'a> { s: ScopeRef<'a>, }, + /// Resolve the lifetimes in the bounds to the lifetime defs in the generics. + /// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + /// `type MyAnonTy<'b> = impl MyTrait<'b>;` + /// ^ ^ this gets resolved in the scope of + /// the opaque_ty generics + Opaque { + /// The opaque type we are traversing. + def_id: LocalDefId, + /// Mapping from each captured lifetime `'a` to the duplicate generic parameter `'b`. + captures: &'a RefCell>, + + s: ScopeRef<'a>, + }, + /// Disallows capturing late-bound vars from parent scopes. /// /// This is necessary for something like `for [(); { /* references T */ }]:`, @@ -192,6 +211,12 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { .field("where_bound_origin", where_bound_origin) .field("s", &"..") .finish(), + Scope::Opaque { captures, def_id, s: _ } => f + .debug_struct("Opaque") + .field("def_id", def_id) + .field("captures", &captures.borrow()) + .field("s", &"..") + .finish(), Scope::Body { id, s: _ } => { f.debug_struct("Body").field("id", id).field("s", &"..").finish() } @@ -226,6 +251,12 @@ pub(crate) fn provide(providers: &mut Providers) { is_late_bound_map, object_lifetime_default, late_bound_vars_map: |tcx, id| &tcx.resolve_bound_vars(id).late_bound_vars, + opaque_captured_lifetimes: |tcx, id| { + &tcx.resolve_bound_vars(tcx.local_def_id_to_hir_id(id).owner) + .opaque_captured_lifetimes + .get(&id) + .map_or(&[][..], |x| &x[..]) + }, ..*providers }; @@ -236,8 +267,11 @@ pub(crate) fn provide(providers: &mut Providers) { /// `named_variable_map`, `is_late_bound_map`, etc. #[instrument(level = "debug", skip(tcx))] fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars { - let mut named_variable_map = - NamedVarMap { defs: Default::default(), late_bound_vars: Default::default() }; + let mut named_variable_map = NamedVarMap { + defs: Default::default(), + late_bound_vars: Default::default(), + opaque_captured_lifetimes: Default::default(), + }; let mut visitor = BoundVarContext { tcx, map: &mut named_variable_map, @@ -264,13 +298,16 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou let defs = named_variable_map.defs.into_sorted_stable_ord(); let late_bound_vars = named_variable_map.late_bound_vars.into_sorted_stable_ord(); + let opaque_captured_lifetimes = named_variable_map.opaque_captured_lifetimes; let rl = ResolveBoundVars { defs: SortedMap::from_presorted_elements(defs), late_bound_vars: SortedMap::from_presorted_elements(late_bound_vars), + opaque_captured_lifetimes, }; debug!(?rl.defs); debug!(?rl.late_bound_vars); + debug!(?rl.opaque_captured_lifetimes); rl } @@ -306,6 +343,26 @@ fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVaria } } +/// Whether this opaque always captures lifetimes in scope. +/// Right now, this is all RPITIT and TAITs, and when `lifetime_capture_rules_2024` +/// is enabled. We don't check the span of the edition, since this is done +/// on a per-opaque basis to account for nested opaques. +fn opaque_captures_all_in_scope_lifetimes<'tcx>( + tcx: TyCtxt<'tcx>, + opaque: &'tcx hir::OpaqueTy<'tcx>, +) -> bool { + match opaque.origin { + // if the opaque has the `use<...>` syntax, the user is telling us that they only want + // to account for those lifetimes, so do not try to be clever. + _ if opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..))) => false, + hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::TyAlias { .. } => true, + _ if tcx.features().lifetime_capture_rules_2024() || opaque.span.at_least_rust_2024() => { + true + } + hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(), + } +} + impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { /// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref. fn poly_trait_ref_binder_info(&mut self) -> (Vec, BinderScopeType) { @@ -317,7 +374,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { break (vec![], BinderScopeType::Normal); } - Scope::ObjectLifetimeDefault { s, .. } | Scope::LateBoundary { s, .. } => { + Scope::Opaque { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::LateBoundary { s, .. } => { scope = s; } @@ -488,29 +547,100 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } + /// Resolve the lifetimes that are applied to the opaque type. + /// These are resolved in the current scope. + /// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + /// `fn foo<'a>() -> MyAnonTy<'a> { ... }` + /// ^ ^this gets resolved in the current scope #[instrument(level = "debug", skip(self))] fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) { - // We want to start our early-bound indices at the end of the parent scope, - // not including any parent `impl Trait`s. - let mut bound_vars = FxIndexMap::default(); - debug!(?opaque.generics.params); - for param in opaque.generics.params { - let arg = ResolvedArg::early(param); - bound_vars.insert(param.def_id, arg); + let mut captures = FxIndexMap::default(); + + let capture_all_in_scope_lifetimes = + opaque_captures_all_in_scope_lifetimes(self.tcx, opaque); + if capture_all_in_scope_lifetimes { + let mut create_def_for_duplicated_param = |original_lifetime: LocalDefId, def| { + captures.entry(def).or_insert_with(|| { + let name = self.tcx.item_name(original_lifetime.to_def_id()); + let span = self.tcx.def_span(original_lifetime); + let feed = self.tcx.create_def(opaque.def_id, name, DefKind::LifetimeParam); + feed.def_span(span); + feed.def_ident_span(Some(span)); + feed.def_id() + }); + }; + + // We list scopes outwards, this causes us to see lifetime parameters in reverse + // declaration order. In order to make it consistent with what `generics_of` might + // give, we will reverse the IndexMap after early captures. + let mut scope = self.scope; + loop { + match *scope { + Scope::Binder { ref bound_vars, s, .. } => { + for (&original_lifetime, &(mut def)) in bound_vars.iter().rev() { + if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) { + if let Err(guar) = + self.check_lifetime_is_capturable(opaque.def_id, def, None) + { + def = ResolvedArg::Error(guar); + } + create_def_for_duplicated_param(original_lifetime, def); + } + } + scope = s; + } + + Scope::Root { mut opt_parent_item } => { + while let Some(parent_item) = opt_parent_item { + let parent_generics = self.tcx.generics_of(parent_item); + for param in parent_generics.own_params.iter().rev() { + if let ty::GenericParamDefKind::Lifetime = param.kind { + create_def_for_duplicated_param( + param.def_id.expect_local(), + ResolvedArg::EarlyBound(param.def_id.expect_local()), + ); + } + } + opt_parent_item = parent_generics.parent.and_then(DefId::as_local); + } + break; + } + + Scope::Opaque { captures: outer_captures, .. } => { + for (_, &duplicated_param) in outer_captures.borrow().iter().rev() { + create_def_for_duplicated_param( + duplicated_param, + ResolvedArg::EarlyBound(duplicated_param), + ); + } + break; + } + + Scope::Body { .. } => { + bug!("{:?}", scope) + } + + Scope::ObjectLifetimeDefault { s, .. } + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } + | Scope::LateBoundary { s, .. } => { + scope = s; + } + } + } + captures.reverse(); } - let hir_id = self.tcx.local_def_id_to_hir_id(opaque.def_id); - let scope = Scope::Binder { - hir_id, - bound_vars, - s: self.scope, - scope_type: BinderScopeType::Normal, - where_bound_origin: None, - }; + let captures = RefCell::new(captures); + + let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque)) - }) + }); + + let captures = captures.into_inner().into_iter().collect(); + self.map.opaque_captured_lifetimes.insert(opaque.def_id, captures); } #[instrument(level = "debug", skip(self))] @@ -685,66 +815,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }; self.with(scope, |this| this.visit_ty(mt.ty)); } - hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => { + hir::TyKind::OpaqueDef(opaque_ty) => { self.visit_opaque_ty(opaque_ty); - - // Resolve the lifetimes in the bounds to the lifetime defs in the generics. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `type MyAnonTy<'b> = impl MyTrait<'b>;` - // ^ ^ this gets resolved in the scope of - // the opaque_ty generics - - // Resolve the lifetimes that are applied to the opaque type. - // These are resolved in the current scope. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `fn foo<'a>() -> MyAnonTy<'a> { ... }` - // ^ ^this gets resolved in the current scope - for lifetime in lifetimes { - let hir::GenericArg::Lifetime(lifetime) = lifetime else { continue }; - self.visit_lifetime(lifetime); - - // Check for predicates like `impl for<'a> Trait>` - // and ban them. Type variables instantiated inside binders aren't - // well-supported at the moment, so this doesn't work. - // In the future, this should be fixed and this error should be removed. - let def = self.map.defs.get(&lifetime.hir_id.local_id).copied(); - let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue }; - let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id); - - let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id)) - { - // Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque - // it must be a reified late-bound lifetime from a trait goal. - hir::Node::OpaqueTy(_) => "higher-ranked lifetime from outer `impl Trait`", - // Other items are fine. - hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => { - continue; - } - hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(_), .. }) => { - "higher-ranked lifetime from function pointer" - } - hir::Node::Ty(hir::Ty { kind: hir::TyKind::TraitObject(..), .. }) => { - "higher-ranked lifetime from `dyn` type" - } - _ => "higher-ranked lifetime", - }; - - let (span, label) = if lifetime.ident.span == self.tcx.def_span(lifetime_def_id) - { - (opaque_ty.span, Some(opaque_ty.span)) - } else { - (lifetime.ident.span, None) - }; - - // Ensure that the parent of the def is an item, not HRTB - self.tcx.dcx().emit_err(errors::OpaqueCapturesHigherRankedLifetime { - span, - label, - decl_span: self.tcx.def_span(lifetime_def_id), - bad_place, - }); - self.uninsert_lifetime_on_error(lifetime, def.unwrap()); - } } _ => intravisit::walk_ty(self, ty), } @@ -1129,6 +1201,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let mut scope = self.scope; let mut outermost_body = None; let mut crossed_late_boundary = None; + let mut opaque_capture_scopes = vec![]; let result = loop { match *scope { Scope::Body { id, s } => { @@ -1204,6 +1277,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { scope = s; } + Scope::Opaque { captures, def_id, s } => { + opaque_capture_scopes.push((def_id, captures)); + late_depth = 0; + scope = s; + } + Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { @@ -1218,6 +1297,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { }; if let Some(mut def) = result { + def = self.remap_opaque_captures(opaque_capture_scopes, def, lifetime_ref.ident); + if let ResolvedArg::EarlyBound(..) = def { // Do not free early-bound regions, only late-bound ones. } else if let ResolvedArg::LateBound(_, _, param_def_id) = def @@ -1291,6 +1372,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Root { .. } => break, Scope::Binder { s, .. } | Scope::Body { s, .. } + | Scope::Opaque { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } @@ -1306,6 +1388,78 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { ); } + /// Check for predicates like `impl for<'a> Trait>` + /// and ban them. Type variables instantiated inside binders aren't + /// well-supported at the moment, so this doesn't work. + /// In the future, this should be fixed and this error should be removed. + fn check_lifetime_is_capturable( + &self, + opaque_def_id: LocalDefId, + lifetime: ResolvedArg, + span: Option, + ) -> Result<(), ErrorGuaranteed> { + let ResolvedArg::LateBound(_, _, lifetime_def_id) = lifetime else { return Ok(()) }; + let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id); + let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id)) { + // Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque + // it must be a reified late-bound lifetime from a trait goal. + hir::Node::OpaqueTy(_) => "higher-ranked lifetime from outer `impl Trait`", + // Other items are fine. + hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => return Ok(()), + hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(_), .. }) => { + "higher-ranked lifetime from function pointer" + } + hir::Node::Ty(hir::Ty { kind: hir::TyKind::TraitObject(..), .. }) => { + "higher-ranked lifetime from `dyn` type" + } + _ => "higher-ranked lifetime", + }; + + let decl_span = self.tcx.def_span(lifetime_def_id); + let (span, label) = if let Some(span) = span + && span != decl_span + { + (span, None) + } else { + let opaque_span = self.tcx.def_span(opaque_def_id); + (opaque_span, Some(opaque_span)) + }; + + // Ensure that the parent of the def is an item, not HRTB + let guar = self.tcx.dcx().emit_err(errors::OpaqueCapturesHigherRankedLifetime { + span, + label, + decl_span, + bad_place, + }); + Err(guar) + } + + fn remap_opaque_captures( + &self, + opaque_capture_scopes: Vec<(LocalDefId, &RefCell>)>, + mut lifetime: ResolvedArg, + ident: Ident, + ) -> ResolvedArg { + for (opaque_def_id, captures) in opaque_capture_scopes.into_iter().rev() { + if let Err(guar) = + self.check_lifetime_is_capturable(opaque_def_id, lifetime, Some(ident.span)) + { + return ResolvedArg::Error(guar); + } + + let mut captures = captures.borrow_mut(); + let remapped = *captures.entry(lifetime).or_insert_with(|| { + let feed = self.tcx.create_def(opaque_def_id, ident.name, DefKind::LifetimeParam); + feed.def_span(ident.span); + feed.def_ident_span(Some(ident.span)); + feed.def_id() + }); + lifetime = ResolvedArg::EarlyBound(remapped); + } + lifetime + } + fn resolve_type_ref(&mut self, param_def_id: LocalDefId, hir_id: HirId) { // Walk up the scope chain, tracking the number of fn scopes // that we pass through, until we find a lifetime with the @@ -1345,6 +1499,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } Scope::ObjectLifetimeDefault { s, .. } + | Scope::Opaque { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { scope = s; @@ -1425,6 +1580,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Root { .. } => break, Scope::Binder { s, .. } | Scope::Body { s, .. } + | Scope::Opaque { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } @@ -1501,6 +1657,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Binder { s, .. } | Scope::ObjectLifetimeDefault { s, .. } + | Scope::Opaque { s, .. } | Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } | Scope::LateBoundary { s, .. } => { @@ -1786,7 +1943,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { let mut late_depth = 0; let mut scope = self.scope; - let lifetime = loop { + let mut opaque_capture_scopes = vec![]; + let mut lifetime = loop { match *scope { Scope::Binder { s, scope_type, .. } => { match scope_type { @@ -1800,7 +1958,15 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, - Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, + Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => { + break l.shifted(late_depth); + } + + Scope::Opaque { captures, def_id, s } => { + opaque_capture_scopes.push((def_id, captures)); + late_depth = 0; + scope = s; + } Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } @@ -1809,7 +1975,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } } }; - self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); + + lifetime = self.remap_opaque_captures(opaque_capture_scopes, lifetime, lifetime_ref.ident); + + self.insert_lifetime(lifetime_ref, lifetime); } #[instrument(level = "debug", skip(self))] @@ -1818,18 +1987,6 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { self.map.defs.insert(lifetime_ref.hir_id.local_id, def); } - /// Sometimes we resolve a lifetime, but later find that it is an - /// error (esp. around impl trait). In that case, we remove the - /// entry into `map.defs` so as not to confuse later code. - fn uninsert_lifetime_on_error( - &mut self, - lifetime_ref: &'tcx hir::Lifetime, - bad_def: ResolvedArg, - ) { - let old_value = self.map.defs.remove(&lifetime_ref.hir_id.local_id); - assert_eq!(old_value, Some(bad_def)); - } - // When we have a return type notation type in a where clause, like // `where ::method(..): Send`, we need to introduce new bound // vars to the existing where clause's binder, to represent the lifetimes @@ -2013,18 +2170,22 @@ fn is_late_bound_map( tcx: TyCtxt<'_>, owner_id: hir::OwnerId, ) -> Option<&FxIndexSet> { - let decl = tcx.hir().fn_decl_by_hir_id(owner_id.into())?; + let sig = tcx.hir().fn_sig_by_hir_id(owner_id.into())?; let generics = tcx.hir().get_generics(owner_id.def_id)?; let mut late_bound = FxIndexSet::default(); let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx }; - for arg_ty in decl.inputs { + for arg_ty in sig.decl.inputs { constrained_by_input.visit_ty(arg_ty); } - let mut appears_in_output = AllCollector::default(); - intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output); + let mut appears_in_output = + AllCollector { tcx, has_fully_capturing_opaque: false, regions: Default::default() }; + intravisit::walk_fn_ret_ty(&mut appears_in_output, &sig.decl.output); + if appears_in_output.has_fully_capturing_opaque { + appears_in_output.regions.extend(generics.params.iter().map(|param| param.def_id)); + } debug!(?constrained_by_input.regions); @@ -2032,7 +2193,8 @@ fn is_late_bound_map( // // Subtle point: because we disallow nested bindings, we can just // ignore binders here and scrape up all names we see. - let mut appears_in_where_clause = AllCollector::default(); + let mut appears_in_where_clause = + AllCollector { tcx, has_fully_capturing_opaque: true, regions: Default::default() }; appears_in_where_clause.visit_generics(generics); debug!(?appears_in_where_clause.regions); @@ -2198,17 +2360,26 @@ fn is_late_bound_map( } } - #[derive(Default)] - struct AllCollector { + struct AllCollector<'tcx> { + tcx: TyCtxt<'tcx>, + has_fully_capturing_opaque: bool, regions: FxHashSet, } - impl<'v> Visitor<'v> for AllCollector { + impl<'v> Visitor<'v> for AllCollector<'v> { fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { if let hir::LifetimeName::Param(def_id) = lifetime_ref.res { self.regions.insert(def_id); } } + + fn visit_opaque_ty(&mut self, opaque: &'v hir::OpaqueTy<'v>) { + if !self.has_fully_capturing_opaque { + self.has_fully_capturing_opaque = + opaque_captures_all_in_scope_lifetimes(self.tcx, opaque); + } + intravisit::walk_opaque_ty(self, opaque); + } } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 2d0c3ec28c37..f2bc17051ab0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -294,13 +294,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { lifetime: &hir::Lifetime, reason: RegionInferReason<'_>, ) -> ty::Region<'tcx> { + if let Some(resolved) = self.tcx().named_bound_var(lifetime.hir_id) { + self.lower_resolved_lifetime(resolved) + } else { + self.re_infer(lifetime.ident.span, reason) + } + } + + /// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*. + #[instrument(level = "debug", skip(self), ret)] + pub fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> { let tcx = self.tcx(); let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id)); - match tcx.named_bound_var(lifetime.hir_id) { - Some(rbv::ResolvedArg::StaticLifetime) => tcx.lifetimes.re_static, + match resolved { + rbv::ResolvedArg::StaticLifetime => tcx.lifetimes.re_static, - Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { + rbv::ResolvedArg::LateBound(debruijn, index, def_id) => { let name = lifetime_name(def_id); let br = ty::BoundRegion { var: ty::BoundVar::from_u32(index), @@ -309,7 +319,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Region::new_bound(tcx, debruijn, br) } - Some(rbv::ResolvedArg::EarlyBound(def_id)) => { + rbv::ResolvedArg::EarlyBound(def_id) => { let name = tcx.hir().ty_param_name(def_id); let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); @@ -317,7 +327,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name }) } - Some(rbv::ResolvedArg::Free(scope, id)) => { + rbv::ResolvedArg::Free(scope, id) => { let name = lifetime_name(id); ty::Region::new_late_param( tcx, @@ -328,9 +338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // (*) -- not late-bound, won't change } - Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar), - - None => self.re_infer(lifetime.ident.span, reason), + rbv::ResolvedArg::Error(guar) => ty::Region::new_error(tcx, guar), } } @@ -2094,13 +2102,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); self.lower_path(opt_self_ty, path, hir_ty.hir_id, false) } - &hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => { - let local_def_id = opaque_ty.def_id; - + &hir::TyKind::OpaqueDef(opaque_ty) => { // If this is an RPITIT and we are using the new RPITIT lowering scheme, we // generate the def_id of an associated type for the trait and return as // type a projection. - match opaque_ty.origin { + let in_trait = match opaque_ty.origin { hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(hir::RpitContext::Trait), .. @@ -2108,11 +2114,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { | hir::OpaqueTyOrigin::AsyncFn { in_trait_or_impl: Some(hir::RpitContext::Trait), .. - } => self.lower_opaque_ty( - tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id(), - lifetimes, - true, - ), + } => true, hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. @@ -2121,10 +2123,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl), .. } - | hir::OpaqueTyOrigin::TyAlias { .. } => { - self.lower_opaque_ty(local_def_id.to_def_id(), lifetimes, false) - } - } + | hir::OpaqueTyOrigin::TyAlias { .. } => false, + }; + + self.lower_opaque_ty(opaque_ty.def_id, in_trait) } // If we encounter a type relative path with RTN generics, then it must have // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore @@ -2264,40 +2266,34 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } /// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR. - #[instrument(level = "debug", skip_all, ret)] - fn lower_opaque_ty( - &self, - def_id: DefId, - lifetimes: &[hir::GenericArg<'_>], - in_trait: bool, - ) -> Ty<'tcx> { - debug!(?def_id, ?lifetimes); + #[instrument(level = "debug", skip(self), ret)] + fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> { let tcx = self.tcx(); + let lifetimes = tcx.opaque_captured_lifetimes(def_id); + debug!(?lifetimes); + + // If this is an RPITIT and we are using the new RPITIT lowering scheme, we + // generate the def_id of an associated type for the trait and return as + // type a projection. + let def_id = if in_trait { + tcx.associated_type_for_impl_trait_in_trait(def_id).to_def_id() + } else { + def_id.to_def_id() + }; + let generics = tcx.generics_of(def_id); debug!(?generics); + // We use `generics.count() - lifetimes.len()` here instead of `generics.parent_count` + // since return-position impl trait in trait squashes all of the generics from its source fn + // into its own generics, so the opaque's "own" params isn't always just lifetimes. + let offset = generics.count() - lifetimes.len(); + let args = ty::GenericArgs::for_item(tcx, def_id, |param, _| { - // We use `generics.count() - lifetimes.len()` here instead of `generics.parent_count` - // since return-position impl trait in trait squashes all of the generics from its source fn - // into its own generics, so the opaque's "own" params isn't always just lifetimes. - if let Some(i) = (param.index as usize).checked_sub(generics.count() - lifetimes.len()) - { - // Resolve our own lifetime parameters. - let GenericParamDefKind::Lifetime { .. } = param.kind else { - span_bug!( - tcx.def_span(param.def_id), - "only expected lifetime for opaque's own generics, got {:?}", - param - ); - }; - let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { - bug!( - "expected lifetime argument for param {param:?}, found {:?}", - &lifetimes[i] - ) - }; - self.lower_lifetime(lifetime, RegionInferReason::Param(¶m)).into() + if let Some(i) = (param.index as usize).checked_sub(offset) { + let (lifetime, _) = lifetimes[i]; + self.lower_resolved_lifetime(lifetime).into() } else { tcx.mk_param_from_def(param) } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 61214b992153..2073f2868b4f 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -659,8 +659,6 @@ impl<'a> State<'a> { fn print_opaque_ty(&mut self, o: &hir::OpaqueTy<'_>) { self.head("opaque"); - self.print_generic_params(o.generics.params); - self.print_where_clause(o.generics); self.word("{"); self.print_bounds("impl", o.bounds); self.word("}"); diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 16a1a5a72bc4..5de0d4bc870f 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -69,7 +69,7 @@ declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]); impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx>) { - let hir::TyKind::OpaqueDef(opaque, _) = &ty.kind else { + let hir::TyKind::OpaqueDef(opaque) = &ty.kind else { return; }; diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs index 13e35cd09098..111ac990bc77 100644 --- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs +++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs @@ -3,7 +3,7 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::ItemLocalId; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable}; use crate::ty; @@ -54,4 +54,6 @@ pub struct ResolveBoundVars { pub defs: SortedMap, pub late_bound_vars: SortedMap>, + + pub opaque_captured_lifetimes: LocalDefIdMap>, } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d7a60a843b71..d7f589631010 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1781,6 +1781,23 @@ rustc_queries! { -> &'tcx SortedMap> { desc { |tcx| "looking up late bound vars inside `{}`", tcx.def_path_str(owner_id) } } + /// For an opaque type, return the list of (captured lifetime, inner generic param). + /// ```ignore (illustrative) + /// fn foo<'a: 'a, 'b, T>(&'b u8) -> impl Into + 'b { ... } + /// ``` + /// + /// We would return `[('a, '_a), ('b, '_b)]`, with `'a` early-bound and `'b` late-bound. + /// + /// After hir_ty_lowering, we get: + /// ```ignore (pseudo-code) + /// opaque foo::<'a>::opaque<'_a, '_b>: Into> + '_b; + /// ^^^^^^^^ inner generic params + /// fn foo<'a>: for<'b> fn(&'b u8) -> foo::<'a>::opaque::<'a, 'b> + /// ^^^^^^ captured lifetimes + /// ``` + query opaque_captured_lifetimes(def_id: LocalDefId) -> &'tcx [(ResolvedArg, LocalDefId)] { + desc { |tcx| "listing captured lifetimes for opaque `{}`", tcx.def_path_str(def_id) } + } /// Computes the visibility of the provided `def_id`. /// diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5cbbc80ebfbb..9616a533ab67 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3060,7 +3060,7 @@ impl<'tcx> TyCtxt<'tcx> { loop { let parent = self.local_parent(opaque_lifetime_param_def_id); - let hir::OpaqueTy { lifetime_mapping, .. } = self.hir().expect_opaque_ty(parent); + let lifetime_mapping = self.opaque_captured_lifetimes(parent); let Some((lifetime, _)) = lifetime_mapping .iter() @@ -3069,8 +3069,8 @@ impl<'tcx> TyCtxt<'tcx> { bug!("duplicated lifetime param should be present"); }; - match self.named_bound_var(lifetime.hir_id) { - Some(resolve_bound_vars::ResolvedArg::EarlyBound(ebv)) => { + match *lifetime { + resolve_bound_vars::ResolvedArg::EarlyBound(ebv) => { let new_parent = self.local_parent(ebv); // If we map to another opaque, then it should be a parent @@ -3089,7 +3089,7 @@ impl<'tcx> TyCtxt<'tcx> { name: self.item_name(ebv.to_def_id()), }); } - Some(resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv)) => { + resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv) => { let new_parent = self.local_parent(lbv); return ty::Region::new_late_param( self, @@ -3100,13 +3100,13 @@ impl<'tcx> TyCtxt<'tcx> { ), ); } - Some(resolve_bound_vars::ResolvedArg::Error(guar)) => { + resolve_bound_vars::ResolvedArg::Error(guar) => { return ty::Region::new_error(self, guar); } _ => { return ty::Region::new_error_with_message( self, - lifetime.ident.span, + self.def_span(opaque_lifetime_param_def_id), "cannot resolve lifetime", ); } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a8327ebc17fe..f54afdbc929f 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1354,6 +1354,7 @@ impl<'tcx> Ty<'tcx> { } } + #[tracing::instrument(level = "trace", skip(tcx))] pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { match self.kind() { FnDef(def_id, args) => tcx.fn_sig(*def_id).instantiate(tcx, args), diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index adb0ba7c8203..5fef8c49eec2 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -841,10 +841,9 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.r.record_partial_res(ty.id, PartialRes::new(res)); visit::walk_ty(self, ty) } - TyKind::ImplTrait(node_id, _) => { + TyKind::ImplTrait(_, _) => { let candidates = self.lifetime_elision_candidates.take(); visit::walk_ty(self, ty); - self.record_lifetime_params_for_impl_trait(*node_id); self.lifetime_elision_candidates = candidates; } TyKind::TraitObject(bounds, ..) => { @@ -977,14 +976,6 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)), &sig.decl.output, ); - - if let Some((coro_node_id, _)) = sig - .header - .coroutine_kind - .map(|coroutine_kind| coroutine_kind.return_id()) - { - this.record_lifetime_params_for_impl_trait(coro_node_id); - } }, ); return; @@ -1026,10 +1017,6 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)), &declaration.output, ); - - if let Some((async_node_id, _)) = coro_node_id { - this.record_lifetime_params_for_impl_trait(async_node_id); - } }, ); @@ -1220,7 +1207,6 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r } }, AssocItemConstraintKind::Bound { ref bounds } => { - self.record_lifetime_params_for_impl_trait(constraint.id); walk_list!(self, visit_param_bound, bounds, BoundKind::Bound); } } @@ -4795,30 +4781,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ) } - /// Construct the list of in-scope lifetime parameters for impl trait lowering. - /// We include all lifetime parameters, either named or "Fresh". - /// The order of those parameters does not matter, as long as it is - /// deterministic. - fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId) { - let mut extra_lifetime_params = vec![]; - - for rib in self.lifetime_ribs.iter().rev() { - extra_lifetime_params - .extend(rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res))); - match rib.kind { - LifetimeRibKind::Item => break, - LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { - if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) { - extra_lifetime_params.extend(earlier_fresh); - } - } - _ => {} - } - } - - self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params); - } - fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> Option { // FIXME: This caching may be incorrect in case of multiple `macro_rules` // items with the same name in the same module. diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 8541621b23b8..2b19db2c14e3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -284,7 +284,7 @@ pub fn suggest_new_region_bound( } match fn_return.kind { // FIXME(precise_captures): Suggest adding to `use<...>` list instead. - TyKind::OpaqueDef(opaque, _) => { + TyKind::OpaqueDef(opaque) => { // Get the identity type for this RPIT let did = opaque.def_id.to_def_id(); let ty = Ty::new_opaque(tcx, did, ty::GenericArgs::identity_for_item(tcx, did)); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 833358b2e14d..438639e72f9d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -862,22 +862,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.add_lt_suggs.push(lt.suggestion(self.new_lt)); } } - - fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) { - let hir::TyKind::OpaqueDef(opaque_ty, _) = ty.kind else { - return hir::intravisit::walk_ty(self, ty); - }; - if let Some(&(_, b)) = - opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle) - { - let prev_needle = - std::mem::replace(&mut self.needle, hir::LifetimeName::Param(b)); - for bound in opaque_ty.bounds { - self.visit_param_bound(bound); - } - self.needle = prev_needle; - } - } } let (lifetime_def_id, lifetime_scope) = diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 8e0bdce1280b..19f5d609272e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -361,7 +361,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) | hir::Node::TraitItem(hir::TraitItem { generics, .. }) | hir::Node::ImplItem(hir::ImplItem { generics, .. }) - | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. }) if param_ty => { // We skip the 0'th arg (self) because we do not want @@ -424,10 +423,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | hir::ItemKind::Const(_, generics, _) | hir::ItemKind::TraitAlias(generics, _), .. - }) - | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. }) - if !param_ty => - { + }) if !param_ty => { // Missing generic type parameter bound. if suggest_arbitrary_trait_bound( self.tcx, diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 16fd28201c22..f177b6094857 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -190,7 +190,7 @@ fn associated_types_for_impl_traits_in_associated_fn( impl<'tcx> Visitor<'tcx> for RPITVisitor { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if let hir::TyKind::OpaqueDef(opaq, _) = ty.kind + if let hir::TyKind::OpaqueDef(opaq) = ty.kind && self.rpits.insert(opaq.def_id) { for bound in opaq.bounds { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 87b629078ff8..58663fcbafec 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1829,7 +1829,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T Array(Box::new(clean_ty(ty, cx)), length.into()) } TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()), - TyKind::OpaqueDef(ty, _) => { + TyKind::OpaqueDef(ty) => { ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect()) } TyKind::Path(_) => clean_qpath(ty, cx), diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 5a3930b8bb84..d55be2b036ac 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -420,15 +420,6 @@ impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> { fn visit_ty(&mut self, ty: &'tcx Ty<'_>) { match ty.kind { - TyKind::OpaqueDef(opaque, bounds) => { - let len = self.lts.len(); - self.visit_opaque_ty(opaque); - self.lts.truncate(len); - self.lts.extend(bounds.iter().filter_map(|bound| match bound { - GenericArg::Lifetime(&l) => Some(l), - _ => None, - })); - }, TyKind::BareFn(&BareFnTy { decl, .. }) => { let mut sub_visitor = RefVisitor::new(self.cx); sub_visitor.visit_fn_decl(decl); diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 67255c1af793..c904137da1a1 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -4,9 +4,11 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, - FnRetTy, GenericArg, GenericBound, ImplItem, Item, LifetimeName, Node, TraitRef, Ty, TyKind, + FnRetTy, GenericBound, ImplItem, Item, Node, OpaqueTy, TraitRef, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::middle::resolve_bound_vars::ResolvedArg; +use rustc_middle::ty; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; @@ -44,21 +46,22 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, span: Span, - def_id: LocalDefId, + fn_def_id: LocalDefId, ) { if let Some(header) = kind.header() && !header.asyncness.is_async() // Check that this function returns `impl Future` && let FnRetTy::Return(ret_ty) = decl.output - && let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty) + && let TyKind::OpaqueDef(opaque) = ret_ty.kind + && let Some(trait_ref) = future_trait_ref(cx, opaque) && let Some(output) = future_output_ty(trait_ref) - && captures_all_lifetimes(decl.inputs, &output_lifetimes) + && captures_all_lifetimes(cx, fn_def_id, opaque.def_id) // Check that the body of the function consists of one async block && let ExprKind::Block(block, _) = body.value.kind && block.stmts.is_empty() && let Some(closure_body) = desugared_async_block(cx, block) && let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) = - cx.tcx.hir_node_by_def_id(def_id) + cx.tcx.hir_node_by_def_id(fn_def_id) { let header_span = span.with_hi(ret_ty.span.hi()); @@ -101,12 +104,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { } } -fn future_trait_ref<'tcx>( - cx: &LateContext<'tcx>, - ty: &'tcx Ty<'tcx>, -) -> Option<(&'tcx TraitRef<'tcx>, Vec)> { - if let TyKind::OpaqueDef(opaque, bounds) = ty.kind - && let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| { +fn future_trait_ref<'tcx>(cx: &LateContext<'tcx>, opaque: &'tcx OpaqueTy<'tcx>) -> Option<&'tcx TraitRef<'tcx>> { + if let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| { if let GenericBound::Trait(poly) = bound { Some(&poly.trait_ref) } else { @@ -115,18 +114,7 @@ fn future_trait_ref<'tcx>( }) && trait_ref.trait_def_id() == cx.tcx.lang_items().future_trait() { - let output_lifetimes = bounds - .iter() - .filter_map(|bound| { - if let GenericArg::Lifetime(lt) = bound { - Some(lt.res) - } else { - None - } - }) - .collect(); - - return Some((trait_ref, output_lifetimes)); + return Some(trait_ref); } None @@ -145,27 +133,35 @@ fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'t None } -fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName]) -> bool { - let input_lifetimes: Vec = inputs - .iter() - .filter_map(|ty| { - if let TyKind::Ref(lt, _) = ty.kind { - Some(lt.res) - } else { - None - } - }) - .collect(); +fn captures_all_lifetimes(cx: &LateContext<'_>, fn_def_id: LocalDefId, opaque_def_id: LocalDefId) -> bool { + let early_input_params = ty::GenericArgs::identity_for_item(cx.tcx, fn_def_id); + let late_input_params = cx.tcx.late_bound_vars(cx.tcx.local_def_id_to_hir_id(fn_def_id)); - // The lint should trigger in one of these cases: - // - There are no input lifetimes - // - There's only one output lifetime bound using `+ '_` - // - All input lifetimes are explicitly bound to the output - input_lifetimes.is_empty() - || (output_lifetimes.len() == 1 && matches!(output_lifetimes[0], LifetimeName::Infer)) - || input_lifetimes - .iter() - .all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt)) + let num_early_lifetimes = early_input_params + .iter() + .filter(|param| param.as_region().is_some()) + .count(); + let num_late_lifetimes = late_input_params + .iter() + .filter(|param_kind| matches!(param_kind, ty::BoundVariableKind::Region(_))) + .count(); + + // There is no lifetime, so they are all captured. + if num_early_lifetimes == 0 && num_late_lifetimes == 0 { + return true; + } + + // By construction, each captured lifetime only appears once in `opaque_captured_lifetimes`. + let num_captured_lifetimes = cx + .tcx + .opaque_captured_lifetimes(opaque_def_id) + .iter() + .filter(|&(lifetime, _)| match *lifetime { + ResolvedArg::EarlyBound(_) | ResolvedArg::LateBound(ty::INNERMOST, _, _) => true, + _ => false, + }) + .count(); + num_captured_lifetimes == num_early_lifetimes + num_late_lifetimes } fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> { diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 181d414cbbde..8004bc68b2ea 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1231,16 +1231,13 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } }, TyKind::Path(ref qpath) => self.hash_qpath(qpath), - TyKind::OpaqueDef(_, arg_list) => { - self.hash_generic_args(arg_list); - }, TyKind::TraitObject(_, lifetime, _) => { self.hash_lifetime(lifetime); }, TyKind::Typeof(anon_const) => { self.hash_body(anon_const.body); }, - TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) | TyKind::AnonAdt(_) => {}, + TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) | TyKind::OpaqueDef(_) | TyKind::AnonAdt(_) => {}, } } diff --git a/src/tools/clippy/tests/ui/issue_4266.stderr b/src/tools/clippy/tests/ui/issue_4266.stderr index c0e817915896..63c568a153b2 100644 --- a/src/tools/clippy/tests/ui/issue_4266.stderr +++ b/src/tools/clippy/tests/ui/issue_4266.stderr @@ -11,7 +11,7 @@ error: the following explicit lifetimes could be elided: 'a --> tests/ui/issue_4266.rs:10:21 | LL | async fn one_to_one<'a>(s: &'a str) -> &'a str { - | ^^ ^^ + | ^^ ^^ ^^ error: methods called `new` usually take no `self` --> tests/ui/issue_4266.rs:31:22 diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs index 19905c608e3b..cd2f43fca9a6 100644 --- a/tests/ui/impl-trait/in-trait/variance.rs +++ b/tests/ui/impl-trait/in-trait/variance.rs @@ -4,7 +4,7 @@ trait Foo<'i> { fn implicit_capture_early<'a: 'a>() -> impl Sized {} - //~^ [Self: o, 'i: o, 'a: *, 'a: o, 'i: o] + //~^ [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] fn explicit_capture_early<'a: 'a>() -> impl Sized + use<'i, 'a, Self> {} //~^ [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] @@ -13,12 +13,12 @@ trait Foo<'i> { //~^ [Self: o, 'i: o, 'a: *, 'i: o] fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} - //~^ [Self: o, 'i: o, 'a: o, 'i: o] + //~^ [Self: o, 'i: o, 'i: o, 'a: o] fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + use<'i, 'a, Self> {} //~^ [Self: o, 'i: o, 'i: o, 'a: o] - fn not_cpatured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {} + fn not_captured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {} //~^ [Self: o, 'i: o, 'i: o] } diff --git a/tests/ui/impl-trait/in-trait/variance.stderr b/tests/ui/impl-trait/in-trait/variance.stderr index f65174e1c358..d45cca982e97 100644 --- a/tests/ui/impl-trait/in-trait/variance.stderr +++ b/tests/ui/impl-trait/in-trait/variance.stderr @@ -1,4 +1,4 @@ -error: [Self: o, 'i: o, 'a: *, 'a: o, 'i: o] +error: [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:6:44 | LL | fn implicit_capture_early<'a: 'a>() -> impl Sized {} @@ -16,7 +16,7 @@ error: [Self: o, 'i: o, 'a: *, 'i: o] LL | fn not_captured_early<'a: 'a>() -> impl Sized + use<'i, Self> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [Self: o, 'i: o, 'a: o, 'i: o] +error: [Self: o, 'i: o, 'i: o, 'a: o] --> $DIR/variance.rs:15:48 | LL | fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} @@ -31,7 +31,7 @@ LL | fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + use<'i, 'a, Sel error: [Self: o, 'i: o, 'i: o] --> $DIR/variance.rs:21:44 | -LL | fn not_cpatured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {} +LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs b/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs index 5ef8542d862e..2ec2fed93d7d 100644 --- a/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs +++ b/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs @@ -6,9 +6,8 @@ #![rustc_variance_of_opaques] fn foo(x: &()) -> impl IntoIterator + use<> { - //~^ ERROR ['_: o] - //~| ERROR ['_: o] - //~| ERROR `impl Trait` captures lifetime parameter + //~^ ERROR [] + //~| ERROR [] [*x] } diff --git a/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr b/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr index b14ed20bd367..02cf8c5fdf27 100644 --- a/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr +++ b/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr @@ -1,22 +1,14 @@ -error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/capturing-implicit.rs:8:11 - | -LL | fn foo(x: &()) -> impl IntoIterator + use<> { - | ^ -------------------------------------------- lifetime captured due to being mentioned in the bounds of the `impl Trait` - | | - | this lifetime parameter is captured - -error: ['_: o] +error: [] --> $DIR/capturing-implicit.rs:8:19 | LL | fn foo(x: &()) -> impl IntoIterator + use<> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: ['_: o] +error: [] --> $DIR/capturing-implicit.rs:8:44 | LL | fn foo(x: &()) -> impl IntoIterator + use<> { | ^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs index df589473a846..e1757ff91527 100644 --- a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs +++ b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs @@ -5,6 +5,7 @@ impl Captures<'_> for T {} fn dyn_hoops() -> dyn for<'a> Iterator> { //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type + //~| ERROR return type cannot have an unboxed trait object loop {} } @@ -12,7 +13,9 @@ pub fn main() { //~^ ERROR item does not constrain `Opaque::{opaque#0}`, but has it in its signature type Opaque = impl Sized; fn define() -> Opaque { + //~^ ERROR the size for values of type `(dyn Iterator> + 'static)` let x: Opaque = dyn_hoops::<()>(); + //~^ ERROR the size for values of type `(dyn Iterator> + 'static)` x } } diff --git a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr index 59d9ff86c6e0..ed44b96d7eb6 100644 --- a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr +++ b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr @@ -10,19 +10,57 @@ note: lifetime declared here LL | fn dyn_hoops() -> dyn for<'a> Iterator> { | ^^ +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/bound-lifetime-through-dyn-trait.rs:6:29 + | +LL | fn dyn_hoops() -> dyn for<'a> Iterator> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | +help: consider returning an `impl Trait` instead of a `dyn Trait` + | +LL | fn dyn_hoops() -> impl for<'a> Iterator> { + | ~~~~ +help: alternatively, box the return type, and wrap all of the returned values in `Box::new` + | +LL ~ fn dyn_hoops() -> Box Iterator>> { +LL | +LL | +LL ~ Box::new(loop {}) + | + error: item does not constrain `Opaque::{opaque#0}`, but has it in its signature - --> $DIR/bound-lifetime-through-dyn-trait.rs:11:8 + --> $DIR/bound-lifetime-through-dyn-trait.rs:12:8 | LL | pub fn main() { | ^^^^ | = note: consider moving the opaque type's declaration and defining uses into a separate module note: this opaque type is in the signature - --> $DIR/bound-lifetime-through-dyn-trait.rs:13:19 + --> $DIR/bound-lifetime-through-dyn-trait.rs:14:19 | LL | type Opaque = impl Sized; | ^^^^^^^^^^ -error: aborting due to 2 previous errors +error[E0277]: the size for values of type `(dyn Iterator> + 'static)` cannot be known at compilation time + --> $DIR/bound-lifetime-through-dyn-trait.rs:15:20 + | +LL | fn define() -> Opaque { + | ^^^^^^ doesn't have a size known at compile-time +... +LL | x + | - return type was inferred to be `(dyn Iterator> + 'static)` here + | + = help: the trait `Sized` is not implemented for `(dyn Iterator> + 'static)` -For more information about this error, try `rustc --explain E0657`. +error[E0277]: the size for values of type `(dyn Iterator> + 'static)` cannot be known at compilation time + --> $DIR/bound-lifetime-through-dyn-trait.rs:17:25 + | +LL | let x: Opaque = dyn_hoops::<()>(); + | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Iterator> + 'static)` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0657, E0746. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs index 1ff200680be5..07206dd2491e 100644 --- a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs +++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs @@ -8,6 +8,7 @@ trait Test<'a> {} pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` +//~| ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` impl Trait<'_> for () { type Assoc = (); diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr index 09f6fba79cfd..c9f0618639af 100644 --- a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr +++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr @@ -10,6 +10,18 @@ note: lifetime declared here LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; | ^^ -error: aborting due to 1 previous error +error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` + --> $DIR/escaping-bound-var.rs:9:57 + | +LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; + | ^^ + | +note: lifetime declared here + --> $DIR/escaping-bound-var.rs:9:25 + | +LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>; + | ^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0657`. diff --git a/tests/ui/type-alias-impl-trait/variance.rs b/tests/ui/type-alias-impl-trait/variance.rs index 113f6a4cc449..40e8ec0129a3 100644 --- a/tests/ui/type-alias-impl-trait/variance.rs +++ b/tests/ui/type-alias-impl-trait/variance.rs @@ -11,11 +11,11 @@ type NotCapturedEarly<'a> = impl Sized; //~ ['a: *, 'a: o] type CapturedEarly<'a> = impl Sized + Captures<'a>; //~ ['a: *, 'a: o] //~^ ERROR: unconstrained opaque type -type NotCapturedLate<'a> = dyn for<'b> Iterator; //~ ['a: *, 'b: o, 'a: o] +type NotCapturedLate<'a> = dyn for<'b> Iterator; //~ ['a: *, 'a: o, 'b: o] //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type //~| ERROR: unconstrained opaque type -type Captured<'a> = dyn for<'b> Iterator>; //~ ['a: *, 'b: o, 'a: o] +type Captured<'a> = dyn for<'b> Iterator>; //~ ['a: *, 'a: o, 'b: o] //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type //~| ERROR: unconstrained opaque type @@ -31,24 +31,24 @@ trait Foo<'i> { } impl<'i> Foo<'i> for &'i () { - type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'a: o, 'i: o] + type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'a: o, 'i: o] + type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'a: o, 'i: o] + type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type } impl<'i> Foo<'i> for () { - type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'a: o, 'i: o] + type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'a: o, 'i: o] + type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type - type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'a: o, 'i: o] + type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'i: o, 'a: o] //~^ ERROR: unconstrained opaque type } diff --git a/tests/ui/type-alias-impl-trait/variance.stderr b/tests/ui/type-alias-impl-trait/variance.stderr index 489dfe03d446..79ce8148f19a 100644 --- a/tests/ui/type-alias-impl-trait/variance.stderr +++ b/tests/ui/type-alias-impl-trait/variance.stderr @@ -122,13 +122,13 @@ error: ['a: *, 'a: o] LL | type CapturedEarly<'a> = impl Sized + Captures<'a>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: ['a: *, 'b: o, 'a: o] +error: ['a: *, 'a: o, 'b: o] --> $DIR/variance.rs:14:56 | LL | type NotCapturedLate<'a> = dyn for<'b> Iterator; | ^^^^^^^^^^ -error: ['a: *, 'b: o, 'a: o] +error: ['a: *, 'a: o, 'b: o] --> $DIR/variance.rs:18:49 | LL | type Captured<'a> = dyn for<'b> Iterator>; @@ -140,37 +140,37 @@ error: ['a: *, 'b: *, T: o, 'a: o, 'b: o] LL | type Bar<'a, 'b: 'b, T> = impl Sized; | ^^^^^^^^^^ -error: ['i: *, 'a: *, 'a: o, 'i: o] +error: ['i: *, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:34:32 | LL | type ImplicitCapture<'a> = impl Sized; | ^^^^^^^^^^ -error: ['i: *, 'a: *, 'a: o, 'i: o] +error: ['i: *, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:37:42 | LL | type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: ['i: *, 'a: *, 'a: o, 'i: o] +error: ['i: *, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:40:39 | LL | type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: ['i: *, 'a: *, 'a: o, 'i: o] +error: ['i: *, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:45:32 | LL | type ImplicitCapture<'a> = impl Sized; | ^^^^^^^^^^ -error: ['i: *, 'a: *, 'a: o, 'i: o] +error: ['i: *, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:48:42 | LL | type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: ['i: *, 'a: *, 'a: o, 'i: o] +error: ['i: *, 'a: *, 'i: o, 'a: o] --> $DIR/variance.rs:51:39 | LL | type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; From d693e1926894824bc4fb2249a17a9cd71c926ac2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 22 Aug 2024 00:25:37 +0000 Subject: [PATCH 36/56] Promote crashes tests to ui. --- tests/crashes/125249.rs | 8 ------ .../impl-trait/closure-in-type.rs} | 3 ++- .../in-trait/return-type-notation.rs | 9 +++++++ .../in-trait/return-type-notation.stderr | 27 +++++++++++++++++++ 4 files changed, 38 insertions(+), 9 deletions(-) delete mode 100644 tests/crashes/125249.rs rename tests/{crashes/126850.rs => ui/impl-trait/closure-in-type.rs} (81%) create mode 100644 tests/ui/impl-trait/in-trait/return-type-notation.rs create mode 100644 tests/ui/impl-trait/in-trait/return-type-notation.stderr diff --git a/tests/crashes/125249.rs b/tests/crashes/125249.rs deleted file mode 100644 index 1cf6338a0d62..000000000000 --- a/tests/crashes/125249.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: rust-lang/rust#125185 -#![feature(return_position_impl_trait_in_trait, return_type_notation)] - -trait IntFactory { - fn stream(&self) -> impl IntFactory + Send>; -} - -pub fn main() {} diff --git a/tests/crashes/126850.rs b/tests/ui/impl-trait/closure-in-type.rs similarity index 81% rename from tests/crashes/126850.rs rename to tests/ui/impl-trait/closure-in-type.rs index 0ddc24c8bb15..1e06e6e21fd2 100644 --- a/tests/crashes/126850.rs +++ b/tests/ui/impl-trait/closure-in-type.rs @@ -1,4 +1,5 @@ -//@ known-bug: rust-lang/rust#126850 +//@ check-pass + fn bug() -> impl Iterator< Item = [(); { |found: &String| Some(false); diff --git a/tests/ui/impl-trait/in-trait/return-type-notation.rs b/tests/ui/impl-trait/in-trait/return-type-notation.rs new file mode 100644 index 000000000000..3945eb9bdeef --- /dev/null +++ b/tests/ui/impl-trait/in-trait/return-type-notation.rs @@ -0,0 +1,9 @@ +#![allow(incomplete_features)] +#![feature(return_type_notation)] + +trait IntFactory { + fn stream(&self) -> impl IntFactory + Send>; + //~^ ERROR cycle detected when resolving lifetimes for `IntFactory::stream` +} + +pub fn main() {} diff --git a/tests/ui/impl-trait/in-trait/return-type-notation.stderr b/tests/ui/impl-trait/in-trait/return-type-notation.stderr new file mode 100644 index 000000000000..d9fd780cdff3 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/return-type-notation.stderr @@ -0,0 +1,27 @@ +error[E0391]: cycle detected when resolving lifetimes for `IntFactory::stream` + --> $DIR/return-type-notation.rs:5:5 + | +LL | fn stream(&self) -> impl IntFactory + Send>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing function signature of `IntFactory::stream`... + --> $DIR/return-type-notation.rs:5:5 + | +LL | fn stream(&self) -> impl IntFactory + Send>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires looking up late bound vars inside `IntFactory::stream`... + --> $DIR/return-type-notation.rs:5:5 + | +LL | fn stream(&self) -> impl IntFactory + Send>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires resolving lifetimes for `IntFactory::stream`, completing the cycle +note: cycle used when listing captured lifetimes for opaque `IntFactory::stream::{opaque#0}` + --> $DIR/return-type-notation.rs:5:25 + | +LL | fn stream(&self) -> impl IntFactory + Send>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. From d804ef8be8a7ce9c680812776276248cdf174e29 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 5 Oct 2024 12:13:24 +0000 Subject: [PATCH 37/56] Adapt comments. --- .../src/collect/resolve_bound_vars.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 675e033e9499..1378e6203164 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -152,11 +152,14 @@ enum Scope<'a> { s: ScopeRef<'a>, }, - /// Resolve the lifetimes in the bounds to the lifetime defs in the generics. - /// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + /// Remap lifetimes that appear in opaque types to fresh lifetime parameters. Given: + /// `fn foo<'a>() -> impl MyTrait<'a> { ... }` + /// + /// HIR tells us that `'a` refer to the lifetime bound on `foo`. + /// However, typeck and borrowck for opaques are work based on using a new generics type. /// `type MyAnonTy<'b> = impl MyTrait<'b>;` - /// ^ ^ this gets resolved in the scope of - /// the opaque_ty generics + /// + /// This scope collects the mapping `'a -> 'b`. Opaque { /// The opaque type we are traversing. def_id: LocalDefId, @@ -547,11 +550,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } - /// Resolve the lifetimes that are applied to the opaque type. - /// These are resolved in the current scope. - /// `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - /// `fn foo<'a>() -> MyAnonTy<'a> { ... }` - /// ^ ^this gets resolved in the current scope + /// Resolve the lifetimes inside the opaque type, and save them into + /// `opaque_captured_lifetimes`. + /// + /// This method has special handling for opaques that capture all lifetimes, + /// like async desugaring. #[instrument(level = "debug", skip(self))] fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) { let mut captures = FxIndexMap::default(); @@ -815,9 +818,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }; self.with(scope, |this| this.visit_ty(mt.ty)); } - hir::TyKind::OpaqueDef(opaque_ty) => { - self.visit_opaque_ty(opaque_ty); - } _ => intravisit::walk_ty(self, ty), } } From 27c958fb442b0285456c2ae186686c696e7ddae1 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 26 Oct 2024 17:34:28 +0000 Subject: [PATCH 38/56] Review comments. --- .../src/lifetime_collector.rs | 151 ------------------ compiler/rustc_hir/src/hir.rs | 5 - .../src/collect/resolve_bound_vars.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- 4 files changed, 2 insertions(+), 158 deletions(-) delete mode 100644 compiler/rustc_ast_lowering/src/lifetime_collector.rs diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs deleted file mode 100644 index 8d47c856bdd2..000000000000 --- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs +++ /dev/null @@ -1,151 +0,0 @@ -use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor}; -use rustc_ast::{ - GenericBound, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind, -}; -use rustc_data_structures::fx::FxIndexSet; -use rustc_hir::def::{DefKind, LifetimeRes, Res}; -use rustc_middle::span_bug; -use rustc_middle::ty::ResolverAstLowering; -use rustc_span::Span; -use rustc_span::symbol::{Ident, kw}; - -use super::ResolverAstLoweringExt; - -struct LifetimeCollectVisitor<'ast> { - resolver: &'ast mut ResolverAstLowering, - always_capture_in_scope: bool, - current_binders: Vec, - collected_lifetimes: FxIndexSet, -} - -impl<'ast> LifetimeCollectVisitor<'ast> { - fn new(resolver: &'ast mut ResolverAstLowering, always_capture_in_scope: bool) -> Self { - Self { - resolver, - always_capture_in_scope, - current_binders: Vec::new(), - collected_lifetimes: FxIndexSet::default(), - } - } - - fn visit_opaque(&mut self, opaque_ty_node_id: NodeId, bounds: &'ast GenericBounds, span: Span) { - // If we're edition 2024 or within a TAIT or RPITIT, *and* there is no - // `use<>` statement to override the default capture behavior, then - // capture all of the in-scope lifetimes. - if (self.always_capture_in_scope || span.at_least_rust_2024()) - && bounds.iter().all(|bound| !matches!(bound, GenericBound::Use(..))) - { - for (ident, id, _) in self.resolver.extra_lifetime_params(opaque_ty_node_id) { - self.record_lifetime_use(Lifetime { id, ident }); - } - } - - // We also recurse on the bounds to make sure we capture all the lifetimes - // mentioned in the bounds. These may disagree with the `use<>` list, in which - // case we will error on these later. We will also recurse to visit any - // nested opaques, which may *implicitly* capture lifetimes. - for bound in bounds { - self.visit_param_bound(bound, BoundKind::Bound); - } - } - - fn record_lifetime_use(&mut self, lifetime: Lifetime) { - match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) { - LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => { - if !self.current_binders.contains(&binder) { - self.collected_lifetimes.insert(lifetime); - } - } - LifetimeRes::Static { .. } | LifetimeRes::Error => { - self.collected_lifetimes.insert(lifetime); - } - LifetimeRes::Infer => {} - res => { - let bug_msg = format!( - "Unexpected lifetime resolution {:?} for {:?} at {:?}", - res, lifetime.ident, lifetime.ident.span - ); - span_bug!(lifetime.ident.span, "{}", bug_msg); - } - } - } - - /// This collect lifetimes that are elided, for nodes like `Foo` where there are no explicit - /// lifetime nodes. Is equivalent to having "pseudo" nodes introduced for each of the node ids - /// in the list start..end. - fn record_elided_anchor(&mut self, node_id: NodeId, span: Span) { - if let Some(LifetimeRes::ElidedAnchor { start, end }) = - self.resolver.get_lifetime_res(node_id) - { - for i in start..end { - let lifetime = Lifetime { id: i, ident: Ident::new(kw::UnderscoreLifetime, span) }; - self.record_lifetime_use(lifetime); - } - } - } -} - -impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> { - fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) { - self.record_lifetime_use(*lifetime); - } - - fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) { - self.record_elided_anchor(path_segment.id, path_segment.ident.span); - visit::walk_path_segment(self, path_segment); - } - - fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) { - self.current_binders.push(t.trait_ref.ref_id); - - visit::walk_poly_trait_ref(self, t); - - self.current_binders.pop(); - } - - fn visit_ty(&mut self, t: &'ast Ty) { - match &t.kind { - TyKind::Path(None, _) => { - // We can sometimes encounter bare trait objects - // which are represented in AST as paths. - if let Some(partial_res) = self.resolver.get_partial_res(t.id) - && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = - partial_res.full_res() - { - self.current_binders.push(t.id); - visit::walk_ty(self, t); - self.current_binders.pop(); - } else { - visit::walk_ty(self, t); - } - } - TyKind::BareFn(_) => { - self.current_binders.push(t.id); - visit::walk_ty(self, t); - self.current_binders.pop(); - } - TyKind::Ref(None, _) | TyKind::PinnedRef(None, _) => { - self.record_elided_anchor(t.id, t.span); - visit::walk_ty(self, t); - } - TyKind::ImplTrait(opaque_ty_node_id, bounds) => { - self.visit_opaque(*opaque_ty_node_id, bounds, t.span) - } - _ => { - visit::walk_ty(self, t); - } - } - } -} - -pub(crate) fn lifetimes_for_opaque( - resolver: &mut ResolverAstLowering, - always_capture_in_scope: bool, - opaque_ty_node_id: NodeId, - bounds: &GenericBounds, - span: Span, -) -> FxIndexSet { - let mut visitor = LifetimeCollectVisitor::new(resolver, always_capture_in_scope); - visitor.visit_opaque(opaque_ty_node_id, bounds, span); - visitor.collected_lifetimes -} diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2cfe10503ac5..12b01266a931 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2849,11 +2849,6 @@ pub enum TyKind<'hir> { /// Type parameters may be stored in each `PathSegment`. Path(QPath<'hir>), /// An opaque type definition itself. This is only used for `impl Trait`. - /// - /// The generic argument list contains the lifetimes (and in the future - /// possibly parameters) that are actually bound on the `impl Trait`. - /// - /// The last parameter specifies whether this opaque appears in a trait definition. OpaqueDef(&'hir OpaqueTy<'hir>), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 1378e6203164..104710dd0351 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -156,7 +156,7 @@ enum Scope<'a> { /// `fn foo<'a>() -> impl MyTrait<'a> { ... }` /// /// HIR tells us that `'a` refer to the lifetime bound on `foo`. - /// However, typeck and borrowck for opaques are work based on using a new generics type. + /// However, typeck and borrowck for opaques work based on using a new generic type. /// `type MyAnonTy<'b> = impl MyTrait<'b>;` /// /// This scope collects the mapping `'a -> 'b`. diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5fef8c49eec2..f4a85c358e38 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -841,7 +841,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.r.record_partial_res(ty.id, PartialRes::new(res)); visit::walk_ty(self, ty) } - TyKind::ImplTrait(_, _) => { + TyKind::ImplTrait(..) => { let candidates = self.lifetime_elision_candidates.take(); visit::walk_ty(self, ty); self.lifetime_elision_candidates = candidates; From 8f6e0a6a4b03c212c0434de417a274d50b7ab0e5 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 26 Oct 2024 17:50:28 +0000 Subject: [PATCH 39/56] Promote test. --- .../return-type-notation/impl-trait-in-trait.rs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/{crashes/131648.rs => ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs} (84%) diff --git a/tests/crashes/131648.rs b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs similarity index 84% rename from tests/crashes/131648.rs rename to tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs index 68046ce2a1fb..982a757a1e93 100644 --- a/tests/crashes/131648.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs @@ -1,7 +1,7 @@ -//@ known-bug: #131648 #![feature(return_type_notation)] trait IntFactory { fn stream(self) -> impl IntFactory; } + fn main() {} From 2d74d8f333d77bf53f8ebd590459c61316a4a324 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 27 Oct 2024 15:53:48 +0000 Subject: [PATCH 40/56] Actually capture all in-scope lifetimes. --- .../src/collect/resolve_bound_vars.rs | 72 ++++++++----------- .../impl-trait-in-trait.rs | 1 + .../impl-trait-in-trait.stderr | 27 +++++++ .../precise-capturing/capturing-implicit.rs | 5 +- .../capturing-implicit.stderr | 14 +++- .../bound-lifetime-through-dyn-trait.rs | 3 - .../bound-lifetime-through-dyn-trait.stderr | 46 ++---------- 7 files changed, 75 insertions(+), 93 deletions(-) create mode 100644 tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 104710dd0351..9483439ae4e8 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -557,37 +557,29 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { /// like async desugaring. #[instrument(level = "debug", skip(self))] fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) { - let mut captures = FxIndexMap::default(); + let captures = RefCell::new(FxIndexMap::default()); let capture_all_in_scope_lifetimes = opaque_captures_all_in_scope_lifetimes(self.tcx, opaque); if capture_all_in_scope_lifetimes { - let mut create_def_for_duplicated_param = |original_lifetime: LocalDefId, def| { - captures.entry(def).or_insert_with(|| { - let name = self.tcx.item_name(original_lifetime.to_def_id()); - let span = self.tcx.def_span(original_lifetime); - let feed = self.tcx.create_def(opaque.def_id, name, DefKind::LifetimeParam); - feed.def_span(span); - feed.def_ident_span(Some(span)); - feed.def_id() - }); + let lifetime_ident = |def_id: LocalDefId| { + let name = self.tcx.item_name(def_id.to_def_id()); + let span = self.tcx.def_span(def_id); + Ident::new(name, span) }; // We list scopes outwards, this causes us to see lifetime parameters in reverse // declaration order. In order to make it consistent with what `generics_of` might // give, we will reverse the IndexMap after early captures. let mut scope = self.scope; + let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)]; loop { match *scope { Scope::Binder { ref bound_vars, s, .. } => { - for (&original_lifetime, &(mut def)) in bound_vars.iter().rev() { + for (&original_lifetime, &def) in bound_vars.iter().rev() { if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) { - if let Err(guar) = - self.check_lifetime_is_capturable(opaque.def_id, def, None) - { - def = ResolvedArg::Error(guar); - } - create_def_for_duplicated_param(original_lifetime, def); + let ident = lifetime_ident(original_lifetime); + self.remap_opaque_captures(&opaque_capture_scopes, def, ident); } } scope = s; @@ -598,10 +590,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let parent_generics = self.tcx.generics_of(parent_item); for param in parent_generics.own_params.iter().rev() { if let ty::GenericParamDefKind::Lifetime = param.kind { - create_def_for_duplicated_param( - param.def_id.expect_local(), - ResolvedArg::EarlyBound(param.def_id.expect_local()), - ); + let def = ResolvedArg::EarlyBound(param.def_id.expect_local()); + let ident = lifetime_ident(param.def_id.expect_local()); + self.remap_opaque_captures(&opaque_capture_scopes, def, ident); } } opt_parent_item = parent_generics.parent.and_then(DefId::as_local); @@ -609,14 +600,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { break; } - Scope::Opaque { captures: outer_captures, .. } => { - for (_, &duplicated_param) in outer_captures.borrow().iter().rev() { - create_def_for_duplicated_param( - duplicated_param, - ResolvedArg::EarlyBound(duplicated_param), - ); - } - break; + Scope::Opaque { captures, def_id, s } => { + opaque_capture_scopes.push((def_id, captures)); + scope = s; } Scope::Body { .. } => { @@ -631,11 +617,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { } } } - captures.reverse(); + captures.borrow_mut().reverse(); } - let captures = RefCell::new(captures); - let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; @@ -643,6 +627,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }); let captures = captures.into_inner().into_iter().collect(); + debug!(?captures); self.map.opaque_captured_lifetimes.insert(opaque.def_id, captures); } @@ -1297,7 +1282,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { }; if let Some(mut def) = result { - def = self.remap_opaque_captures(opaque_capture_scopes, def, lifetime_ref.ident); + def = self.remap_opaque_captures(&opaque_capture_scopes, def, lifetime_ref.ident); if let ResolvedArg::EarlyBound(..) = def { // Do not free early-bound regions, only late-bound ones. @@ -1396,7 +1381,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { &self, opaque_def_id: LocalDefId, lifetime: ResolvedArg, - span: Option, + capture_span: Span, ) -> Result<(), ErrorGuaranteed> { let ResolvedArg::LateBound(_, _, lifetime_def_id) = lifetime else { return Ok(()) }; let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id); @@ -1416,10 +1401,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { }; let decl_span = self.tcx.def_span(lifetime_def_id); - let (span, label) = if let Some(span) = span - && span != decl_span - { - (span, None) + let (span, label) = if capture_span != decl_span { + (capture_span, None) } else { let opaque_span = self.tcx.def_span(opaque_def_id); (opaque_span, Some(opaque_span)) @@ -1435,19 +1418,22 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Err(guar) } + #[instrument(level = "trace", skip(self, opaque_capture_scopes), ret)] fn remap_opaque_captures( &self, - opaque_capture_scopes: Vec<(LocalDefId, &RefCell>)>, + opaque_capture_scopes: &Vec<(LocalDefId, &RefCell>)>, mut lifetime: ResolvedArg, ident: Ident, ) -> ResolvedArg { - for (opaque_def_id, captures) in opaque_capture_scopes.into_iter().rev() { + if let Some(&(opaque_def_id, _)) = opaque_capture_scopes.last() { if let Err(guar) = - self.check_lifetime_is_capturable(opaque_def_id, lifetime, Some(ident.span)) + self.check_lifetime_is_capturable(opaque_def_id, lifetime, ident.span) { - return ResolvedArg::Error(guar); + lifetime = ResolvedArg::Error(guar); } + } + for &(opaque_def_id, captures) in opaque_capture_scopes.iter().rev() { let mut captures = captures.borrow_mut(); let remapped = *captures.entry(lifetime).or_insert_with(|| { let feed = self.tcx.create_def(opaque_def_id, ident.name, DefKind::LifetimeParam); @@ -1976,7 +1962,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } }; - lifetime = self.remap_opaque_captures(opaque_capture_scopes, lifetime, lifetime_ref.ident); + lifetime = self.remap_opaque_captures(&opaque_capture_scopes, lifetime, lifetime_ref.ident); self.insert_lifetime(lifetime_ref, lifetime); } diff --git a/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs index 982a757a1e93..0d3e6f9c8e3a 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs @@ -2,6 +2,7 @@ trait IntFactory { fn stream(self) -> impl IntFactory; + //~^ ERROR cycle detected when resolving lifetimes for `IntFactory::stream` } fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr new file mode 100644 index 000000000000..0ed54415b9e0 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr @@ -0,0 +1,27 @@ +error[E0391]: cycle detected when resolving lifetimes for `IntFactory::stream` + --> $DIR/impl-trait-in-trait.rs:4:5 + | +LL | fn stream(self) -> impl IntFactory; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing function signature of `IntFactory::stream`... + --> $DIR/impl-trait-in-trait.rs:4:5 + | +LL | fn stream(self) -> impl IntFactory; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires looking up late bound vars inside `IntFactory::stream`... + --> $DIR/impl-trait-in-trait.rs:4:5 + | +LL | fn stream(self) -> impl IntFactory; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires resolving lifetimes for `IntFactory::stream`, completing the cycle +note: cycle used when listing captured lifetimes for opaque `IntFactory::stream::{opaque#0}` + --> $DIR/impl-trait-in-trait.rs:4:24 + | +LL | fn stream(self) -> impl IntFactory; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs b/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs index 2ec2fed93d7d..5ef8542d862e 100644 --- a/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs +++ b/tests/ui/impl-trait/precise-capturing/capturing-implicit.rs @@ -6,8 +6,9 @@ #![rustc_variance_of_opaques] fn foo(x: &()) -> impl IntoIterator + use<> { - //~^ ERROR [] - //~| ERROR [] + //~^ ERROR ['_: o] + //~| ERROR ['_: o] + //~| ERROR `impl Trait` captures lifetime parameter [*x] } diff --git a/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr b/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr index 02cf8c5fdf27..b14ed20bd367 100644 --- a/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr +++ b/tests/ui/impl-trait/precise-capturing/capturing-implicit.stderr @@ -1,14 +1,22 @@ -error: [] +error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list + --> $DIR/capturing-implicit.rs:8:11 + | +LL | fn foo(x: &()) -> impl IntoIterator + use<> { + | ^ -------------------------------------------- lifetime captured due to being mentioned in the bounds of the `impl Trait` + | | + | this lifetime parameter is captured + +error: ['_: o] --> $DIR/capturing-implicit.rs:8:19 | LL | fn foo(x: &()) -> impl IntoIterator + use<> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [] +error: ['_: o] --> $DIR/capturing-implicit.rs:8:44 | LL | fn foo(x: &()) -> impl IntoIterator + use<> { | ^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs index e1757ff91527..df589473a846 100644 --- a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs +++ b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs @@ -5,7 +5,6 @@ impl Captures<'_> for T {} fn dyn_hoops() -> dyn for<'a> Iterator> { //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type - //~| ERROR return type cannot have an unboxed trait object loop {} } @@ -13,9 +12,7 @@ pub fn main() { //~^ ERROR item does not constrain `Opaque::{opaque#0}`, but has it in its signature type Opaque = impl Sized; fn define() -> Opaque { - //~^ ERROR the size for values of type `(dyn Iterator> + 'static)` let x: Opaque = dyn_hoops::<()>(); - //~^ ERROR the size for values of type `(dyn Iterator> + 'static)` x } } diff --git a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr index ed44b96d7eb6..59d9ff86c6e0 100644 --- a/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr +++ b/tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr @@ -10,57 +10,19 @@ note: lifetime declared here LL | fn dyn_hoops() -> dyn for<'a> Iterator> { | ^^ -error[E0746]: return type cannot have an unboxed trait object - --> $DIR/bound-lifetime-through-dyn-trait.rs:6:29 - | -LL | fn dyn_hoops() -> dyn for<'a> Iterator> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | -help: consider returning an `impl Trait` instead of a `dyn Trait` - | -LL | fn dyn_hoops() -> impl for<'a> Iterator> { - | ~~~~ -help: alternatively, box the return type, and wrap all of the returned values in `Box::new` - | -LL ~ fn dyn_hoops() -> Box Iterator>> { -LL | -LL | -LL ~ Box::new(loop {}) - | - error: item does not constrain `Opaque::{opaque#0}`, but has it in its signature - --> $DIR/bound-lifetime-through-dyn-trait.rs:12:8 + --> $DIR/bound-lifetime-through-dyn-trait.rs:11:8 | LL | pub fn main() { | ^^^^ | = note: consider moving the opaque type's declaration and defining uses into a separate module note: this opaque type is in the signature - --> $DIR/bound-lifetime-through-dyn-trait.rs:14:19 + --> $DIR/bound-lifetime-through-dyn-trait.rs:13:19 | LL | type Opaque = impl Sized; | ^^^^^^^^^^ -error[E0277]: the size for values of type `(dyn Iterator> + 'static)` cannot be known at compilation time - --> $DIR/bound-lifetime-through-dyn-trait.rs:15:20 - | -LL | fn define() -> Opaque { - | ^^^^^^ doesn't have a size known at compile-time -... -LL | x - | - return type was inferred to be `(dyn Iterator> + 'static)` here - | - = help: the trait `Sized` is not implemented for `(dyn Iterator> + 'static)` +error: aborting due to 2 previous errors -error[E0277]: the size for values of type `(dyn Iterator> + 'static)` cannot be known at compilation time - --> $DIR/bound-lifetime-through-dyn-trait.rs:17:25 - | -LL | let x: Opaque = dyn_hoops::<()>(); - | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `(dyn Iterator> + 'static)` - -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0277, E0657, E0746. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0657`. From 802f3a78a6eea323617964a168a612d1b0826bd6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 29 Oct 2024 23:42:59 +0000 Subject: [PATCH 41/56] Merge HostPolarity and BoundConstness --- compiler/rustc_hir_analysis/src/bounds.rs | 4 +- .../src/check/compare_impl_item.rs | 10 ++-- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- .../src/collect/predicates_of.rs | 12 ++-- .../src/hir_ty_lowering/mod.rs | 9 ++- compiler/rustc_hir_typeck/src/callee.rs | 4 +- compiler/rustc_middle/src/ty/context.rs | 6 +- compiler/rustc_middle/src/ty/flags.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 8 +-- .../src/solve/effect_goals.rs | 11 ++-- compiler/rustc_privacy/src/lib.rs | 2 +- .../traits/fulfillment_errors.rs | 13 ++--- .../src/traits/effects.rs | 5 +- compiler/rustc_ty_utils/src/ty.rs | 2 +- compiler/rustc_type_ir/src/elaborate.rs | 2 +- compiler/rustc_type_ir/src/predicate.rs | 55 ++++++------------- 16 files changed, 66 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 09ddc6ca9de1..9b02651a8bdf 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -84,11 +84,11 @@ impl<'tcx> Bounds<'tcx> { &mut self, tcx: TyCtxt<'tcx>, bound_trait_ref: ty::PolyTraitRef<'tcx>, - host: ty::HostPolarity, + constness: ty::BoundConstness, span: Span, ) { if tcx.is_const_trait(bound_trait_ref.def_id()) { - self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, host), span)); + self.clauses.push((bound_trait_ref.to_host_effect_clause(tcx, constness), span)); } else { tcx.dcx().span_delayed_bug(span, "tried to lower {host:?} bound for non-const trait"); } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index db2c44fd29df..796999c65243 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -218,7 +218,7 @@ fn compare_method_predicate_entailment<'tcx>( tcx.const_conditions(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args), ) .map(|(trait_ref, _)| { - trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe) + trait_ref.to_host_effect_clause(tcx, ty::BoundConstness::Maybe) }), ); } @@ -272,7 +272,7 @@ fn compare_method_predicate_entailment<'tcx>( tcx, cause, param_env, - const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + const_condition.to_host_effect_clause(tcx, ty::BoundConstness::Maybe), )); } } @@ -1942,7 +1942,7 @@ fn compare_type_predicate_entailment<'tcx>( tcx.const_conditions(trait_ty.def_id).instantiate_own(tcx, trait_to_impl_args), ) .map(|(trait_ref, _)| { - trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe) + trait_ref.to_host_effect_clause(tcx, ty::BoundConstness::Maybe) }), ); } @@ -1985,7 +1985,7 @@ fn compare_type_predicate_entailment<'tcx>( tcx, cause, param_env, - const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + const_condition.to_host_effect_clause(tcx, ty::BoundConstness::Maybe), )); } } @@ -2091,7 +2091,7 @@ pub(super) fn check_type_bounds<'tcx>( tcx, mk_cause(span), param_env, - c.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + c.to_host_effect_clause(tcx, ty::BoundConstness::Maybe), ) }), ); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 12ed7b89f68b..b9e18d784ce9 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1389,7 +1389,7 @@ fn check_impl<'tcx>( ObligationCauseCode::WellFormed(None), ), wfcx.param_env, - bound.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + bound.to_host_effect_clause(tcx, ty::BoundConstness::Maybe), )) } } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 644ff0c667c6..2a0751ba0910 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -716,7 +716,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( match clause.kind().skip_binder() { ty::ClauseKind::HostEffect(ty::HostEffectPredicate { trait_ref: _, - host: ty::HostPolarity::Maybe, + constness: ty::BoundConstness::Maybe, }) => {} _ => { bug!( @@ -732,8 +732,8 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( match clause.kind().skip_binder() { ty::ClauseKind::HostEffect(pred) => { assert_eq!( - pred.host, - ty::HostPolarity::Maybe, + pred.constness, + ty::BoundConstness::Maybe, "expected `~const` predicate when computing `{filter:?}` \ implied bounds: {clause:?}", ); @@ -943,7 +943,7 @@ pub(super) fn const_conditions<'tcx>( bounds.push_const_bound( tcx, ty::Binder::dummy(ty::TraitRef::identity(tcx, def_id.to_def_id())), - ty::HostPolarity::Maybe, + ty::BoundConstness::Maybe, DUMMY_SP, ); @@ -963,7 +963,7 @@ pub(super) fn const_conditions<'tcx>( clause.kind().map_bound(|clause| match clause { ty::ClauseKind::HostEffect(ty::HostEffectPredicate { trait_ref, - host: ty::HostPolarity::Maybe, + constness: ty::BoundConstness::Maybe, }) => trait_ref, _ => bug!("converted {clause:?}"), }), @@ -1001,7 +1001,7 @@ pub(super) fn implied_const_bounds<'tcx>( clause.kind().map_bound(|clause| match clause { ty::ClauseKind::HostEffect(ty::HostEffectPredicate { trait_ref, - host: ty::HostPolarity::Maybe, + constness: ty::BoundConstness::Maybe, }) => trait_ref, _ => bug!("converted {clause:?}"), }), diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 2d0c3ec28c37..74bd0174cf56 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -713,7 +713,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds.push_const_bound( tcx, poly_trait_ref, - ty::HostPolarity::Const, + ty::BoundConstness::Const, span, ); } @@ -736,7 +736,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => match constness { hir::BoundConstness::Maybe(span) => { if polarity == ty::PredicatePolarity::Positive { - bounds.push_const_bound(tcx, poly_trait_ref, ty::HostPolarity::Maybe, span); + bounds.push_const_bound( + tcx, + poly_trait_ref, + ty::BoundConstness::Maybe, + span, + ); } } hir::BoundConstness::Always(_) | hir::BoundConstness::Never => {} diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 9cf1ea3fcb88..93d50bf3d7b3 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -853,9 +853,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let host = match self.tcx.hir().body_const_context(self.body_id) { Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => { - ty::HostPolarity::Const + ty::BoundConstness::Const } - Some(hir::ConstContext::ConstFn) => ty::HostPolarity::Maybe, + Some(hir::ConstContext::ConstFn) => ty::BoundConstness::Maybe, None => return, }; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5cbbc80ebfbb..a3c0908ce5b2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -76,8 +76,8 @@ use crate::traits::solve::{ }; use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericArg, GenericArgs, - GenericArgsRef, GenericParamDefKind, HostPolarity, ImplPolarity, List, ListWithCachedTypeInfo, + self, AdtDef, AdtDefData, AdtKind, Binder, BoundConstness, Clause, Clauses, Const, GenericArg, + GenericArgs, GenericArgsRef, GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, Visibility, @@ -2205,7 +2205,7 @@ macro_rules! nop_slice_lift { nop_slice_lift! {ty::ValTree<'a> => ty::ValTree<'tcx>} TrivialLiftImpls! { - ImplPolarity, PredicatePolarity, Promoted, HostPolarity, + ImplPolarity, PredicatePolarity, Promoted, BoundConstness, } macro_rules! sty_debug_print { diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 704a197aa49d..04d03187541c 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -267,7 +267,7 @@ impl FlagComputation { } ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate { trait_ref, - host: _, + constness: _, })) => { self.add_args(trait_ref.args); } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 0248aad53e24..2480cee3dc4b 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1959,7 +1959,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::BoundConstness::Const => { p!("const "); } - ty::BoundConstness::ConstIfConst => { + ty::BoundConstness::Maybe => { p!("~const "); } } @@ -3076,9 +3076,9 @@ define_print! { } ty::HostEffectPredicate<'tcx> { - let constness = match self.host { - ty::HostPolarity::Const => { "const" } - ty::HostPolarity::Maybe => { "~const" } + let constness = match self.constness { + ty::BoundConstness::Const => { "const" } + ty::BoundConstness::Maybe => { "~const" } }; p!(print(self.trait_ref.self_ty()), ": {constness} "); p!(print(self.trait_ref.print_trait_sugared())) diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 8d57ad8f2551..5bfc156ed94f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -44,7 +44,7 @@ where ) -> Result, NoSolution> { if let Some(host_clause) = assumption.as_host_effect_clause() { if host_clause.def_id() == goal.predicate.def_id() - && host_clause.host().satisfies(goal.predicate.host) + && host_clause.constness().satisfies(goal.predicate.constness) { if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( goal.predicate.trait_ref.args, @@ -91,7 +91,7 @@ where cx, cx.implied_const_bounds(alias_ty.def_id) .iter_instantiated(cx, alias_ty.args) - .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.host)), + .map(|trait_ref| trait_ref.to_host_effect_clause(cx, goal.predicate.constness)), ) { candidates.extend(Self::probe_and_match_goal_against_assumption( ecx, @@ -107,7 +107,7 @@ where .map(|trait_ref| { goal.with( cx, - trait_ref.to_host_effect_clause(cx, goal.predicate.host), + trait_ref.to_host_effect_clause(cx, goal.predicate.constness), ) }), ); @@ -163,7 +163,10 @@ where .const_conditions(impl_def_id) .iter_instantiated(cx, impl_args) .map(|bound_trait_ref| { - goal.with(cx, bound_trait_ref.to_host_effect_clause(cx, goal.predicate.host)) + goal.with( + cx, + bound_trait_ref.to_host_effect_clause(cx, goal.predicate.constness), + ) }); ecx.add_goals(GoalSource::ImplWhereBound, const_conditions); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 05954143aee0..1a5c29afdc93 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -139,7 +139,7 @@ where } ty::ClauseKind::HostEffect(pred) => { try_visit!(self.visit_trait(pred.trait_ref)); - pred.host.visit_with(self) + pred.constness.visit_with(self) } ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_term: projection_ty, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 6014ed555b64..612e92ea7843 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -545,10 +545,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { polarity: ty::PredicatePolarity::Positive, }), None, - Some(match predicate.host { - ty::HostPolarity::Maybe => ty::BoundConstness::ConstIfConst, - ty::HostPolarity::Const => ty::BoundConstness::Const, - }), + Some(predicate.constness), None, String::new(), ); @@ -2238,18 +2235,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (None, _) => Some(cannot_do_this), // suggested using default post message ( - Some(ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst), + Some(ty::BoundConstness::Const | ty::BoundConstness::Maybe), Some(AppendConstMessage::Default), ) => Some(format!("{cannot_do_this} in const contexts")), // overridden post message ( - Some(ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst), + Some(ty::BoundConstness::Const | ty::BoundConstness::Maybe), Some(AppendConstMessage::Custom(custom_msg, _)), ) => Some(format!("{cannot_do_this}{custom_msg}")), // fallback to generic message - (Some(ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst), None) => { - None - } + (Some(ty::BoundConstness::Const | ty::BoundConstness::Maybe), None) => None, } }) .unwrap_or_else(|| { diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 60b3357810a6..cb36f1a62dbf 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -47,7 +47,7 @@ fn match_candidate<'tcx>( obligation: &HostEffectObligation<'tcx>, candidate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, ) -> Result>, NoSolution> { - if !candidate.skip_binder().host.satisfies(obligation.predicate.host) { + if !candidate.skip_binder().constness.satisfies(obligation.predicate.constness) { return Err(NoSolution); } @@ -135,7 +135,8 @@ fn evaluate_host_effect_from_selection_candiate<'tcx>( .map(|(trait_ref, _)| { obligation.with( tcx, - trait_ref.to_host_effect_clause(tcx, obligation.predicate.host), + trait_ref + .to_host_effect_clause(tcx, obligation.predicate.constness), ) }), ); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index aa499995bcb9..731d42fc006c 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -155,7 +155,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { if tcx.is_conditionally_const(def_id) { predicates.extend( tcx.const_conditions(def_id).instantiate_identity(tcx).into_iter().map( - |(trait_ref, _)| trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe), + |(trait_ref, _)| trait_ref.to_host_effect_clause(tcx, ty::BoundConstness::Maybe), ), ); } diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 72d392ecd7bd..3fbce7886edc 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -160,7 +160,7 @@ impl> Elaborator { cx.implied_const_bounds(data.def_id()).iter_identity().map(|trait_ref| { elaboratable.child( trait_ref - .to_host_effect_clause(cx, data.host) + .to_host_effect_clause(cx, data.constness) .instantiate_supertrait(cx, bound_clause.rebind(data.trait_ref)), ) }), diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index c31645503487..0cade1d68855 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -112,9 +112,9 @@ impl ty::Binder> { self.skip_binder().def_id } - pub fn to_host_effect_clause(self, cx: I, host: HostPolarity) -> I::Clause { + pub fn to_host_effect_clause(self, cx: I, constness: BoundConstness) -> I::Clause { self.map_bound(|trait_ref| { - ty::ClauseKind::HostEffect(HostEffectPredicate { trait_ref, host }) + ty::ClauseKind::HostEffect(HostEffectPredicate { trait_ref, constness }) }) .upcast(cx) } @@ -757,7 +757,7 @@ impl fmt::Debug for NormalizesTo { #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub struct HostEffectPredicate { pub trait_ref: ty::TraitRef, - pub host: HostPolarity, + pub constness: BoundConstness, } impl HostEffectPredicate { @@ -785,28 +785,8 @@ impl ty::Binder> { } #[inline] - pub fn host(self) -> HostPolarity { - self.skip_binder().host - } -} - -#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] -pub enum HostPolarity { - /// May be called in const environments if the callee is const. - Maybe, - /// Always allowed to be called in const environments. - Const, -} - -impl HostPolarity { - pub fn satisfies(self, goal: HostPolarity) -> bool { - match (self, goal) { - (HostPolarity::Const, HostPolarity::Const | HostPolarity::Maybe) => true, - (HostPolarity::Maybe, HostPolarity::Maybe) => true, - (HostPolarity::Maybe, HostPolarity::Const) => false, - } + pub fn constness(self) -> BoundConstness { + self.skip_binder().constness } } @@ -831,8 +811,8 @@ pub struct CoercePredicate { pub b: I::Ty, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))] +#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum BoundConstness { /// `Type: const Trait` /// @@ -841,14 +821,22 @@ pub enum BoundConstness { /// `Type: ~const Trait` /// /// Requires resolving to const only when we are in a const context. - ConstIfConst, + Maybe, } impl BoundConstness { + pub fn satisfies(self, goal: BoundConstness) -> bool { + match (self, goal) { + (BoundConstness::Const, BoundConstness::Const | BoundConstness::Maybe) => true, + (BoundConstness::Maybe, BoundConstness::Maybe) => true, + (BoundConstness::Maybe, BoundConstness::Const) => false, + } + } + pub fn as_str(self) -> &'static str { match self { Self::Const => "const", - Self::ConstIfConst => "~const", + Self::Maybe => "~const", } } } @@ -857,14 +845,7 @@ impl fmt::Display for BoundConstness { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Const => f.write_str("const"), - Self::ConstIfConst => f.write_str("~const"), + Self::Maybe => f.write_str("~const"), } } } - -impl Lift for BoundConstness { - type Lifted = BoundConstness; - fn lift_to_interner(self, _: I) -> Option { - Some(self) - } -} From ec033e5bf1914094257932de0e7351a998cf40c1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 30 Oct 2024 17:27:12 +0000 Subject: [PATCH 42/56] Do not enforce ~const constness effects in typeck if rustc_do_mot_const_check --- compiler/rustc_hir_typeck/src/callee.rs | 5 +++++ tests/ui/traits/const-traits/do-not-const-check.rs | 3 ++- .../ui/traits/const-traits/do-not-const-check.stderr | 11 +++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/ui/traits/const-traits/do-not-const-check.stderr diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 9cf1ea3fcb88..6fc53f66feb2 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -851,6 +851,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } + // If we have `rustc_do_not_const_check`, do not check `~const` bounds. + if self.tcx.has_attr(self.body_id, sym::rustc_do_not_const_check) { + return; + } + let host = match self.tcx.hir().body_const_context(self.body_id) { Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => { ty::HostPolarity::Const diff --git a/tests/ui/traits/const-traits/do-not-const-check.rs b/tests/ui/traits/const-traits/do-not-const-check.rs index 443b63857357..d227a9a9c094 100644 --- a/tests/ui/traits/const-traits/do-not-const-check.rs +++ b/tests/ui/traits/const-traits/do-not-const-check.rs @@ -1,5 +1,6 @@ //@ check-pass -#![feature(const_trait_impl, rustc_attrs)] +#![feature(const_trait_impl, rustc_attrs, effects)] +//~^ WARN the feature `effects` is incomplete #[const_trait] trait IntoIter { diff --git a/tests/ui/traits/const-traits/do-not-const-check.stderr b/tests/ui/traits/const-traits/do-not-const-check.stderr new file mode 100644 index 000000000000..0d81ef74e8d3 --- /dev/null +++ b/tests/ui/traits/const-traits/do-not-const-check.stderr @@ -0,0 +1,11 @@ +warning: the feature `effects` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/do-not-const-check.rs:2:43 + | +LL | #![feature(const_trait_impl, rustc_attrs, effects)] + | ^^^^^^^ + | + = note: see issue #102090 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + From c62f0977a0474c2d85b1823969e8ce8399d60953 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 30 Oct 2024 19:23:13 +0000 Subject: [PATCH 43/56] Remove do_not_const_check from Iterator methods --- library/core/src/iter/traits/iterator.rs | 76 ------------------------ 1 file changed, 76 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 302720eddef2..ffaf1bc56e94 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -106,7 +106,6 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_next_chunk", reason = "recently added", issue = "98326")] - #[rustc_do_not_const_check] fn next_chunk( &mut self, ) -> Result<[Self::Item; N], array::IntoIter> @@ -184,7 +183,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn size_hint(&self) -> (usize, Option) { (0, None) } @@ -220,7 +218,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn count(self) -> usize where Self: Sized, @@ -249,7 +246,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn last(self) -> Option where Self: Sized, @@ -297,7 +293,6 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] - #[rustc_do_not_const_check] fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { for i in 0..n { if self.next().is_none() { @@ -349,7 +344,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn nth(&mut self, n: usize) -> Option { self.advance_by(n).ok()?; self.next() @@ -400,7 +394,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_step_by", since = "1.28.0")] - #[rustc_do_not_const_check] fn step_by(self, step: usize) -> StepBy where Self: Sized, @@ -472,7 +465,6 @@ pub trait Iterator { /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn chain(self, other: U) -> Chain where Self: Sized, @@ -591,7 +583,6 @@ pub trait Iterator { /// [`zip`]: crate::iter::zip #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn zip(self, other: U) -> Zip where Self: Sized, @@ -634,7 +625,6 @@ pub trait Iterator { /// [`intersperse_with`]: Iterator::intersperse_with #[inline] #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] - #[rustc_do_not_const_check] fn intersperse(self, separator: Self::Item) -> Intersperse where Self: Sized, @@ -693,7 +683,6 @@ pub trait Iterator { /// [`intersperse`]: Iterator::intersperse #[inline] #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] - #[rustc_do_not_const_check] fn intersperse_with(self, separator: G) -> IntersperseWith where Self: Sized, @@ -753,7 +742,6 @@ pub trait Iterator { #[rustc_diagnostic_item = "IteratorMap"] #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn map(self, f: F) -> Map where Self: Sized, @@ -799,7 +787,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_for_each", since = "1.21.0")] - #[rustc_do_not_const_check] fn for_each(self, f: F) where Self: Sized, @@ -875,7 +862,6 @@ pub trait Iterator { /// Note that `iter.filter(f).next()` is equivalent to `iter.find(f)`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] #[cfg_attr(not(test), rustc_diagnostic_item = "iter_filter")] fn filter

(self, predicate: P) -> Filter where @@ -922,7 +908,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn filter_map(self, f: F) -> FilterMap where Self: Sized, @@ -969,7 +954,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] #[cfg_attr(not(test), rustc_diagnostic_item = "enumerate_method")] fn enumerate(self) -> Enumerate where @@ -1042,7 +1026,6 @@ pub trait Iterator { /// [`next`]: Iterator::next #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn peekable(self) -> Peekable where Self: Sized, @@ -1108,7 +1091,6 @@ pub trait Iterator { #[inline] #[doc(alias = "drop_while")] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn skip_while

(self, predicate: P) -> SkipWhile where Self: Sized, @@ -1190,7 +1172,6 @@ pub trait Iterator { /// the iteration should stop, but wasn't placed back into the iterator. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn take_while

(self, predicate: P) -> TakeWhile where Self: Sized, @@ -1279,7 +1260,6 @@ pub trait Iterator { /// [`fuse`]: Iterator::fuse #[inline] #[stable(feature = "iter_map_while", since = "1.57.0")] - #[rustc_do_not_const_check] fn map_while(self, predicate: P) -> MapWhile where Self: Sized, @@ -1309,7 +1289,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn skip(self, n: usize) -> Skip where Self: Sized, @@ -1363,7 +1342,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn take(self, n: usize) -> Take where Self: Sized, @@ -1411,7 +1389,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn scan(self, initial_state: St, f: F) -> Scan where Self: Sized, @@ -1450,7 +1427,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn flat_map(self, f: F) -> FlatMap where Self: Sized, @@ -1535,7 +1511,6 @@ pub trait Iterator { /// [`flat_map()`]: Iterator::flat_map #[inline] #[stable(feature = "iterator_flatten", since = "1.29.0")] - #[rustc_do_not_const_check] fn flatten(self) -> Flatten where Self: Sized, @@ -1692,7 +1667,6 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")] - #[rustc_do_not_const_check] fn map_windows(self, f: F) -> MapWindows where Self: Sized, @@ -1759,7 +1733,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn fuse(self) -> Fuse where Self: Sized, @@ -1844,7 +1817,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn inspect(self, f: F) -> Inspect where Self: Sized, @@ -1873,7 +1845,6 @@ pub trait Iterator { /// assert_eq!(of_rust, vec!["of", "Rust"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn by_ref(&mut self) -> &mut Self where Self: Sized, @@ -1993,7 +1964,6 @@ pub trait Iterator { #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"] #[cfg_attr(not(test), rustc_diagnostic_item = "iterator_collect_fn")] - #[rustc_do_not_const_check] fn collect>(self) -> B where Self: Sized, @@ -2072,7 +2042,6 @@ pub trait Iterator { /// [`collect`]: Iterator::collect #[inline] #[unstable(feature = "iterator_try_collect", issue = "94047")] - #[rustc_do_not_const_check] fn try_collect(&mut self) -> ChangeOutputType where Self: Sized, @@ -2145,7 +2114,6 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iter_collect_into", reason = "new API", issue = "94780")] - #[rustc_do_not_const_check] fn collect_into>(self, collection: &mut E) -> &mut E where Self: Sized, @@ -2178,7 +2146,6 @@ pub trait Iterator { /// assert_eq!(odd, vec![1, 3]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn partition(self, f: F) -> (B, B) where Self: Sized, @@ -2241,7 +2208,6 @@ pub trait Iterator { /// assert!(a[i..].iter().all(|&n| n % 2 == 1)); // odds /// ``` #[unstable(feature = "iter_partition_in_place", reason = "new API", issue = "62543")] - #[rustc_do_not_const_check] fn partition_in_place<'a, T: 'a, P>(mut self, ref mut predicate: P) -> usize where Self: Sized + DoubleEndedIterator, @@ -2299,7 +2265,6 @@ pub trait Iterator { /// assert!(!"IntoIterator".chars().is_partitioned(char::is_uppercase)); /// ``` #[unstable(feature = "iter_is_partitioned", reason = "new API", issue = "62544")] - #[rustc_do_not_const_check] fn is_partitioned

(mut self, mut predicate: P) -> bool where Self: Sized, @@ -2394,7 +2359,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] - #[rustc_do_not_const_check] fn try_fold(&mut self, init: B, mut f: F) -> R where Self: Sized, @@ -2453,7 +2417,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] - #[rustc_do_not_const_check] fn try_for_each(&mut self, f: F) -> R where Self: Sized, @@ -2573,7 +2536,6 @@ pub trait Iterator { #[doc(alias = "inject", alias = "foldl")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn fold(mut self, init: B, mut f: F) -> B where Self: Sized, @@ -2611,7 +2573,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_fold_self", since = "1.51.0")] - #[rustc_do_not_const_check] fn reduce(mut self, f: F) -> Option where Self: Sized, @@ -2683,7 +2644,6 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "iterator_try_reduce", reason = "new API", issue = "87053")] - #[rustc_do_not_const_check] fn try_reduce( &mut self, f: impl FnMut(Self::Item, Self::Item) -> R, @@ -2742,7 +2702,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn all(&mut self, f: F) -> bool where Self: Sized, @@ -2796,7 +2755,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn any(&mut self, f: F) -> bool where Self: Sized, @@ -2860,7 +2818,6 @@ pub trait Iterator { /// Note that `iter.find(f)` is equivalent to `iter.filter(f).next()`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn find

(&mut self, predicate: P) -> Option where Self: Sized, @@ -2892,7 +2849,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_find_map", since = "1.30.0")] - #[rustc_do_not_const_check] fn find_map(&mut self, f: F) -> Option where Self: Sized, @@ -2951,7 +2907,6 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "try_find", reason = "new API", issue = "63178")] - #[rustc_do_not_const_check] fn try_find( &mut self, f: impl FnMut(&Self::Item) -> R, @@ -3035,7 +2990,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn position

(&mut self, predicate: P) -> Option where Self: Sized, @@ -3100,7 +3054,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn rposition

(&mut self, predicate: P) -> Option where P: FnMut(Self::Item) -> bool, @@ -3150,7 +3103,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn max(self) -> Option where Self: Sized, @@ -3187,7 +3139,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn min(self) -> Option where Self: Sized, @@ -3210,7 +3161,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] - #[rustc_do_not_const_check] fn max_by_key(self, f: F) -> Option where Self: Sized, @@ -3244,7 +3194,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_max_by", since = "1.15.0")] - #[rustc_do_not_const_check] fn max_by(self, compare: F) -> Option where Self: Sized, @@ -3272,7 +3221,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] - #[rustc_do_not_const_check] fn min_by_key(self, f: F) -> Option where Self: Sized, @@ -3306,7 +3254,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "iter_min_by", since = "1.15.0")] - #[rustc_do_not_const_check] fn min_by(self, compare: F) -> Option where Self: Sized, @@ -3344,7 +3291,6 @@ pub trait Iterator { #[inline] #[doc(alias = "reverse")] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn rev(self) -> Rev where Self: Sized + DoubleEndedIterator, @@ -3381,7 +3327,6 @@ pub trait Iterator { /// assert_eq!(z, [3, 6]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] fn unzip(self) -> (FromA, FromB) where FromA: Default + Extend, @@ -3412,7 +3357,6 @@ pub trait Iterator { /// assert_eq!(v_map, vec![1, 2, 3]); /// ``` #[stable(feature = "iter_copied", since = "1.36.0")] - #[rustc_do_not_const_check] #[cfg_attr(not(test), rustc_diagnostic_item = "iter_copied")] fn copied<'a, T: 'a>(self) -> Copied where @@ -3461,7 +3405,6 @@ pub trait Iterator { /// assert_eq!(&[vec![23]], &faster[..]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_do_not_const_check] #[cfg_attr(not(test), rustc_diagnostic_item = "iter_cloned")] fn cloned<'a, T: 'a>(self) -> Cloned where @@ -3495,7 +3438,6 @@ pub trait Iterator { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - #[rustc_do_not_const_check] fn cycle(self) -> Cycle where Self: Sized + Clone, @@ -3539,7 +3481,6 @@ pub trait Iterator { /// ``` #[track_caller] #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] - #[rustc_do_not_const_check] fn array_chunks(self) -> ArrayChunks where Self: Sized, @@ -3571,7 +3512,6 @@ pub trait Iterator { /// assert_eq!(sum, 6); /// ``` #[stable(feature = "iter_arith", since = "1.11.0")] - #[rustc_do_not_const_check] fn sum(self) -> S where Self: Sized, @@ -3604,7 +3544,6 @@ pub trait Iterator { /// assert_eq!(factorial(5), 120); /// ``` #[stable(feature = "iter_arith", since = "1.11.0")] - #[rustc_do_not_const_check] fn product

(self) -> P where Self: Sized, @@ -3626,7 +3565,6 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().cmp([1].iter()), Ordering::Greater); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] - #[rustc_do_not_const_check] fn cmp(self, other: I) -> Ordering where I: IntoIterator, @@ -3654,7 +3592,6 @@ pub trait Iterator { /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] - #[rustc_do_not_const_check] fn cmp_by(self, other: I, cmp: F) -> Ordering where Self: Sized, @@ -3711,7 +3648,6 @@ pub trait Iterator { /// ``` /// #[stable(feature = "iter_order", since = "1.5.0")] - #[rustc_do_not_const_check] fn partial_cmp(self, other: I) -> Option where I: IntoIterator, @@ -3748,7 +3684,6 @@ pub trait Iterator { /// ); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] - #[rustc_do_not_const_check] fn partial_cmp_by(self, other: I, partial_cmp: F) -> Option where Self: Sized, @@ -3782,7 +3717,6 @@ pub trait Iterator { /// assert_eq!([1].iter().eq([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] - #[rustc_do_not_const_check] fn eq(self, other: I) -> bool where I: IntoIterator, @@ -3806,7 +3740,6 @@ pub trait Iterator { /// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y)); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] - #[rustc_do_not_const_check] fn eq_by(self, other: I, eq: F) -> bool where Self: Sized, @@ -3839,7 +3772,6 @@ pub trait Iterator { /// assert_eq!([1].iter().ne([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] - #[rustc_do_not_const_check] fn ne(self, other: I) -> bool where I: IntoIterator, @@ -3861,7 +3793,6 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().lt([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] - #[rustc_do_not_const_check] fn lt(self, other: I) -> bool where I: IntoIterator, @@ -3883,7 +3814,6 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().le([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] - #[rustc_do_not_const_check] fn le(self, other: I) -> bool where I: IntoIterator, @@ -3905,7 +3835,6 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().gt([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] - #[rustc_do_not_const_check] fn gt(self, other: I) -> bool where I: IntoIterator, @@ -3927,7 +3856,6 @@ pub trait Iterator { /// assert_eq!([1, 2].iter().ge([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] - #[rustc_do_not_const_check] fn ge(self, other: I) -> bool where I: IntoIterator, @@ -3957,7 +3885,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "is_sorted", since = "1.82.0")] - #[rustc_do_not_const_check] fn is_sorted(self) -> bool where Self: Sized, @@ -3984,7 +3911,6 @@ pub trait Iterator { /// assert!(std::iter::empty::().is_sorted_by(|a, b| true)); /// ``` #[stable(feature = "is_sorted", since = "1.82.0")] - #[rustc_do_not_const_check] fn is_sorted_by(mut self, compare: F) -> bool where Self: Sized, @@ -4029,7 +3955,6 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "is_sorted", since = "1.82.0")] - #[rustc_do_not_const_check] fn is_sorted_by_key(self, f: F) -> bool where Self: Sized, @@ -4045,7 +3970,6 @@ pub trait Iterator { #[inline] #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] - #[rustc_do_not_const_check] unsafe fn __iterator_get_unchecked(&mut self, _idx: usize) -> Self::Item where Self: TrustedRandomAccessNoCoerce, From ac7de1a0d925af4504f9fb100be071e2fd346d13 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 29 Oct 2024 23:21:54 -0700 Subject: [PATCH 44/56] Ignore Windows due to its differing path syntax --- .../relative-path-include-bytes-132203.edition2015.stdout | 8 ++++---- .../doctest/relative-path-include-bytes-132203.rs | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout index 535d68175019..ca6e77502640 100644 --- a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout +++ b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.edition2015.stdout @@ -1,12 +1,12 @@ running 1 test -test $DIR/relative-path-include-bytes-132203.rs - (line 17) ... FAILED +test $DIR/relative-path-include-bytes-132203.rs - (line 18) ... FAILED failures: ----- $DIR/relative-path-include-bytes-132203.rs - (line 17) stdout ---- +---- $DIR/relative-path-include-bytes-132203.rs - (line 18) stdout ---- error: couldn't read `$DIR/relative-dir-empty-file`: No such file or directory (os error 2) - --> $DIR/relative-path-include-bytes-132203.rs:18:9 + --> $DIR/relative-path-include-bytes-132203.rs:19:9 | LL | let x = include_bytes!("relative-dir-empty-file"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ error: aborting due to 1 previous error Couldn't compile the test. failures: - $DIR/relative-path-include-bytes-132203.rs - (line 17) + $DIR/relative-path-include-bytes-132203.rs - (line 18) test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs index 6ec41a3c0528..b393d126306a 100644 --- a/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs +++ b/tests/rustdoc-ui/doctest/relative-path-include-bytes-132203.rs @@ -1,3 +1,4 @@ +//@ ignore-windows //@ revisions: edition2015 edition2024 //@[edition2015]edition:2015 //@[edition2015]check-fail From 4b52bbcf03fc5ab00d4c8d3f7096a74f78eabcbb Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 30 Oct 2024 19:35:56 +0300 Subject: [PATCH 45/56] pass `RUSTC_HOST_FLAGS` at once without the for loop Signed-off-by: onur-ozkan --- src/bootstrap/src/bin/rustc.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index 18f5a1a58db9..88595ff7e519 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -175,9 +175,7 @@ fn main() { // Find any host flags that were passed by bootstrap. // The flags are stored in a RUSTC_HOST_FLAGS variable, separated by spaces. if let Ok(flags) = std::env::var("RUSTC_HOST_FLAGS") { - for flag in flags.split(' ') { - cmd.arg(flag); - } + cmd.args(flags.split(' ')); } } From d53ca634532d548ad30cb75af3f93030f1b415f4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 30 Oct 2024 22:30:28 +0000 Subject: [PATCH 46/56] Make sure type_param_predicates resolves correctly for RPITIT --- .../rustc_hir_analysis/src/collect/predicates_of.rs | 10 ++++++++++ .../shorthand-projection-in-rpitit-bound.rs | 13 +++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 tests/ui/impl-trait/in-trait/shorthand-projection-in-rpitit-bound.rs diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 644ff0c667c6..4cdf0fc545c7 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -764,6 +764,16 @@ pub(super) fn type_param_predicates<'tcx>( tcx: TyCtxt<'tcx>, (item_def_id, def_id, assoc_name): (LocalDefId, LocalDefId, Ident), ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> { + match tcx.opt_rpitit_info(item_def_id.to_def_id()) { + Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { + return tcx.type_param_predicates((opaque_def_id.expect_local(), def_id, assoc_name)); + } + Some(ty::ImplTraitInTraitData::Impl { .. }) => { + unreachable!("should not be lowering bounds on RPITIT in impl") + } + None => {} + } + use rustc_hir::*; use rustc_middle::ty::Ty; diff --git a/tests/ui/impl-trait/in-trait/shorthand-projection-in-rpitit-bound.rs b/tests/ui/impl-trait/in-trait/shorthand-projection-in-rpitit-bound.rs new file mode 100644 index 000000000000..102b53f49570 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/shorthand-projection-in-rpitit-bound.rs @@ -0,0 +1,13 @@ +//@ check-pass + +// Ensure that we can resolve a shorthand projection in an item bound in an RPITIT. + +pub trait Bar { + type Foo; +} + +pub trait Baz { + fn boom() -> impl Bar; +} + +fn main() {} From a6bbdf0fd41989c09c1f77f42be9026d29475075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 30 Oct 2024 23:52:10 +0100 Subject: [PATCH 47/56] Remove dead code stemming from the old effects desugaring --- compiler/rustc_hir_analysis/src/check/check.rs | 3 +-- .../rustc_hir_analysis/src/check/compare_impl_item.rs | 2 +- compiler/rustc_hir_analysis/src/collect/item_bounds.rs | 3 --- .../src/hir_ty_lowering/dyn_compatibility.rs | 4 +--- compiler/rustc_hir_typeck/src/method/probe.rs | 1 - compiler/rustc_metadata/src/rmeta/decoder.rs | 5 +---- compiler/rustc_metadata/src/rmeta/encoder.rs | 3 --- compiler/rustc_metadata/src/rmeta/mod.rs | 1 - compiler/rustc_middle/src/ty/assoc.rs | 2 -- compiler/rustc_middle/src/ty/mod.rs | 10 ---------- .../src/error_reporting/traits/suggestions.rs | 6 ------ compiler/rustc_ty_utils/src/assoc.rs | 4 ---- 12 files changed, 4 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f830108a02f4..79e84e507bc4 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -821,8 +821,7 @@ pub(super) fn check_specialization_validity<'tcx>( let result = opt_result.unwrap_or(Ok(())); if let Err(parent_impl) = result { - // FIXME(effects) the associated type from effects could be specialized - if !tcx.is_impl_trait_in_trait(impl_item) && !tcx.is_effects_desugared_assoc_ty(impl_item) { + if !tcx.is_impl_trait_in_trait(impl_item) { report_forbidden_specialization(tcx, impl_item, parent_impl); } else { tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default")); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index db2c44fd29df..cdd85e4ead53 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2042,7 +2042,7 @@ pub(super) fn check_type_bounds<'tcx>( // A synthetic impl Trait for RPITIT desugaring or assoc type for effects desugaring has no HIR, // which we currently use to get the span for an impl's associated type. Instead, for these, // use the def_span for the synthesized associated type. - let impl_ty_span = if impl_ty.is_impl_trait_in_trait() || impl_ty.is_effects_desugaring { + let impl_ty_span = if impl_ty.is_impl_trait_in_trait() { tcx.def_span(impl_ty_def_id) } else { match tcx.hir_node_by_def_id(impl_ty_def_id) { diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 5c4cecc02f0e..da779a165690 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -379,9 +379,6 @@ pub(super) fn explicit_item_bounds_with_filter( } let bounds = match tcx.hir_node_by_def_id(def_id) { - _ if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) => { - associated_type_bounds(tcx, def_id, &[], tcx.def_span(def_id), filter) - } hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(bounds, _), span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index f2ee4b0ccd41..46a5cbb0af44 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -140,9 +140,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.associated_items(pred.def_id()) .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) - .filter(|item| { - !item.is_impl_trait_in_trait() && !item.is_effects_desugaring - }) + .filter(|item| !item.is_impl_trait_in_trait()) .map(|item| item.def_id), ); } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 569fdea11ce7..eb5581f421b8 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1365,7 +1365,6 @@ impl<'tcx> Pick<'tcx> { trait_item_def_id: _, fn_has_self_parameter: _, opt_rpitit_info: _, - is_effects_desugaring: _, }, kind: _, import_ids: _, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 4b406496337a..ebfd3c09fc1a 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1317,9 +1317,7 @@ impl<'a> CrateMetadataRef<'a> { } fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem { - let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() - || self.root.tables.is_effects_desugaring.get(self, id) - { + let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() { kw::Empty } else { self.item_name(id) @@ -1342,7 +1340,6 @@ impl<'a> CrateMetadataRef<'a> { container, fn_has_self_parameter: has_self, opt_rpitit_info, - is_effects_desugaring: self.root.tables.is_effects_desugaring.get(self, id), } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b5ac302c597d..b4b485704537 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1677,9 +1677,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_precise_capturing_args(def_id); } } - if item.is_effects_desugaring { - self.tables.is_effects_desugaring.set(def_id.index, true); - } } fn encode_precise_capturing_args(&mut self, def_id: DefId) { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index f1844045677e..927c9fa47a1c 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -396,7 +396,6 @@ define_tables! { inherent_impls: Table>, associated_types_for_impl_traits_in_associated_fn: Table>, opt_rpitit_info: Table>>, - is_effects_desugaring: Table, unused_generic_params: Table, // Reexported names are not associated with individual `DefId`s, // e.g. a glob import can introduce a lot of names, all with the same `DefId`. diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index db56e0016a2d..3137fe9bd1da 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -34,8 +34,6 @@ pub struct AssocItem { /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData` /// provides additional information about its source. pub opt_rpitit_info: Option, - - pub is_effects_desugaring: bool, } impl AssocItem { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index bd32e5837b38..dac81a6dfbb1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1625,16 +1625,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Whether the `def_id` is an associated type that was desugared from a - /// `#[const_trait]` or `impl_const`. - pub fn is_effects_desugared_assoc_ty(self, def_id: DefId) -> bool { - if let DefKind::AssocTy = self.def_kind(def_id) { - self.associated_item(def_id).is_effects_desugaring - } else { - false - } - } - pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option { variant.fields.iter_enumerated().find_map(|(i, field)| { self.hygienic_eq(ident, field.ident(self), variant.def_id).then_some(i) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 8e0bdce1280b..834eb94b3ad6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -5226,12 +5226,6 @@ fn point_at_assoc_type_restriction( let ty::ClauseKind::Projection(proj) = clause else { return; }; - // avoid ICEing since effects desugared associated types don't have names. - // this path should only be hit for `~const` on invalid places, so they - // will have an informative error already. - if tcx.is_effects_desugared_assoc_ty(proj.projection_term.def_id) { - return; - } let name = tcx.item_name(proj.projection_term.def_id); let mut predicates = generics.predicates.iter().peekable(); let mut prev: Option<&hir::WhereBoundPredicate<'_>> = None; diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 16fd28201c22..7d72474f9a41 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -143,7 +143,6 @@ fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty container: ty::TraitContainer, fn_has_self_parameter: has_self, opt_rpitit_info: None, - is_effects_desugaring: false, } } @@ -163,7 +162,6 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A container: ty::ImplContainer, fn_has_self_parameter: has_self, opt_rpitit_info: None, - is_effects_desugaring: false, } } @@ -275,7 +273,6 @@ fn associated_type_for_impl_trait_in_trait( fn_def_id: fn_def_id.to_def_id(), opaque_def_id: opaque_ty_def_id.to_def_id(), }), - is_effects_desugaring: false, }); // Copy visility of the containing function. @@ -327,7 +324,6 @@ fn associated_type_for_impl_trait_in_impl( container: ty::ImplContainer, fn_has_self_parameter: false, opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }), - is_effects_desugaring: false, }); // Copy visility of the containing function. From 37c38841523a98cc05b4b63fa4dd25012c6c8c78 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 30 Oct 2024 16:47:47 -0700 Subject: [PATCH 48/56] Annotate `input` reference tests --- tests/ui/json/json-bom-plus-crlf-multifile.rs | 2 ++ tests/ui/json/json-bom-plus-crlf.rs | 2 ++ tests/ui/json/json-bom-plus-crlf.stderr | 8 ++--- ...line-endings-string-literal-doc-comment.rs | 1 + tests/ui/macros/not-utf8.rs | 2 ++ tests/ui/macros/not-utf8.stderr | 2 +- .../parser/shebang/issue-71471-ignore-tidy.rs | 2 ++ tests/ui/parser/shebang/multiline-attrib.rs | 1 + tests/ui/parser/shebang/regular-attrib.rs | 1 + tests/ui/parser/shebang/shebang-and-attrib.rs | 1 + tests/ui/parser/shebang/shebang-comment.rs | 1 + .../ui/parser/shebang/shebang-doc-comment.rs | 2 ++ tests/ui/parser/shebang/shebang-empty.rs | 1 + .../parser/shebang/shebang-must-start-file.rs | 2 ++ tests/ui/parser/shebang/shebang-space.rs | 1 + tests/ui/parser/shebang/sneaky-attrib.rs | 1 + tests/ui/parser/shebang/valid-shebang.rs | 1 + tests/ui/parser/utf16-be-without-bom.rs | Bin 127 -> 162 bytes tests/ui/parser/utf16-be-without-bom.stderr | 28 +++++++++--------- tests/ui/parser/utf16-le-without-bom.rs | Bin 128 -> 163 bytes tests/ui/parser/utf16-le-without-bom.stderr | 28 +++++++++--------- tests/ui/utf8-bom.rs | 1 + 22 files changed, 55 insertions(+), 33 deletions(-) diff --git a/tests/ui/json/json-bom-plus-crlf-multifile.rs b/tests/ui/json/json-bom-plus-crlf-multifile.rs index ae608770aae3..79c4b2430e1d 100644 --- a/tests/ui/json/json-bom-plus-crlf-multifile.rs +++ b/tests/ui/json/json-bom-plus-crlf-multifile.rs @@ -1,6 +1,8 @@ // (This line has BOM so it's ignored by compiletest for directives) // //@ compile-flags: --json=diagnostic-short --error-format=json +//@ reference: input.byte-order-mark +//@ reference: input.crlf // ignore-tidy-cr #[path = "json-bom-plus-crlf-multifile-aux.rs"] diff --git a/tests/ui/json/json-bom-plus-crlf.rs b/tests/ui/json/json-bom-plus-crlf.rs index 4a309128199f..9e250c256ebe 100644 --- a/tests/ui/json/json-bom-plus-crlf.rs +++ b/tests/ui/json/json-bom-plus-crlf.rs @@ -1,6 +1,8 @@ // (This line has BOM so it's ignored by compiletest for directives) // //@ compile-flags: --json=diagnostic-short --error-format=json +//@ reference: input.byte-order-mark +//@ reference: input.crlf // ignore-tidy-cr // For easier verifying, the byte offsets in this file should match those diff --git a/tests/ui/json/json-bom-plus-crlf.stderr b/tests/ui/json/json-bom-plus-crlf.stderr index cd1e3665b3e5..fee70431bdfb 100644 --- a/tests/ui/json/json-bom-plus-crlf.stderr +++ b/tests/ui/json/json-bom-plus-crlf.stderr @@ -24,7 +24,7 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":607,"byte_end":608,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":598,"byte_end":604,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":608,"byte_end":608,"line_start":16,"line_end":16,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types: expected `String`, found integer +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":672,"byte_end":673,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":663,"byte_end":669,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":673,"byte_end":673,"line_start":18,"line_end":18,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types: expected `String`, found integer "} {"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -52,7 +52,7 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":667,"byte_end":668,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":658,"byte_end":664,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":668,"byte_end":668,"line_start":18,"line_end":18,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types: expected `String`, found integer +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":732,"byte_end":733,"line_start":20,"line_end":20,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":723,"byte_end":729,"line_start":20,"line_end":20,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":733,"byte_end":733,"line_start":20,"line_end":20,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:20:22: error[E0308]: mismatched types: expected `String`, found integer "} {"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -80,7 +80,7 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":731,"byte_end":732,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":721,"byte_end":727,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":732,"byte_end":732,"line_start":22,"line_end":22,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types: expected `String`, found integer +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":796,"byte_end":797,"line_start":24,"line_end":24,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":792,"line_start":23,"line_end":23,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":797,"byte_end":797,"line_start":24,"line_end":24,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:24:1: error[E0308]: mismatched types: expected `String`, found integer "} {"$message_type":"diagnostic","message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -108,7 +108,7 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":787,"byte_end":795,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":778,"byte_end":784,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types: expected `String`, found `()` +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":852,"byte_end":860,"line_start":26,"line_end":27,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":843,"byte_end":849,"line_start":26,"line_end":26,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:26:22: error[E0308]: mismatched types: expected `String`, found `()` "} {"$message_type":"diagnostic","message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors "} diff --git a/tests/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs b/tests/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs index b355997a4b37..ee193a58ce1b 100644 --- a/tests/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs +++ b/tests/ui/lexer/lexer-crlf-line-endings-string-literal-doc-comment.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ reference: input.crlf // ignore-tidy-cr // ignore-tidy-cr (repeated again because of tidy bug) // license is ignored because tidy can't handle the CRLF here properly. diff --git a/tests/ui/macros/not-utf8.rs b/tests/ui/macros/not-utf8.rs index 3c433a4e27c9..8100d65a9f81 100644 --- a/tests/ui/macros/not-utf8.rs +++ b/tests/ui/macros/not-utf8.rs @@ -1,4 +1,6 @@ //@ error-pattern: did not contain valid UTF-8 +//@ reference: input.encoding.utf8 +//@ reference: input.encoding.invalid fn foo() { include!("not-utf8.bin") diff --git a/tests/ui/macros/not-utf8.stderr b/tests/ui/macros/not-utf8.stderr index bf4704285c0d..0d587cab5f3e 100644 --- a/tests/ui/macros/not-utf8.stderr +++ b/tests/ui/macros/not-utf8.stderr @@ -1,5 +1,5 @@ error: couldn't read $DIR/not-utf8.bin: stream did not contain valid UTF-8 - --> $DIR/not-utf8.rs:4:5 + --> $DIR/not-utf8.rs:6:5 | LL | include!("not-utf8.bin") | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/parser/shebang/issue-71471-ignore-tidy.rs b/tests/ui/parser/shebang/issue-71471-ignore-tidy.rs index a2505180884a..e9bff91f1e8c 100644 --- a/tests/ui/parser/shebang/issue-71471-ignore-tidy.rs +++ b/tests/ui/parser/shebang/issue-71471-ignore-tidy.rs @@ -1,2 +1,4 @@ #!B //~ expected `[`, found `B` + +//@ reference: input.shebang diff --git a/tests/ui/parser/shebang/multiline-attrib.rs b/tests/ui/parser/shebang/multiline-attrib.rs index bb083610e551..2d2e02986386 100644 --- a/tests/ui/parser/shebang/multiline-attrib.rs +++ b/tests/ui/parser/shebang/multiline-attrib.rs @@ -1,6 +1,7 @@ #! [allow(unused_variables)] //@ check-pass +//@ reference: input.shebang.inner-attribute fn main() { let x = 5; diff --git a/tests/ui/parser/shebang/regular-attrib.rs b/tests/ui/parser/shebang/regular-attrib.rs index aed633d3ef1e..c2ac25661ef0 100644 --- a/tests/ui/parser/shebang/regular-attrib.rs +++ b/tests/ui/parser/shebang/regular-attrib.rs @@ -1,5 +1,6 @@ #![allow(unused_variables)] //@ check-pass +//@ reference: input.shebang.inner-attribute fn main() { let x = 5; } diff --git a/tests/ui/parser/shebang/shebang-and-attrib.rs b/tests/ui/parser/shebang/shebang-and-attrib.rs index a66c10db5321..d73db6b22f05 100644 --- a/tests/ui/parser/shebang/shebang-and-attrib.rs +++ b/tests/ui/parser/shebang/shebang-and-attrib.rs @@ -1,6 +1,7 @@ #!/usr/bin/env run-cargo-script //@ check-pass +//@ reference: input.shebang.inner-attribute #![allow(unused_variables)] diff --git a/tests/ui/parser/shebang/shebang-comment.rs b/tests/ui/parser/shebang/shebang-comment.rs index 37bcac8b29ee..6f89e8954c3a 100644 --- a/tests/ui/parser/shebang/shebang-comment.rs +++ b/tests/ui/parser/shebang/shebang-comment.rs @@ -1,6 +1,7 @@ #!//bin/bash //@ check-pass +//@ reference: input.shebang fn main() { println!("a valid shebang (that is also a rust comment)") } diff --git a/tests/ui/parser/shebang/shebang-doc-comment.rs b/tests/ui/parser/shebang/shebang-doc-comment.rs index 72866753e0e6..4992c758325a 100644 --- a/tests/ui/parser/shebang/shebang-doc-comment.rs +++ b/tests/ui/parser/shebang/shebang-doc-comment.rs @@ -1,3 +1,5 @@ #!///bin/bash [allow(unused_variables)] //~^ ERROR expected item, found `[` + +//@ reference: input.shebang.inner-attribute diff --git a/tests/ui/parser/shebang/shebang-empty.rs b/tests/ui/parser/shebang/shebang-empty.rs index bb0df599783e..51bf8a07c907 100644 --- a/tests/ui/parser/shebang/shebang-empty.rs +++ b/tests/ui/parser/shebang/shebang-empty.rs @@ -1,4 +1,5 @@ #! //@ check-pass +//@ reference: input.shebang fn main() {} diff --git a/tests/ui/parser/shebang/shebang-must-start-file.rs b/tests/ui/parser/shebang/shebang-must-start-file.rs index e0392572dc81..f91e32f744e1 100644 --- a/tests/ui/parser/shebang/shebang-must-start-file.rs +++ b/tests/ui/parser/shebang/shebang-must-start-file.rs @@ -1,6 +1,8 @@ // something on the first line for tidy #!/bin/bash //~ expected `[`, found `/` +//@ reference: input.shebang + fn main() { println!("ok!"); } diff --git a/tests/ui/parser/shebang/shebang-space.rs b/tests/ui/parser/shebang/shebang-space.rs index cc58eed8b8ab..803d4e040572 100644 --- a/tests/ui/parser/shebang/shebang-space.rs +++ b/tests/ui/parser/shebang/shebang-space.rs @@ -1,5 +1,6 @@ #! //@ check-pass +//@ reference: input.shebang // ignore-tidy-end-whitespace fn main() {} diff --git a/tests/ui/parser/shebang/sneaky-attrib.rs b/tests/ui/parser/shebang/sneaky-attrib.rs index eb814c6af247..e22c45cc39f5 100644 --- a/tests/ui/parser/shebang/sneaky-attrib.rs +++ b/tests/ui/parser/shebang/sneaky-attrib.rs @@ -11,6 +11,7 @@ [allow(unused_variables)] //@ check-pass +//@ reference: input.shebang.inner-attribute fn main() { let x = 5; } diff --git a/tests/ui/parser/shebang/valid-shebang.rs b/tests/ui/parser/shebang/valid-shebang.rs index e59d4074ddf9..f93b0e15d772 100644 --- a/tests/ui/parser/shebang/valid-shebang.rs +++ b/tests/ui/parser/shebang/valid-shebang.rs @@ -1,6 +1,7 @@ #!/usr/bin/env run-cargo-script //@ check-pass +//@ reference: input.shebang fn main() { println!("Hello World!"); } diff --git a/tests/ui/parser/utf16-be-without-bom.rs b/tests/ui/parser/utf16-be-without-bom.rs index 68e89bc7c223cc5497d1f15a726568019b4e4447..f5fe8dc5a8c79bf7c01402d57dd7380553efd29e 100644 GIT binary patch delta 68 zcmb $DIR/utf16-be-without-bom.rs:4:1 + --> $DIR/utf16-be-without-bom.rs:5:1 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -7,7 +7,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-be-without-bom.rs:4:3 + --> $DIR/utf16-be-without-bom.rs:5:3 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -15,7 +15,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-be-without-bom.rs:4:5 + --> $DIR/utf16-be-without-bom.rs:5:5 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -23,7 +23,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-be-without-bom.rs:4:7 + --> $DIR/utf16-be-without-bom.rs:5:7 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -31,7 +31,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-be-without-bom.rs:4:9 + --> $DIR/utf16-be-without-bom.rs:5:9 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -39,7 +39,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-be-without-bom.rs:4:11 + --> $DIR/utf16-be-without-bom.rs:5:11 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -47,7 +47,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-be-without-bom.rs:4:13 + --> $DIR/utf16-be-without-bom.rs:5:13 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -55,7 +55,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-be-without-bom.rs:4:15 + --> $DIR/utf16-be-without-bom.rs:5:15 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -63,7 +63,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-be-without-bom.rs:4:17 + --> $DIR/utf16-be-without-bom.rs:5:17 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -71,7 +71,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-be-without-bom.rs:4:19 + --> $DIR/utf16-be-without-bom.rs:5:19 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -79,7 +79,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-be-without-bom.rs:4:21 + --> $DIR/utf16-be-without-bom.rs:5:21 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -87,7 +87,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-be-without-bom.rs:4:23 + --> $DIR/utf16-be-without-bom.rs:5:23 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -95,7 +95,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-be-without-bom.rs:4:25 + --> $DIR/utf16-be-without-bom.rs:5:25 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -103,7 +103,7 @@ LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: expected one of `!` or `::`, found `n` - --> $DIR/utf16-be-without-bom.rs:4:4 + --> $DIR/utf16-be-without-bom.rs:5:4 | LL | ␀f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ expected one of `!` or `::` diff --git a/tests/ui/parser/utf16-le-without-bom.rs b/tests/ui/parser/utf16-le-without-bom.rs index bdf4860d016f30c969d73eada6e9da16245340b8..8c781b27dc02efc15938bf6798e745bfcb656509 100644 GIT binary patch delta 70 zcmZo*T+BEj#a>_EL7^x$Ewv~$FFDmpAv3R_v_vm8FF8LYGcR4Qv?R@fiz|&Gk3oSU Zmm!fMlOc~mgF%x)fuWkAmVt|b3jhmx5~KhC delta 35 qcmZ3?*uXd;MTRSlA&)_UA(tVMA(J7GL4!e)L4l!~p_YM*feQeMY6eyS diff --git a/tests/ui/parser/utf16-le-without-bom.stderr b/tests/ui/parser/utf16-le-without-bom.stderr index ad272a70f062..d937a07bc660 100644 --- a/tests/ui/parser/utf16-le-without-bom.stderr +++ b/tests/ui/parser/utf16-le-without-bom.stderr @@ -1,5 +1,5 @@ error: unknown start of token: \u{0} - --> $DIR/utf16-le-without-bom.rs:4:2 + --> $DIR/utf16-le-without-bom.rs:5:2 | LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -7,7 +7,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-le-without-bom.rs:4:4 + --> $DIR/utf16-le-without-bom.rs:5:4 | LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -15,7 +15,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-le-without-bom.rs:4:6 + --> $DIR/utf16-le-without-bom.rs:5:6 | LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -23,7 +23,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-le-without-bom.rs:4:8 + --> $DIR/utf16-le-without-bom.rs:5:8 | LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -31,7 +31,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-le-without-bom.rs:4:10 + --> $DIR/utf16-le-without-bom.rs:5:10 | LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -39,7 +39,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-le-without-bom.rs:4:12 + --> $DIR/utf16-le-without-bom.rs:5:12 | LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -47,7 +47,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-le-without-bom.rs:4:14 + --> $DIR/utf16-le-without-bom.rs:5:14 | LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -55,7 +55,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-le-without-bom.rs:4:16 + --> $DIR/utf16-le-without-bom.rs:5:16 | LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -63,7 +63,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-le-without-bom.rs:4:18 + --> $DIR/utf16-le-without-bom.rs:5:18 | LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -71,7 +71,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-le-without-bom.rs:4:20 + --> $DIR/utf16-le-without-bom.rs:5:20 | LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -79,7 +79,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-le-without-bom.rs:4:22 + --> $DIR/utf16-le-without-bom.rs:5:22 | LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -87,7 +87,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-le-without-bom.rs:4:24 + --> $DIR/utf16-le-without-bom.rs:5:24 | LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ @@ -95,7 +95,7 @@ LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: unknown start of token: \u{0} - --> $DIR/utf16-le-without-bom.rs:5:1 + --> $DIR/utf16-le-without-bom.rs:6:1 | LL | ␀ | ^ @@ -103,7 +103,7 @@ LL | ␀ = help: source files must contain UTF-8 encoded text, unexpected null bytes might occur when a different encoding is used error: expected one of `!` or `::`, found `n` - --> $DIR/utf16-le-without-bom.rs:4:3 + --> $DIR/utf16-le-without-bom.rs:5:3 | LL | f␀n␀ ␀m␀a␀i␀n␀(␀)␀ ␀{␀}␀ | ^ expected one of `!` or `::` diff --git a/tests/ui/utf8-bom.rs b/tests/ui/utf8-bom.rs index 5b9e27fb7b94..eb82f6652cb2 100644 --- a/tests/ui/utf8-bom.rs +++ b/tests/ui/utf8-bom.rs @@ -1,4 +1,5 @@ // This file has utf-8 BOM, it should be compiled normally without error. //@ run-pass +//@ reference: input.byte-order-mark pub fn main() {} From e093b82a41906c8c228643314e2f799568b37ee9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 2 Oct 2024 23:16:31 -0400 Subject: [PATCH 49/56] Encode cross-crate opaque type origin --- compiler/rustc_ast_lowering/src/lib.rs | 6 +++--- .../src/region_infer/opaque_types.rs | 2 +- compiler/rustc_hir/src/hir.rs | 16 +++++++++------- compiler/rustc_hir_analysis/src/check/check.rs | 4 ++-- compiler/rustc_hir_analysis/src/collect.rs | 17 +++++++++++++---- .../src/hir_ty_lowering/mod.rs | 3 ++- compiler/rustc_hir_typeck/src/_match.rs | 2 +- .../rustc_infer/src/infer/opaque_types/mod.rs | 5 ++++- .../src/rmeta/decoder/cstore_impl.rs | 5 +---- compiler/rustc_metadata/src/rmeta/encoder.rs | 6 ++---- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/query/erase.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 5 ++--- compiler/rustc_middle/src/ty/context.rs | 8 +++----- compiler/rustc_middle/src/ty/parameterized.rs | 1 + .../error_reporting/infer/note_and_explain.rs | 5 ++++- .../traits/fulfillment_errors.rs | 2 +- compiler/rustc_ty_utils/src/assoc.rs | 4 +--- compiler/rustc_ty_utils/src/opaque_types.rs | 2 +- 19 files changed, 53 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e1ee3d0af491..5a0e9e8aec0c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -272,7 +272,7 @@ enum ImplTraitContext { /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually /// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`. /// - OpaqueTy { origin: hir::OpaqueTyOrigin }, + OpaqueTy { origin: hir::OpaqueTyOrigin }, /// `impl Trait` is unstably accepted in this position. FeatureGated(ImplTraitPosition, Symbol), /// `impl Trait` is not accepted in this position. @@ -1416,7 +1416,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_opaque_impl_trait( &mut self, span: Span, - origin: hir::OpaqueTyOrigin, + origin: hir::OpaqueTyOrigin, opaque_ty_node_id: NodeId, bounds: &GenericBounds, itctx: ImplTraitContext, @@ -1458,7 +1458,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_opaque_inner( &mut self, opaque_ty_node_id: NodeId, - origin: hir::OpaqueTyOrigin, + origin: hir::OpaqueTyOrigin, opaque_ty_span: Span, lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], ) -> hir::TyKind<'hir> { diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 741dac9e7639..3a2f5c35c722 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -502,7 +502,7 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> { } let &Self { tcx, def_id, .. } = self; - let origin = tcx.opaque_type_origin(def_id); + let origin = tcx.local_opaque_ty_origin(def_id); let parent = match origin { hir::OpaqueTyOrigin::FnReturn { parent, .. } | hir::OpaqueTyOrigin::AsyncFn { parent, .. } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 12b01266a931..fa76f8652ea1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2746,7 +2746,7 @@ pub struct OpaqueTy<'hir> { pub hir_id: HirId, pub def_id: LocalDefId, pub bounds: GenericBounds<'hir>, - pub origin: OpaqueTyOrigin, + pub origin: OpaqueTyOrigin, pub span: Span, } @@ -2784,33 +2784,35 @@ pub struct PreciseCapturingNonLifetimeArg { pub res: Res, } -#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(HashStable_Generic, Encodable, Decodable)] pub enum RpitContext { Trait, TraitImpl, } /// From whence the opaque type came. -#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)] -pub enum OpaqueTyOrigin { +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(HashStable_Generic, Encodable, Decodable)] +pub enum OpaqueTyOrigin { /// `-> impl Trait` FnReturn { /// The defining function. - parent: LocalDefId, + parent: D, // Whether this is an RPITIT (return position impl trait in trait) in_trait_or_impl: Option, }, /// `async fn` AsyncFn { /// The defining function. - parent: LocalDefId, + parent: D, // Whether this is an AFIT (async fn in trait) in_trait_or_impl: Option, }, /// type aliases: `type Foo = impl Trait;` TyAlias { /// The type alias or associated type parent of the TAIT/ATPIT - parent: LocalDefId, + parent: D, /// associated types in impl blocks for traits. in_assoc_ty: bool, }, diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index f830108a02f4..29555ebff50f 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -268,7 +268,7 @@ fn check_opaque_meets_bounds<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span, - origin: &hir::OpaqueTyOrigin, + origin: &hir::OpaqueTyOrigin, ) -> Result<(), ErrorGuaranteed> { let defining_use_anchor = match *origin { hir::OpaqueTyOrigin::FnReturn { parent, .. } @@ -677,7 +677,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { DefKind::OpaqueTy => { check_opaque_precise_captures(tcx, def_id); - let origin = tcx.opaque_type_origin(def_id); + let origin = tcx.local_opaque_ty_origin(def_id); if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } = origin && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index c41117d213f2..3f6198dbd319 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -86,7 +86,7 @@ pub fn provide(providers: &mut Providers) { impl_trait_header, coroutine_kind, coroutine_for_closure, - is_type_alias_impl_trait, + opaque_ty_origin, rendered_precise_capturing_args, ..*providers }; @@ -1759,9 +1759,18 @@ fn coroutine_for_closure(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DefId { def_id.to_def_id() } -fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { - let opaque = tcx.hir().expect_opaque_ty(def_id); - matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }) +fn opaque_ty_origin<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> hir::OpaqueTyOrigin { + match tcx.hir_node_by_def_id(def_id).expect_opaque_ty().origin { + hir::OpaqueTyOrigin::FnReturn { parent, in_trait_or_impl } => { + hir::OpaqueTyOrigin::FnReturn { parent: parent.to_def_id(), in_trait_or_impl } + } + hir::OpaqueTyOrigin::AsyncFn { parent, in_trait_or_impl } => { + hir::OpaqueTyOrigin::AsyncFn { parent: parent.to_def_id(), in_trait_or_impl } + } + hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty } => { + hir::OpaqueTyOrigin::TyAlias { parent: parent.to_def_id(), in_assoc_ty } + } + } } fn rendered_precise_capturing_args<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 2bd8a5223aa3..d70e4d8345a1 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -20,6 +20,7 @@ pub mod errors; pub mod generics; mod lint; +use std::assert_matches::assert_matches; use std::slice; use rustc_ast::TraitObjectSyntax; @@ -1811,7 +1812,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match path.res { Res::Def(DefKind::OpaqueTy, did) => { // Check for desugared `impl Trait`. - assert!(tcx.is_type_alias_impl_trait(did)); + assert_matches!(tcx.opaque_ty_origin(did), hir::OpaqueTyOrigin::TyAlias { .. }); let item_segment = path.segments.split_last().unwrap(); let _ = self .prohibit_generic_args(item_segment.1.iter(), GenericsArgsErrExtend::OpaqueTy); diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 3372cae7a510..1774772b50b4 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -601,7 +601,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return None, }; let hir::OpaqueTyOrigin::FnReturn { parent: parent_def_id, .. } = - self.tcx.opaque_type_origin(def_id) + self.tcx.local_opaque_ty_origin(def_id) else { return None; }; diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 498d25aea640..2bc006c37dac 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -155,7 +155,10 @@ impl<'tcx> InferCtxt<'tcx> { // however in `fn fut() -> impl Future { async { 42 } }`, where // it is of no concern, so we only check for TAITs. if self.can_define_opaque_ty(b_def_id) - && self.tcx.is_type_alias_impl_trait(b_def_id) + && matches!( + self.tcx.opaque_ty_origin(b_def_id), + hir::OpaqueTyOrigin::TyAlias { .. } + ) { self.dcx().emit_err(OpaqueHiddenTypeDiag { span, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 926eb4f6210b..f06f2fdc5e56 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -316,10 +316,7 @@ provide! { tcx, def_id, other, cdata, }) .unwrap_or_default() } - is_type_alias_impl_trait => { - debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy); - cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index) - } + opaque_ty_origin => { table } assumed_wf_types_for_rpitit => { table } collect_return_position_impl_trait_in_trait_tys => { Ok(cdata diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b5ac302c597d..4dafe36f5cd8 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1188,7 +1188,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::SyntheticCoroutineBody => true, DefKind::OpaqueTy => { - let origin = tcx.opaque_type_origin(def_id); + let origin = tcx.local_opaque_ty_origin(def_id); if let hir::OpaqueTyOrigin::FnReturn { parent, .. } | hir::OpaqueTyOrigin::AsyncFn { parent, .. } = origin && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(parent) @@ -1530,9 +1530,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let DefKind::OpaqueTy = def_kind { self.encode_explicit_item_bounds(def_id); self.encode_explicit_item_super_predicates(def_id); - self.tables - .is_type_alias_impl_trait - .set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id)); + record!(self.tables.opaque_ty_origin[def_id] <- self.tcx.opaque_ty_origin(def_id)); self.encode_precise_capturing_args(def_id); } if tcx.impl_method_has_trait_impl_trait_tys(def_id) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index f1844045677e..082dac5f8e7a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -378,7 +378,6 @@ define_tables! { - defaulted: intrinsic: Table>>, is_macro_rules: Table, - is_type_alias_impl_trait: Table, type_alias_is_lazy: Table, attr_flags: Table, // The u64 is the crate-local part of the DefPathHash. All hashes in this crate have the same @@ -469,6 +468,7 @@ define_tables! { doc_link_resolutions: Table>, doc_link_traits_in_scope: Table>, assumed_wf_types_for_rpitit: Table, Span)>>, + opaque_ty_origin: Table>>, } #[derive(TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 5f8427bd707a..8cfc7f1e33ec 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -280,6 +280,7 @@ trivial! { rustc_hir::IsAsync, rustc_hir::ItemLocalId, rustc_hir::LangItem, + rustc_hir::OpaqueTyOrigin, rustc_hir::OwnerId, rustc_hir::Upvar, rustc_index::bit_set::FiniteBitSet, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d7f589631010..088b5d4ec965 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -260,11 +260,10 @@ rustc_queries! { separate_provide_extern } - query is_type_alias_impl_trait(key: DefId) -> bool + query opaque_ty_origin(key: DefId) -> hir::OpaqueTyOrigin { - desc { "determine whether the opaque is a type-alias impl trait" } + desc { "determine where the opaque originates from" } separate_provide_extern - feedable } query unsizing_params_for_adt(key: DefId) -> &'tcx rustc_index::bit_set::BitSet diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index ac36b940725a..9f1ffabc4f80 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2103,11 +2103,9 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns the origin of the opaque type `def_id`. - #[track_caller] - pub fn opaque_type_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin { - let origin = self.hir().expect_opaque_ty(def_id).origin; - trace!("opaque_type_origin({def_id:?}) => {origin:?}"); - origin + #[instrument(skip(self), level = "trace", ret)] + pub fn local_opaque_ty_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin { + self.hir().expect_opaque_ty(def_id).origin } } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 43bdce5b576d..7c280bc8b49e 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -94,6 +94,7 @@ trivially_parameterized_over_tcx! { rustc_hir::def_id::DefId, rustc_hir::def_id::DefIndex, rustc_hir::definitions::DefKey, + rustc_hir::OpaqueTyOrigin, rustc_index::bit_set::BitSet, rustc_index::bit_set::FiniteBitSet, rustc_session::cstore::ForeignModule, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 0cf7c43beb54..b97f3dc303ba 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -384,7 +384,10 @@ impl Trait for X { | DefKind::AssocFn | DefKind::AssocConst ) - && tcx.is_type_alias_impl_trait(opaque_ty.def_id) + && matches!( + tcx.opaque_ty_origin(opaque_ty.def_id), + hir::OpaqueTyOrigin::TyAlias { .. } + ) && !tcx .opaque_types_defined_by(body_owner_def_id.expect_local()) .contains(&opaque_ty.def_id.expect_local()) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 612e92ea7843..7aa558cfd3ff 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2648,7 +2648,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, def_id: DefId, ) -> ErrorGuaranteed { - let name = match self.tcx.opaque_type_origin(def_id.expect_local()) { + let name = match self.tcx.local_opaque_ty_origin(def_id.expect_local()) { hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } => { "opaque type".to_string() } diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index f177b6094857..88d81cfa3778 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -246,7 +246,7 @@ fn associated_type_for_impl_trait_in_trait( ) -> LocalDefId { let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) = - tcx.opaque_type_origin(opaque_ty_def_id) + tcx.local_opaque_ty_origin(opaque_ty_def_id) else { bug!("expected opaque for {opaque_ty_def_id:?}"); }; @@ -284,8 +284,6 @@ fn associated_type_for_impl_trait_in_trait( // Copy defaultness of the containing function. trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id)); - trait_assoc_ty.is_type_alias_impl_trait(false); - // There are no inferred outlives for the synthesized associated type. trait_assoc_ty.inferred_outlives_of(&[]); diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 5e2232ff47d7..34f461aac58a 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -139,7 +139,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { } // TAITs outside their defining scopes are ignored. - let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local()); + let origin = self.tcx.local_opaque_ty_origin(alias_ty.def_id.expect_local()); trace!(?origin); match origin { rustc_hir::OpaqueTyOrigin::FnReturn { .. } From c1457798db03ffb7f207eaf208d8d4d77ba01563 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 3 Oct 2024 00:44:14 -0400 Subject: [PATCH 50/56] Try to point out when edition 2024 lifetime capture rules cause borrowck issues --- .../src/diagnostics/conflict_errors.rs | 8 +- .../rustc_borrowck/src/diagnostics/mod.rs | 1 + .../src/diagnostics/opaque_suggestions.rs | 224 ++++++++++++++ compiler/rustc_middle/src/ty/context.rs | 2 +- .../precise-capturing/auxiliary/foreign.rs | 6 + .../precise-capturing/foreign-2021.rs | 15 + .../precise-capturing/foreign-2021.stderr | 26 ++ .../precise-capturing/migration-note.rs | 190 ++++++++++++ .../precise-capturing/migration-note.stderr | 284 ++++++++++++++++++ 9 files changed, 754 insertions(+), 2 deletions(-) create mode 100644 compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs create mode 100644 tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs create mode 100644 tests/ui/impl-trait/precise-capturing/foreign-2021.rs create mode 100644 tests/ui/impl-trait/precise-capturing/foreign-2021.stderr create mode 100644 tests/ui/impl-trait/precise-capturing/migration-note.rs create mode 100644 tests/ui/impl-trait/precise-capturing/migration-note.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index c687be69b1a6..1bfb54a7bb70 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1489,6 +1489,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { &borrow_msg, &value_msg, ); + self.note_due_to_edition_2024_opaque_capture_rules(borrow, &mut err); borrow_spans.var_path_only_subdiag(&mut err, crate::InitializationRequiringAction::Borrow); @@ -1561,6 +1562,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { borrow_span, &self.describe_any_place(borrow.borrowed_place.as_ref()), ); + self.note_due_to_edition_2024_opaque_capture_rules(borrow, &mut err); + borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; let place = &borrow.borrowed_place; @@ -1820,6 +1823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { unreachable!() } }; + self.note_due_to_edition_2024_opaque_capture_rules(issued_borrow, &mut err); if issued_spans == borrow_spans { borrow_spans.var_subdiag(&mut err, Some(gen_borrow_kind), |kind, var_span| { @@ -2860,7 +2864,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { debug!(?place_desc, ?explanation); - let err = match (place_desc, explanation) { + let mut err = match (place_desc, explanation) { // If the outlives constraint comes from inside the closure, // for example: // @@ -2939,6 +2943,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { explanation, ), }; + self.note_due_to_edition_2024_opaque_capture_rules(borrow, &mut err); self.buffer_error(err); } @@ -3777,6 +3782,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place); + self.note_due_to_edition_2024_opaque_capture_rules(loan, &mut err); loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 801c7af2de70..3b6007160361 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -48,6 +48,7 @@ mod conflict_errors; mod explain_borrow; mod move_errors; mod mutability_errors; +mod opaque_suggestions; mod region_errors; pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo}; diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs new file mode 100644 index 000000000000..bfd7e83501c7 --- /dev/null +++ b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs @@ -0,0 +1,224 @@ +#![allow(rustc::diagnostic_outside_of_impl)] +#![allow(rustc::untranslatable_diagnostic)] + +use std::ops::ControlFlow; + +use either::Either; +use rustc_data_structures::fx::FxIndexSet; +use rustc_errors::{Applicability, Diag}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_middle::mir::{self, ConstraintCategory, Location}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, +}; +use rustc_span::Symbol; + +use crate::MirBorrowckCtxt; +use crate::borrow_set::BorrowData; +use crate::consumers::RegionInferenceContext; +use crate::type_check::Locations; + +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { + /// Try to note when an opaque is involved in a borrowck error and that + /// opaque captures lifetimes due to edition 2024. + // FIXME: This code is otherwise somewhat general, and could easily be adapted + // to explain why other things overcapture... like async fn and RPITITs. + pub(crate) fn note_due_to_edition_2024_opaque_capture_rules( + &self, + borrow: &BorrowData<'tcx>, + diag: &mut Diag<'_>, + ) { + // We look at all the locals. Why locals? Because it's the best thing + // I could think of that's correlated with the *instantiated* higer-ranked + // binder for calls, since we don't really store those anywhere else. + for ty in self.body.local_decls.iter().map(|local| local.ty) { + if !ty.has_opaque_types() { + continue; + } + + let tcx = self.infcx.tcx; + let ControlFlow::Break((opaque_def_id, offending_region_idx, location)) = ty + .visit_with(&mut FindOpaqueRegion { + regioncx: &self.regioncx, + tcx, + borrow_region: borrow.region, + }) + else { + continue; + }; + + // If an opaque explicitly captures a lifetime, then no need to point it out. + // FIXME: We should be using a better heuristic for `use<>`. + if tcx.rendered_precise_capturing_args(opaque_def_id).is_some() { + continue; + } + + // If one of the opaque's bounds mentions the region, then no need to + // point it out, since it would've been captured on edition 2021 as well. + // + // Also, while we're at it, collect all the lifetimes that the opaque + // *does* mention. We'll use that for the `+ use<'a>` suggestion below. + let mut visitor = CheckExplicitRegionMentionAndCollectGenerics { + tcx, + offending_region_idx, + seen_opaques: [opaque_def_id].into_iter().collect(), + seen_lifetimes: Default::default(), + }; + if tcx + .explicit_item_bounds(opaque_def_id) + .skip_binder() + .visit_with(&mut visitor) + .is_break() + { + continue; + } + + // If we successfully located a terminator, then point it out + // and provide a suggestion if it's local. + match self.body.stmt_at(location) { + Either::Right(mir::Terminator { source_info, .. }) => { + diag.span_note( + source_info.span, + "this call may capture more lifetimes than intended, \ + because Rust 2024 has adjusted the `impl Trait` lifetime capture rules", + ); + let mut seen_generics: Vec<_> = + visitor.seen_lifetimes.iter().map(ToString::to_string).collect(); + // Capture all in-scope ty/const params. + seen_generics.extend( + ty::GenericArgs::identity_for_item(tcx, opaque_def_id) + .iter() + .filter(|arg| { + matches!( + arg.unpack(), + ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_) + ) + }) + .map(|arg| arg.to_string()), + ); + if opaque_def_id.is_local() { + diag.span_suggestion_verbose( + tcx.def_span(opaque_def_id).shrink_to_hi(), + "add a precise capturing bound to avoid overcapturing", + format!(" + use<{}>", seen_generics.join(", ")), + Applicability::MaybeIncorrect, + ); + } else { + diag.span_help( + tcx.def_span(opaque_def_id), + format!( + "if you can modify this crate, add a precise \ + capturing bound to avoid overcapturing: `+ use<{}>`", + seen_generics.join(", ") + ), + ); + } + return; + } + Either::Left(_) => {} + } + } + } +} + +/// This visitor contains the bulk of the logic for this lint. +struct FindOpaqueRegion<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + regioncx: &'a RegionInferenceContext<'tcx>, + borrow_region: ty::RegionVid, +} + +impl<'tcx> TypeVisitor> for FindOpaqueRegion<'_, 'tcx> { + type Result = ControlFlow<(DefId, usize, Location), ()>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + // If we find an opaque in a local ty, then for each of its captured regions, + // try to find a path between that captured regions and our borrow region... + if let ty::Alias(ty::Opaque, opaque) = *ty.kind() + && let hir::OpaqueTyOrigin::FnReturn { parent, in_trait_or_impl: None } = + self.tcx.opaque_ty_origin(opaque.def_id) + { + let variances = self.tcx.variances_of(opaque.def_id); + for (idx, (arg, variance)) in std::iter::zip(opaque.args, variances).enumerate() { + // Skip uncaptured args. + if *variance == ty::Bivariant { + continue; + } + // We only care about regions. + let Some(opaque_region) = arg.as_region() else { + continue; + }; + // Don't try to convert a late-bound region, which shouldn't exist anyways (yet). + if opaque_region.is_bound() { + continue; + } + let opaque_region_vid = self.regioncx.to_region_vid(opaque_region); + + // Find a path between the borrow region and our opaque capture. + if let Some((path, _)) = + self.regioncx.find_constraint_paths_between_regions(self.borrow_region, |r| { + r == opaque_region_vid + }) + { + for constraint in path { + // If we find a call in this path, then check if it defines the opaque. + if let ConstraintCategory::CallArgument(Some(call_ty)) = constraint.category + && let ty::FnDef(call_def_id, _) = *call_ty.kind() + // This function defines the opaque :D + && call_def_id == parent + && let Locations::Single(location) = constraint.locations + { + return ControlFlow::Break((opaque.def_id, idx, location)); + } + } + } + } + } + + ty.super_visit_with(self) + } +} + +struct CheckExplicitRegionMentionAndCollectGenerics<'tcx> { + tcx: TyCtxt<'tcx>, + offending_region_idx: usize, + seen_opaques: FxIndexSet, + seen_lifetimes: FxIndexSet, +} + +impl<'tcx> TypeVisitor> for CheckExplicitRegionMentionAndCollectGenerics<'tcx> { + type Result = ControlFlow<(), ()>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + match *ty.kind() { + ty::Alias(ty::Opaque, opaque) => { + if self.seen_opaques.insert(opaque.def_id) { + for (bound, _) in self + .tcx + .explicit_item_bounds(opaque.def_id) + .iter_instantiated_copied(self.tcx, opaque.args) + { + bound.visit_with(self)?; + } + } + ControlFlow::Continue(()) + } + _ => ty.super_visit_with(self), + } + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result { + match r.kind() { + ty::ReEarlyParam(param) => { + if param.index as usize == self.offending_region_idx { + ControlFlow::Break(()) + } else { + self.seen_lifetimes.insert(param.name); + ControlFlow::Continue(()) + } + } + _ => ControlFlow::Continue(()), + } + } +} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9f1ffabc4f80..9abad6d1a680 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -55,7 +55,7 @@ use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::lang_items::TraitSolverLangItem; pub use rustc_type_ir::lift::Lift; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph}; -use tracing::{debug, trace}; +use tracing::{debug, instrument}; use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; diff --git a/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs b/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs new file mode 100644 index 000000000000..49015bc48baf --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/auxiliary/foreign.rs @@ -0,0 +1,6 @@ +//@ edition: 2024 +//@ compile-flags: -Zunstable-options + +use std::fmt::Display; + +pub fn hello(x: &Vec) -> impl Display { 0 } diff --git a/tests/ui/impl-trait/precise-capturing/foreign-2021.rs b/tests/ui/impl-trait/precise-capturing/foreign-2021.rs new file mode 100644 index 000000000000..aee412ff7f13 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/foreign-2021.rs @@ -0,0 +1,15 @@ +//@ aux-build: foreign.rs + +extern crate foreign; + +fn main() { + let mut x = vec![]; + let h = foreign::hello(&x); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE immutable borrow occurs here + x.push(0); + //~^ ERROR cannot borrow `x` as mutable + //~| NOTE mutable borrow occurs here + println!("{h}"); + //~^ NOTE immutable borrow later used here +} diff --git a/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr b/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr new file mode 100644 index 000000000000..2a17ef72912a --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/foreign-2021.stderr @@ -0,0 +1,26 @@ +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/foreign-2021.rs:10:5 + | +LL | let h = foreign::hello(&x); + | -- immutable borrow occurs here +... +LL | x.push(0); + | ^^^^^^^^^ mutable borrow occurs here +... +LL | println!("{h}"); + | --- immutable borrow later used here + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/foreign-2021.rs:7:13 + | +LL | let h = foreign::hello(&x); + | ^^^^^^^^^^^^^^^^^^ +help: if you can modify this crate, add a precise capturing bound to avoid overcapturing: `+ use<>` + --> $DIR/auxiliary/foreign.rs:6:31 + | +LL | pub fn hello(x: &Vec) -> impl Display { 0 } + | ^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.rs b/tests/ui/impl-trait/precise-capturing/migration-note.rs new file mode 100644 index 000000000000..a5bade4ddc53 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/migration-note.rs @@ -0,0 +1,190 @@ +//@ edition: 2024 +//@ compile-flags: -Zunstable-options + +use std::fmt::Display; + +fn display_len(x: &Vec) -> impl Display { + //~^ NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + x.len() +} + +fn conflicting_borrow() { + let mut x = vec![]; + let a = display_len(&x); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE immutable borrow occurs here + x.push(1); + //~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable + //~| NOTE mutable borrow occurs here + println!("{a}"); + //~^ NOTE immutable borrow later used here +} + +fn needs_static() { + let x = vec![1]; + //~^ NOTE binding `x` declared here + let a = display_len(&x); + //~^ ERROR `x` does not live long enough + //~| NOTE this call may capture more lifetimes than intended + //~| NOTE argument requires that `x` is borrowed for `'static` + //~| NOTE borrowed value does not live long enoug + + fn needs_static(_: impl Sized + 'static) {} + needs_static(a); +} +//~^ NOTE `x` dropped here while still borrowed + +fn is_moved() { + let x = vec![1]; + //~^ NOTE binding `x` declared here + let a = display_len(&x); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE borrow of `x` occurs here + + fn mv(_: impl Sized) {} + mv(x); + //~^ ERROR cannot move out of `x` because it is borrowed + //~| NOTE move out of `x` occurs here +} +//~^ NOTE borrow might be used here, when `a` is dropped + +fn display_len_mut(x: &mut Vec) -> impl Display { + //~^ NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + x.len() +} + +fn conflicting_borrow_mut() { + let mut x = vec![]; + let a = display_len_mut(&mut x); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE first mutable borrow occurs here + x.push(1); + //~^ ERROR cannot borrow `x` as mutable more than once + //~| NOTE second mutable borrow occurs here + println!("{a}"); + //~^ NOTE first borrow later used here +} + +fn needs_static_mut() { + let mut x = vec![1]; + //~^ NOTE binding `x` declared here + let a = display_len_mut(&mut x); + //~^ ERROR `x` does not live long enough + //~| NOTE this call may capture more lifetimes than intended + //~| NOTE argument requires that `x` is borrowed for `'static` + //~| NOTE borrowed value does not live long enough + + fn needs_static(_: impl Sized + 'static) {} + needs_static(a); +} +//~^ NOTE `x` dropped here while still borrowed + +fn is_move_mut() { + let mut x = vec![1]; + //~^ NOTE binding `x` declared here + let a = display_len_mut(&mut x); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE borrow of `x` occurs here + + fn mv(_: impl Sized) {} + mv(x); + //~^ ERROR cannot move out of `x` because it is borrowed + //~| NOTE move out of `x` occurs here +} +//~^ NOTE borrow might be used here, when `a` is dropped + +struct S { f: i32 } + +fn display_field(t: &T) -> impl Display { + //~^ NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + //~| NOTE in this expansion of desugaring of `impl Trait` + *t +} + +fn conflicting_borrow_field() { + let mut s = S { f: 0 }; + let a = display_field(&s.f); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE `s.f` is borrowed here + s.f = 1; + //~^ ERROR cannot assign to `s.f` because it is borrowed + //~| NOTE `s.f` is assigned to here but it was already borrowed + println!("{a}"); + //~^ NOTE borrow later used here +} + +fn display_field_mut(t: &mut T) -> impl Display { + *t +} + +fn conflicting_borrow_field_mut() { + let mut s = S { f: 0 }; + let a = display_field(&mut s.f); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE `s.f` is borrowed here + s.f = 1; + //~^ ERROR cannot assign to `s.f` because it is borrowed + //~| NOTE `s.f` is assigned to here but it was already borrowed + println!("{a}"); + //~^ NOTE borrow later used here +} + +fn field_move() { + let mut s = S { f: 0 }; + let a = display_field(&mut s.f); + //~^ NOTE this call may capture more lifetimes than intended + //~| NOTE `s.f` is borrowed here + s.f; + //~^ ERROR cannot use `s.f` because it was mutably borrowed + //~| NOTE use of borrowed `s.f` + println!("{a}"); + //~^ NOTE borrow later used here +} + +struct Z { + f: Vec, +} + +fn live_long() { + let x; + { + let z = Z { f: vec![1] }; + //~^ NOTE binding `z` declared here + x = display_len(&z.f); + //~^ ERROR `z.f` does not live long enough + //~| NOTE this call may capture more lifetimes than intended + //~| NOTE values in a scope are dropped in the opposite order they are defined + //~| NOTE borrowed value does not live long enough + } + //~^ NOTE `z.f` dropped here while still borrowed +} +//~^ NOTE borrow might be used here, when `x` is dropped + +fn temp() { + let x = { let x = display_len(&mut vec![0]); x }; + //~^ ERROR temporary value dropped while borrowed + //~| NOTE this call may capture more lifetimes than intended + //~| NOTE consider using a `let` binding to create a longer lived value + //~| NOTE borrow later used here + //~| NOTE temporary value is freed at the end of this statement +} + +// FIXME: This doesn't display a useful Rust 2024 suggestion :( +fn returned() -> impl Sized { + let x = vec![0]; + //~^ NOTE binding `x` declared here + display_len(&x) + //~^ ERROR `x` does not live long enough + //~| NOTE borrowed value does not live long enough + //~| NOTE argument requires that `x` is borrowed for `'static` +} +//~^ NOTE `x` dropped here while still borrowed + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/migration-note.stderr b/tests/ui/impl-trait/precise-capturing/migration-note.stderr new file mode 100644 index 000000000000..3ac47ed1bcd3 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/migration-note.stderr @@ -0,0 +1,284 @@ +error[E0597]: `x` does not live long enough + --> $DIR/migration-note.rs:183:17 + | +LL | let x = vec![0]; + | - binding `x` declared here +LL | +LL | display_len(&x) + | ------------^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'static` +... +LL | } + | - `x` dropped here while still borrowed + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/migration-note.rs:20:5 + | +LL | let a = display_len(&x); + | -- immutable borrow occurs here +... +LL | x.push(1); + | ^^^^^^^^^ mutable borrow occurs here +... +LL | println!("{a}"); + | --- immutable borrow later used here + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:17:13 + | +LL | let a = display_len(&x); + | ^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len(x: &Vec) -> impl Display + use { + | ++++++++ + +error[E0597]: `x` does not live long enough + --> $DIR/migration-note.rs:30:25 + | +LL | let x = vec![1]; + | - binding `x` declared here +LL | +LL | let a = display_len(&x); + | ------------^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'static` +... +LL | } + | - `x` dropped here while still borrowed + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:30:13 + | +LL | let a = display_len(&x); + | ^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len(x: &Vec) -> impl Display + use { + | ++++++++ + +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/migration-note.rs:49:8 + | +LL | let x = vec![1]; + | - binding `x` declared here +LL | +LL | let a = display_len(&x); + | -- borrow of `x` occurs here +... +LL | mv(x); + | ^ move out of `x` occurs here +... +LL | } + | - borrow might be used here, when `a` is dropped and runs the destructor for type `impl std::fmt::Display` + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:44:13 + | +LL | let a = display_len(&x); + | ^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len(x: &Vec) -> impl Display + use { + | ++++++++ +help: consider cloning the value if the performance cost is acceptable + | +LL | let a = display_len(&x.clone()); + | ++++++++ + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/migration-note.rs:67:5 + | +LL | let a = display_len_mut(&mut x); + | ------ first mutable borrow occurs here +... +LL | x.push(1); + | ^ second mutable borrow occurs here +... +LL | println!("{a}"); + | --- first borrow later used here + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:64:13 + | +LL | let a = display_len_mut(&mut x); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len_mut(x: &mut Vec) -> impl Display + use { + | ++++++++ + +error[E0597]: `x` does not live long enough + --> $DIR/migration-note.rs:77:29 + | +LL | let mut x = vec![1]; + | ----- binding `x` declared here +LL | +LL | let a = display_len_mut(&mut x); + | ----------------^^^^^^- + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'static` +... +LL | } + | - `x` dropped here while still borrowed + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:77:13 + | +LL | let a = display_len_mut(&mut x); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len_mut(x: &mut Vec) -> impl Display + use { + | ++++++++ + +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/migration-note.rs:96:8 + | +LL | let mut x = vec![1]; + | ----- binding `x` declared here +LL | +LL | let a = display_len_mut(&mut x); + | ------ borrow of `x` occurs here +... +LL | mv(x); + | ^ move out of `x` occurs here +... +LL | } + | - borrow might be used here, when `a` is dropped and runs the destructor for type `impl std::fmt::Display` + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:91:13 + | +LL | let a = display_len_mut(&mut x); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len_mut(x: &mut Vec) -> impl Display + use { + | ++++++++ +help: consider cloning the value if the performance cost is acceptable + | +LL | let a = display_len_mut(&mut x.clone()); + | ++++++++ + +error[E0506]: cannot assign to `s.f` because it is borrowed + --> $DIR/migration-note.rs:116:5 + | +LL | let a = display_field(&s.f); + | ---- `s.f` is borrowed here +... +LL | s.f = 1; + | ^^^^^^^ `s.f` is assigned to here but it was already borrowed +... +LL | println!("{a}"); + | --- borrow later used here + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:113:13 + | +LL | let a = display_field(&s.f); + | ^^^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_field(t: &T) -> impl Display + use { + | ++++++++ + +error[E0506]: cannot assign to `s.f` because it is borrowed + --> $DIR/migration-note.rs:132:5 + | +LL | let a = display_field(&mut s.f); + | -------- `s.f` is borrowed here +... +LL | s.f = 1; + | ^^^^^^^ `s.f` is assigned to here but it was already borrowed +... +LL | println!("{a}"); + | --- borrow later used here + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:129:13 + | +LL | let a = display_field(&mut s.f); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_field(t: &T) -> impl Display + use { + | ++++++++ + +error[E0503]: cannot use `s.f` because it was mutably borrowed + --> $DIR/migration-note.rs:144:5 + | +LL | let a = display_field(&mut s.f); + | -------- `s.f` is borrowed here +... +LL | s.f; + | ^^^ use of borrowed `s.f` +... +LL | println!("{a}"); + | --- borrow later used here + | +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:141:13 + | +LL | let a = display_field(&mut s.f); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_field(t: &T) -> impl Display + use { + | ++++++++ + +error[E0597]: `z.f` does not live long enough + --> $DIR/migration-note.rs:160:25 + | +LL | let z = Z { f: vec![1] }; + | - binding `z` declared here +LL | +LL | x = display_len(&z.f); + | ^^^^ borrowed value does not live long enough +... +LL | } + | - `z.f` dropped here while still borrowed +LL | +LL | } + | - borrow might be used here, when `x` is dropped and runs the destructor for type `impl std::fmt::Display` + | + = note: values in a scope are dropped in the opposite order they are defined +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:160:13 + | +LL | x = display_len(&z.f); + | ^^^^^^^^^^^^^^^^^ +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len(x: &Vec) -> impl Display + use { + | ++++++++ + +error[E0716]: temporary value dropped while borrowed + --> $DIR/migration-note.rs:171:40 + | +LL | let x = { let x = display_len(&mut vec![0]); x }; + | ^^^^^^^ - - borrow later used here + | | | + | | temporary value is freed at the end of this statement + | creates a temporary value which is freed while still in use + | + = note: consider using a `let` binding to create a longer lived value +note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules + --> $DIR/migration-note.rs:171:23 + | +LL | let x = { let x = display_len(&mut vec![0]); x }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) +help: add a precise capturing bound to avoid overcapturing + | +LL | fn display_len(x: &Vec) -> impl Display + use { + | ++++++++ + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0499, E0502, E0503, E0505, E0506, E0597, E0716. +For more information about an error, try `rustc --explain E0499`. From 911edbfe42c557774488d46fbb0440994d555084 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Oct 2024 14:47:25 +1100 Subject: [PATCH 51/56] Remove `ValueAnalysis` and `ValueAnalysisWrapper`. They represent a lot of abstraction and indirection, but they're only used for `ConstAnalysis`, and apparently won't be used for any other analyses in the future. This commit inlines and removes them, which makes `ConstAnalysis` easier to read and understand. --- .../rustc_mir_dataflow/src/value_analysis.rs | 416 +----------------- .../src/dataflow_const_prop.rs | 333 +++++++++++--- 2 files changed, 278 insertions(+), 471 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 80151b8ba2de..af2d514fc76e 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -1,38 +1,3 @@ -//! This module provides a framework on top of the normal MIR dataflow framework to simplify the -//! implementation of analyses that track information about the values stored in certain places. -//! We are using the term "place" here to refer to a `mir::Place` (a place expression) instead of -//! an `interpret::Place` (a memory location). -//! -//! The default methods of [`ValueAnalysis`] (prefixed with `super_` instead of `handle_`) -//! provide some behavior that should be valid for all abstract domains that are based only on the -//! value stored in a certain place. On top of these default rules, an implementation should -//! override some of the `handle_` methods. For an example, see `ConstAnalysis`. -//! -//! An implementation must also provide a [`Map`]. Before the analysis begins, all places that -//! should be tracked during the analysis must be registered. During the analysis, no new places -//! can be registered. The [`State`] can be queried to retrieve the abstract value stored for a -//! certain place by passing the map. -//! -//! This framework is currently experimental. Originally, it supported shared references and enum -//! variants. However, it was discovered that both of these were unsound, and especially references -//! had subtle but serious issues. In the future, they could be added back in, but we should clarify -//! the rules for optimizations that rely on the aliasing model first. -//! -//! -//! # Notes -//! -//! - The bottom state denotes uninitialized memory. Because we are only doing a sound approximation -//! of the actual execution, we can also use this state for places where access would be UB. -//! -//! - The assignment logic in `State::insert_place_idx` assumes that the places are non-overlapping, -//! or identical. Note that this refers to place expressions, not memory locations. -//! -//! - Currently, places that have their reference taken cannot be tracked. Although this would be -//! possible, it has to rely on some aliasing model, which we are not ready to commit to yet. -//! Because of that, we can assume that the only way to change the value behind a tracked place is -//! by direct assignment. - -use std::assert_matches::assert_matches; use std::fmt::{Debug, Formatter}; use std::ops::Range; @@ -42,359 +7,14 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; -use rustc_middle::bug; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; use tracing::debug; -use crate::fmt::DebugWithContext; +use crate::JoinSemiLattice; use crate::lattice::{HasBottom, HasTop}; -use crate::{Analysis, JoinSemiLattice, SwitchIntEdgeEffects}; - -pub trait ValueAnalysis<'tcx> { - /// For each place of interest, the analysis tracks a value of the given type. - type Value: Clone + JoinSemiLattice + HasBottom + HasTop + Debug; - - const NAME: &'static str; - - fn map(&self) -> &Map<'tcx>; - - fn handle_statement(&self, statement: &Statement<'tcx>, state: &mut State) { - self.super_statement(statement, state) - } - - fn super_statement(&self, statement: &Statement<'tcx>, state: &mut State) { - match &statement.kind { - StatementKind::Assign(box (place, rvalue)) => { - self.handle_assign(*place, rvalue, state); - } - StatementKind::SetDiscriminant { box place, variant_index } => { - self.handle_set_discriminant(*place, *variant_index, state); - } - StatementKind::Intrinsic(box intrinsic) => { - self.handle_intrinsic(intrinsic, state); - } - StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { - // StorageLive leaves the local in an uninitialized state. - // StorageDead makes it UB to access the local afterwards. - state.flood_with(Place::from(*local).as_ref(), self.map(), Self::Value::BOTTOM); - } - StatementKind::Deinit(box place) => { - // Deinit makes the place uninitialized. - state.flood_with(place.as_ref(), self.map(), Self::Value::BOTTOM); - } - StatementKind::Retag(..) => { - // We don't track references. - } - StatementKind::ConstEvalCounter - | StatementKind::Nop - | StatementKind::FakeRead(..) - | StatementKind::PlaceMention(..) - | StatementKind::Coverage(..) - | StatementKind::AscribeUserType(..) => (), - } - } - - fn handle_set_discriminant( - &self, - place: Place<'tcx>, - variant_index: VariantIdx, - state: &mut State, - ) { - self.super_set_discriminant(place, variant_index, state) - } - - fn super_set_discriminant( - &self, - place: Place<'tcx>, - _variant_index: VariantIdx, - state: &mut State, - ) { - state.flood_discr(place.as_ref(), self.map()); - } - - fn handle_intrinsic( - &self, - intrinsic: &NonDivergingIntrinsic<'tcx>, - state: &mut State, - ) { - self.super_intrinsic(intrinsic, state); - } - - fn super_intrinsic( - &self, - intrinsic: &NonDivergingIntrinsic<'tcx>, - _state: &mut State, - ) { - match intrinsic { - NonDivergingIntrinsic::Assume(..) => { - // Could use this, but ignoring it is sound. - } - NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { - dst: _, - src: _, - count: _, - }) => { - // This statement represents `*dst = *src`, `count` times. - } - } - } - - fn handle_assign( - &self, - target: Place<'tcx>, - rvalue: &Rvalue<'tcx>, - state: &mut State, - ) { - self.super_assign(target, rvalue, state) - } - - fn super_assign( - &self, - target: Place<'tcx>, - rvalue: &Rvalue<'tcx>, - state: &mut State, - ) { - let result = self.handle_rvalue(rvalue, state); - state.assign(target.as_ref(), result, self.map()); - } - - fn handle_rvalue( - &self, - rvalue: &Rvalue<'tcx>, - state: &mut State, - ) -> ValueOrPlace { - self.super_rvalue(rvalue, state) - } - - fn super_rvalue( - &self, - rvalue: &Rvalue<'tcx>, - state: &mut State, - ) -> ValueOrPlace { - match rvalue { - Rvalue::Use(operand) => self.handle_operand(operand, state), - Rvalue::CopyForDeref(place) => self.handle_operand(&Operand::Copy(*place), state), - Rvalue::Ref(..) | Rvalue::RawPtr(..) => { - // We don't track such places. - ValueOrPlace::TOP - } - Rvalue::Repeat(..) - | Rvalue::ThreadLocalRef(..) - | Rvalue::Len(..) - | Rvalue::Cast(..) - | Rvalue::BinaryOp(..) - | Rvalue::NullaryOp(..) - | Rvalue::UnaryOp(..) - | Rvalue::Discriminant(..) - | Rvalue::Aggregate(..) - | Rvalue::ShallowInitBox(..) => { - // No modification is possible through these r-values. - ValueOrPlace::TOP - } - } - } - - fn handle_operand( - &self, - operand: &Operand<'tcx>, - state: &mut State, - ) -> ValueOrPlace { - self.super_operand(operand, state) - } - - fn super_operand( - &self, - operand: &Operand<'tcx>, - state: &mut State, - ) -> ValueOrPlace { - match operand { - Operand::Constant(box constant) => { - ValueOrPlace::Value(self.handle_constant(constant, state)) - } - Operand::Copy(place) | Operand::Move(place) => { - // On move, we would ideally flood the place with bottom. But with the current - // framework this is not possible (similar to `InterpCx::eval_operand`). - self.map() - .find(place.as_ref()) - .map(ValueOrPlace::Place) - .unwrap_or(ValueOrPlace::TOP) - } - } - } - - fn handle_constant( - &self, - constant: &ConstOperand<'tcx>, - state: &mut State, - ) -> Self::Value { - self.super_constant(constant, state) - } - - fn super_constant( - &self, - _constant: &ConstOperand<'tcx>, - _state: &mut State, - ) -> Self::Value { - Self::Value::TOP - } - - /// The effect of a successful function call return should not be - /// applied here, see [`Analysis::apply_terminator_effect`]. - fn handle_terminator<'mir>( - &self, - terminator: &'mir Terminator<'tcx>, - state: &mut State, - ) -> TerminatorEdges<'mir, 'tcx> { - self.super_terminator(terminator, state) - } - - fn super_terminator<'mir>( - &self, - terminator: &'mir Terminator<'tcx>, - state: &mut State, - ) -> TerminatorEdges<'mir, 'tcx> { - match &terminator.kind { - TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => { - // Effect is applied by `handle_call_return`. - } - TerminatorKind::Drop { place, .. } => { - state.flood_with(place.as_ref(), self.map(), Self::Value::BOTTOM); - } - TerminatorKind::Yield { .. } => { - // They would have an effect, but are not allowed in this phase. - bug!("encountered disallowed terminator"); - } - TerminatorKind::SwitchInt { discr, targets } => { - return self.handle_switch_int(discr, targets, state); - } - TerminatorKind::TailCall { .. } => { - // FIXME(explicit_tail_calls): determine if we need to do something here (probably not) - } - TerminatorKind::Goto { .. } - | TerminatorKind::UnwindResume - | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::Assert { .. } - | TerminatorKind::CoroutineDrop - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } => { - // These terminators have no effect on the analysis. - } - } - terminator.edges() - } - - fn handle_call_return( - &self, - return_places: CallReturnPlaces<'_, 'tcx>, - state: &mut State, - ) { - self.super_call_return(return_places, state) - } - - fn super_call_return( - &self, - return_places: CallReturnPlaces<'_, 'tcx>, - state: &mut State, - ) { - return_places.for_each(|place| { - state.flood(place.as_ref(), self.map()); - }) - } - - fn handle_switch_int<'mir>( - &self, - discr: &'mir Operand<'tcx>, - targets: &'mir SwitchTargets, - state: &mut State, - ) -> TerminatorEdges<'mir, 'tcx> { - self.super_switch_int(discr, targets, state) - } - - fn super_switch_int<'mir>( - &self, - discr: &'mir Operand<'tcx>, - targets: &'mir SwitchTargets, - _state: &mut State, - ) -> TerminatorEdges<'mir, 'tcx> { - TerminatorEdges::SwitchInt { discr, targets } - } - - fn wrap(self) -> ValueAnalysisWrapper - where - Self: Sized, - { - ValueAnalysisWrapper(self) - } -} - -pub struct ValueAnalysisWrapper(pub T); - -impl<'tcx, T: ValueAnalysis<'tcx>> Analysis<'tcx> for ValueAnalysisWrapper { - type Domain = State; - - const NAME: &'static str = T::NAME; - - fn bottom_value(&self, _body: &Body<'tcx>) -> Self::Domain { - State::Unreachable - } - - fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) { - // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥. - assert_matches!(state, State::Unreachable); - *state = State::new_reachable(); - for arg in body.args_iter() { - state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map()); - } - } - - fn apply_statement_effect( - &mut self, - state: &mut Self::Domain, - statement: &Statement<'tcx>, - _location: Location, - ) { - if state.is_reachable() { - self.0.handle_statement(statement, state); - } - } - - fn apply_terminator_effect<'mir>( - &mut self, - state: &mut Self::Domain, - terminator: &'mir Terminator<'tcx>, - _location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { - if state.is_reachable() { - self.0.handle_terminator(terminator, state) - } else { - TerminatorEdges::None - } - } - - fn apply_call_return_effect( - &mut self, - state: &mut Self::Domain, - _block: BasicBlock, - return_places: CallReturnPlaces<'_, 'tcx>, - ) { - if state.is_reachable() { - self.0.handle_call_return(return_places, state) - } - } - - fn apply_switch_int_edge_effects( - &mut self, - _block: BasicBlock, - _discr: &Operand<'tcx>, - _apply_edge_effects: &mut impl SwitchIntEdgeEffects, - ) { - } -} rustc_index::newtype_index!( /// This index uniquely identifies a place. @@ -464,7 +84,7 @@ impl JoinSemiLattice for StateData { } } -/// The dataflow state for an instance of [`ValueAnalysis`]. +/// Dataflow state. /// /// Every instance specifies a lattice that represents the possible values of a single tracked /// place. If we call this lattice `V` and set of tracked places `P`, then a [`State`] is an @@ -514,7 +134,7 @@ impl State { } } - fn is_reachable(&self) -> bool { + pub fn is_reachable(&self) -> bool { matches!(self, State::Reachable(_)) } @@ -1317,34 +937,6 @@ pub fn excluded_locals(body: &Body<'_>) -> BitSet { collector.result } -/// This is used to visualize the dataflow analysis. -impl<'tcx, T> DebugWithContext> for State -where - T: ValueAnalysis<'tcx>, - T::Value: Debug, -{ - fn fmt_with(&self, ctxt: &ValueAnalysisWrapper, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - State::Reachable(values) => debug_with_context(values, None, ctxt.0.map(), f), - State::Unreachable => write!(f, "unreachable"), - } - } - - fn fmt_diff_with( - &self, - old: &Self, - ctxt: &ValueAnalysisWrapper, - f: &mut Formatter<'_>, - ) -> std::fmt::Result { - match (self, old) { - (State::Reachable(this), State::Reachable(old)) => { - debug_with_context(this, Some(old), ctxt.0.map(), f) - } - _ => Ok(()), // Consider printing something here. - } - } -} - fn debug_with_context_rec( place: PlaceIndex, place_str: &str, @@ -1391,7 +983,7 @@ fn debug_with_context_rec( Ok(()) } -fn debug_with_context( +pub fn debug_with_context( new: &StateData, old: Option<&StateData>, map: &Map<'_>, diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index c084b20772fa..b8e35587b87f 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -2,6 +2,9 @@ //! //! Currently, this pass only propagates scalar values. +use std::assert_matches::assert_matches; +use std::fmt::Formatter; + use rustc_abi::{BackendRepr, FIRST_VARIANT, FieldIdx, Size, VariantIdx}; use rustc_const_eval::const_eval::{DummyMachine, throw_machine_stop_str}; use rustc_const_eval::interpret::{ @@ -15,9 +18,10 @@ use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_mir_dataflow::lattice::FlatSet; +use rustc_mir_dataflow::fmt::DebugWithContext; +use rustc_mir_dataflow::lattice::{FlatSet, HasBottom}; use rustc_mir_dataflow::value_analysis::{ - Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace, + Map, PlaceIndex, State, TrackElem, ValueOrPlace, debug_with_context, }; use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor}; use rustc_span::DUMMY_SP; @@ -58,8 +62,8 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { // Perform the actual dataflow analysis. let analysis = ConstAnalysis::new(tcx, body, map); - let mut results = debug_span!("analyze") - .in_scope(|| analysis.wrap().iterate_to_fixpoint(tcx, body, None)); + let mut results = + debug_span!("analyze").in_scope(|| analysis.iterate_to_fixpoint(tcx, body, None)); // Collect results and patch the body afterwards. let mut visitor = Collector::new(tcx, &body.local_decls); @@ -69,6 +73,10 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { } } +// Note: Currently, places that have their reference taken cannot be tracked. Although this would +// be possible, it has to rely on some aliasing model, which we are not ready to commit to yet. +// Because of that, we can assume that the only way to change the value behind a tracked place is +// by direct assignment. struct ConstAnalysis<'a, 'tcx> { map: Map<'tcx>, tcx: TyCtxt<'tcx>, @@ -77,20 +85,198 @@ struct ConstAnalysis<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, } -impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { - type Value = FlatSet; +impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { + type Domain = State>; const NAME: &'static str = "ConstAnalysis"; - fn map(&self) -> &Map<'tcx> { - &self.map + // The bottom state denotes uninitialized memory. Because we are only doing a sound + // approximation of the actual execution, we can also use this state for places where access + // would be UB. + fn bottom_value(&self, _body: &Body<'tcx>) -> Self::Domain { + State::Unreachable + } + + fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) { + // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥. + assert_matches!(state, State::Unreachable); + *state = State::new_reachable(); + for arg in body.args_iter() { + state.flood(PlaceRef { local: arg, projection: &[] }, &self.map); + } + } + + fn apply_statement_effect( + &mut self, + state: &mut Self::Domain, + statement: &Statement<'tcx>, + _location: Location, + ) { + if state.is_reachable() { + self.handle_statement(statement, state); + } + } + + fn apply_terminator_effect<'mir>( + &mut self, + state: &mut Self::Domain, + terminator: &'mir Terminator<'tcx>, + _location: Location, + ) -> TerminatorEdges<'mir, 'tcx> { + if state.is_reachable() { + self.handle_terminator(terminator, state) + } else { + TerminatorEdges::None + } + } + + fn apply_call_return_effect( + &mut self, + state: &mut Self::Domain, + _block: BasicBlock, + return_places: CallReturnPlaces<'_, 'tcx>, + ) { + if state.is_reachable() { + self.handle_call_return(return_places, state) + } + } +} + +impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { + fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self { + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + Self { + map, + tcx, + local_decls: &body.local_decls, + ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine), + param_env, + } + } + + fn handle_statement(&self, statement: &Statement<'tcx>, state: &mut State>) { + match &statement.kind { + StatementKind::Assign(box (place, rvalue)) => { + self.handle_assign(*place, rvalue, state); + } + StatementKind::SetDiscriminant { box place, variant_index } => { + self.handle_set_discriminant(*place, *variant_index, state); + } + StatementKind::Intrinsic(box intrinsic) => { + self.handle_intrinsic(intrinsic); + } + StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { + // StorageLive leaves the local in an uninitialized state. + // StorageDead makes it UB to access the local afterwards. + state.flood_with( + Place::from(*local).as_ref(), + &self.map, + FlatSet::::BOTTOM, + ); + } + StatementKind::Deinit(box place) => { + // Deinit makes the place uninitialized. + state.flood_with(place.as_ref(), &self.map, FlatSet::::BOTTOM); + } + StatementKind::Retag(..) => { + // We don't track references. + } + StatementKind::ConstEvalCounter + | StatementKind::Nop + | StatementKind::FakeRead(..) + | StatementKind::PlaceMention(..) + | StatementKind::Coverage(..) + | StatementKind::AscribeUserType(..) => (), + } + } + + fn handle_intrinsic(&self, intrinsic: &NonDivergingIntrinsic<'tcx>) { + match intrinsic { + NonDivergingIntrinsic::Assume(..) => { + // Could use this, but ignoring it is sound. + } + NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { + dst: _, + src: _, + count: _, + }) => { + // This statement represents `*dst = *src`, `count` times. + } + } + } + + fn handle_operand( + &self, + operand: &Operand<'tcx>, + state: &mut State>, + ) -> ValueOrPlace> { + match operand { + Operand::Constant(box constant) => { + ValueOrPlace::Value(self.handle_constant(constant, state)) + } + Operand::Copy(place) | Operand::Move(place) => { + // On move, we would ideally flood the place with bottom. But with the current + // framework this is not possible (similar to `InterpCx::eval_operand`). + self.map.find(place.as_ref()).map(ValueOrPlace::Place).unwrap_or(ValueOrPlace::TOP) + } + } + } + + /// The effect of a successful function call return should not be + /// applied here, see [`Analysis::apply_terminator_effect`]. + fn handle_terminator<'mir>( + &self, + terminator: &'mir Terminator<'tcx>, + state: &mut State>, + ) -> TerminatorEdges<'mir, 'tcx> { + match &terminator.kind { + TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => { + // Effect is applied by `handle_call_return`. + } + TerminatorKind::Drop { place, .. } => { + state.flood_with(place.as_ref(), &self.map, FlatSet::::BOTTOM); + } + TerminatorKind::Yield { .. } => { + // They would have an effect, but are not allowed in this phase. + bug!("encountered disallowed terminator"); + } + TerminatorKind::SwitchInt { discr, targets } => { + return self.handle_switch_int(discr, targets, state); + } + TerminatorKind::TailCall { .. } => { + // FIXME(explicit_tail_calls): determine if we need to do something here (probably + // not) + } + TerminatorKind::Goto { .. } + | TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate(_) + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::Assert { .. } + | TerminatorKind::CoroutineDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } => { + // These terminators have no effect on the analysis. + } + } + terminator.edges() + } + + fn handle_call_return( + &self, + return_places: CallReturnPlaces<'_, 'tcx>, + state: &mut State>, + ) { + return_places.for_each(|place| { + state.flood(place.as_ref(), &self.map); + }) } fn handle_set_discriminant( &self, place: Place<'tcx>, variant_index: VariantIdx, - state: &mut State, + state: &mut State>, ) { state.flood_discr(place.as_ref(), &self.map); if self.map.find_discr(place.as_ref()).is_some() { @@ -109,17 +295,17 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { &self, target: Place<'tcx>, rvalue: &Rvalue<'tcx>, - state: &mut State, + state: &mut State>, ) { match rvalue { Rvalue::Use(operand) => { - state.flood(target.as_ref(), self.map()); + state.flood(target.as_ref(), &self.map); if let Some(target) = self.map.find(target.as_ref()) { self.assign_operand(state, target, operand); } } Rvalue::CopyForDeref(rhs) => { - state.flood(target.as_ref(), self.map()); + state.flood(target.as_ref(), &self.map); if let Some(target) = self.map.find(target.as_ref()) { self.assign_operand(state, target, &Operand::Copy(*rhs)); } @@ -127,9 +313,9 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { Rvalue::Aggregate(kind, operands) => { // If we assign `target = Enum::Variant#0(operand)`, // we must make sure that all `target as Variant#i` are `Top`. - state.flood(target.as_ref(), self.map()); + state.flood(target.as_ref(), &self.map); - let Some(target_idx) = self.map().find(target.as_ref()) else { return }; + let Some(target_idx) = self.map.find(target.as_ref()) else { return }; let (variant_target, variant_index) = match **kind { AggregateKind::Tuple | AggregateKind::Closure(..) => (Some(target_idx), None), @@ -148,14 +334,14 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { if let Some(variant_target_idx) = variant_target { for (field_index, operand) in operands.iter_enumerated() { if let Some(field) = - self.map().apply(variant_target_idx, TrackElem::Field(field_index)) + self.map.apply(variant_target_idx, TrackElem::Field(field_index)) { self.assign_operand(state, field, operand); } } } if let Some(variant_index) = variant_index - && let Some(discr_idx) = self.map().apply(target_idx, TrackElem::Discriminant) + && let Some(discr_idx) = self.map.apply(target_idx, TrackElem::Discriminant) { // We are assigning the discriminant as part of an aggregate. // This discriminant can only alias a variant field's value if the operand @@ -170,23 +356,23 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { } Rvalue::BinaryOp(op, box (left, right)) if op.is_overflowing() => { // Flood everything now, so we can use `insert_value_idx` directly later. - state.flood(target.as_ref(), self.map()); + state.flood(target.as_ref(), &self.map); - let Some(target) = self.map().find(target.as_ref()) else { return }; + let Some(target) = self.map.find(target.as_ref()) else { return }; - let value_target = self.map().apply(target, TrackElem::Field(0_u32.into())); - let overflow_target = self.map().apply(target, TrackElem::Field(1_u32.into())); + let value_target = self.map.apply(target, TrackElem::Field(0_u32.into())); + let overflow_target = self.map.apply(target, TrackElem::Field(1_u32.into())); if value_target.is_some() || overflow_target.is_some() { let (val, overflow) = self.binary_op(state, *op, left, right); if let Some(value_target) = value_target { // We have flooded `target` earlier. - state.insert_value_idx(value_target, val, self.map()); + state.insert_value_idx(value_target, val, &self.map); } if let Some(overflow_target) = overflow_target { // We have flooded `target` earlier. - state.insert_value_idx(overflow_target, overflow, self.map()); + state.insert_value_idx(overflow_target, overflow, &self.map); } } } @@ -196,27 +382,30 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { _, ) => { let pointer = self.handle_operand(operand, state); - state.assign(target.as_ref(), pointer, self.map()); + state.assign(target.as_ref(), pointer, &self.map); - if let Some(target_len) = self.map().find_len(target.as_ref()) + if let Some(target_len) = self.map.find_len(target.as_ref()) && let operand_ty = operand.ty(self.local_decls, self.tcx) && let Some(operand_ty) = operand_ty.builtin_deref(true) && let ty::Array(_, len) = operand_ty.kind() && let Some(len) = Const::Ty(self.tcx.types.usize, *len) .try_eval_scalar_int(self.tcx, self.param_env) { - state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map()); + state.insert_value_idx(target_len, FlatSet::Elem(len.into()), &self.map); } } - _ => self.super_assign(target, rvalue, state), + _ => { + let result = self.handle_rvalue(rvalue, state); + state.assign(target.as_ref(), result, &self.map); + } } } fn handle_rvalue( &self, rvalue: &Rvalue<'tcx>, - state: &mut State, - ) -> ValueOrPlace { + state: &mut State>, + ) -> ValueOrPlace> { let val = match rvalue { Rvalue::Len(place) => { let place_ty = place.ty(self.local_decls, self.tcx); @@ -225,7 +414,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { .try_eval_scalar(self.tcx, self.param_env) .map_or(FlatSet::Top, FlatSet::Elem) } else if let [ProjectionElem::Deref] = place.projection[..] { - state.get_len(place.local.into(), self.map()) + state.get_len(place.local.into(), &self.map) } else { FlatSet::Top } @@ -296,8 +485,24 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { }; FlatSet::Elem(Scalar::from_target_usize(val, &self.tcx)) } - Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), self.map()), - _ => return self.super_rvalue(rvalue, state), + Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map), + Rvalue::Use(operand) => return self.handle_operand(operand, state), + Rvalue::CopyForDeref(place) => { + return self.handle_operand(&Operand::Copy(*place), state); + } + Rvalue::Ref(..) | Rvalue::RawPtr(..) => { + // We don't track such places. + return ValueOrPlace::TOP; + } + Rvalue::Repeat(..) + | Rvalue::ThreadLocalRef(..) + | Rvalue::Cast(..) + | Rvalue::BinaryOp(..) + | Rvalue::Aggregate(..) + | Rvalue::ShallowInitBox(..) => { + // No modification is possible through these r-values. + return ValueOrPlace::TOP; + } }; ValueOrPlace::Value(val) } @@ -305,8 +510,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { fn handle_constant( &self, constant: &ConstOperand<'tcx>, - _state: &mut State, - ) -> Self::Value { + _state: &mut State>, + ) -> FlatSet { constant .const_ .try_eval_scalar(self.tcx, self.param_env) @@ -317,11 +522,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { &self, discr: &'mir Operand<'tcx>, targets: &'mir SwitchTargets, - state: &mut State, + state: &mut State>, ) -> TerminatorEdges<'mir, 'tcx> { let value = match self.handle_operand(discr, state) { ValueOrPlace::Value(value) => value, - ValueOrPlace::Place(place) => state.get_idx(place, self.map()), + ValueOrPlace::Place(place) => state.get_idx(place, &self.map), }; match value { // We are branching on uninitialized data, this is UB, treat it as unreachable. @@ -334,19 +539,6 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { FlatSet::Top => TerminatorEdges::SwitchInt { discr, targets }, } } -} - -impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { - fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map<'tcx>) -> Self { - let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - Self { - map, - tcx, - local_decls: &body.local_decls, - ecx: InterpCx::new(tcx, DUMMY_SP, param_env, DummyMachine), - param_env, - } - } /// The caller must have flooded `place`. fn assign_operand( @@ -537,6 +729,30 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } +/// This is used to visualize the dataflow analysis. +impl<'tcx> DebugWithContext> for State> { + fn fmt_with(&self, ctxt: &ConstAnalysis<'_, 'tcx>, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + State::Reachable(values) => debug_with_context(values, None, &ctxt.map, f), + State::Unreachable => write!(f, "unreachable"), + } + } + + fn fmt_diff_with( + &self, + old: &Self, + ctxt: &ConstAnalysis<'_, 'tcx>, + f: &mut Formatter<'_>, + ) -> std::fmt::Result { + match (self, old) { + (State::Reachable(this), State::Reachable(old)) => { + debug_with_context(this, Some(old), &ctxt.map, f) + } + _ => Ok(()), // Consider printing something here. + } + } +} + pub(crate) struct Patch<'tcx> { tcx: TyCtxt<'tcx>, @@ -725,8 +941,7 @@ fn try_write_constant<'tcx>( interp_ok(()) } -impl<'mir, 'tcx> - ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper>>> +impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx>>> for Collector<'_, 'tcx> { type Domain = State>; @@ -734,7 +949,7 @@ impl<'mir, 'tcx> #[instrument(level = "trace", skip(self, results, statement))] fn visit_statement_before_primary_effect( &mut self, - results: &mut Results<'tcx, ValueAnalysisWrapper>>, + results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, state: &Self::Domain, statement: &'mir Statement<'tcx>, location: Location, @@ -744,8 +959,8 @@ impl<'mir, 'tcx> OperandCollector { state, visitor: self, - ecx: &mut results.analysis.0.ecx, - map: &results.analysis.0.map, + ecx: &mut results.analysis.ecx, + map: &results.analysis.map, } .visit_rvalue(rvalue, location); } @@ -756,7 +971,7 @@ impl<'mir, 'tcx> #[instrument(level = "trace", skip(self, results, statement))] fn visit_statement_after_primary_effect( &mut self, - results: &mut Results<'tcx, ValueAnalysisWrapper>>, + results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, state: &Self::Domain, statement: &'mir Statement<'tcx>, location: Location, @@ -767,10 +982,10 @@ impl<'mir, 'tcx> } StatementKind::Assign(box (place, _)) => { if let Some(value) = self.try_make_constant( - &mut results.analysis.0.ecx, + &mut results.analysis.ecx, place, state, - &results.analysis.0.map, + &results.analysis.map, ) { self.patch.assignments.insert(location, value); } @@ -781,7 +996,7 @@ impl<'mir, 'tcx> fn visit_terminator_before_primary_effect( &mut self, - results: &mut Results<'tcx, ValueAnalysisWrapper>>, + results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, state: &Self::Domain, terminator: &'mir Terminator<'tcx>, location: Location, @@ -789,8 +1004,8 @@ impl<'mir, 'tcx> OperandCollector { state, visitor: self, - ecx: &mut results.analysis.0.ecx, - map: &results.analysis.0.map, + ecx: &mut results.analysis.ecx, + map: &results.analysis.map, } .visit_terminator(terminator, location); } From 846e20c3b6b861275bb02558f6bbde47e3be272d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 30 Oct 2024 16:07:26 +1100 Subject: [PATCH 52/56] Reduce some visibilities. --- compiler/rustc_mir_transform/src/dataflow_const_prop.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index b8e35587b87f..dd85d06540d1 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -753,16 +753,16 @@ impl<'tcx> DebugWithContext> for State> } } -pub(crate) struct Patch<'tcx> { +struct Patch<'tcx> { tcx: TyCtxt<'tcx>, /// For a given MIR location, this stores the values of the operands used by that location. In /// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are /// properly captured. (This may become UB soon, but it is currently emitted even by safe code.) - pub(crate) before_effect: FxHashMap<(Location, Place<'tcx>), Const<'tcx>>, + before_effect: FxHashMap<(Location, Place<'tcx>), Const<'tcx>>, /// Stores the assigned values for assignments where the Rvalue is constant. - pub(crate) assignments: FxHashMap>, + assignments: FxHashMap>, } impl<'tcx> Patch<'tcx> { From 1c88af65603b3df97411a9c0c46427100ab997a3 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 31 Oct 2024 04:55:42 +0000 Subject: [PATCH 53/56] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 0e3537b185fc..2ec411b54b18 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -16422dbd8958179379214e8f43fdb73a06b2eada +75eff9a5749411ba5a0b37cc3299116c4e263075 From c8b76bcf58298cced4ef3ca9dd823eb318fc11f5 Mon Sep 17 00:00:00 2001 From: Luca Versari Date: Sat, 13 Jul 2024 19:35:05 +0200 Subject: [PATCH 54/56] Emit warning when calling/declaring functions with unavailable vectors. On some architectures, vector types may have a different ABI depending on whether the relevant target features are enabled. (The ABI when the feature is disabled is often not specified, but LLVM implements some de-facto ABI.) As discussed in rust-lang/lang-team#235, this turns out to very easily lead to unsound code. This commit makes it a post-monomorphization future-incompat warning to declare or call functions using those vector types in a context in which the corresponding target features are disabled, if using an ABI for which the difference is relevant. This ensures that these functions are always called with a consistent ABI. See the [nomination comment](https://github.com/rust-lang/rust/pull/127731#issuecomment-2288558187) for more discussion. Part of #116558 --- compiler/rustc_lint_defs/src/builtin.rs | 67 ++++++++ compiler/rustc_middle/src/query/mod.rs | 8 + compiler/rustc_monomorphize/messages.ftl | 9 + compiler/rustc_monomorphize/src/collector.rs | 4 + .../src/collector/abi_check.rs | 162 ++++++++++++++++++ compiler/rustc_monomorphize/src/errors.rs | 18 ++ compiler/rustc_target/src/target_features.rs | 17 ++ tests/crashes/131342-2.rs | 40 ----- tests/crashes/131342.rs | 17 +- tests/ui/layout/post-mono-layout-cycle-2.rs | 1 - .../ui/layout/post-mono-layout-cycle-2.stderr | 10 +- tests/ui/layout/post-mono-layout-cycle.rs | 1 - tests/ui/layout/post-mono-layout-cycle.stderr | 10 +- tests/ui/simd-abi-checks.rs | 81 +++++++++ tests/ui/simd-abi-checks.stderr | 93 ++++++++++ tests/ui/sse-abi-checks.rs | 24 +++ tests/ui/sse-abi-checks.stderr | 13 ++ 17 files changed, 514 insertions(+), 61 deletions(-) create mode 100644 compiler/rustc_monomorphize/src/collector/abi_check.rs delete mode 100644 tests/crashes/131342-2.rs create mode 100644 tests/ui/simd-abi-checks.rs create mode 100644 tests/ui/simd-abi-checks.stderr create mode 100644 tests/ui/sse-abi-checks.rs create mode 100644 tests/ui/sse-abi-checks.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 06a3e4a67430..51146cfd2e9a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -16,6 +16,7 @@ declare_lint_pass! { /// that are used by other parts of the compiler. HardwiredLints => [ // tidy-alphabetical-start + ABI_UNSUPPORTED_VECTOR_TYPES, ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_ASSOCIATED_ITEMS, AMBIGUOUS_GLOB_IMPORTS, @@ -5031,3 +5032,69 @@ declare_lint! { }; crate_level_only } + +declare_lint! { + /// The `abi_unsupported_vector_types` lint detects function definitions and calls + /// whose ABI depends on enabling certain target features, but those features are not enabled. + /// + /// ### Example + /// + /// ```rust,ignore (fails on non-x86_64) + /// extern "C" fn missing_target_feature(_: std::arch::x86_64::__m256) { + /// todo!() + /// } + /// + /// #[target_feature(enable = "avx")] + /// unsafe extern "C" fn with_target_feature(_: std::arch::x86_64::__m256) { + /// todo!() + /// } + /// + /// fn main() { + /// let v = unsafe { std::mem::zeroed() }; + /// unsafe { with_target_feature(v); } + /// } + /// ``` + /// + /// ```text + /// warning: ABI error: this function call uses a avx vector type, which is not enabled in the caller + /// --> lint_example.rs:18:12 + /// | + /// | unsafe { with_target_feature(v); } + /// | ^^^^^^^^^^^^^^^^^^^^^^ function called here + /// | + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #116558 + /// = help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) + /// = note: `#[warn(abi_unsupported_vector_types)]` on by default + /// + /// + /// warning: ABI error: this function definition uses a avx vector type, which is not enabled + /// --> lint_example.rs:3:1 + /// | + /// | pub extern "C" fn with_target_feature(_: std::arch::x86_64::__m256) { + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + /// | + /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + /// = note: for more information, see issue #116558 + /// = help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) + /// ``` + /// + /// + /// + /// ### Explanation + /// + /// The C ABI for `__m256` requires the value to be passed in an AVX register, + /// which is only possible when the `avx` target feature is enabled. + /// Therefore, `missing_target_feature` cannot be compiled without that target feature. + /// A similar (but complementary) message is triggered when `with_target_feature` is called + /// by a function that does not enable the `avx` target feature. + /// + /// Note that this lint is very similar to the `-Wpsabi` warning in `gcc`/`clang`. + pub ABI_UNSUPPORTED_VECTOR_TYPES, + Warn, + "this function call or definition uses a vector type which is not enabled", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reference: "issue #116558 ", + }; +} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 088b5d4ec965..3f61d7cc66f7 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2315,6 +2315,14 @@ rustc_queries! { desc { "whether the item should be made inlinable across crates" } separate_provide_extern } + + /// Check the signature of this function as well as all the call expressions inside of it + /// to ensure that any target features required by the ABI are enabled. + /// Should be called on a fully monomorphized instance. + query check_feature_dependent_abi(key: ty::Instance<'tcx>) { + desc { "check for feature-dependent ABI" } + cache_on_disk_if { true } + } } rustc_query_append! { define_callbacks! } diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 7210701d4828..6da387bbebcc 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -1,3 +1,12 @@ +monomorphize_abi_error_disabled_vector_type_call = + ABI error: this function call uses a vector type that requires the `{$required_feature}` target feature, which is not enabled in the caller + .label = function called here + .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`) +monomorphize_abi_error_disabled_vector_type_def = + ABI error: this function definition uses a vector type that requires the `{$required_feature}` target feature, which is not enabled + .label = function defined here + .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`) + monomorphize_couldnt_dump_mono_stats = unexpected error occurred while dumping monomorphization stats: {$error} diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 8df6e63deeb1..63afad5df497 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -205,6 +205,7 @@ //! this is not implemented however: a mono item will be produced //! regardless of whether it is actually needed or not. +mod abi_check; mod move_check; use std::path::PathBuf; @@ -1207,6 +1208,8 @@ fn collect_items_of_instance<'tcx>( mentioned_items: &mut MonoItems<'tcx>, mode: CollectionMode, ) { + tcx.ensure().check_feature_dependent_abi(instance); + let body = tcx.instance_mir(instance.def); // Naively, in "used" collection mode, all functions get added to *both* `used_items` and // `mentioned_items`. Mentioned items processing will then notice that they have already been @@ -1623,4 +1626,5 @@ pub(crate) fn collect_crate_mono_items<'tcx>( pub(crate) fn provide(providers: &mut Providers) { providers.hooks.should_codegen_locally = should_codegen_locally; + abi_check::provide(providers); } diff --git a/compiler/rustc_monomorphize/src/collector/abi_check.rs b/compiler/rustc_monomorphize/src/collector/abi_check.rs new file mode 100644 index 000000000000..f1c57f1e9975 --- /dev/null +++ b/compiler/rustc_monomorphize/src/collector/abi_check.rs @@ -0,0 +1,162 @@ +//! This module ensures that if a function's ABI requires a particular target feature, +//! that target feature is enabled both on the callee and all callers. +use rustc_hir::CRATE_HIR_ID; +use rustc_middle::mir::visit::Visitor as MirVisitor; +use rustc_middle::mir::{self, Location, traversal}; +use rustc_middle::query::Providers; +use rustc_middle::ty::inherent::*; +use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt}; +use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES; +use rustc_span::def_id::DefId; +use rustc_span::{DUMMY_SP, Span, Symbol}; +use rustc_target::abi::call::{FnAbi, PassMode}; +use rustc_target::abi::{BackendRepr, RegKind}; + +use crate::errors::{AbiErrorDisabledVectorTypeCall, AbiErrorDisabledVectorTypeDef}; + +fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool { + match mode { + PassMode::Ignore | PassMode::Indirect { .. } => false, + PassMode::Cast { pad_i32: _, cast } => { + cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector)) + || cast.rest.unit.kind == RegKind::Vector + } + PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::Vector { .. }), + } +} + +fn do_check_abi<'tcx>( + tcx: TyCtxt<'tcx>, + abi: &FnAbi<'tcx, Ty<'tcx>>, + target_feature_def: DefId, + mut emit_err: impl FnMut(&'static str), +) { + let Some(feature_def) = tcx.sess.target.features_for_correct_vector_abi() else { + return; + }; + let codegen_attrs = tcx.codegen_fn_attrs(target_feature_def); + for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) { + let size = arg_abi.layout.size; + if uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) { + // Find the first feature that provides at least this vector size. + let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) { + Some((_, feature)) => feature, + None => { + emit_err(""); + continue; + } + }; + let feature_sym = Symbol::intern(feature); + if !tcx.sess.unstable_target_features.contains(&feature_sym) + && !codegen_attrs.target_features.iter().any(|x| x.name == feature_sym) + { + emit_err(feature); + } + } + } +} + +/// Checks that the ABI of a given instance of a function does not contain vector-passed arguments +/// or return values for which the corresponding target feature is not enabled. +fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { + let param_env = ParamEnv::reveal_all(); + let Ok(abi) = tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) else { + // An error will be reported during codegen if we cannot determine the ABI of this + // function. + return; + }; + do_check_abi(tcx, abi, instance.def_id(), |required_feature| { + let span = tcx.def_span(instance.def_id()); + tcx.emit_node_span_lint( + ABI_UNSUPPORTED_VECTOR_TYPES, + CRATE_HIR_ID, + span, + AbiErrorDisabledVectorTypeDef { span, required_feature }, + ); + }) +} + +/// Checks that a call expression does not try to pass a vector-passed argument which requires a +/// target feature that the caller does not have, as doing so causes UB because of ABI mismatch. +fn check_call_site_abi<'tcx>( + tcx: TyCtxt<'tcx>, + callee: Ty<'tcx>, + span: Span, + caller: InstanceKind<'tcx>, +) { + if callee.fn_sig(tcx).abi().is_rust() { + // "Rust" ABI never passes arguments in vector registers. + return; + } + let param_env = ParamEnv::reveal_all(); + let callee_abi = match *callee.kind() { + ty::FnPtr(..) => { + tcx.fn_abi_of_fn_ptr(param_env.and((callee.fn_sig(tcx), ty::List::empty()))) + } + ty::FnDef(def_id, args) => { + // Intrinsics are handled separately by the compiler. + if tcx.intrinsic(def_id).is_some() { + return; + } + let instance = ty::Instance::expect_resolve(tcx, param_env, def_id, args, DUMMY_SP); + tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) + } + _ => { + panic!("Invalid function call"); + } + }; + + let Ok(callee_abi) = callee_abi else { + // ABI failed to compute; this will not get through codegen. + return; + }; + do_check_abi(tcx, callee_abi, caller.def_id(), |required_feature| { + tcx.emit_node_span_lint( + ABI_UNSUPPORTED_VECTOR_TYPES, + CRATE_HIR_ID, + span, + AbiErrorDisabledVectorTypeCall { span, required_feature }, + ); + }); +} + +struct MirCallesAbiCheck<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + instance: Instance<'tcx>, +} + +impl<'a, 'tcx> MirVisitor<'tcx> for MirCallesAbiCheck<'a, 'tcx> { + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, _: Location) { + match terminator.kind { + mir::TerminatorKind::Call { ref func, ref fn_span, .. } + | mir::TerminatorKind::TailCall { ref func, ref fn_span, .. } => { + let callee_ty = func.ty(self.body, self.tcx); + let callee_ty = self.instance.instantiate_mir_and_normalize_erasing_regions( + self.tcx, + ty::ParamEnv::reveal_all(), + ty::EarlyBinder::bind(callee_ty), + ); + check_call_site_abi(self.tcx, callee_ty, *fn_span, self.body.source.instance); + } + _ => {} + } + } +} + +fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { + let body = tcx.instance_mir(instance.def); + let mut visitor = MirCallesAbiCheck { tcx, body, instance }; + for (bb, data) in traversal::mono_reachable(body, tcx, instance) { + visitor.visit_basic_block_data(bb, data) + } +} + +fn check_feature_dependent_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { + check_instance_abi(tcx, instance); + check_callees_abi(tcx, instance); +} + +pub(super) fn provide(providers: &mut Providers) { + *providers = Providers { check_feature_dependent_abi, ..*providers } +} diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index d5fae6e23cb4..5048a8d5d993 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -92,3 +92,21 @@ pub(crate) struct StartNotFound; pub(crate) struct UnknownCguCollectionMode<'a> { pub mode: &'a str, } + +#[derive(LintDiagnostic)] +#[diag(monomorphize_abi_error_disabled_vector_type_def)] +#[help] +pub(crate) struct AbiErrorDisabledVectorTypeDef<'a> { + #[label] + pub span: Span, + pub required_feature: &'a str, +} + +#[derive(LintDiagnostic)] +#[diag(monomorphize_abi_error_disabled_vector_type_call)] +#[help] +pub(crate) struct AbiErrorDisabledVectorTypeCall<'a> { + #[label] + pub span: Span, + pub required_feature: &'a str, +} diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 3df8f0590a35..94f771954e14 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -524,6 +524,13 @@ pub fn all_known_features() -> impl Iterator { .map(|(f, s, _)| (f, s)) } +// These arrays represent the least-constraining feature that is required for vector types up to a +// certain size to have their "proper" ABI on each architecture. +// Note that they must be kept sorted by vector size. +const X86_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "sse"), (256, "avx"), (512, "avx512f")]; +const AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "neon")]; + impl super::spec::Target { pub fn supported_target_features( &self, @@ -545,6 +552,16 @@ impl super::spec::Target { } } + // Returns None if we do not support ABI checks on the given target yet. + pub fn features_for_correct_vector_abi(&self) -> Option<&'static [(u64, &'static str)]> { + match &*self.arch { + "x86" | "x86_64" => Some(X86_FEATURES_FOR_CORRECT_VECTOR_ABI), + "aarch64" => Some(AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI), + // FIXME: add support for non-tier1 architectures + _ => None, + } + } + pub fn tied_target_features(&self) -> &'static [&'static [&'static str]] { match &*self.arch { "aarch64" | "arm64ec" => AARCH64_TIED_FEATURES, diff --git a/tests/crashes/131342-2.rs b/tests/crashes/131342-2.rs deleted file mode 100644 index 79b6a837a49f..000000000000 --- a/tests/crashes/131342-2.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@ known-bug: #131342 -// see also: 131342.rs - -fn main() { - problem_thingy(Once); -} - -struct Once; - -impl Iterator for Once { - type Item = (); -} - -fn problem_thingy(items: impl Iterator) { - let peeker = items.peekable(); - problem_thingy(&peeker); -} - -trait Iterator { - type Item; - - fn peekable(self) -> Peekable - where - Self: Sized, - { - loop {} - } -} - -struct Peekable { - _peeked: I::Item, -} - -impl Iterator for Peekable { - type Item = I::Item; -} - -impl Iterator for &I { - type Item = I::Item; -} diff --git a/tests/crashes/131342.rs b/tests/crashes/131342.rs index 7f7ee9c9ac11..f4404092917a 100644 --- a/tests/crashes/131342.rs +++ b/tests/crashes/131342.rs @@ -1,16 +1,15 @@ //@ known-bug: #131342 -// see also: 131342-2.rs fn main() { - let mut items = vec![1, 2, 3, 4, 5].into_iter(); - problem_thingy(&mut items); + let mut items = vec![1, 2, 3, 4, 5].into_iter(); + problem_thingy(&mut items); } fn problem_thingy(items: &mut impl Iterator) { - let mut peeker = items.peekable(); - match peeker.peek() { - Some(_) => (), - None => return (), - } - problem_thingy(&mut peeker); + let mut peeker = items.peekable(); + match peeker.peek() { + Some(_) => (), + None => return (), + } + problem_thingy(&mut peeker); } diff --git a/tests/ui/layout/post-mono-layout-cycle-2.rs b/tests/ui/layout/post-mono-layout-cycle-2.rs index 356f1e777c7d..e9a5292fbbdf 100644 --- a/tests/ui/layout/post-mono-layout-cycle-2.rs +++ b/tests/ui/layout/post-mono-layout-cycle-2.rs @@ -45,7 +45,6 @@ where T: Blah, { async fn ice(&mut self) { - //~^ ERROR a cycle occurred during layout computation let arr: [(); 0] = []; self.t.iter(arr.into_iter()).await; } diff --git a/tests/ui/layout/post-mono-layout-cycle-2.stderr b/tests/ui/layout/post-mono-layout-cycle-2.stderr index ad01c2694faf..2e8d237844e8 100644 --- a/tests/ui/layout/post-mono-layout-cycle-2.stderr +++ b/tests/ui/layout/post-mono-layout-cycle-2.stderr @@ -12,12 +12,12 @@ LL | Blah::iter(self, iterator).await | = note: a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future -error: a cycle occurred during layout computation - --> $DIR/post-mono-layout-cycle-2.rs:47:5 +note: the above error was encountered while instantiating `fn Wrap::<()>::ice` + --> $DIR/post-mono-layout-cycle-2.rs:56:9 | -LL | async fn ice(&mut self) { - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | t.ice(); + | ^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0733`. diff --git a/tests/ui/layout/post-mono-layout-cycle.rs b/tests/ui/layout/post-mono-layout-cycle.rs index 8d136190c005..6753c01267ec 100644 --- a/tests/ui/layout/post-mono-layout-cycle.rs +++ b/tests/ui/layout/post-mono-layout-cycle.rs @@ -14,7 +14,6 @@ struct Wrapper { } fn abi(_: Option>) {} -//~^ ERROR a cycle occurred during layout computation fn indirect() { abi::(None); diff --git a/tests/ui/layout/post-mono-layout-cycle.stderr b/tests/ui/layout/post-mono-layout-cycle.stderr index 47f7f30b1cb4..7f246b3d409a 100644 --- a/tests/ui/layout/post-mono-layout-cycle.stderr +++ b/tests/ui/layout/post-mono-layout-cycle.stderr @@ -5,12 +5,12 @@ error[E0391]: cycle detected when computing layout of `Wrapper<()>` = note: cycle used when computing layout of `core::option::Option>` = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: a cycle occurred during layout computation - --> $DIR/post-mono-layout-cycle.rs:16:1 +note: the above error was encountered while instantiating `fn abi::<()>` + --> $DIR/post-mono-layout-cycle.rs:19:5 | -LL | fn abi(_: Option>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | abi::(None); + | ^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/simd-abi-checks.rs b/tests/ui/simd-abi-checks.rs new file mode 100644 index 000000000000..094c89930b75 --- /dev/null +++ b/tests/ui/simd-abi-checks.rs @@ -0,0 +1,81 @@ +//@ only-x86_64 +//@ build-pass +//@ ignore-pass (test emits codegen-time warnings) + +#![feature(avx512_target_feature)] +#![feature(portable_simd)] +#![allow(improper_ctypes_definitions)] + +use std::arch::x86_64::*; + +#[repr(transparent)] +struct Wrapper(__m256); + +unsafe extern "C" fn w(_: Wrapper) { + //~^ ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled + //~| WARNING this was previously accepted by the compiler + todo!() +} + +unsafe extern "C" fn f(_: __m256) { + //~^ ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled + //~| WARNING this was previously accepted by the compiler + todo!() +} + +unsafe extern "C" fn g() -> __m256 { + //~^ ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled + //~| WARNING this was previously accepted by the compiler + todo!() +} + +#[target_feature(enable = "avx")] +unsafe extern "C" fn favx() -> __m256 { + todo!() +} + +// avx2 implies avx, so no error here. +#[target_feature(enable = "avx2")] +unsafe extern "C" fn gavx(_: __m256) { + todo!() +} + +// No error because of "Rust" ABI. +fn as_f64x8(d: __m512d) -> std::simd::f64x8 { + unsafe { std::mem::transmute(d) } +} + +unsafe fn test() { + let arg = std::mem::transmute([0.0f64; 8]); + as_f64x8(arg); +} + +fn main() { + unsafe { + f(g()); + //~^ WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + //~| WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + //~| WARNING this was previously accepted by the compiler + //~| WARNING this was previously accepted by the compiler + } + + unsafe { + gavx(favx()); + //~^ WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + //~| WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + //~| WARNING this was previously accepted by the compiler + //~| WARNING this was previously accepted by the compiler + } + + unsafe { + test(); + } + + unsafe { + w(Wrapper(g())); + //~^ WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + //~| WARNING ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + //~| WARNING this was previously accepted by the compiler + //~| WARNING this was previously accepted by the compiler + } +} diff --git a/tests/ui/simd-abi-checks.stderr b/tests/ui/simd-abi-checks.stderr new file mode 100644 index 000000000000..aa7e94001698 --- /dev/null +++ b/tests/ui/simd-abi-checks.stderr @@ -0,0 +1,93 @@ +warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + --> $DIR/simd-abi-checks.rs:55:11 + | +LL | f(g()); + | ^^^ function called here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + = note: `#[warn(abi_unsupported_vector_types)]` on by default + +warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + --> $DIR/simd-abi-checks.rs:55:9 + | +LL | f(g()); + | ^^^^^^ function called here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + --> $DIR/simd-abi-checks.rs:63:14 + | +LL | gavx(favx()); + | ^^^^^^ function called here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + --> $DIR/simd-abi-checks.rs:63:9 + | +LL | gavx(favx()); + | ^^^^^^^^^^^^ function called here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + --> $DIR/simd-abi-checks.rs:75:19 + | +LL | w(Wrapper(g())); + | ^^^ function called here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller + --> $DIR/simd-abi-checks.rs:75:9 + | +LL | w(Wrapper(g())); + | ^^^^^^^^^^^^^^^ function called here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled + --> $DIR/simd-abi-checks.rs:26:1 + | +LL | unsafe extern "C" fn g() -> __m256 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled + --> $DIR/simd-abi-checks.rs:20:1 + | +LL | unsafe extern "C" fn f(_: __m256) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: ABI error: this function definition uses a vector type that requires the `avx` target feature, which is not enabled + --> $DIR/simd-abi-checks.rs:14:1 + | +LL | unsafe extern "C" fn w(_: Wrapper) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`) + +warning: 9 warnings emitted + diff --git a/tests/ui/sse-abi-checks.rs b/tests/ui/sse-abi-checks.rs new file mode 100644 index 000000000000..d2afd38fcc85 --- /dev/null +++ b/tests/ui/sse-abi-checks.rs @@ -0,0 +1,24 @@ +//! Ensure we trigger abi_unsupported_vector_types for target features that are usually enabled +//! on a target, but disabled in this file via a `-C` flag. +//@ compile-flags: --crate-type=rlib --target=i686-unknown-linux-gnu -C target-feature=-sse,-sse2 +//@ build-pass +//@ ignore-pass (test emits codegen-time warnings) +//@ needs-llvm-components: x86 +#![feature(no_core, lang_items, repr_simd)] +#![no_core] +#![allow(improper_ctypes_definitions)] + +#[lang = "sized"] +trait Sized {} + +#[lang = "copy"] +trait Copy {} + +#[repr(simd)] +pub struct SseVector([i64; 2]); + +#[no_mangle] +pub unsafe extern "C" fn f(_: SseVector) { + //~^ ABI error: this function definition uses a vector type that requires the `sse` target feature, which is not enabled + //~| WARNING this was previously accepted by the compiler +} diff --git a/tests/ui/sse-abi-checks.stderr b/tests/ui/sse-abi-checks.stderr new file mode 100644 index 000000000000..77c4e1fc07ab --- /dev/null +++ b/tests/ui/sse-abi-checks.stderr @@ -0,0 +1,13 @@ +warning: ABI error: this function definition uses a vector type that requires the `sse` target feature, which is not enabled + --> $DIR/sse-abi-checks.rs:21:1 + | +LL | pub unsafe extern "C" fn f(_: SseVector) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116558 + = help: consider enabling it globally (`-C target-feature=+sse`) or locally (`#[target_feature(enable="sse")]`) + = note: `#[warn(abi_unsupported_vector_types)]` on by default + +warning: 1 warning emitted + From ef6b9a9513cebe12605352c2a1ecbdcbcc686fa8 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 31 Oct 2024 05:04:44 +0000 Subject: [PATCH 55/56] fmt --- src/tools/miri/src/shims/native_lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index 525bcd381d52..e7a4251242e2 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -3,9 +3,9 @@ use std::ops::Deref; use libffi::high::call as ffi; use libffi::low::CodePtr; +use rustc_abi::{BackendRepr, HasDataLayout}; use rustc_middle::ty::{self as ty, IntTy, UintTy}; use rustc_span::Symbol; -use rustc_abi::{BackendRepr, HasDataLayout}; use crate::*; From b8bd7becb419084397adc6b797136c20046fdacb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 31 Oct 2024 08:14:56 +0100 Subject: [PATCH 56/56] silence clippy --- src/tools/miri/src/shims/x86/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index e2b02873aefe..2f63876327f7 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -1000,6 +1000,7 @@ fn mask_load<'tcx>( let dest = this.project_index(&dest, i)?; if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { + #[allow(clippy::arithmetic_side_effects)] // `Size` arithmetic is checked let ptr = ptr.wrapping_offset(dest.layout.size * i, &this.tcx); // Unaligned copy, which is what we want. this.mem_copy(ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?; @@ -1035,6 +1036,7 @@ fn mask_store<'tcx>( if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { // *Non-inbounds* pointer arithmetic to compute the destination. // (That's why we can't use a place projection.) + #[allow(clippy::arithmetic_side_effects)] // `Size` arithmetic is checked let ptr = ptr.wrapping_offset(value.layout.size * i, &this.tcx); // Deref the pointer *unaligned*, and do the copy. let dest = this.ptr_to_mplace_unaligned(ptr, value.layout);