Merge from rustc
This commit is contained in:
commit
6ab7af4d41
1956 changed files with 70980 additions and 22786 deletions
|
|
@ -14,3 +14,5 @@ c34fbfaad38cf5829ef5cfe780dc9d58480adeaa
|
|||
cf2dff2b1e3fa55fa5415d524200070d0d7aacfe
|
||||
# Run rustfmt on bootstrap
|
||||
b39a1d6f1a30ba29f25d7141038b9a5bf0126e36
|
||||
# reorder fluent message files
|
||||
f97fddab91fbf290ea5b691fe355d6f915220b6e
|
||||
|
|
|
|||
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -25,7 +25,7 @@
|
|||
[submodule "src/llvm-project"]
|
||||
path = src/llvm-project
|
||||
url = https://github.com/rust-lang/llvm-project.git
|
||||
branch = rustc/16.0-2023-04-05
|
||||
branch = rustc/16.0-2023-06-05
|
||||
[submodule "src/doc/embedded-book"]
|
||||
path = src/doc/embedded-book
|
||||
url = https://github.com/rust-embedded/book.git
|
||||
|
|
|
|||
158
Cargo.lock
158
Cargo.lock
|
|
@ -294,7 +294,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"sha2",
|
||||
"tar",
|
||||
"toml",
|
||||
"toml 0.5.7",
|
||||
"xz2",
|
||||
]
|
||||
|
||||
|
|
@ -311,14 +311,14 @@ dependencies = [
|
|||
"indexmap",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"toml",
|
||||
"toml 0.5.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.12.1"
|
||||
version = "3.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8"
|
||||
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
|
|
@ -581,7 +581,7 @@ checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
|
|||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.71"
|
||||
version = "0.1.72"
|
||||
dependencies = [
|
||||
"clap 4.2.1",
|
||||
"clippy_lints",
|
||||
|
|
@ -596,7 +596,6 @@ dependencies = [
|
|||
"quote",
|
||||
"regex",
|
||||
"rustc-semver",
|
||||
"rustc-workspace-hack",
|
||||
"rustc_tools_util",
|
||||
"serde",
|
||||
"syn 2.0.8",
|
||||
|
|
@ -604,7 +603,7 @@ dependencies = [
|
|||
"termize",
|
||||
"tester",
|
||||
"tokio",
|
||||
"toml",
|
||||
"toml 0.7.4",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
|
|
@ -623,7 +622,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.71"
|
||||
version = "0.1.72"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"cargo_metadata 0.15.3",
|
||||
|
|
@ -639,7 +638,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"toml",
|
||||
"toml 0.7.4",
|
||||
"unicode-normalization",
|
||||
"unicode-script",
|
||||
"url",
|
||||
|
|
@ -647,7 +646,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.71"
|
||||
version = "0.1.72"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"if_chain",
|
||||
|
|
@ -849,7 +848,7 @@ dependencies = [
|
|||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset",
|
||||
"memoffset 0.8.0",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
|
|
@ -872,16 +871,6 @@ dependencies = [
|
|||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cstr"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c11a39d776a3b35896711da8a04dc1835169dcd36f710878187637314e47941b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctrlc"
|
||||
version = "3.3.1"
|
||||
|
|
@ -930,7 +919,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
|
|||
|
||||
[[package]]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.71"
|
||||
version = "0.1.72"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"quote",
|
||||
|
|
@ -1204,11 +1193,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "field-offset"
|
||||
version = "0.3.5"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535"
|
||||
checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"memoffset 0.9.0",
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
|
|
@ -1220,7 +1209,7 @@ checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.10",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
|
|
@ -1762,7 +1751,6 @@ dependencies = [
|
|||
"flate2",
|
||||
"num_cpus",
|
||||
"rayon",
|
||||
"remove_dir_all",
|
||||
"tar",
|
||||
"walkdir",
|
||||
"xz2",
|
||||
|
|
@ -1914,9 +1902,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.143"
|
||||
version = "0.2.146"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edc207893e85c5d6be840e969b496b53d94cec8be2d501b214f50daa97fa8024"
|
||||
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
|
@ -2111,7 +2099,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"shlex",
|
||||
"tempfile",
|
||||
"toml",
|
||||
"toml 0.5.7",
|
||||
"topological-sort",
|
||||
]
|
||||
|
||||
|
|
@ -2157,6 +2145,15 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.16"
|
||||
|
|
@ -2446,7 +2443,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.10",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
|
@ -2459,7 +2456,7 @@ checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.10",
|
||||
"smallvec",
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
|
@ -2802,6 +2799,15 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.0"
|
||||
|
|
@ -2809,7 +2815,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2861,15 +2867,6 @@ version = "0.1.0"
|
|||
name = "remote-test-server"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "replace-version-placeholder"
|
||||
version = "0.1.0"
|
||||
|
|
@ -3180,7 +3177,6 @@ name = "rustc_codegen_llvm"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cstr",
|
||||
"libc",
|
||||
"measureme",
|
||||
"object 0.31.1",
|
||||
|
|
@ -3608,6 +3604,7 @@ dependencies = [
|
|||
name = "rustc_interface"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"libloading",
|
||||
"rustc-rayon",
|
||||
"rustc-rayon-core",
|
||||
|
|
@ -3988,7 +3985,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"field-offset",
|
||||
"measureme",
|
||||
"memoffset",
|
||||
"memoffset 0.9.0",
|
||||
"rustc-rayon-core",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
|
|
@ -4072,6 +4069,7 @@ dependencies = [
|
|||
name = "rustc_session"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"getopts",
|
||||
"libc",
|
||||
"rustc_ast",
|
||||
|
|
@ -4363,7 +4361,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"term",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"toml 0.5.7",
|
||||
"unicode-segmentation",
|
||||
"unicode-width",
|
||||
"unicode_categories",
|
||||
|
|
@ -4484,6 +4482,15 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.5"
|
||||
|
|
@ -4781,16 +4788,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.3.0"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||
checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4976,14 +4982,14 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.8.4"
|
||||
version = "1.28.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50dae83881bc9b0403dd5b44ea9deed3e939856cc8722d5be37f0d6e5c6d53dd"
|
||||
checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4995,6 +5001,40 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "topological-sort"
|
||||
version = "0.2.2"
|
||||
|
|
@ -5358,7 +5398,6 @@ dependencies = [
|
|||
"idna",
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5685,6 +5724,15 @@ version = "0.48.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.5.1"
|
||||
|
|
|
|||
|
|
@ -414,7 +414,9 @@ pub struct Size {
|
|||
// Safety: Ord is implement as just comparing numerical values and numerical values
|
||||
// are not changed by (de-)serialization.
|
||||
#[cfg(feature = "nightly")]
|
||||
unsafe impl StableOrd for Size {}
|
||||
unsafe impl StableOrd for Size {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = true;
|
||||
}
|
||||
|
||||
// This is debug-printed a lot in larger structs, don't waste too much space there
|
||||
impl fmt::Debug for Size {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,20 @@
|
|||
//! Definitions shared by macros / syntax extensions and e.g. `rustc_middle`.
|
||||
|
||||
use rustc_span::{def_id::DefId, symbol::Ident};
|
||||
|
||||
use crate::MetaItem;
|
||||
|
||||
pub mod allocator;
|
||||
|
||||
#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct StrippedCfgItem<ModId = DefId> {
|
||||
pub parent_module: ModId,
|
||||
pub name: Ident,
|
||||
pub cfg: MetaItem,
|
||||
}
|
||||
|
||||
impl<ModId> StrippedCfgItem<ModId> {
|
||||
pub fn map_mod_id<New>(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem<New> {
|
||||
StrippedCfgItem { parent_module: f(self.parent_module), name: self.name, cfg: self.cfg }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,9 +71,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let kind = match &e.kind {
|
||||
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
||||
ExprKind::ConstBlock(anon_const) => {
|
||||
let anon_const = self.lower_anon_const(anon_const);
|
||||
hir::ExprKind::ConstBlock(anon_const)
|
||||
ExprKind::ConstBlock(c) => {
|
||||
let c = self.with_new_scopes(|this| hir::ConstBlock {
|
||||
def_id: this.local_def_id(c.id),
|
||||
hir_id: this.lower_node_id(c.id),
|
||||
body: this.lower_const_body(c.value.span, Some(&c.value)),
|
||||
});
|
||||
hir::ExprKind::ConstBlock(c)
|
||||
}
|
||||
ExprKind::Repeat(expr, count) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
|
|
|
|||
|
|
@ -223,6 +223,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
});
|
||||
}
|
||||
|
||||
fn visit_inline_const(&mut self, constant: &'hir ConstBlock) {
|
||||
self.insert(DUMMY_SP, constant.hir_id, Node::ConstBlock(constant));
|
||||
|
||||
self.with_parent(constant.hir_id, |this| {
|
||||
intravisit::walk_inline_const(this, constant);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
|
||||
self.insert(expr.span, expr.hir_id, Node::Expr(expr));
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use rustc_ast as ast;
|
|||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::{attr, AssocConstraint, AssocConstraintKind, NodeId};
|
||||
use rustc_ast::{PatKind, RangeEnd};
|
||||
use rustc_errors::{Applicability, StashKey};
|
||||
use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
|
||||
use rustc_session::Session;
|
||||
|
|
@ -374,55 +373,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, stmt: &'a ast::Stmt) {
|
||||
if let ast::StmtKind::Semi(expr) = &stmt.kind
|
||||
&& let ast::ExprKind::Assign(lhs, _, _) = &expr.kind
|
||||
&& let ast::ExprKind::Type(..) = lhs.kind
|
||||
&& self.sess.parse_sess.span_diagnostic.err_count() == 0
|
||||
&& !self.features.type_ascription
|
||||
&& !lhs.span.allows_unstable(sym::type_ascription)
|
||||
{
|
||||
// When we encounter a statement of the form `foo: Ty = val;`, this will emit a type
|
||||
// ascription error, but the likely intention was to write a `let` statement. (#78907).
|
||||
feature_err(
|
||||
&self.sess.parse_sess,
|
||||
sym::type_ascription,
|
||||
lhs.span,
|
||||
"type ascription is experimental",
|
||||
).span_suggestion_verbose(
|
||||
lhs.span.shrink_to_lo(),
|
||||
"you might have meant to introduce a new binding",
|
||||
"let ",
|
||||
Applicability::MachineApplicable,
|
||||
).emit();
|
||||
}
|
||||
visit::walk_stmt(self, stmt);
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, e: &'a ast::Expr) {
|
||||
match e.kind {
|
||||
ast::ExprKind::Type(..) => {
|
||||
if self.sess.parse_sess.span_diagnostic.err_count() == 0 {
|
||||
// To avoid noise about type ascription in common syntax errors,
|
||||
// only emit if it is the *only* error.
|
||||
gate_feature_post!(
|
||||
&self,
|
||||
type_ascription,
|
||||
e.span,
|
||||
"type ascription is experimental"
|
||||
);
|
||||
} else {
|
||||
// And if it isn't, cancel the early-pass warning.
|
||||
if let Some(err) = self
|
||||
.sess
|
||||
.parse_sess
|
||||
.span_diagnostic
|
||||
.steal_diagnostic(e.span, StashKey::EarlySyntaxWarning)
|
||||
{
|
||||
err.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ExprKind::TryBlock(_) => {
|
||||
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
|
||||
}
|
||||
|
|
@ -629,7 +581,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
|||
gate_all!(box_patterns, "box pattern syntax is experimental");
|
||||
gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
|
||||
gate_all!(try_blocks, "`try` blocks are unstable");
|
||||
gate_all!(type_ascription, "type ascription is experimental");
|
||||
|
||||
visit::walk_crate(&mut visitor, krate);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ use rustc_infer::infer::InferCtxt;
|
|||
use rustc_middle::mir::visit::TyContext;
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{
|
||||
BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue,
|
||||
SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
|
||||
Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, SourceInfo, Statement,
|
||||
StatementKind, Terminator, TerminatorKind, UserTypeProjection,
|
||||
};
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::visit::TypeVisitable;
|
||||
|
|
@ -49,10 +49,6 @@ struct ConstraintGeneration<'cg, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'cg, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'tcx> {
|
||||
fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
|
||||
self.super_basic_block_data(bb, data);
|
||||
}
|
||||
|
||||
/// We sometimes have `substs` within an rvalue, or within a
|
||||
/// call. Make them live at the location where they appear.
|
||||
fn visit_substs(&mut self, substs: &SubstsRef<'tcx>, location: Location) {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ macro_rules! impl_visitable {
|
|||
}
|
||||
|
||||
fn reconstruct_before_statement_effect(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut Self::FlowState,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -69,7 +69,7 @@ macro_rules! impl_visitable {
|
|||
}
|
||||
|
||||
fn reconstruct_statement_effect(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut Self::FlowState,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -79,7 +79,7 @@ macro_rules! impl_visitable {
|
|||
}
|
||||
|
||||
fn reconstruct_before_terminator_effect(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut Self::FlowState,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -89,7 +89,7 @@ macro_rules! impl_visitable {
|
|||
}
|
||||
|
||||
fn reconstruct_terminator_effect(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut Self::FlowState,
|
||||
term: &mir::Terminator<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -343,7 +343,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
type Idx = BorrowIndex;
|
||||
|
||||
fn before_statement_effect(
|
||||
&self,
|
||||
&mut self,
|
||||
trans: &mut impl GenKill<Self::Idx>,
|
||||
_statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -352,7 +352,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn statement_effect(
|
||||
&self,
|
||||
&mut self,
|
||||
trans: &mut impl GenKill<Self::Idx>,
|
||||
stmt: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -400,7 +400,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn before_terminator_effect(
|
||||
&self,
|
||||
&mut self,
|
||||
trans: &mut impl GenKill<Self::Idx>,
|
||||
_terminator: &mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -409,7 +409,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn terminator_effect(
|
||||
&self,
|
||||
&mut self,
|
||||
trans: &mut impl GenKill<Self::Idx>,
|
||||
terminator: &mir::Terminator<'tcx>,
|
||||
_location: Location,
|
||||
|
|
@ -426,7 +426,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn call_return_effect(
|
||||
&self,
|
||||
&mut self,
|
||||
_trans: &mut impl GenKill<Self::Idx>,
|
||||
_block: mir::BasicBlock,
|
||||
_return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
|
|
|
|||
|
|
@ -416,12 +416,28 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
_,
|
||||
) = pat.kind
|
||||
{
|
||||
err.span_suggestion(
|
||||
upvar_ident.span,
|
||||
"consider changing this to be mutable",
|
||||
format!("mut {}", upvar_ident.name),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
if upvar_ident.name == kw::SelfLower {
|
||||
for (_, node) in self.infcx.tcx.hir().parent_iter(upvar_hir_id) {
|
||||
if let Some(fn_decl) = node.fn_decl() {
|
||||
if !matches!(fn_decl.implicit_self, hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef) {
|
||||
err.span_suggestion(
|
||||
upvar_ident.span,
|
||||
"consider changing this to be mutable",
|
||||
format!("mut {}", upvar_ident.name),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err.span_suggestion(
|
||||
upvar_ident.span,
|
||||
"consider changing this to be mutable",
|
||||
format!("mut {}", upvar_ident.name),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
|
|
|
|||
|
|
@ -368,7 +368,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
// Compute and report region errors, if any.
|
||||
mbcx.report_region_errors(nll_errors);
|
||||
|
||||
let results = BorrowckResults {
|
||||
let mut results = BorrowckResults {
|
||||
ever_inits: flow_ever_inits,
|
||||
uninits: flow_uninits,
|
||||
borrows: flow_borrows,
|
||||
|
|
@ -379,7 +379,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
rustc_mir_dataflow::visit_results(
|
||||
body,
|
||||
traversal::reverse_postorder(body).map(|(bb, _)| bb),
|
||||
&results,
|
||||
&mut results,
|
||||
&mut mbcx,
|
||||
);
|
||||
|
||||
|
|
@ -598,11 +598,12 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// 2. loans made in overlapping scopes do not conflict
|
||||
// 3. assignments do not affect things loaned out as immutable
|
||||
// 4. moves do not affect things loaned out in any way
|
||||
impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> {
|
||||
impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorrowckCtxt<'cx, 'tcx> {
|
||||
type FlowState = Flows<'cx, 'tcx>;
|
||||
|
||||
fn visit_statement_before_primary_effect(
|
||||
&mut self,
|
||||
_results: &R,
|
||||
flow_state: &Flows<'cx, 'tcx>,
|
||||
stmt: &'cx Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -672,6 +673,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
|||
|
||||
fn visit_terminator_before_primary_effect(
|
||||
&mut self,
|
||||
_results: &R,
|
||||
flow_state: &Flows<'cx, 'tcx>,
|
||||
term: &'cx Terminator<'tcx>,
|
||||
loc: Location,
|
||||
|
|
@ -782,6 +784,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
|||
|
||||
fn visit_terminator_after_primary_effect(
|
||||
&mut self,
|
||||
_results: &R,
|
||||
flow_state: &Flows<'cx, 'tcx>,
|
||||
term: &'cx Terminator<'tcx>,
|
||||
loc: Location,
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
|||
let infcx = self
|
||||
.tcx
|
||||
.infer_ctxt()
|
||||
.with_opaque_type_inference(if self.tcx.trait_solver_next() {
|
||||
.with_opaque_type_inference(if self.next_trait_solver() {
|
||||
DefiningAnchor::Bind(def_id)
|
||||
} else {
|
||||
DefiningAnchor::Bubble
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
|||
|
||||
// FIXME(-Ztrait-solver=next): A bit dubious that we're only registering
|
||||
// predefined opaques in the typeck root.
|
||||
if infcx.tcx.trait_solver_next() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
|
||||
if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
|
||||
checker.register_predefined_opaques_in_new_solver();
|
||||
}
|
||||
|
||||
|
|
@ -477,9 +477,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
|
||||
fn visit_body(&mut self, body: &Body<'tcx>) {
|
||||
self.sanitize_type(&"return type", body.return_ty());
|
||||
for local_decl in &body.local_decls {
|
||||
self.sanitize_type(local_decl, local_decl.ty);
|
||||
}
|
||||
// The types of local_decls are checked above which is called in super_body.
|
||||
self.super_body(body);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -554,9 +554,6 @@ fn report_missing_placeholders(
|
|||
fmt_span: Span,
|
||||
) {
|
||||
let mut diag = if let &[(span, named)] = &unused[..] {
|
||||
//let mut diag = ecx.struct_span_err(span, msg);
|
||||
//diag.span_label(span, msg);
|
||||
//diag
|
||||
ecx.create_err(errors::FormatUnusedArg { span, named })
|
||||
} else {
|
||||
let unused_labels =
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ impl OngoingCodegen {
|
|||
self,
|
||||
sess: &Session,
|
||||
backend_config: &BackendConfig,
|
||||
) -> (CodegenResults, FxHashMap<WorkProductId, WorkProduct>) {
|
||||
let mut work_products = FxHashMap::default();
|
||||
) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
let mut work_products = FxIndexMap::default();
|
||||
let mut modules = vec![];
|
||||
|
||||
for module_codegen in self.modules {
|
||||
|
|
|
|||
|
|
@ -475,9 +475,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
sym::unchecked_add
|
||||
| sym::unchecked_sub
|
||||
| sym::unchecked_mul
|
||||
| sym::unchecked_div
|
||||
| sym::exact_div
|
||||
| sym::unchecked_rem
|
||||
| sym::unchecked_shl
|
||||
| sym::unchecked_shr => {
|
||||
intrinsic_args!(fx, args => (x, y); intrinsic);
|
||||
|
|
@ -487,8 +485,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
sym::unchecked_add => BinOp::Add,
|
||||
sym::unchecked_sub => BinOp::Sub,
|
||||
sym::unchecked_mul => BinOp::Mul,
|
||||
sym::unchecked_div | sym::exact_div => BinOp::Div,
|
||||
sym::unchecked_rem => BinOp::Rem,
|
||||
sym::exact_div => BinOp::Div,
|
||||
sym::unchecked_shl => BinOp::Shl,
|
||||
sym::unchecked_shr => BinOp::Shr,
|
||||
_ => unreachable!(),
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ mod prelude {
|
|||
};
|
||||
pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT};
|
||||
|
||||
pub(crate) use rustc_data_structures::fx::FxHashMap;
|
||||
pub(crate) use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
|
||||
pub(crate) use rustc_index::Idx;
|
||||
|
||||
|
|
@ -223,7 +223,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
ongoing_codegen: Box<dyn Any>,
|
||||
sess: &Session,
|
||||
_outputs: &OutputFilenames,
|
||||
) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
|
||||
) -> Result<(CodegenResults, FxIndexMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
|
||||
Ok(ongoing_codegen
|
||||
.downcast::<driver::aot::OngoingCodegen>()
|
||||
.unwrap()
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig,
|
|||
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
|
||||
use rustc_codegen_ssa::target_features::supported_target_features;
|
||||
use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMessage};
|
||||
use rustc_fluent_macro::fluent_messages;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
|
|
@ -137,7 +137,7 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
Box::new(res)
|
||||
}
|
||||
|
||||
fn join_codegen(&self, ongoing_codegen: Box<dyn Any>, sess: &Session, _outputs: &OutputFilenames) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
|
||||
fn join_codegen(&self, ongoing_codegen: Box<dyn Any>, sess: &Session, _outputs: &OutputFilenames) -> Result<(CodegenResults, FxIndexMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
|
||||
let (codegen_results, work_products) = ongoing_codegen
|
||||
.downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<GccCodegenBackend>>()
|
||||
.expect("Expected GccCodegenBackend's OngoingCodegen, found Box<Any>")
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ test = false
|
|||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
cstr = "0.2"
|
||||
libc = "0.2"
|
||||
measureme = "10.0.0"
|
||||
object = { version = "0.31.1", default-features = false, features = [
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ pub(crate) unsafe fn codegen(
|
|||
llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
|
||||
llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
|
||||
|
||||
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
|
||||
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr().cast());
|
||||
|
||||
let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
|
||||
llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
|
||||
|
|
@ -129,7 +129,7 @@ pub(crate) unsafe fn codegen(
|
|||
attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
|
||||
llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
|
||||
|
||||
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
|
||||
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr().cast());
|
||||
|
||||
let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
|
||||
llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
|
||||
|
|
|
|||
|
|
@ -595,7 +595,7 @@ pub(crate) fn run_pass_manager(
|
|||
llvm::LLVMRustAddModuleFlag(
|
||||
module.module_llvm.llmod(),
|
||||
llvm::LLVMModFlagBehavior::Error,
|
||||
"LTOPostLink\0".as_ptr().cast(),
|
||||
c"LTOPostLink".as_ptr().cast(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -891,11 +891,11 @@ unsafe fn embed_bitcode(
|
|||
let llglobal = llvm::LLVMAddGlobal(
|
||||
llmod,
|
||||
common::val_ty(llconst),
|
||||
"rustc.embedded.module\0".as_ptr().cast(),
|
||||
c"rustc.embedded.module".as_ptr().cast(),
|
||||
);
|
||||
llvm::LLVMSetInitializer(llglobal, llconst);
|
||||
|
||||
let section = if is_apple { "__LLVM,__bitcode\0" } else { ".llvmbc\0" };
|
||||
let section = if is_apple { c"__LLVM,__bitcode" } else { c".llvmbc" };
|
||||
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
|
||||
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
|
||||
|
|
@ -904,10 +904,10 @@ unsafe fn embed_bitcode(
|
|||
let llglobal = llvm::LLVMAddGlobal(
|
||||
llmod,
|
||||
common::val_ty(llconst),
|
||||
"rustc.embedded.cmdline\0".as_ptr().cast(),
|
||||
c"rustc.embedded.cmdline".as_ptr().cast(),
|
||||
);
|
||||
llvm::LLVMSetInitializer(llglobal, llconst);
|
||||
let section = if is_apple { "__LLVM,__cmdline\0" } else { ".llvmcmd\0" };
|
||||
let section = if is_apple { c"__LLVM,__cmdline" } else { c".llvmcmd" };
|
||||
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
|
||||
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ use crate::context::CodegenCx;
|
|||
use crate::llvm;
|
||||
use crate::value::Value;
|
||||
|
||||
use cstr::cstr;
|
||||
|
||||
use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
|
||||
use rustc_codegen_ssa::mono_item::MonoItemExt;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
|
|
@ -110,11 +108,11 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen
|
|||
|
||||
// Create the llvm.used and llvm.compiler.used variables.
|
||||
if !cx.used_statics.borrow().is_empty() {
|
||||
cx.create_used_variable_impl(cstr!("llvm.used"), &*cx.used_statics.borrow());
|
||||
cx.create_used_variable_impl(c"llvm.used", &*cx.used_statics.borrow());
|
||||
}
|
||||
if !cx.compiler_used_statics.borrow().is_empty() {
|
||||
cx.create_used_variable_impl(
|
||||
cstr!("llvm.compiler.used"),
|
||||
c"llvm.compiler.used",
|
||||
&*cx.compiler_used_statics.borrow(),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, True}
|
|||
use crate::type_::Type;
|
||||
use crate::type_of::LayoutLlvmExt;
|
||||
use crate::value::Value;
|
||||
use cstr::cstr;
|
||||
use libc::{c_char, c_uint};
|
||||
use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, SynchronizationScope, TypeKind};
|
||||
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
|
||||
|
|
@ -25,7 +24,6 @@ use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi, Typ
|
|||
use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
|
||||
use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target};
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::CStr;
|
||||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
|
|
@ -45,13 +43,10 @@ impl Drop for Builder<'_, '_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(eddyb) use a checked constructor when they become `const fn`.
|
||||
const EMPTY_C_STR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"\0") };
|
||||
|
||||
/// Empty string, to be used where LLVM expects an instruction name, indicating
|
||||
/// that the instruction is to be left unnamed (i.e. numbered, in textual IR).
|
||||
// FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer.
|
||||
const UNNAMED: *const c_char = EMPTY_C_STR.as_ptr();
|
||||
const UNNAMED: *const c_char = c"".as_ptr();
|
||||
|
||||
impl<'ll, 'tcx> BackendTypes for Builder<'_, 'll, 'tcx> {
|
||||
type Value = <CodegenCx<'ll, 'tcx> as BackendTypes>::Value;
|
||||
|
|
@ -1010,14 +1005,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
fn cleanup_pad(&mut self, parent: Option<&'ll Value>, args: &[&'ll Value]) -> Funclet<'ll> {
|
||||
let name = cstr!("cleanuppad");
|
||||
let ret = unsafe {
|
||||
llvm::LLVMBuildCleanupPad(
|
||||
self.llbuilder,
|
||||
parent,
|
||||
args.as_ptr(),
|
||||
args.len() as c_uint,
|
||||
name.as_ptr(),
|
||||
c"cleanuppad".as_ptr(),
|
||||
)
|
||||
};
|
||||
Funclet::new(ret.expect("LLVM does not have support for cleanuppad"))
|
||||
|
|
@ -1031,14 +1025,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
fn catch_pad(&mut self, parent: &'ll Value, args: &[&'ll Value]) -> Funclet<'ll> {
|
||||
let name = cstr!("catchpad");
|
||||
let ret = unsafe {
|
||||
llvm::LLVMBuildCatchPad(
|
||||
self.llbuilder,
|
||||
parent,
|
||||
args.as_ptr(),
|
||||
args.len() as c_uint,
|
||||
name.as_ptr(),
|
||||
c"catchpad".as_ptr(),
|
||||
)
|
||||
};
|
||||
Funclet::new(ret.expect("LLVM does not have support for catchpad"))
|
||||
|
|
@ -1050,14 +1043,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
unwind: Option<&'ll BasicBlock>,
|
||||
handlers: &[&'ll BasicBlock],
|
||||
) -> &'ll Value {
|
||||
let name = cstr!("catchswitch");
|
||||
let ret = unsafe {
|
||||
llvm::LLVMBuildCatchSwitch(
|
||||
self.llbuilder,
|
||||
parent,
|
||||
unwind,
|
||||
handlers.len() as c_uint,
|
||||
name.as_ptr(),
|
||||
c"catchswitch".as_ptr(),
|
||||
)
|
||||
};
|
||||
let ret = ret.expect("LLVM does not have support for catchswitch");
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ use crate::llvm::{self, True};
|
|||
use crate::type_::Type;
|
||||
use crate::type_of::LayoutLlvmExt;
|
||||
use crate::value::Value;
|
||||
use cstr::cstr;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
|
|
@ -482,9 +481,9 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
|
|||
.all(|&byte| byte == 0);
|
||||
|
||||
let sect_name = if all_bytes_are_zero {
|
||||
cstr!("__DATA,__thread_bss")
|
||||
c"__DATA,__thread_bss"
|
||||
} else {
|
||||
cstr!("__DATA,__thread_data")
|
||||
c"__DATA,__thread_data"
|
||||
};
|
||||
llvm::LLVMSetSection(g, sect_name.as_ptr());
|
||||
}
|
||||
|
|
@ -513,7 +512,7 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
|
|||
let val = llvm::LLVMMetadataAsValue(self.llcx, meta);
|
||||
llvm::LLVMAddNamedMetadataOperand(
|
||||
self.llmod,
|
||||
"wasm.custom_sections\0".as_ptr().cast(),
|
||||
c"wasm.custom_sections".as_ptr().cast(),
|
||||
val,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ use crate::llvm_util;
|
|||
use crate::type_::Type;
|
||||
use crate::value::Value;
|
||||
|
||||
use cstr::cstr;
|
||||
use rustc_codegen_ssa::base::wants_msvc_seh;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_data_structures::base_n;
|
||||
|
|
@ -224,36 +223,42 @@ pub unsafe fn create_module<'ll>(
|
|||
// If skipping the PLT is enabled, we need to add some module metadata
|
||||
// to ensure intrinsic calls don't use it.
|
||||
if !sess.needs_plt() {
|
||||
let avoid_plt = "RtLibUseGOT\0".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"RtLibUseGOT".as_ptr().cast(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
// Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
|
||||
if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
|
||||
let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
canonical_jump_tables,
|
||||
c"CFI Canonical Jump Tables".as_ptr().cast(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
// Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.)
|
||||
if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
|
||||
let enable_split_lto_unit = "EnableSplitLTOUnit\0".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
enable_split_lto_unit,
|
||||
c"EnableSplitLTOUnit".as_ptr().cast(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
|
||||
if sess.is_sanitizer_kcfi_enabled() {
|
||||
let kcfi = "kcfi\0".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
c"kcfi".as_ptr().cast(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
|
||||
|
|
@ -265,7 +270,7 @@ pub unsafe fn create_module<'ll>(
|
|||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
"cfguard\0".as_ptr() as *const _,
|
||||
c"cfguard".as_ptr() as *const _,
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
|
@ -274,7 +279,7 @@ pub unsafe fn create_module<'ll>(
|
|||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
"cfguard\0".as_ptr() as *const _,
|
||||
c"cfguard".as_ptr() as *const _,
|
||||
2,
|
||||
)
|
||||
}
|
||||
|
|
@ -292,26 +297,26 @@ pub unsafe fn create_module<'ll>(
|
|||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
behavior,
|
||||
"branch-target-enforcement\0".as_ptr().cast(),
|
||||
c"branch-target-enforcement".as_ptr().cast(),
|
||||
bti.into(),
|
||||
);
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
behavior,
|
||||
"sign-return-address\0".as_ptr().cast(),
|
||||
c"sign-return-address".as_ptr().cast(),
|
||||
pac_ret.is_some().into(),
|
||||
);
|
||||
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
behavior,
|
||||
"sign-return-address-all\0".as_ptr().cast(),
|
||||
c"sign-return-address-all".as_ptr().cast(),
|
||||
pac_opts.leaf.into(),
|
||||
);
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
behavior,
|
||||
"sign-return-address-with-bkey\0".as_ptr().cast(),
|
||||
c"sign-return-address-with-bkey".as_ptr().cast(),
|
||||
u32::from(pac_opts.key == PAuthKey::B),
|
||||
);
|
||||
} else {
|
||||
|
|
@ -327,7 +332,7 @@ pub unsafe fn create_module<'ll>(
|
|||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
"cf-protection-branch\0".as_ptr().cast(),
|
||||
c"cf-protection-branch".as_ptr().cast(),
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
|
@ -335,7 +340,7 @@ pub unsafe fn create_module<'ll>(
|
|||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
"cf-protection-return\0".as_ptr().cast(),
|
||||
c"cf-protection-return".as_ptr().cast(),
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
|
@ -344,7 +349,7 @@ pub unsafe fn create_module<'ll>(
|
|||
llvm::LLVMRustAddModuleFlag(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Error,
|
||||
"Virtual Function Elim\0".as_ptr().cast(),
|
||||
c"Virtual Function Elim".as_ptr().cast(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
|
@ -476,14 +481,13 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
}
|
||||
|
||||
pub(crate) fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {
|
||||
let section = cstr!("llvm.metadata");
|
||||
let array = self.const_array(self.type_ptr_to(self.type_i8()), values);
|
||||
|
||||
unsafe {
|
||||
let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
|
||||
llvm::LLVMSetInitializer(g, array);
|
||||
llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
|
||||
llvm::LLVMSetSection(g, section.as_ptr());
|
||||
llvm::LLVMSetSection(g, c"llvm.metadata".as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, '
|
|||
unsafe { llvm::LLVMGetNamedGlobal(cx.llmod, c_section_var_name.as_ptr().cast()) };
|
||||
|
||||
section_var.unwrap_or_else(|| {
|
||||
let section_name = b".debug_gdb_scripts\0";
|
||||
let mut section_contents = Vec::new();
|
||||
|
||||
// Add the pretty printers for the standard library first.
|
||||
|
|
@ -71,7 +70,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'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, section_name.as_ptr().cast());
|
||||
llvm::LLVMSetSection(section_var, c".debug_gdb_scripts".as_ptr().cast());
|
||||
llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents));
|
||||
llvm::LLVMSetGlobalConstant(section_var, llvm::True);
|
||||
llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ use crate::llvm::debuginfo::{
|
|||
};
|
||||
use crate::value::Value;
|
||||
|
||||
use cstr::cstr;
|
||||
use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo;
|
||||
use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
|
|
@ -812,7 +811,6 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
|
|||
|
||||
let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
|
||||
let work_dir = tcx.sess.opts.working_dir.to_string_lossy(FileNameDisplayPreference::Remapped);
|
||||
let flags = "\0";
|
||||
let output_filenames = tcx.output_filenames(());
|
||||
let split_name = if tcx.sess.target_can_use_split_dwarf() {
|
||||
output_filenames
|
||||
|
|
@ -849,7 +847,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
|
|||
producer.as_ptr().cast(),
|
||||
producer.len(),
|
||||
tcx.sess.opts.optimize != config::OptLevel::No,
|
||||
flags.as_ptr().cast(),
|
||||
c"".as_ptr().cast(),
|
||||
0,
|
||||
// NB: this doesn't actually have any perceptible effect, it seems. LLVM will instead
|
||||
// put the path supplied to `MCSplitDwarfFile` into the debug info of the final
|
||||
|
|
@ -878,8 +876,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
|
|||
);
|
||||
let val = llvm::LLVMMetadataAsValue(debug_context.llcontext, gcov_metadata);
|
||||
|
||||
let llvm_gcov_ident = cstr!("llvm.gcov");
|
||||
llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, llvm_gcov_ident.as_ptr(), val);
|
||||
llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, c"llvm.gcov".as_ptr(), val);
|
||||
}
|
||||
|
||||
// Insert `llvm.ident` metadata on the wasm targets since that will
|
||||
|
|
@ -892,7 +889,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
|
|||
);
|
||||
llvm::LLVMAddNamedMetadataOperand(
|
||||
debug_context.llmod,
|
||||
cstr!("llvm.ident").as_ptr(),
|
||||
c"llvm.ident".as_ptr(),
|
||||
llvm::LLVMMDNodeInContext(debug_context.llcontext, &name_metadata, 1),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
|
|||
llvm::LLVMRustAddModuleFlag(
|
||||
self.llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
"Dwarf Version\0".as_ptr().cast(),
|
||||
c"Dwarf Version".as_ptr().cast(),
|
||||
dwarf_version,
|
||||
);
|
||||
} else {
|
||||
|
|
@ -121,17 +121,16 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
|
|||
llvm::LLVMRustAddModuleFlag(
|
||||
self.llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
"CodeView\0".as_ptr().cast(),
|
||||
c"CodeView".as_ptr().cast(),
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
||||
// Prevent bitcode readers from deleting the debug info.
|
||||
let ptr = "Debug Info Version\0".as_ptr();
|
||||
llvm::LLVMRustAddModuleFlag(
|
||||
self.llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
ptr.cast(),
|
||||
c"Debug Info Version".as_ptr().cast(),
|
||||
llvm::LLVMRustDebugMetadataVersion(),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#![feature(let_chains)]
|
||||
#![feature(never_type)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![feature(c_str_literals)]
|
||||
#![recursion_limit = "256"]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
|
|
@ -33,7 +34,7 @@ use rustc_codegen_ssa::back::write::{
|
|||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_codegen_ssa::ModuleCodegen;
|
||||
use rustc_codegen_ssa::{CodegenResults, CompiledModule};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, FatalError, Handler, SubdiagnosticMessage};
|
||||
use rustc_fluent_macro::fluent_messages;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
|
|
@ -355,7 +356,7 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
ongoing_codegen: Box<dyn Any>,
|
||||
sess: &Session,
|
||||
outputs: &OutputFilenames,
|
||||
) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
|
||||
) -> Result<(CodegenResults, FxIndexMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
|
||||
let (codegen_results, work_products) = ongoing_codegen
|
||||
.downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
|
||||
.expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
|
||||
|
|
|
|||
|
|
@ -288,6 +288,9 @@ impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
fn reg_backend_type(&self, ty: &Reg) -> &'ll Type {
|
||||
ty.llvm_type(self)
|
||||
}
|
||||
fn scalar_copy_backend_type(&self, layout: TyAndLayout<'tcx>) -> Option<Self::Type> {
|
||||
layout.scalar_copy_llvm_type(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use rustc_middle::bug;
|
|||
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
use rustc_target::abi::HasDataLayout;
|
||||
use rustc_target::abi::{Abi, Align, FieldsShape};
|
||||
use rustc_target::abi::{Int, Pointer, F32, F64};
|
||||
use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants};
|
||||
|
|
@ -192,6 +193,7 @@ pub trait LayoutLlvmExt<'tcx> {
|
|||
) -> &'a Type;
|
||||
fn llvm_field_index<'a>(&self, cx: &CodegenCx<'a, 'tcx>, index: usize) -> u64;
|
||||
fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option<PointeeInfo>;
|
||||
fn scalar_copy_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<&'a Type>;
|
||||
}
|
||||
|
||||
impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
|
||||
|
|
@ -414,4 +416,35 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
|
|||
cx.pointee_infos.borrow_mut().insert((self.ty, offset), result);
|
||||
result
|
||||
}
|
||||
|
||||
fn scalar_copy_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<&'a Type> {
|
||||
debug_assert!(self.is_sized());
|
||||
|
||||
// FIXME: this is a fairly arbitrary choice, but 128 bits on WASM
|
||||
// (matching the 128-bit SIMD types proposal) and 256 bits on x64
|
||||
// (like AVX2 registers) seems at least like a tolerable starting point.
|
||||
let threshold = cx.data_layout().pointer_size * 4;
|
||||
if self.layout.size() > threshold {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Vectors, even for non-power-of-two sizes, have the same layout as
|
||||
// arrays but don't count as aggregate types
|
||||
if let FieldsShape::Array { count, .. } = self.layout.fields()
|
||||
&& let element = self.field(cx, 0)
|
||||
&& element.ty.is_integral()
|
||||
{
|
||||
// `cx.type_ix(bits)` is tempting here, but while that works great
|
||||
// for things that *stay* as memory-to-memory copies, it also ends
|
||||
// up suppressing vectorization as it introduces shifts when it
|
||||
// extracts all the individual values.
|
||||
|
||||
let ety = element.llvm_type(cx);
|
||||
return Some(cx.type_vector(ety, *count));
|
||||
}
|
||||
|
||||
// FIXME: The above only handled integer arrays; surely more things
|
||||
// would also be possible. Be careful about provenance, though!
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ libc = "0.2.50"
|
|||
[dependencies.object]
|
||||
version = "0.31.1"
|
||||
default-features = false
|
||||
features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
|
||||
features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write"]
|
||||
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.48.0"
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ codegen_ssa_archive_build_failure =
|
|||
|
||||
codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
|
||||
|
||||
codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty
|
||||
|
||||
codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
|
||||
|
||||
codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_errors::{ErrorGuaranteed, Handler};
|
|||
use rustc_fs_util::fix_windows_verbatim_for_gcc;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_metadata::find_native_static_library;
|
||||
use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME};
|
||||
use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME};
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
use rustc_middle::middle::dependency_format::Linkage;
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
|
|
@ -68,6 +68,7 @@ pub fn link_binary<'a>(
|
|||
) -> Result<(), ErrorGuaranteed> {
|
||||
let _timer = sess.timer("link_binary");
|
||||
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
|
||||
let mut tempfiles_for_stdout_output: Vec<PathBuf> = Vec::new();
|
||||
for &crate_type in sess.crate_types().iter() {
|
||||
// Ignore executable crates if we have -Z no-codegen, as they will error.
|
||||
if (sess.opts.unstable_opts.no_codegen || !sess.opts.output_types.should_codegen())
|
||||
|
|
@ -97,12 +98,15 @@ pub fn link_binary<'a>(
|
|||
.tempdir()
|
||||
.unwrap_or_else(|error| sess.emit_fatal(errors::CreateTempDir { error }));
|
||||
let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps);
|
||||
let out_filename = out_filename(
|
||||
let output = out_filename(
|
||||
sess,
|
||||
crate_type,
|
||||
outputs,
|
||||
codegen_results.crate_info.local_crate_name,
|
||||
);
|
||||
let crate_name = format!("{}", codegen_results.crate_info.local_crate_name);
|
||||
let out_filename =
|
||||
output.file_for_writing(outputs, OutputType::Exe, Some(crate_name.as_str()));
|
||||
match crate_type {
|
||||
CrateType::Rlib => {
|
||||
let _timer = sess.timer("link_rlib");
|
||||
|
|
@ -152,6 +156,17 @@ pub fn link_binary<'a>(
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
if output.is_stdout() {
|
||||
if output.is_tty() {
|
||||
sess.emit_err(errors::BinaryOutputToTty {
|
||||
shorthand: OutputType::Exe.shorthand(),
|
||||
});
|
||||
} else if let Err(e) = copy_to_stdout(&out_filename) {
|
||||
sess.emit_err(errors::CopyPath::new(&out_filename, output.as_path(), e));
|
||||
}
|
||||
tempfiles_for_stdout_output.push(out_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -189,6 +204,11 @@ pub fn link_binary<'a>(
|
|||
remove_temps_from_module(allocator_module);
|
||||
}
|
||||
|
||||
// Remove the temporary files if output goes to stdout
|
||||
for temp in tempfiles_for_stdout_output {
|
||||
ensure_removed(sess.diagnostic(), &temp);
|
||||
}
|
||||
|
||||
// If no requested outputs require linking, then the object temporaries should
|
||||
// be kept.
|
||||
if !sess.opts.output_types.should_link() {
|
||||
|
|
@ -2097,7 +2117,14 @@ fn linker_with_args<'a>(
|
|||
cmd.add_as_needed();
|
||||
|
||||
// Local native libraries of all kinds.
|
||||
add_local_native_libraries(cmd, sess, archive_builder_builder, codegen_results, tmpdir);
|
||||
add_local_native_libraries(
|
||||
cmd,
|
||||
sess,
|
||||
archive_builder_builder,
|
||||
codegen_results,
|
||||
tmpdir,
|
||||
link_output_kind,
|
||||
);
|
||||
|
||||
// Upstream rust crates and their non-dynamic native libraries.
|
||||
add_upstream_rust_crates(
|
||||
|
|
@ -2107,10 +2134,18 @@ fn linker_with_args<'a>(
|
|||
codegen_results,
|
||||
crate_type,
|
||||
tmpdir,
|
||||
link_output_kind,
|
||||
);
|
||||
|
||||
// Dynamic native libraries from upstream crates.
|
||||
add_upstream_native_libraries(cmd, sess, archive_builder_builder, codegen_results, tmpdir);
|
||||
add_upstream_native_libraries(
|
||||
cmd,
|
||||
sess,
|
||||
archive_builder_builder,
|
||||
codegen_results,
|
||||
tmpdir,
|
||||
link_output_kind,
|
||||
);
|
||||
|
||||
// Link with the import library generated for any raw-dylib functions.
|
||||
for (raw_dylib_name, raw_dylib_imports) in
|
||||
|
|
@ -2256,11 +2291,13 @@ fn add_order_independent_options(
|
|||
} else if flavor == LinkerFlavor::Bpf {
|
||||
cmd.arg("--cpu");
|
||||
cmd.arg(&codegen_results.crate_info.target_cpu);
|
||||
cmd.arg("--cpu-features");
|
||||
cmd.arg(match &sess.opts.cg.target_feature {
|
||||
feat if !feat.is_empty() => feat.as_ref(),
|
||||
_ => sess.target.options.features.as_ref(),
|
||||
});
|
||||
if let Some(feat) = [sess.opts.cg.target_feature.as_str(), &sess.target.options.features]
|
||||
.into_iter()
|
||||
.find(|feat| !feat.is_empty())
|
||||
{
|
||||
cmd.arg("--cpu-features");
|
||||
cmd.arg(feat);
|
||||
}
|
||||
}
|
||||
|
||||
cmd.linker_plugin_lto();
|
||||
|
|
@ -2365,6 +2402,7 @@ fn add_native_libs_from_crate(
|
|||
cnum: CrateNum,
|
||||
link_static: bool,
|
||||
link_dynamic: bool,
|
||||
link_output_kind: LinkOutputKind,
|
||||
) {
|
||||
if !sess.opts.unstable_opts.link_native_libraries {
|
||||
// If `-Zlink-native-libraries=false` is set, then the assumption is that an
|
||||
|
|
@ -2444,8 +2482,16 @@ fn add_native_libs_from_crate(
|
|||
}
|
||||
}
|
||||
NativeLibKind::Unspecified => {
|
||||
if link_dynamic {
|
||||
cmd.link_dylib(name, verbatim, true);
|
||||
// If we are generating a static binary, prefer static library when the
|
||||
// link kind is unspecified.
|
||||
if !link_output_kind.can_link_dylib() && !sess.target.crt_static_allows_dylibs {
|
||||
if link_static {
|
||||
cmd.link_staticlib(name, verbatim)
|
||||
}
|
||||
} else {
|
||||
if link_dynamic {
|
||||
cmd.link_dylib(name, verbatim, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeLibKind::Framework { as_needed } => {
|
||||
|
|
@ -2472,6 +2518,7 @@ fn add_local_native_libraries(
|
|||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||
codegen_results: &CodegenResults,
|
||||
tmpdir: &Path,
|
||||
link_output_kind: LinkOutputKind,
|
||||
) {
|
||||
if sess.opts.unstable_opts.link_native_libraries {
|
||||
// User-supplied library search paths (-L on the command line). These are the same paths
|
||||
|
|
@ -2501,6 +2548,7 @@ fn add_local_native_libraries(
|
|||
LOCAL_CRATE,
|
||||
link_static,
|
||||
link_dynamic,
|
||||
link_output_kind,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -2511,6 +2559,7 @@ fn add_upstream_rust_crates<'a>(
|
|||
codegen_results: &CodegenResults,
|
||||
crate_type: CrateType,
|
||||
tmpdir: &Path,
|
||||
link_output_kind: LinkOutputKind,
|
||||
) {
|
||||
// All of the heavy lifting has previously been accomplished by the
|
||||
// dependency_format module of the compiler. This is just crawling the
|
||||
|
|
@ -2588,6 +2637,7 @@ fn add_upstream_rust_crates<'a>(
|
|||
cnum,
|
||||
link_static,
|
||||
link_dynamic,
|
||||
link_output_kind,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -2598,6 +2648,7 @@ fn add_upstream_native_libraries(
|
|||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||
codegen_results: &CodegenResults,
|
||||
tmpdir: &Path,
|
||||
link_output_kind: LinkOutputKind,
|
||||
) {
|
||||
let search_path = OnceCell::new();
|
||||
for &cnum in &codegen_results.crate_info.used_crates {
|
||||
|
|
@ -2626,6 +2677,7 @@ fn add_upstream_native_libraries(
|
|||
cnum,
|
||||
link_static,
|
||||
link_dynamic,
|
||||
link_output_kind,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ use std::path::Path;
|
|||
|
||||
use object::write::{self, StandardSegment, Symbol, SymbolSection};
|
||||
use object::{
|
||||
elf, pe, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection,
|
||||
SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope,
|
||||
elf, pe, xcoff, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection,
|
||||
ObjectSymbol, SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope,
|
||||
};
|
||||
|
||||
use snap::write::FrameEncoder;
|
||||
|
|
@ -35,6 +35,8 @@ use rustc_target::spec::{RelocModel, Target};
|
|||
#[derive(Debug)]
|
||||
pub struct DefaultMetadataLoader;
|
||||
|
||||
static AIX_METADATA_SYMBOL_NAME: &'static str = "__aix_rust_metadata";
|
||||
|
||||
fn load_metadata_with(
|
||||
path: &Path,
|
||||
f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>,
|
||||
|
|
@ -48,7 +50,7 @@ fn load_metadata_with(
|
|||
}
|
||||
|
||||
impl MetadataLoader for DefaultMetadataLoader {
|
||||
fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> {
|
||||
fn get_rlib_metadata(&self, target: &Target, path: &Path) -> Result<OwnedSlice, String> {
|
||||
load_metadata_with(path, |data| {
|
||||
let archive = object::read::archive::ArchiveFile::parse(&*data)
|
||||
.map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
|
||||
|
|
@ -60,7 +62,11 @@ impl MetadataLoader for DefaultMetadataLoader {
|
|||
let data = entry
|
||||
.data(data)
|
||||
.map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
|
||||
return search_for_section(path, data, ".rmeta");
|
||||
if target.is_like_aix {
|
||||
return get_metadata_xcoff(path, data);
|
||||
} else {
|
||||
return search_for_section(path, data, ".rmeta");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -68,8 +74,12 @@ impl MetadataLoader for DefaultMetadataLoader {
|
|||
})
|
||||
}
|
||||
|
||||
fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> {
|
||||
load_metadata_with(path, |data| search_for_section(path, data, ".rustc"))
|
||||
fn get_dylib_metadata(&self, target: &Target, path: &Path) -> Result<OwnedSlice, String> {
|
||||
if target.is_like_aix {
|
||||
load_metadata_with(path, |data| get_metadata_xcoff(path, data))
|
||||
} else {
|
||||
load_metadata_with(path, |data| search_for_section(path, data, ".rustc"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -141,6 +151,33 @@ fn add_gnu_property_note(
|
|||
file.append_section_data(section, &data, 8);
|
||||
}
|
||||
|
||||
pub(super) fn get_metadata_xcoff<'a>(path: &Path, data: &'a [u8]) -> Result<&'a [u8], String> {
|
||||
let Ok(file) = object::File::parse(data) else {
|
||||
return Ok(data);
|
||||
};
|
||||
let info_data = search_for_section(path, data, ".info")?;
|
||||
if let Some(metadata_symbol) =
|
||||
file.symbols().find(|sym| sym.name() == Ok(AIX_METADATA_SYMBOL_NAME))
|
||||
{
|
||||
let offset = metadata_symbol.address() as usize;
|
||||
if offset < 4 {
|
||||
return Err(format!("Invalid metadata symbol offset: {}", offset));
|
||||
}
|
||||
// The offset specifies the location of rustc metadata in the comment section.
|
||||
// The metadata is preceded by a 4-byte length field.
|
||||
let len = u32::from_be_bytes(info_data[(offset - 4)..offset].try_into().unwrap()) as usize;
|
||||
if offset + len > (info_data.len() as usize) {
|
||||
return Err(format!(
|
||||
"Metadata at offset {} with size {} is beyond .info section",
|
||||
offset, len
|
||||
));
|
||||
}
|
||||
return Ok(&info_data[offset..(offset + len)]);
|
||||
} else {
|
||||
return Err(format!("Unable to find symbol {}", AIX_METADATA_SYMBOL_NAME));
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
|
||||
let endianness = match sess.target.options.endian {
|
||||
Endian::Little => Endianness::Little,
|
||||
|
|
@ -183,6 +220,8 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
|||
BinaryFormat::MachO
|
||||
} else if sess.target.is_like_windows {
|
||||
BinaryFormat::Coff
|
||||
} else if sess.target.is_like_aix {
|
||||
BinaryFormat::Xcoff
|
||||
} else {
|
||||
BinaryFormat::Elf
|
||||
};
|
||||
|
|
@ -351,11 +390,15 @@ pub fn create_wrapper_file(
|
|||
// to add a case above.
|
||||
return (data.to_vec(), MetadataPosition::Last);
|
||||
};
|
||||
let section = file.add_section(
|
||||
file.segment_name(StandardSegment::Debug).to_vec(),
|
||||
section_name,
|
||||
SectionKind::Debug,
|
||||
);
|
||||
let section = if file.format() == BinaryFormat::Xcoff {
|
||||
file.add_section(Vec::new(), b".info".to_vec(), SectionKind::Debug)
|
||||
} else {
|
||||
file.add_section(
|
||||
file.segment_name(StandardSegment::Debug).to_vec(),
|
||||
section_name,
|
||||
SectionKind::Debug,
|
||||
)
|
||||
};
|
||||
match file.format() {
|
||||
BinaryFormat::Coff => {
|
||||
file.section_mut(section).flags =
|
||||
|
|
@ -365,6 +408,31 @@ pub fn create_wrapper_file(
|
|||
file.section_mut(section).flags =
|
||||
SectionFlags::Elf { sh_flags: elf::SHF_EXCLUDE as u64 };
|
||||
}
|
||||
BinaryFormat::Xcoff => {
|
||||
// AIX system linker may aborts if it meets a valid XCOFF file in archive with no .text, no .data and no .bss.
|
||||
file.add_section(Vec::new(), b".text".to_vec(), SectionKind::Text);
|
||||
file.section_mut(section).flags =
|
||||
SectionFlags::Xcoff { s_flags: xcoff::STYP_INFO as u32 };
|
||||
|
||||
let len = data.len() as u32;
|
||||
let offset = file.append_section_data(section, &len.to_be_bytes(), 1);
|
||||
// Add a symbol referring to the data in .info section.
|
||||
file.add_symbol(Symbol {
|
||||
name: AIX_METADATA_SYMBOL_NAME.into(),
|
||||
value: offset + 4,
|
||||
size: 0,
|
||||
kind: SymbolKind::Unknown,
|
||||
scope: SymbolScope::Compilation,
|
||||
weak: false,
|
||||
section: SymbolSection::Section(section),
|
||||
flags: SymbolFlags::Xcoff {
|
||||
n_sclass: xcoff::C_INFO,
|
||||
x_smtyp: xcoff::C_HIDEXT,
|
||||
x_smclas: xcoff::C_HIDEXT,
|
||||
containing_csect: None,
|
||||
},
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
file.append_section_data(section, data, 1);
|
||||
|
|
@ -401,6 +469,9 @@ pub fn create_compressed_metadata_file(
|
|||
let Some(mut file) = create_object_file(sess) else {
|
||||
return compressed.to_vec();
|
||||
};
|
||||
if file.format() == BinaryFormat::Xcoff {
|
||||
return create_compressed_metadata_file_for_xcoff(file, &compressed, symbol_name);
|
||||
}
|
||||
let section = file.add_section(
|
||||
file.segment_name(StandardSegment::Data).to_vec(),
|
||||
b".rustc".to_vec(),
|
||||
|
|
@ -430,3 +501,61 @@ pub fn create_compressed_metadata_file(
|
|||
|
||||
file.write().unwrap()
|
||||
}
|
||||
|
||||
/// * Xcoff - On AIX, custom sections are merged into predefined sections,
|
||||
/// so custom .rustc section is not preserved during linking.
|
||||
/// For this reason, we store metadata in predefined .info section, and
|
||||
/// define a symbol to reference the metadata. To preserve metadata during
|
||||
/// linking on AIX, we have to
|
||||
/// 1. Create an empty .text section, a empty .data section.
|
||||
/// 2. Define an empty symbol named `symbol_name` inside .data section.
|
||||
/// 3. Define an symbol named `AIX_METADATA_SYMBOL_NAME` referencing
|
||||
/// data inside .info section.
|
||||
/// From XCOFF's view, (2) creates a csect entry in the symbol table, the
|
||||
/// symbol created by (3) is a info symbol for the preceding csect. Thus
|
||||
/// two symbols are preserved during linking and we can use the second symbol
|
||||
/// to reference the metadata.
|
||||
pub fn create_compressed_metadata_file_for_xcoff(
|
||||
mut file: write::Object<'_>,
|
||||
data: &[u8],
|
||||
symbol_name: &str,
|
||||
) -> Vec<u8> {
|
||||
assert!(file.format() == BinaryFormat::Xcoff);
|
||||
// AIX system linker may aborts if it meets a valid XCOFF file in archive with no .text, no .data and no .bss.
|
||||
file.add_section(Vec::new(), b".text".to_vec(), SectionKind::Text);
|
||||
let data_section = file.add_section(Vec::new(), b".data".to_vec(), SectionKind::Data);
|
||||
let section = file.add_section(Vec::new(), b".info".to_vec(), SectionKind::Debug);
|
||||
file.add_file_symbol("lib.rmeta".into());
|
||||
file.section_mut(section).flags = SectionFlags::Xcoff { s_flags: xcoff::STYP_INFO as u32 };
|
||||
// Add a global symbol to data_section.
|
||||
file.add_symbol(Symbol {
|
||||
name: symbol_name.as_bytes().into(),
|
||||
value: 0,
|
||||
size: 0,
|
||||
kind: SymbolKind::Data,
|
||||
scope: SymbolScope::Dynamic,
|
||||
weak: true,
|
||||
section: SymbolSection::Section(data_section),
|
||||
flags: SymbolFlags::None,
|
||||
});
|
||||
let len = data.len() as u32;
|
||||
let offset = file.append_section_data(section, &len.to_be_bytes(), 1);
|
||||
// Add a symbol referring to the rustc metadata.
|
||||
file.add_symbol(Symbol {
|
||||
name: AIX_METADATA_SYMBOL_NAME.into(),
|
||||
value: offset + 4, // The metadata is preceded by a 4-byte length field.
|
||||
size: 0,
|
||||
kind: SymbolKind::Unknown,
|
||||
scope: SymbolScope::Dynamic,
|
||||
weak: false,
|
||||
section: SymbolSection::Section(section),
|
||||
flags: SymbolFlags::Xcoff {
|
||||
n_sclass: xcoff::C_INFO,
|
||||
x_smtyp: xcoff::C_HIDEXT,
|
||||
x_smclas: xcoff::C_HIDEXT,
|
||||
containing_csect: None,
|
||||
},
|
||||
});
|
||||
file.append_section_data(section, data, 1);
|
||||
file.write().unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
};
|
||||
use jobserver::{Acquired, Client};
|
||||
use rustc_ast::attr;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||
use rustc_data_structures::profiling::TimingGuard;
|
||||
|
|
@ -23,12 +23,13 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
|||
use rustc_incremental::{
|
||||
copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess,
|
||||
};
|
||||
use rustc_metadata::fs::copy_to_stdout;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportInfo;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::cgu_reuse_tracker::CguReuseTracker;
|
||||
use rustc_session::config::{self, CrateType, Lto, OutputFilenames, OutputType};
|
||||
use rustc_session::config::{self, CrateType, Lto, OutFileName, OutputFilenames, OutputType};
|
||||
use rustc_session::config::{Passes, SwitchWithOptPath};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
|
|
@ -498,8 +499,8 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
|
||||
sess: &Session,
|
||||
compiled_modules: &CompiledModules,
|
||||
) -> FxHashMap<WorkProductId, WorkProduct> {
|
||||
let mut work_products = FxHashMap::default();
|
||||
) -> FxIndexMap<WorkProductId, WorkProduct> {
|
||||
let mut work_products = FxIndexMap::default();
|
||||
|
||||
if sess.opts.incremental.is_none() {
|
||||
return work_products;
|
||||
|
|
@ -535,9 +536,16 @@ fn produce_final_output_artifacts(
|
|||
let mut user_wants_objects = false;
|
||||
|
||||
// Produce final compile outputs.
|
||||
let copy_gracefully = |from: &Path, to: &Path| {
|
||||
if let Err(e) = fs::copy(from, to) {
|
||||
sess.emit_err(errors::CopyPath::new(from, to, e));
|
||||
let copy_gracefully = |from: &Path, to: &OutFileName| match to {
|
||||
OutFileName::Stdout => {
|
||||
if let Err(e) = copy_to_stdout(from) {
|
||||
sess.emit_err(errors::CopyPath::new(from, to.as_path(), e));
|
||||
}
|
||||
}
|
||||
OutFileName::Real(path) => {
|
||||
if let Err(e) = fs::copy(from, path) {
|
||||
sess.emit_err(errors::CopyPath::new(from, path, e));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -547,7 +555,12 @@ fn produce_final_output_artifacts(
|
|||
// to copy `foo.0.x` to `foo.x`.
|
||||
let module_name = Some(&compiled_modules.modules[0].name[..]);
|
||||
let path = crate_output.temp_path(output_type, module_name);
|
||||
copy_gracefully(&path, &crate_output.path(output_type));
|
||||
let output = crate_output.path(output_type);
|
||||
if !output_type.is_text_output() && output.is_tty() {
|
||||
sess.emit_err(errors::BinaryOutputToTty { shorthand: output_type.shorthand() });
|
||||
} else {
|
||||
copy_gracefully(&path, &output);
|
||||
}
|
||||
if !sess.opts.cg.save_temps && !keep_numbered {
|
||||
// The user just wants `foo.x`, not `foo.#module-name#.x`.
|
||||
ensure_removed(sess.diagnostic(), &path);
|
||||
|
|
@ -1885,7 +1898,7 @@ pub struct OngoingCodegen<B: ExtraBackendMethods> {
|
|||
}
|
||||
|
||||
impl<B: ExtraBackendMethods> OngoingCodegen<B> {
|
||||
pub fn join(self, sess: &Session) -> (CodegenResults, FxHashMap<WorkProductId, WorkProduct>) {
|
||||
pub fn join(self, sess: &Session) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
|
||||
let _timer = sess.timer("finish_ongoing_codegen");
|
||||
|
||||
self.shared_emitter_main.check(sess, true);
|
||||
|
|
|
|||
|
|
@ -380,7 +380,19 @@ pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
return;
|
||||
}
|
||||
|
||||
bx.memcpy(dst, dst_align, src, src_align, bx.cx().const_usize(size), flags);
|
||||
if flags == MemFlags::empty()
|
||||
&& let Some(bty) = bx.cx().scalar_copy_backend_type(layout)
|
||||
{
|
||||
// I look forward to only supporting opaque pointers
|
||||
let pty = bx.type_ptr_to(bty);
|
||||
let src = bx.pointercast(src, pty);
|
||||
let dst = bx.pointercast(dst, pty);
|
||||
|
||||
let temp = bx.load(bty, src, src_align);
|
||||
bx.store(temp, dst, dst_align);
|
||||
} else {
|
||||
bx.memcpy(dst, dst_align, src, src_align, bx.cx().const_usize(size), flags);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
|
|
|
|||
|
|
@ -82,6 +82,12 @@ impl IntoDiagnosticArg for DebugArgPath<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_binary_output_to_tty)]
|
||||
pub struct BinaryOutputToTty {
|
||||
pub shorthand: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_ignoring_emit_path)]
|
||||
pub struct IgnoringEmitPath {
|
||||
|
|
|
|||
|
|
@ -211,8 +211,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
args[1].val.unaligned_volatile_store(bx, dst);
|
||||
return;
|
||||
}
|
||||
| sym::unchecked_div
|
||||
| sym::unchecked_rem
|
||||
| sym::unchecked_shl
|
||||
| sym::unchecked_shr
|
||||
| sym::unchecked_add
|
||||
|
|
@ -229,20 +227,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bx.exactudiv(args[0].immediate(), args[1].immediate())
|
||||
}
|
||||
}
|
||||
sym::unchecked_div => {
|
||||
if signed {
|
||||
bx.sdiv(args[0].immediate(), args[1].immediate())
|
||||
} else {
|
||||
bx.udiv(args[0].immediate(), args[1].immediate())
|
||||
}
|
||||
}
|
||||
sym::unchecked_rem => {
|
||||
if signed {
|
||||
bx.srem(args[0].immediate(), args[1].immediate())
|
||||
} else {
|
||||
bx.urem(args[0].immediate(), args[1].immediate())
|
||||
}
|
||||
}
|
||||
sym::unchecked_shl => bx.shl(args[0].immediate(), args[1].immediate()),
|
||||
sym::unchecked_shr => {
|
||||
if signed {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use crate::back::write::TargetMachineFactoryFn;
|
|||
use crate::{CodegenResults, ModuleCodegen};
|
||||
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::sync::{DynSend, DynSync};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
|
|
@ -101,7 +101,7 @@ pub trait CodegenBackend {
|
|||
ongoing_codegen: Box<dyn Any>,
|
||||
sess: &Session,
|
||||
outputs: &OutputFilenames,
|
||||
) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorGuaranteed>;
|
||||
) -> Result<(CodegenResults, FxIndexMap<WorkProductId, WorkProduct>), ErrorGuaranteed>;
|
||||
|
||||
/// This is called on the returned `Box<dyn Any>` from `join_codegen`
|
||||
///
|
||||
|
|
|
|||
|
|
@ -126,6 +126,28 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
|
|||
index: usize,
|
||||
immediate: bool,
|
||||
) -> Self::Type;
|
||||
|
||||
/// A type that can be used in a [`super::BuilderMethods::load`] +
|
||||
/// [`super::BuilderMethods::store`] pair to implement a *typed* copy,
|
||||
/// such as a MIR `*_0 = *_1`.
|
||||
///
|
||||
/// It's always legal to return `None` here, as the provided impl does,
|
||||
/// in which case callers should use [`super::BuilderMethods::memcpy`]
|
||||
/// instead of the `load`+`store` pair.
|
||||
///
|
||||
/// This can be helpful for things like arrays, where the LLVM backend type
|
||||
/// `[3 x i16]` optimizes to three separate loads and stores, but it can
|
||||
/// instead be copied via an `i48` that stays as the single `load`+`store`.
|
||||
/// (As of 2023-05 LLVM cannot necessarily optimize away a `memcpy` in these
|
||||
/// cases, due to `poison` handling, but in codegen we have more information
|
||||
/// about the type invariants, so can emit something better instead.)
|
||||
///
|
||||
/// This *should* return `None` for particularly-large types, where leaving
|
||||
/// the `memcpy` may well be important to avoid code size explosion.
|
||||
fn scalar_copy_backend_type(&self, layout: TyAndLayout<'tcx>) -> Option<Self::Type> {
|
||||
let _ = layout;
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// For backends that support CFI using type membership (i.e., testing whether a given pointer is
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
|
|||
}
|
||||
sym::type_id => {
|
||||
ensure_monomorphic_enough(tcx, tp_ty)?;
|
||||
ConstValue::from_u64(tcx.type_id_hash(tp_ty).as_u64())
|
||||
ConstValue::from_u128(tcx.type_id_hash(tp_ty).as_u128())
|
||||
}
|
||||
sym::variant_count => match tp_ty.kind() {
|
||||
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
|
||||
|
|
@ -169,7 +169,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
let ty = match intrinsic_name {
|
||||
sym::pref_align_of | sym::variant_count => self.tcx.types.usize,
|
||||
sym::needs_drop => self.tcx.types.bool,
|
||||
sym::type_id => self.tcx.types.u64,
|
||||
sym::type_id => self.tcx.types.u128,
|
||||
sym::type_name => self.tcx.mk_static_str(),
|
||||
_ => bug!(),
|
||||
};
|
||||
|
|
@ -238,9 +238,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
| sym::unchecked_shr
|
||||
| sym::unchecked_add
|
||||
| sym::unchecked_sub
|
||||
| sym::unchecked_mul
|
||||
| sym::unchecked_div
|
||||
| sym::unchecked_rem => {
|
||||
| sym::unchecked_mul => {
|
||||
let l = self.read_immediate(&args[0])?;
|
||||
let r = self.read_immediate(&args[1])?;
|
||||
let bin_op = match intrinsic_name {
|
||||
|
|
@ -249,8 +247,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
sym::unchecked_add => BinOp::Add,
|
||||
sym::unchecked_sub => BinOp::Sub,
|
||||
sym::unchecked_mul => BinOp::Mul,
|
||||
sym::unchecked_div => BinOp::Div,
|
||||
sym::unchecked_rem => BinOp::Rem,
|
||||
_ => bug!(),
|
||||
};
|
||||
let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, &l, &r)?;
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ where
|
|||
Q: Qualif,
|
||||
{
|
||||
fn apply_statement_effect(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
statement: &mir::Statement<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -346,7 +346,7 @@ where
|
|||
}
|
||||
|
||||
fn apply_terminator_effect(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
terminator: &mir::Terminator<'tcx>,
|
||||
location: Location,
|
||||
|
|
@ -355,7 +355,7 @@ where
|
|||
}
|
||||
|
||||
fn apply_call_return_effect(
|
||||
&self,
|
||||
&mut self,
|
||||
state: &mut Self::Domain,
|
||||
block: BasicBlock,
|
||||
return_places: CallReturnPlaces<'_, 'tcx>,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::stable_hasher::{HashStable, StableHasher};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{self, Debug};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
|
|
@ -20,7 +21,6 @@ mod private {
|
|||
/// The `PrivateZst` field means you can pattern match with `Interned(v, _)`
|
||||
/// but you can only construct a `Interned` with `new_unchecked`, and not
|
||||
/// directly.
|
||||
#[derive(Debug)]
|
||||
#[rustc_pass_by_value]
|
||||
pub struct Interned<'a, T>(pub &'a T, pub private::PrivateZst);
|
||||
|
||||
|
|
@ -108,5 +108,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Debug> Debug for Interned<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
|||
|
|
@ -233,7 +233,17 @@ pub trait ToStableHashKey<HCX> {
|
|||
/// - `DefIndex`, `CrateNum`, `LocalDefId`, because their concrete
|
||||
/// values depend on state that might be different between
|
||||
/// compilation sessions.
|
||||
pub unsafe trait StableOrd: Ord {}
|
||||
///
|
||||
/// The associated constant `CAN_USE_UNSTABLE_SORT` denotes whether
|
||||
/// unstable sorting can be used for this type. Set to true if and
|
||||
/// only if `a == b` implies `a` and `b` are fully indistinguishable.
|
||||
pub unsafe trait StableOrd: Ord {
|
||||
const CAN_USE_UNSTABLE_SORT: bool;
|
||||
}
|
||||
|
||||
unsafe impl<T: StableOrd> StableOrd for &T {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT;
|
||||
}
|
||||
|
||||
/// Implement HashStable by just calling `Hash::hash()`. Also implement `StableOrd` for the type since
|
||||
/// that has the same requirements.
|
||||
|
|
@ -253,7 +263,9 @@ macro_rules! impl_stable_traits_for_trivial_type {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe impl $crate::stable_hasher::StableOrd for $t {}
|
||||
unsafe impl $crate::stable_hasher::StableOrd for $t {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -339,6 +351,10 @@ impl<T1: HashStable<CTX>, T2: HashStable<CTX>, CTX> HashStable<CTX> for (T1, T2)
|
|||
}
|
||||
}
|
||||
|
||||
unsafe impl<T1: StableOrd, T2: StableOrd> StableOrd for (T1, T2) {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = T1::CAN_USE_UNSTABLE_SORT && T2::CAN_USE_UNSTABLE_SORT;
|
||||
}
|
||||
|
||||
impl<T1, T2, T3, CTX> HashStable<CTX> for (T1, T2, T3)
|
||||
where
|
||||
T1: HashStable<CTX>,
|
||||
|
|
@ -353,6 +369,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
unsafe impl<T1: StableOrd, T2: StableOrd, T3: StableOrd> StableOrd for (T1, T2, T3) {
|
||||
const CAN_USE_UNSTABLE_SORT: bool =
|
||||
T1::CAN_USE_UNSTABLE_SORT && T2::CAN_USE_UNSTABLE_SORT && T3::CAN_USE_UNSTABLE_SORT;
|
||||
}
|
||||
|
||||
impl<T1, T2, T3, T4, CTX> HashStable<CTX> for (T1, T2, T3, T4)
|
||||
where
|
||||
T1: HashStable<CTX>,
|
||||
|
|
@ -369,6 +390,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
unsafe impl<T1: StableOrd, T2: StableOrd, T3: StableOrd, T4: StableOrd> StableOrd
|
||||
for (T1, T2, T3, T4)
|
||||
{
|
||||
const CAN_USE_UNSTABLE_SORT: bool = T1::CAN_USE_UNSTABLE_SORT
|
||||
&& T2::CAN_USE_UNSTABLE_SORT
|
||||
&& T3::CAN_USE_UNSTABLE_SORT
|
||||
&& T4::CAN_USE_UNSTABLE_SORT;
|
||||
}
|
||||
|
||||
impl<T: HashStable<CTX>, CTX> HashStable<CTX> for [T] {
|
||||
default fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.len().hash_stable(ctx, hasher);
|
||||
|
|
@ -459,6 +489,10 @@ impl<CTX> HashStable<CTX> for str {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe impl StableOrd for &str {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = true;
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for String {
|
||||
#[inline]
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
|
|
@ -468,7 +502,9 @@ impl<CTX> HashStable<CTX> for String {
|
|||
|
||||
// Safety: String comparison only depends on their contents and the
|
||||
// contents are not changed by (de-)serialization.
|
||||
unsafe impl StableOrd for String {}
|
||||
unsafe impl StableOrd for String {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = true;
|
||||
}
|
||||
|
||||
impl<HCX> ToStableHashKey<HCX> for String {
|
||||
type KeyType = String;
|
||||
|
|
@ -494,7 +530,9 @@ impl<CTX> HashStable<CTX> for bool {
|
|||
}
|
||||
|
||||
// Safety: sort order of bools is not changed by (de-)serialization.
|
||||
unsafe impl StableOrd for bool {}
|
||||
unsafe impl StableOrd for bool {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = true;
|
||||
}
|
||||
|
||||
impl<T, CTX> HashStable<CTX> for Option<T>
|
||||
where
|
||||
|
|
@ -512,7 +550,9 @@ where
|
|||
}
|
||||
|
||||
// Safety: the Option wrapper does not add instability to comparison.
|
||||
unsafe impl<T: StableOrd> StableOrd for Option<T> {}
|
||||
unsafe impl<T: StableOrd> StableOrd for Option<T> {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT;
|
||||
}
|
||||
|
||||
impl<T1, T2, CTX> HashStable<CTX> for Result<T1, T2>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ impl Drop for MaybeTempDir {
|
|||
// occur.
|
||||
let dir = unsafe { ManuallyDrop::take(&mut self.dir) };
|
||||
if self.keep {
|
||||
dir.into_path();
|
||||
let _ = dir.into_path();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,12 +140,12 @@ impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_sorted_stable_ord(self, use_stable_sort: bool) -> Vec<T>
|
||||
pub fn into_sorted_stable_ord(self) -> Vec<T>
|
||||
where
|
||||
T: Ord + StableOrd,
|
||||
{
|
||||
let mut items: Vec<T> = self.0.collect();
|
||||
if use_stable_sort {
|
||||
if !T::CAN_USE_UNSTABLE_SORT {
|
||||
items.sort();
|
||||
} else {
|
||||
items.sort_unstable()
|
||||
|
|
@ -161,6 +161,10 @@ impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
|
|||
items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
|
||||
items
|
||||
}
|
||||
|
||||
pub fn collect<C: From<UnordItems<T, I>>>(self) -> C {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a set collection type that tries very hard to not expose
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// This crate is intentionally empty and a rexport of `rustc_driver_impl` to allow the code in
|
||||
// This crate is intentionally empty and a re-export of `rustc_driver_impl` to allow the code in
|
||||
// `rustc_driver_impl` to be compiled in parallel with other crates.
|
||||
|
||||
pub use rustc_driver_impl::*;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,9 @@ use rustc_interface::{interface, Queries};
|
|||
use rustc_lint::LintStore;
|
||||
use rustc_metadata::locator;
|
||||
use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
|
||||
use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
|
||||
use rustc_session::config::{
|
||||
ErrorOutputType, Input, OutFileName, OutputType, PrintRequest, TrimmedDefPaths,
|
||||
};
|
||||
use rustc_session::cstore::MetadataLoader;
|
||||
use rustc_session::getopts::{self, Matches};
|
||||
use rustc_session::lint::{Lint, LintId};
|
||||
|
|
@ -58,11 +60,18 @@ use std::str;
|
|||
use std::sync::OnceLock;
|
||||
use std::time::Instant;
|
||||
|
||||
#[allow(unused_macros)]
|
||||
macro do_not_use_print($($t:tt)*) {
|
||||
std::compile_error!(
|
||||
"Don't use `print` or `println` here, use `safe_print` or `safe_println` instead"
|
||||
)
|
||||
}
|
||||
|
||||
// This import blocks the use of panicking `print` and `println` in all the code
|
||||
// below. Please use `safe_print` and `safe_println` to avoid ICE when
|
||||
// encountering an I/O error during print.
|
||||
#[allow(unused_imports)]
|
||||
use std::{compile_error as print, compile_error as println};
|
||||
use {do_not_use_print as print, do_not_use_print as println};
|
||||
|
||||
pub mod args;
|
||||
pub mod pretty;
|
||||
|
|
@ -447,9 +456,12 @@ fn run_compiler(
|
|||
}
|
||||
|
||||
// Extract output directory and file from matches.
|
||||
fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
|
||||
fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<OutFileName>) {
|
||||
let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
|
||||
let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o));
|
||||
let ofile = matches.opt_str("o").map(|o| match o.as_str() {
|
||||
"-" => OutFileName::Stdout,
|
||||
path => OutFileName::Real(PathBuf::from(path)),
|
||||
});
|
||||
(odir, ofile)
|
||||
}
|
||||
|
||||
|
|
@ -695,7 +707,7 @@ fn print_crate_info(
|
|||
for &style in &crate_types {
|
||||
let fname =
|
||||
rustc_session::output::filename_for_input(sess, style, id, &t_outputs);
|
||||
safe_println!("{}", fname.file_name().unwrap().to_string_lossy());
|
||||
safe_println!("{}", fname.as_path().file_name().unwrap().to_string_lossy());
|
||||
}
|
||||
}
|
||||
Cfg => {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_hir_pretty as pprust_hir;
|
|||
use rustc_middle::hir::map as hir_map;
|
||||
use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::config::{PpAstTreeMode, PpHirMode, PpMode, PpSourceMode};
|
||||
use rustc_session::config::{OutFileName, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::FileName;
|
||||
|
|
@ -359,8 +359,8 @@ fn get_source(sess: &Session) -> (String, FileName) {
|
|||
|
||||
fn write_or_print(out: &str, sess: &Session) {
|
||||
match &sess.io.output_file {
|
||||
None => print!("{out}"),
|
||||
Some(p) => {
|
||||
None | Some(OutFileName::Stdout) => print!("{out}"),
|
||||
Some(OutFileName::Real(p)) => {
|
||||
if let Err(e) = std::fs::write(p, out) {
|
||||
sess.emit_fatal(UnprettyDumpFail {
|
||||
path: p.display().to_string(),
|
||||
|
|
|
|||
|
|
@ -10,15 +10,19 @@ struct A;
|
|||
struct B<const X: A>; // error!
|
||||
```
|
||||
|
||||
Only structural-match types (that is, types that derive `PartialEq` and `Eq`)
|
||||
may be used as the types of const generic parameters.
|
||||
Only structural-match types, which are types that derive `PartialEq` and `Eq`
|
||||
and implement `ConstParamTy`, may be used as the types of const generic
|
||||
parameters.
|
||||
|
||||
To fix the previous code example, we derive `PartialEq` and `Eq`:
|
||||
To fix the previous code example, we derive `PartialEq`, `Eq`, and
|
||||
`ConstParamTy`:
|
||||
|
||||
```
|
||||
#![feature(adt_const_params)]
|
||||
|
||||
#[derive(PartialEq, Eq)] // We derive both traits here.
|
||||
use std::marker::ConstParamTy;
|
||||
|
||||
#[derive(PartialEq, Eq, ConstParamTy)] // We derive both traits here.
|
||||
struct A;
|
||||
|
||||
struct B<const X: A>; // ok!
|
||||
|
|
|
|||
|
|
@ -115,36 +115,22 @@ pub trait EmissionGuarantee: Sized {
|
|||
) -> DiagnosticBuilder<'_, Self>;
|
||||
}
|
||||
|
||||
/// Private module for sealing the `IsError` helper trait.
|
||||
mod sealed_level_is_error {
|
||||
use crate::Level;
|
||||
|
||||
/// Sealed helper trait for statically checking that a `Level` is an error.
|
||||
pub(crate) trait IsError<const L: Level> {}
|
||||
|
||||
impl IsError<{ Level::Bug }> for () {}
|
||||
impl IsError<{ Level::DelayedBug }> for () {}
|
||||
impl IsError<{ Level::Fatal }> for () {}
|
||||
// NOTE(eddyb) `Level::Error { lint: true }` is also an error, but lints
|
||||
// don't need error guarantees, as their levels are always dynamic.
|
||||
impl IsError<{ Level::Error { lint: false } }> for () {}
|
||||
}
|
||||
|
||||
impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
/// Convenience function for internal use, clients should use one of the
|
||||
/// `struct_*` methods on [`Handler`].
|
||||
#[track_caller]
|
||||
pub(crate) fn new_guaranteeing_error<M: Into<DiagnosticMessage>, const L: Level>(
|
||||
pub(crate) fn new_guaranteeing_error<M: Into<DiagnosticMessage>>(
|
||||
handler: &'a Handler,
|
||||
message: M,
|
||||
) -> Self
|
||||
where
|
||||
(): sealed_level_is_error::IsError<L>,
|
||||
{
|
||||
) -> Self {
|
||||
Self {
|
||||
inner: DiagnosticBuilderInner {
|
||||
state: DiagnosticBuilderState::Emittable(handler),
|
||||
diagnostic: Box::new(Diagnostic::new_with_code(L, None, message)),
|
||||
diagnostic: Box::new(Diagnostic::new_with_code(
|
||||
Level::Error { lint: false },
|
||||
None,
|
||||
message,
|
||||
)),
|
||||
},
|
||||
_marker: PhantomData,
|
||||
}
|
||||
|
|
@ -203,9 +189,7 @@ impl EmissionGuarantee for ErrorGuaranteed {
|
|||
handler: &Handler,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, Self> {
|
||||
DiagnosticBuilder::new_guaranteeing_error::<_, { Level::Error { lint: false } }>(
|
||||
handler, msg,
|
||||
)
|
||||
DiagnosticBuilder::new_guaranteeing_error(handler, msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
#![feature(array_windows)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(adt_const_params)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(never_type)]
|
||||
#![feature(result_option_inspect)]
|
||||
|
|
@ -384,7 +383,7 @@ pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
|
|||
pub use diagnostic_impls::{
|
||||
DiagnosticArgFromDisplay, DiagnosticSymbolList, LabelKind, SingleLabelManySpans,
|
||||
};
|
||||
use std::backtrace::Backtrace;
|
||||
use std::backtrace::{Backtrace, BacktraceStatus};
|
||||
|
||||
/// A handler deals with errors and other compiler output.
|
||||
/// Certain errors (fatal, bug, unimpl) may cause immediate exit,
|
||||
|
|
@ -845,7 +844,7 @@ impl Handler {
|
|||
&self,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
DiagnosticBuilder::new_guaranteeing_error::<_, { Level::Error { lint: false } }>(self, msg)
|
||||
DiagnosticBuilder::new_guaranteeing_error(self, msg)
|
||||
}
|
||||
|
||||
/// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors.
|
||||
|
|
@ -1332,7 +1331,7 @@ impl HandlerInner {
|
|||
// once *any* errors were emitted (and truncate `delayed_span_bugs`
|
||||
// when an error is first emitted, also), but maybe there's a case
|
||||
// in which that's not sound? otherwise this is really inefficient.
|
||||
let backtrace = std::backtrace::Backtrace::force_capture();
|
||||
let backtrace = std::backtrace::Backtrace::capture();
|
||||
self.delayed_span_bugs
|
||||
.push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
|
||||
|
||||
|
|
@ -1621,7 +1620,7 @@ impl HandlerInner {
|
|||
if self.flags.report_delayed_bugs {
|
||||
self.emit_diagnostic(&mut diagnostic);
|
||||
}
|
||||
let backtrace = std::backtrace::Backtrace::force_capture();
|
||||
let backtrace = std::backtrace::Backtrace::capture();
|
||||
self.delayed_good_path_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
|
||||
}
|
||||
|
||||
|
|
@ -1740,7 +1739,17 @@ impl DelayedDiagnostic {
|
|||
}
|
||||
|
||||
fn decorate(mut self) -> Diagnostic {
|
||||
self.inner.note(format!("delayed at {}\n{}", self.inner.emitted_at, self.note));
|
||||
match self.note.status() {
|
||||
BacktraceStatus::Captured => {
|
||||
self.inner.note(format!("delayed at {}\n{}", self.inner.emitted_at, self.note));
|
||||
}
|
||||
// Avoid the needless newline when no backtrace has been captured,
|
||||
// the display impl should just be a single line.
|
||||
_ => {
|
||||
self.inner.note(format!("delayed at {} - {}", self.inner.emitted_at, self.note));
|
||||
}
|
||||
}
|
||||
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -947,6 +947,8 @@ pub trait ResolverExpand {
|
|||
/// HIR proc macros items back to their harness items.
|
||||
fn declare_proc_macro(&mut self, id: NodeId);
|
||||
|
||||
fn append_stripped_cfg_item(&mut self, parent_node: NodeId, name: Ident, cfg: ast::MetaItem);
|
||||
|
||||
/// Tools registered with `#![register_tool]` and used by tool attributes and lints.
|
||||
fn registered_tools(&self) -> &RegisteredTools;
|
||||
}
|
||||
|
|
@ -965,7 +967,7 @@ pub trait LintStoreExpand {
|
|||
|
||||
type LintStoreExpandDyn<'a> = Option<&'a (dyn LintStoreExpand + 'a)>;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ModuleData {
|
||||
/// Path to the module starting from the crate name, like `my_crate::foo::bar`.
|
||||
pub mod_path: Vec<Ident>,
|
||||
|
|
@ -1108,6 +1110,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_span_err<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
sp: S,
|
||||
|
|
@ -1116,6 +1119,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
self.sess.parse_sess.span_diagnostic.struct_span_err(sp, msg)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn create_err(
|
||||
&self,
|
||||
err: impl IntoDiagnostic<'a>,
|
||||
|
|
@ -1123,6 +1127,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
self.sess.create_err(err)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn emit_err(&self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
|
||||
self.sess.emit_err(err)
|
||||
}
|
||||
|
|
@ -1133,10 +1138,12 @@ impl<'a> ExtCtxt<'a> {
|
|||
/// Compilation will be stopped in the near future (at the end of
|
||||
/// the macro expansion phase).
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
|
||||
self.sess.parse_sess.span_diagnostic.span_err(sp, msg);
|
||||
}
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
|
||||
self.sess.parse_sess.span_diagnostic.span_warn(sp, msg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,9 +197,11 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec
|
|||
config_tokens: false,
|
||||
lint_node_id: ast::CRATE_NODE_ID,
|
||||
};
|
||||
let attrs: ast::AttrVec =
|
||||
attrs.iter().flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)).collect();
|
||||
if strip_unconfigured.in_cfg(&attrs) { attrs } else { ast::AttrVec::new() }
|
||||
attrs
|
||||
.iter()
|
||||
.flat_map(|attr| strip_unconfigured.process_cfg_attr(attr))
|
||||
.take_while(|attr| !is_cfg(attr) || strip_unconfigured.cfg_true(attr).0)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
|
@ -416,20 +418,28 @@ impl<'a> StripUnconfigured<'a> {
|
|||
|
||||
/// Determines if a node with the given attributes should be included in this configuration.
|
||||
fn in_cfg(&self, attrs: &[Attribute]) -> bool {
|
||||
attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr))
|
||||
attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr).0)
|
||||
}
|
||||
|
||||
pub(crate) fn cfg_true(&self, attr: &Attribute) -> bool {
|
||||
pub(crate) fn cfg_true(&self, attr: &Attribute) -> (bool, Option<MetaItem>) {
|
||||
let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) {
|
||||
Ok(meta_item) => meta_item,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
return true;
|
||||
return (true, None);
|
||||
}
|
||||
};
|
||||
parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
|
||||
attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.lint_node_id, self.features)
|
||||
})
|
||||
(
|
||||
parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
|
||||
attr::cfg_matches(
|
||||
&meta_item,
|
||||
&self.sess.parse_sess,
|
||||
self.lint_node_id,
|
||||
self.features,
|
||||
)
|
||||
}),
|
||||
Some(meta_item),
|
||||
)
|
||||
}
|
||||
|
||||
/// If attributes are not allowed on expressions, emit an error for `attr`
|
||||
|
|
|
|||
|
|
@ -1039,9 +1039,20 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
|
|||
) -> Result<Self::OutputTy, Self> {
|
||||
Ok(noop_flat_map(node, collector))
|
||||
}
|
||||
fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, span: Span) {
|
||||
fn expand_cfg_false(
|
||||
&mut self,
|
||||
collector: &mut InvocationCollector<'_, '_>,
|
||||
_pos: usize,
|
||||
span: Span,
|
||||
) {
|
||||
collector.cx.emit_err(RemoveNodeNotSupported { span, descr: Self::descr() });
|
||||
}
|
||||
|
||||
/// All of the names (items) declared by this node.
|
||||
/// This is an approximation and should only be used for diagnostics.
|
||||
fn declared_names(&self) -> Vec<Ident> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl InvocationCollectorNode for P<ast::Item> {
|
||||
|
|
@ -1148,6 +1159,27 @@ impl InvocationCollectorNode for P<ast::Item> {
|
|||
collector.cx.current_expansion.module = orig_module;
|
||||
res
|
||||
}
|
||||
fn declared_names(&self) -> Vec<Ident> {
|
||||
if let ItemKind::Use(ut) = &self.kind {
|
||||
fn collect_use_tree_leaves(ut: &ast::UseTree, idents: &mut Vec<Ident>) {
|
||||
match &ut.kind {
|
||||
ast::UseTreeKind::Glob => {}
|
||||
ast::UseTreeKind::Simple(_) => idents.push(ut.ident()),
|
||||
ast::UseTreeKind::Nested(nested) => {
|
||||
for (ut, _) in nested {
|
||||
collect_use_tree_leaves(&ut, idents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut idents = Vec::new();
|
||||
collect_use_tree_leaves(&ut, &mut idents);
|
||||
return idents;
|
||||
}
|
||||
|
||||
vec![self.ident]
|
||||
}
|
||||
}
|
||||
|
||||
struct TraitItemTag;
|
||||
|
|
@ -1382,8 +1414,15 @@ impl InvocationCollectorNode for ast::Crate {
|
|||
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
|
||||
noop_visit_crate(self, visitor)
|
||||
}
|
||||
fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, _span: Span) {
|
||||
self.attrs.clear();
|
||||
fn expand_cfg_false(
|
||||
&mut self,
|
||||
collector: &mut InvocationCollector<'_, '_>,
|
||||
pos: usize,
|
||||
_span: Span,
|
||||
) {
|
||||
// Attributes above `cfg(FALSE)` are left in place, because we may want to configure
|
||||
// some global crate properties even on fully unconfigured crates.
|
||||
self.attrs.truncate(pos);
|
||||
// Standard prelude imports are left in the crate for backward compatibility.
|
||||
self.items.truncate(collector.cx.num_standard_library_imports);
|
||||
}
|
||||
|
|
@ -1685,8 +1724,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
node: &mut impl HasAttrs,
|
||||
attr: ast::Attribute,
|
||||
pos: usize,
|
||||
) -> bool {
|
||||
let res = self.cfg().cfg_true(&attr);
|
||||
) -> (bool, Option<ast::MetaItem>) {
|
||||
let (res, meta_item) = self.cfg().cfg_true(&attr);
|
||||
if res {
|
||||
// FIXME: `cfg(TRUE)` attributes do not currently remove themselves during expansion,
|
||||
// and some tools like rustdoc and clippy rely on that. Find a way to remove them
|
||||
|
|
@ -1694,7 +1733,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
self.cx.expanded_inert_attrs.mark(&attr);
|
||||
node.visit_attrs(|attrs| attrs.insert(pos, attr));
|
||||
}
|
||||
res
|
||||
|
||||
(res, meta_item)
|
||||
}
|
||||
|
||||
fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) {
|
||||
|
|
@ -1715,9 +1755,20 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
return match self.take_first_attr(&mut node) {
|
||||
Some((attr, pos, derives)) => match attr.name_or_empty() {
|
||||
sym::cfg => {
|
||||
if self.expand_cfg_true(&mut node, attr, pos) {
|
||||
let (res, meta_item) = self.expand_cfg_true(&mut node, attr, pos);
|
||||
if res {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(meta_item) = meta_item {
|
||||
for name in node.declared_names() {
|
||||
self.cx.resolver.append_stripped_cfg_item(
|
||||
self.cx.current_expansion.lint_node_id,
|
||||
name,
|
||||
meta_item.clone(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Default::default()
|
||||
}
|
||||
sym::cfg_attr => {
|
||||
|
|
@ -1761,11 +1812,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
Some((attr, pos, derives)) => match attr.name_or_empty() {
|
||||
sym::cfg => {
|
||||
let span = attr.span;
|
||||
if self.expand_cfg_true(node, attr, pos) {
|
||||
if self.expand_cfg_true(node, attr, pos).0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
node.expand_cfg_false(self, span);
|
||||
node.expand_cfg_false(self, pos, span);
|
||||
continue;
|
||||
}
|
||||
sym::cfg_attr => {
|
||||
|
|
|
|||
|
|
@ -249,6 +249,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> {
|
|||
}
|
||||
|
||||
/// A single matcher position, representing the state of matching.
|
||||
#[derive(Debug)]
|
||||
struct MatcherPos {
|
||||
/// The index into `TtParser::locs`, which represents the "dot".
|
||||
idx: usize,
|
||||
|
|
|
|||
|
|
@ -628,6 +628,40 @@ fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree)
|
|||
// after parsing/expansion. we can report every error in every macro this way.
|
||||
}
|
||||
|
||||
fn is_empty_token_tree(sess: &ParseSess, seq: &mbe::SequenceRepetition) -> bool {
|
||||
if seq.separator.is_some() {
|
||||
false
|
||||
} else {
|
||||
let mut is_empty = true;
|
||||
let mut iter = seq.tts.iter().peekable();
|
||||
while let Some(tt) = iter.next() {
|
||||
match tt {
|
||||
mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => {}
|
||||
mbe::TokenTree::Token(t @ Token { kind: DocComment(..), .. }) => {
|
||||
let mut now = t;
|
||||
while let Some(&mbe::TokenTree::Token(
|
||||
next @ Token { kind: DocComment(..), .. },
|
||||
)) = iter.peek()
|
||||
{
|
||||
now = next;
|
||||
iter.next();
|
||||
}
|
||||
let span = t.span.to(now.span);
|
||||
sess.span_diagnostic.span_note_without_error(
|
||||
span,
|
||||
"doc comments are ignored in matcher position",
|
||||
);
|
||||
}
|
||||
mbe::TokenTree::Sequence(_, sub_seq)
|
||||
if (sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
|
||||
|| sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne) => {}
|
||||
_ => is_empty = false,
|
||||
}
|
||||
}
|
||||
is_empty
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that the lhs contains no repetition which could match an empty token
|
||||
/// tree, because then the matcher would hang indefinitely.
|
||||
fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
|
||||
|
|
@ -644,16 +678,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
|
|||
}
|
||||
}
|
||||
TokenTree::Sequence(span, seq) => {
|
||||
if seq.separator.is_none()
|
||||
&& seq.tts.iter().all(|seq_tt| match seq_tt {
|
||||
TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true,
|
||||
TokenTree::Sequence(_, sub_seq) => {
|
||||
sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
|
||||
|| sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
{
|
||||
if is_empty_token_tree(sess, seq) {
|
||||
let sp = span.entire();
|
||||
sess.span_diagnostic.span_err(sp, "repetition matches empty token tree");
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1675,6 +1675,14 @@ pub struct AnonConst {
|
|||
pub body: BodyId,
|
||||
}
|
||||
|
||||
/// An inline constant expression `const { something }`.
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic)]
|
||||
pub struct ConstBlock {
|
||||
pub hir_id: HirId,
|
||||
pub def_id: LocalDefId,
|
||||
pub body: BodyId,
|
||||
}
|
||||
|
||||
/// An expression.
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct Expr<'hir> {
|
||||
|
|
@ -1922,7 +1930,7 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
|
|||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub enum ExprKind<'hir> {
|
||||
/// Allow anonymous constants from an inline `const` block
|
||||
ConstBlock(AnonConst),
|
||||
ConstBlock(ConstBlock),
|
||||
/// An array (e.g., `[a, b, c, d]`).
|
||||
Array(&'hir [Expr<'hir>]),
|
||||
/// A function call.
|
||||
|
|
@ -3641,6 +3649,7 @@ pub enum Node<'hir> {
|
|||
Variant(&'hir Variant<'hir>),
|
||||
Field(&'hir FieldDef<'hir>),
|
||||
AnonConst(&'hir AnonConst),
|
||||
ConstBlock(&'hir ConstBlock),
|
||||
Expr(&'hir Expr<'hir>),
|
||||
ExprField(&'hir ExprField<'hir>),
|
||||
Stmt(&'hir Stmt<'hir>),
|
||||
|
|
@ -3695,6 +3704,7 @@ impl<'hir> Node<'hir> {
|
|||
Node::TypeBinding(b) => Some(b.ident),
|
||||
Node::Param(..)
|
||||
| Node::AnonConst(..)
|
||||
| Node::ConstBlock(..)
|
||||
| Node::Expr(..)
|
||||
| Node::Stmt(..)
|
||||
| Node::Block(..)
|
||||
|
|
@ -3758,7 +3768,7 @@ impl<'hir> Node<'hir> {
|
|||
})
|
||||
| Node::Expr(Expr {
|
||||
kind:
|
||||
ExprKind::ConstBlock(AnonConst { body, .. })
|
||||
ExprKind::ConstBlock(ConstBlock { body, .. })
|
||||
| ExprKind::Closure(Closure { body, .. })
|
||||
| ExprKind::Repeat(_, ArrayLen::Body(AnonConst { body, .. })),
|
||||
..
|
||||
|
|
@ -3878,6 +3888,13 @@ impl<'hir> Node<'hir> {
|
|||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::ConstBlock`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_inline_const(self) -> &'hir ConstBlock {
|
||||
let Node::ConstBlock(this) = self else { self.expect_failed("an inline constant") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Expr`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_expr(self) -> &'hir Expr<'hir> {
|
||||
|
|
|
|||
|
|
@ -166,7 +166,9 @@ impl ItemLocalId {
|
|||
|
||||
// Safety: Ord is implement as just comparing the ItemLocalId's numerical
|
||||
// values and these are not changed by (de-)serialization.
|
||||
unsafe impl StableOrd for ItemLocalId {}
|
||||
unsafe impl StableOrd for ItemLocalId {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = true;
|
||||
}
|
||||
|
||||
/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
|
||||
pub const CRATE_HIR_ID: HirId =
|
||||
|
|
|
|||
|
|
@ -335,6 +335,9 @@ pub trait Visitor<'v>: Sized {
|
|||
fn visit_anon_const(&mut self, c: &'v AnonConst) {
|
||||
walk_anon_const(self, c)
|
||||
}
|
||||
fn visit_inline_const(&mut self, c: &'v ConstBlock) {
|
||||
walk_inline_const(self, c)
|
||||
}
|
||||
fn visit_expr(&mut self, ex: &'v Expr<'v>) {
|
||||
walk_expr(self, ex)
|
||||
}
|
||||
|
|
@ -679,13 +682,18 @@ pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonCo
|
|||
visitor.visit_nested_body(constant.body);
|
||||
}
|
||||
|
||||
pub fn walk_inline_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v ConstBlock) {
|
||||
visitor.visit_id(constant.hir_id);
|
||||
visitor.visit_nested_body(constant.body);
|
||||
}
|
||||
|
||||
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) {
|
||||
visitor.visit_id(expression.hir_id);
|
||||
match expression.kind {
|
||||
ExprKind::Array(subexpressions) => {
|
||||
walk_list!(visitor, visit_expr, subexpressions);
|
||||
}
|
||||
ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
|
||||
ExprKind::ConstBlock(ref const_block) => visitor.visit_inline_const(const_block),
|
||||
ExprKind::Repeat(ref element, ref count) => {
|
||||
visitor.visit_expr(element);
|
||||
visitor.visit_array_length(count)
|
||||
|
|
|
|||
|
|
@ -195,6 +195,13 @@ hir_analysis_return_type_notation_conflicting_bound =
|
|||
hir_analysis_return_type_notation_equality_bound =
|
||||
return type notation is not allowed to use type equality
|
||||
|
||||
hir_analysis_return_type_notation_illegal_param_const =
|
||||
return type notation is not allowed for functions that have const parameters
|
||||
.label = const parameter declared here
|
||||
hir_analysis_return_type_notation_illegal_param_type =
|
||||
return type notation is not allowed for functions that have type parameters
|
||||
.label = type parameter declared here
|
||||
|
||||
hir_analysis_return_type_notation_missing_method =
|
||||
cannot find associated function `{$assoc_name}` for `{$ty_name}`
|
||||
|
||||
|
|
|
|||
|
|
@ -26,10 +26,8 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
|||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{walk_generics, Visitor as _};
|
||||
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use rustc_middle::middle::stability::AllowUnstable;
|
||||
use rustc_middle::ty::fold::FnMutDelegate;
|
||||
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
|
||||
|
|
@ -1215,6 +1213,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
|
||||
let projection_ty = if return_type_notation {
|
||||
let mut emitted_bad_param_err = false;
|
||||
// If we have an method return type bound, then we need to substitute
|
||||
// the method's early bound params with suitable late-bound params.
|
||||
let mut num_bound_vars = candidate.bound_vars().len();
|
||||
|
|
@ -1230,16 +1229,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
},
|
||||
)
|
||||
.into(),
|
||||
GenericParamDefKind::Type { .. } => tcx
|
||||
.mk_bound(
|
||||
GenericParamDefKind::Type { .. } => {
|
||||
if !emitted_bad_param_err {
|
||||
tcx.sess.emit_err(
|
||||
crate::errors::ReturnTypeNotationIllegalParam::Type {
|
||||
span: path_span,
|
||||
param_span: tcx.def_span(param.def_id),
|
||||
},
|
||||
);
|
||||
emitted_bad_param_err = true;
|
||||
}
|
||||
tcx.mk_bound(
|
||||
ty::INNERMOST,
|
||||
ty::BoundTy {
|
||||
var: ty::BoundVar::from_usize(num_bound_vars),
|
||||
kind: ty::BoundTyKind::Param(param.def_id, param.name),
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
.into()
|
||||
}
|
||||
GenericParamDefKind::Const { .. } => {
|
||||
if !emitted_bad_param_err {
|
||||
tcx.sess.emit_err(
|
||||
crate::errors::ReturnTypeNotationIllegalParam::Const {
|
||||
span: path_span,
|
||||
param_span: tcx.def_span(param.def_id),
|
||||
},
|
||||
);
|
||||
emitted_bad_param_err = true;
|
||||
}
|
||||
let ty = tcx
|
||||
.type_of(param.def_id)
|
||||
.no_bound_vars()
|
||||
|
|
@ -1601,7 +1619,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
tcx.associated_items(pred.def_id())
|
||||
.in_definition_order()
|
||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||
.filter(|item| tcx.opt_rpitit_info(item.def_id).is_none())
|
||||
.filter(|item| item.opt_rpitit_info.is_none())
|
||||
.map(|item| item.def_id),
|
||||
);
|
||||
}
|
||||
|
|
@ -1643,6 +1661,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
}
|
||||
|
||||
// `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where <Self as Trait>::Assoc = Foo`.
|
||||
// So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
|
||||
// types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
|
||||
// corresponding `Projection` clause
|
||||
for (projection_bound, _) in &projection_bounds {
|
||||
for def_ids in associated_types.values_mut() {
|
||||
def_ids.remove(&projection_bound.projection_def_id());
|
||||
|
|
@ -2468,7 +2490,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
infcx.probe(|_| {
|
||||
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
|
||||
|
||||
let impl_substs = infcx.fresh_item_substs(impl_);
|
||||
let impl_substs = infcx.fresh_substs_for_item(span, impl_);
|
||||
let impl_ty = tcx.type_of(impl_).subst(tcx, impl_substs);
|
||||
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
|
||||
|
||||
|
|
@ -3755,36 +3777,3 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
|
||||
fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx> {
|
||||
InternalSubsts::for_item(self.tcx, def_id, |param, _| match param.kind {
|
||||
GenericParamDefKind::Lifetime => self.tcx.lifetimes.re_erased.into(),
|
||||
GenericParamDefKind::Type { .. } => self
|
||||
.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::SubstitutionPlaceholder,
|
||||
span: self.tcx.def_span(def_id),
|
||||
})
|
||||
.into(),
|
||||
GenericParamDefKind::Const { .. } => {
|
||||
let span = self.tcx.def_span(def_id);
|
||||
let origin = ConstVariableOrigin {
|
||||
kind: ConstVariableOriginKind::SubstitutionPlaceholder,
|
||||
span,
|
||||
};
|
||||
self.next_const_var(
|
||||
self.tcx
|
||||
.type_of(param.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic"),
|
||||
origin,
|
||||
)
|
||||
.into()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
|
|||
// NOTE: we may still need to normalize the built-in deref in case
|
||||
// we have some type like `&<Ty as Trait>::Assoc`, since users of
|
||||
// autoderef expect this type to have been structurally normalized.
|
||||
if self.infcx.tcx.trait_solver_next()
|
||||
if self.infcx.next_trait_solver()
|
||||
&& let ty::Alias(ty::Projection, _) = ty.kind()
|
||||
{
|
||||
let (normalized_ty, obligations) = self.structurally_normalize(ty)?;
|
||||
|
|
@ -161,8 +161,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
|||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(tcx);
|
||||
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(self.infcx);
|
||||
|
||||
let cause = traits::ObligationCause::misc(self.span, self.body_id);
|
||||
let normalized_ty = match self
|
||||
|
|
|
|||
|
|
@ -704,7 +704,7 @@ pub(super) fn check_specialization_validity<'tcx>(
|
|||
// grandparent. In that case, if parent is a `default impl`, inherited items use the
|
||||
// "defaultness" from the grandparent, else they are final.
|
||||
None => {
|
||||
if tcx.impl_defaultness(parent_impl.def_id()).is_default() {
|
||||
if tcx.defaultness(parent_impl.def_id()).is_default() {
|
||||
None
|
||||
} else {
|
||||
Some(Err(parent_impl.def_id()))
|
||||
|
|
@ -803,7 +803,7 @@ fn check_impl_items_against_trait<'tcx>(
|
|||
.as_ref()
|
||||
.is_some_and(|node_item| node_item.item.defaultness(tcx).has_value());
|
||||
|
||||
if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
|
||||
if !is_implemented && tcx.defaultness(impl_id).is_final() {
|
||||
missing_items.push(tcx.associated_item(trait_item_id));
|
||||
}
|
||||
|
||||
|
|
@ -1549,7 +1549,7 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
.with_opaque_type_inference(DefiningAnchor::Bind(def_id))
|
||||
.build();
|
||||
|
||||
let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||
let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx);
|
||||
for (predicate, cause) in generator_interior_predicates {
|
||||
let obligation = Obligation::new(tcx, cause.clone(), param_env, *predicate);
|
||||
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
return Err(emitted);
|
||||
}
|
||||
|
||||
if check_implied_wf == CheckImpliedWfMode::Check {
|
||||
if check_implied_wf == CheckImpliedWfMode::Check && !(impl_sig, trait_sig).references_error() {
|
||||
// We need to check that the impl's args are well-formed given
|
||||
// the hybrid param-env (impl + trait method where-clauses).
|
||||
ocx.register_obligation(traits::Obligation::new(
|
||||
|
|
@ -1216,7 +1216,7 @@ fn compare_number_of_generics<'tcx>(
|
|||
// has mismatched type or const generic arguments, then the method that it's
|
||||
// inheriting the generics from will also have mismatched arguments, and
|
||||
// we'll report an error for that instead. Delay a bug for safety, though.
|
||||
if tcx.opt_rpitit_info(trait_.def_id).is_some() {
|
||||
if trait_.opt_rpitit_info.is_some() {
|
||||
return Err(tcx.sess.delay_span_bug(
|
||||
rustc_span::DUMMY_SP,
|
||||
"errors comparing numbers of generics of trait/impl functions were not emitted",
|
||||
|
|
@ -2006,7 +2006,7 @@ pub(super) fn check_type_bounds<'tcx>(
|
|||
// A synthetic impl Trait for RPITIT 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 tcx.opt_rpitit_info(impl_ty.def_id).is_some() {
|
||||
let impl_ty_span = if impl_ty.opt_rpitit_info.is_some() {
|
||||
tcx.def_span(impl_ty_def_id)
|
||||
} else {
|
||||
match tcx.hir().get_by_def_id(impl_ty_def_id) {
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
|
|||
sym::needs_drop => (1, Vec::new(), tcx.types.bool),
|
||||
|
||||
sym::type_name => (1, Vec::new(), tcx.mk_static_str()),
|
||||
sym::type_id => (1, Vec::new(), tcx.types.u64),
|
||||
sym::type_id => (1, Vec::new(), tcx.types.u128),
|
||||
sym::offset => (2, vec![param(0), param(1)], param(0)),
|
||||
sym::arith_offset => (
|
||||
1,
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ fn missing_items_err(
|
|||
full_impl_span: Span,
|
||||
) {
|
||||
let missing_items =
|
||||
missing_items.iter().filter(|trait_item| tcx.opt_rpitit_info(trait_item.def_id).is_none());
|
||||
missing_items.iter().filter(|trait_item| trait_item.opt_rpitit_info.is_none());
|
||||
|
||||
let missing_items_msg = missing_items
|
||||
.clone()
|
||||
|
|
|
|||
|
|
@ -392,7 +392,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
|
|||
// Manually recurse over closures and inline consts, because they are the only
|
||||
// case of nested bodies that share the parent environment.
|
||||
hir::ExprKind::Closure(&hir::Closure { body, .. })
|
||||
| hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => {
|
||||
| hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) => {
|
||||
let body = visitor.tcx.hir().body(body);
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -829,83 +829,20 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
|
|||
let ty = tcx.type_of(param.def_id).subst_identity();
|
||||
|
||||
if tcx.features().adt_const_params {
|
||||
if let Some(non_structural_match_ty) =
|
||||
traits::search_for_adt_const_param_violation(param.span, tcx, ty)
|
||||
{
|
||||
// We use the same error code in both branches, because this is really the same
|
||||
// issue: we just special-case the message for type parameters to make it
|
||||
// clearer.
|
||||
match non_structural_match_ty.kind() {
|
||||
ty::Param(_) => {
|
||||
// Const parameters may not have type parameters as their types,
|
||||
// because we cannot be sure that the type parameter derives `PartialEq`
|
||||
// and `Eq` (just implementing them is not enough for `structural_match`).
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
hir_ty.span,
|
||||
E0741,
|
||||
"`{ty}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
|
||||
used as the type of a const parameter",
|
||||
)
|
||||
.span_label(
|
||||
hir_ty.span,
|
||||
format!("`{ty}` may not derive both `PartialEq` and `Eq`"),
|
||||
)
|
||||
.note(
|
||||
"it is not currently possible to use a type parameter as the type of a \
|
||||
const parameter",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
ty::Float(_) => {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
hir_ty.span,
|
||||
E0741,
|
||||
"`{ty}` is forbidden as the type of a const generic parameter",
|
||||
)
|
||||
.note("floats do not derive `Eq` or `Ord`, which are required for const parameters")
|
||||
.emit();
|
||||
}
|
||||
ty::FnPtr(_) => {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
hir_ty.span,
|
||||
E0741,
|
||||
"using function pointers as const generic parameters is forbidden",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
ty::RawPtr(_) => {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
hir_ty.span,
|
||||
E0741,
|
||||
"using raw pointers as const generic parameters is forbidden",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
_ => {
|
||||
let mut diag = struct_span_err!(
|
||||
tcx.sess,
|
||||
hir_ty.span,
|
||||
E0741,
|
||||
"`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
|
||||
the type of a const parameter",
|
||||
non_structural_match_ty,
|
||||
);
|
||||
|
||||
if ty == non_structural_match_ty {
|
||||
diag.span_label(
|
||||
hir_ty.span,
|
||||
format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
|
||||
);
|
||||
}
|
||||
|
||||
diag.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| {
|
||||
let trait_def_id =
|
||||
tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span));
|
||||
wfcx.register_bound(
|
||||
ObligationCause::new(
|
||||
hir_ty.span,
|
||||
param.def_id,
|
||||
ObligationCauseCode::ConstParam(ty),
|
||||
),
|
||||
wfcx.param_env,
|
||||
ty,
|
||||
trait_def_id,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
let err_ty_str;
|
||||
let mut is_ptr = true;
|
||||
|
|
@ -1808,9 +1745,11 @@ fn check_variances_for_type_defn<'tcx>(
|
|||
item: &hir::Item<'tcx>,
|
||||
hir_generics: &hir::Generics<'_>,
|
||||
) {
|
||||
let ty = tcx.type_of(item.owner_id).subst_identity();
|
||||
if tcx.has_error_field(ty) {
|
||||
return;
|
||||
let identity_substs = ty::InternalSubsts::identity_for_item(tcx, item.owner_id);
|
||||
for field in tcx.adt_def(item.owner_id).all_fields() {
|
||||
if field.ty(tcx, identity_substs).references_error() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let ty_predicates = tcx.predicates_of(item.owner_id);
|
||||
|
|
|
|||
|
|
@ -941,7 +941,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
|
||||
match item {
|
||||
Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
|
||||
if !tcx.impl_defaultness(item.id.owner_id).has_value() {
|
||||
if !tcx.defaultness(item.id.owner_id).has_value() {
|
||||
tcx.sess.emit_err(errors::FunctionNotHaveDefaultImplementation {
|
||||
span: item.span,
|
||||
note_span: attr_span,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
// We do not allow generic parameters in anon consts if we are inside
|
||||
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
|
||||
None
|
||||
} else if tcx.lazy_normalization() {
|
||||
} else if tcx.features().generic_const_exprs {
|
||||
let parent_node = tcx.hir().get_parent(hir_id);
|
||||
if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
|
||||
&& constant.hir_id == hir_id
|
||||
|
|
@ -123,9 +123,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
{
|
||||
Some(parent_def_id.to_def_id())
|
||||
}
|
||||
Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
|
||||
Some(tcx.typeck_root_def_id(def_id.to_def_id()))
|
||||
}
|
||||
// Exclude `GlobalAsm` here which cannot have generics.
|
||||
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
||||
if asm.operands.iter().any(|(op, _op_sp)| match op {
|
||||
|
|
@ -142,7 +139,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
}
|
||||
}
|
||||
}
|
||||
Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
|
||||
Node::ConstBlock(_)
|
||||
| Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
|
||||
Some(tcx.typeck_root_def_id(def_id.to_def_id()))
|
||||
}
|
||||
Node::Item(item) => match item.kind {
|
||||
|
|
@ -339,17 +337,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
}
|
||||
|
||||
// provide junk type parameter defs for const blocks.
|
||||
if let Node::AnonConst(_) = node {
|
||||
let parent_node = tcx.hir().get_parent(hir_id);
|
||||
if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
|
||||
params.push(ty::GenericParamDef {
|
||||
index: next_index(),
|
||||
name: Symbol::intern("<const_ty>"),
|
||||
def_id: def_id.to_def_id(),
|
||||
pure_wrt_drop: false,
|
||||
kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
|
||||
});
|
||||
}
|
||||
if let Node::ConstBlock(_) = node {
|
||||
params.push(ty::GenericParamDef {
|
||||
index: next_index(),
|
||||
name: Symbol::intern("<const_ty>"),
|
||||
def_id: def_id.to_def_id(),
|
||||
pure_wrt_drop: false,
|
||||
kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
|
||||
});
|
||||
}
|
||||
|
||||
let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
|
||||
|
|
|
|||
|
|
@ -463,7 +463,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
|
||||
if matches!(def_kind, DefKind::AnonConst) && tcx.features().generic_const_exprs {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let parent_def_id = tcx.hir().get_parent_item(hir_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,12 +34,6 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||
Node::Ty(&Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => {
|
||||
return tcx.typeck(def_id).node_type(e.hir_id)
|
||||
}
|
||||
Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
|
||||
if anon_const.hir_id == hir_id =>
|
||||
{
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
|
||||
return substs.as_inline_const().ty()
|
||||
}
|
||||
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
||||
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
|
||||
if asm.operands.iter().any(|(op, _op_sp)| match op {
|
||||
|
|
@ -435,7 +429,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
|
|||
in_trait,
|
||||
..
|
||||
}) => {
|
||||
if in_trait && !tcx.impl_defaultness(owner).has_value() {
|
||||
if in_trait && !tcx.defaultness(owner).has_value() {
|
||||
span_bug!(
|
||||
tcx.def_span(def_id),
|
||||
"tried to get type of this RPITIT with no definition"
|
||||
|
|
@ -487,6 +481,11 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
|
|||
|
||||
Node::AnonConst(_) => anon_const_type_of(tcx, def_id),
|
||||
|
||||
Node::ConstBlock(_) => {
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
|
||||
substs.as_inline_const().ty()
|
||||
}
|
||||
|
||||
Node::GenericParam(param) => match ¶m.kind {
|
||||
GenericParamKind::Type { default: Some(ty), .. }
|
||||
| GenericParamKind::Const { ty, .. } => icx.to_ty(ty),
|
||||
|
|
|
|||
|
|
@ -857,3 +857,21 @@ pub(crate) enum DropImplPolarity {
|
|||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
pub(crate) enum ReturnTypeNotationIllegalParam {
|
||||
#[diag(hir_analysis_return_type_notation_illegal_param_type)]
|
||||
Type {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[label]
|
||||
param_span: Span,
|
||||
},
|
||||
#[diag(hir_analysis_return_type_notation_illegal_param_const)]
|
||||
Const {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[label]
|
||||
param_span: Span,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ pub fn provide(providers: &mut Providers) {
|
|||
fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clause<'_>, Span)] {
|
||||
let id = tcx.hir().local_def_id_to_hir_id(item_def_id);
|
||||
|
||||
if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization()
|
||||
if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst)
|
||||
&& tcx.features().generic_const_exprs
|
||||
{
|
||||
if tcx.hir().opt_const_param_default_param_def_id(id).is_some() {
|
||||
// In `generics_of` we set the generics' parent to be our parent's parent which means that
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ impl<'a> State<'a> {
|
|||
Node::ImplItem(a) => self.print_impl_item(a),
|
||||
Node::Variant(a) => self.print_variant(a),
|
||||
Node::AnonConst(a) => self.print_anon_const(a),
|
||||
Node::ConstBlock(a) => self.print_inline_const(a),
|
||||
Node::Expr(a) => self.print_expr(a),
|
||||
Node::ExprField(a) => self.print_expr_field(&a),
|
||||
Node::Stmt(a) => self.print_stmt(a),
|
||||
|
|
@ -1095,10 +1096,10 @@ impl<'a> State<'a> {
|
|||
self.end()
|
||||
}
|
||||
|
||||
fn print_expr_anon_const(&mut self, anon_const: &hir::AnonConst) {
|
||||
fn print_inline_const(&mut self, constant: &hir::ConstBlock) {
|
||||
self.ibox(INDENT_UNIT);
|
||||
self.word_space("const");
|
||||
self.print_anon_const(anon_const);
|
||||
self.ann.nested(self, Nested::Body(constant.body));
|
||||
self.end()
|
||||
}
|
||||
|
||||
|
|
@ -1370,7 +1371,7 @@ impl<'a> State<'a> {
|
|||
self.print_expr_vec(exprs);
|
||||
}
|
||||
hir::ExprKind::ConstBlock(ref anon_const) => {
|
||||
self.print_expr_anon_const(anon_const);
|
||||
self.print_inline_const(anon_const);
|
||||
}
|
||||
hir::ExprKind::Repeat(element, ref count) => {
|
||||
self.print_expr_repeat(element, count);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ hir_typeck_const_select_must_be_fn = this argument must be a function item
|
|||
|
||||
hir_typeck_convert_to_str = try converting the passed type into a `&str`
|
||||
|
||||
hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to `{$expected}`
|
||||
|
||||
hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private
|
||||
|
||||
hir_typeck_expected_default_return_type = expected `()` because of default return type
|
||||
|
|
|
|||
|
|
@ -689,8 +689,6 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
|
||||
let t_cast = self.cast_ty;
|
||||
let t_expr = self.expr_ty;
|
||||
let type_asc_or =
|
||||
if fcx.tcx.features().type_ascription { "type ascription or " } else { "" };
|
||||
let (adjective, lint) = if t_cast.is_numeric() && t_expr.is_numeric() {
|
||||
("numeric ", lint::builtin::TRIVIAL_NUMERIC_CASTS)
|
||||
} else {
|
||||
|
|
@ -711,7 +709,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
|lint| {
|
||||
lint.help(format!(
|
||||
"cast can be replaced by coercion; this might \
|
||||
require {type_asc_or}a temporary variable"
|
||||
require a temporary variable"
|
||||
))
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -96,7 +96,19 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
// for simple cases like `fn foo(x: Trait)`,
|
||||
// where we would error once on the parameter as a whole, and once on the binding `x`.
|
||||
if param.pat.simple_ident().is_none() && !params_can_be_unsized {
|
||||
fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
|
||||
fcx.require_type_is_sized(
|
||||
param_ty,
|
||||
param.pat.span,
|
||||
// ty_span == binding_span iff this is a closure parameter with no type ascription,
|
||||
// or if it's an implicit `self` parameter
|
||||
traits::SizedArgumentType(
|
||||
if ty_span == Some(param.span) && tcx.is_closure(fn_def_id.into()) {
|
||||
None
|
||||
} else {
|
||||
ty_span
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
fcx.write_ty(param.hir_id, param_ty);
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
// In the new solver, lazy norm may allow us to shallowly equate
|
||||
// more types, but we emit possibly impossible-to-satisfy obligations.
|
||||
// Filter these cases out to make sure our coercion is more accurate.
|
||||
if self.tcx.trait_solver_next() {
|
||||
if self.next_trait_solver() {
|
||||
if let Ok(res) = &res {
|
||||
for obligation in &res.obligations {
|
||||
if !self.predicate_may_hold(&obligation) {
|
||||
|
|
@ -1595,7 +1595,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
Some(blk_id),
|
||||
);
|
||||
if !fcx.tcx.features().unsized_locals {
|
||||
unsized_return = self.is_return_ty_unsized(fcx, blk_id);
|
||||
unsized_return = self.is_return_ty_definitely_unsized(fcx);
|
||||
}
|
||||
if let Some(expression) = expression
|
||||
&& let hir::ExprKind::Loop(loop_blk, ..) = expression.kind {
|
||||
|
|
@ -1614,8 +1614,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
None,
|
||||
);
|
||||
if !fcx.tcx.features().unsized_locals {
|
||||
let id = fcx.tcx.hir().parent_id(id);
|
||||
unsized_return = self.is_return_ty_unsized(fcx, id);
|
||||
unsized_return = self.is_return_ty_definitely_unsized(fcx);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -1896,15 +1895,24 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
err.help("you could instead create a new `enum` with a variant for each returned type");
|
||||
}
|
||||
|
||||
fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
|
||||
if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id)
|
||||
&& let hir::FnRetTy::Return(ty) = fn_decl.output
|
||||
&& let ty = fcx.astconv().ast_ty_to_ty( ty)
|
||||
&& let ty::Dynamic(..) = ty.kind()
|
||||
{
|
||||
return true;
|
||||
/// Checks whether the return type is unsized via an obligation, which makes
|
||||
/// sure we consider `dyn Trait: Sized` where clauses, which are trivially
|
||||
/// false but technically valid for typeck.
|
||||
fn is_return_ty_definitely_unsized(&self, fcx: &FnCtxt<'_, 'tcx>) -> bool {
|
||||
if let Some(sig) = fcx.body_fn_sig() {
|
||||
!fcx.predicate_may_hold(&Obligation::new(
|
||||
fcx.tcx,
|
||||
ObligationCause::dummy(),
|
||||
fcx.param_env,
|
||||
ty::TraitRef::new(
|
||||
fcx.tcx,
|
||||
fcx.tcx.require_lang_item(hir::LangItem::Sized, None),
|
||||
[sig.output()],
|
||||
),
|
||||
))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use rustc_ast::util::parser::PREC_POSTFIX;
|
|||
use rustc_errors::MultiSpan;
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::CtorKind;
|
||||
use rustc_hir::def::{CtorKind, Res};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{is_range_literal, Node};
|
||||
|
|
@ -91,6 +91,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.note_wrong_return_ty_due_to_generic_arg(err, expr, expr_ty);
|
||||
}
|
||||
|
||||
/// Really hacky heuristic to remap an `assert_eq!` error to the user
|
||||
/// expressions provided to the macro.
|
||||
fn adjust_expr_for_assert_eq_macro(
|
||||
&self,
|
||||
found_expr: &mut &'tcx hir::Expr<'tcx>,
|
||||
expected_expr: &mut Option<&'tcx hir::Expr<'tcx>>,
|
||||
) {
|
||||
let Some(expected_expr) = expected_expr else { return; };
|
||||
|
||||
if !found_expr.span.eq_ctxt(expected_expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !found_expr
|
||||
.span
|
||||
.ctxt()
|
||||
.outer_expn_data()
|
||||
.macro_def_id
|
||||
.is_some_and(|def_id| self.tcx.is_diagnostic_item(sym::assert_eq_macro, def_id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let hir::ExprKind::Unary(
|
||||
hir::UnOp::Deref,
|
||||
hir::Expr { kind: hir::ExprKind::Path(found_path), .. },
|
||||
) = found_expr.kind else { return; };
|
||||
let hir::ExprKind::Unary(
|
||||
hir::UnOp::Deref,
|
||||
hir::Expr { kind: hir::ExprKind::Path(expected_path), .. },
|
||||
) = expected_expr.kind else { return; };
|
||||
|
||||
for (path, name, idx, var) in [
|
||||
(expected_path, "left_val", 0, expected_expr),
|
||||
(found_path, "right_val", 1, found_expr),
|
||||
] {
|
||||
if let hir::QPath::Resolved(_, path) = path
|
||||
&& let [segment] = path.segments
|
||||
&& segment.ident.name.as_str() == name
|
||||
&& let Res::Local(hir_id) = path.res
|
||||
&& let Some((_, hir::Node::Expr(match_expr))) = self.tcx.hir().parent_iter(hir_id).nth(2)
|
||||
&& let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind
|
||||
&& let hir::ExprKind::Tup(exprs) = scrutinee.kind
|
||||
&& let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind
|
||||
{
|
||||
*var = macro_arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Requires that the two types unify, and prints an error message if
|
||||
/// they don't.
|
||||
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
|
||||
|
|
@ -156,7 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
pub fn demand_coerce(
|
||||
&self,
|
||||
expr: &hir::Expr<'tcx>,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
checked_ty: Ty<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
|
|
@ -177,10 +227,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
#[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
|
||||
pub fn demand_coerce_diag(
|
||||
&self,
|
||||
expr: &hir::Expr<'tcx>,
|
||||
mut expr: &'tcx hir::Expr<'tcx>,
|
||||
checked_ty: Ty<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
allow_two_phase: AllowTwoPhase,
|
||||
) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>) {
|
||||
let expected = self.resolve_vars_with_obligations(expected);
|
||||
|
|
@ -190,6 +240,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Err(e) => e,
|
||||
};
|
||||
|
||||
self.adjust_expr_for_assert_eq_macro(&mut expr, &mut expected_ty_expr);
|
||||
|
||||
self.set_tainted_by_errors(self.tcx.sess.delay_span_bug(
|
||||
expr.span,
|
||||
"`TypeError` when attempting coercion but no error emitted",
|
||||
|
|
|
|||
|
|
@ -327,3 +327,19 @@ pub struct CtorIsPrivate {
|
|||
pub span: Span,
|
||||
pub def: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
hir_typeck_convert_using_method,
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub struct SuggestConvertViaMethod<'tcx> {
|
||||
#[suggestion_part(code = "{sugg}")]
|
||||
pub span: Span,
|
||||
#[suggestion_part(code = "")]
|
||||
pub borrow_removal_span: Option<Span>,
|
||||
pub sugg: &'static str,
|
||||
pub expected: Ty<'tcx>,
|
||||
pub found: Ty<'tcx>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -348,9 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
|
||||
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
|
||||
ExprKind::ConstBlock(ref anon_const) => {
|
||||
self.check_expr_const_block(anon_const, expected, expr)
|
||||
}
|
||||
ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected, expr),
|
||||
ExprKind::Repeat(element, ref count) => {
|
||||
self.check_expr_repeat(element, count, expected, expr)
|
||||
}
|
||||
|
|
@ -1368,20 +1366,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
fn check_expr_const_block(
|
||||
&self,
|
||||
anon_const: &'tcx hir::AnonConst,
|
||||
block: &'tcx hir::ConstBlock,
|
||||
expected: Expectation<'tcx>,
|
||||
_expr: &'tcx hir::Expr<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let body = self.tcx.hir().body(anon_const.body);
|
||||
let body = self.tcx.hir().body(block.body);
|
||||
|
||||
// Create a new function context.
|
||||
let def_id = anon_const.def_id;
|
||||
let def_id = block.def_id;
|
||||
let fcx = FnCtxt::new(self, self.param_env.with_const(), def_id);
|
||||
crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
|
||||
|
||||
let ty = fcx.check_expr_with_expectation(&body.value, expected);
|
||||
fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
|
||||
fcx.write_ty(anon_const.hir_id, ty);
|
||||
fcx.write_ty(block.hir_id, ty);
|
||||
ty
|
||||
}
|
||||
|
||||
|
|
@ -2083,13 +2081,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
},
|
||||
_ => {
|
||||
// prevent all specified fields from being suggested
|
||||
let skip_fields = skip_fields.iter().map(|x| x.ident.name);
|
||||
if let Some(field_name) = self.suggest_field_name(
|
||||
variant,
|
||||
field.ident.name,
|
||||
skip_fields.collect(),
|
||||
expr_span,
|
||||
) {
|
||||
let skip_fields: Vec<_> = skip_fields.iter().map(|x| x.ident.name).collect();
|
||||
if let Some(field_name) =
|
||||
self.suggest_field_name(variant, field.ident.name, &skip_fields, expr_span)
|
||||
{
|
||||
err.span_suggestion(
|
||||
field.ident.span,
|
||||
"a field with a similar name exists",
|
||||
|
|
@ -2110,9 +2105,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
format!("`{ty}` does not have this field"),
|
||||
);
|
||||
}
|
||||
let available_field_names =
|
||||
let mut available_field_names =
|
||||
self.available_field_names(variant, expr_span);
|
||||
if !available_field_names.is_empty() {
|
||||
available_field_names
|
||||
.retain(|name| skip_fields.iter().all(|skip| name != skip));
|
||||
if available_field_names.is_empty() {
|
||||
err.note("all struct fields are already assigned");
|
||||
} else {
|
||||
err.note(format!(
|
||||
"available fields are: {}",
|
||||
self.name_series_display(available_field_names)
|
||||
|
|
@ -2132,7 +2131,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
variant: &'tcx ty::VariantDef,
|
||||
field: Symbol,
|
||||
skip: Vec<Symbol>,
|
||||
skip: &[Symbol],
|
||||
// The span where stability will be checked
|
||||
span: Span,
|
||||
) -> Option<Symbol> {
|
||||
|
|
@ -2584,7 +2583,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
access_span: Span,
|
||||
) {
|
||||
if let Some(suggested_field_name) =
|
||||
self.suggest_field_name(def.non_enum_variant(), field.name, vec![], access_span)
|
||||
self.suggest_field_name(def.non_enum_variant(), field.name, &[], access_span)
|
||||
{
|
||||
err.span_suggestion(
|
||||
field.span,
|
||||
|
|
@ -3117,16 +3116,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
ty::Tuple(tys) => {
|
||||
let fstr = field.as_str();
|
||||
if let Ok(index) = field.as_str().parse::<usize>()
|
||||
&& field.name == sym::integer(index)
|
||||
{
|
||||
for ty in tys.iter().take(index + 1) {
|
||||
self.require_type_is_sized(ty, expr.span, traits::MiscObligation);
|
||||
}
|
||||
if let Some(&field_ty) = tys.get(index) {
|
||||
field_indices.push(index.into());
|
||||
current_container = field_ty;
|
||||
|
||||
if let Ok(index) = fstr.parse::<usize>() {
|
||||
if fstr == index.to_string() {
|
||||
if let Some(&field_ty) = tys.get(index) {
|
||||
field_indices.push(index.into());
|
||||
current_container = field_ty;
|
||||
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1476,7 +1476,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
let mut ty = self.resolve_vars_with_obligations(ty);
|
||||
|
||||
if self.tcx.trait_solver_next()
|
||||
if self.next_trait_solver()
|
||||
&& let ty::Alias(ty::Projection, _) = ty.kind()
|
||||
{
|
||||
match self
|
||||
|
|
|
|||
|
|
@ -362,7 +362,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
continue;
|
||||
}
|
||||
|
||||
let is_closure = matches!(arg.kind, ExprKind::Closure { .. });
|
||||
// For this check, we do *not* want to treat async generator closures (async blocks)
|
||||
// as proper closures. Doing so would regress type inference when feeding
|
||||
// the return value of an argument-position async block to an argument-position
|
||||
// closure wrapped in a block.
|
||||
// See <https://github.com/rust-lang/rust/issues/112225>.
|
||||
let is_closure = if let ExprKind::Closure(closure) = arg.kind {
|
||||
!tcx.generator_is_async(closure.def_id.to_def_id())
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if is_closure != check_closures {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1395,7 +1404,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// type of the place it is referencing, and not some
|
||||
// supertype thereof.
|
||||
let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m));
|
||||
self.demand_eqtype(init.span, local_ty, init_ty);
|
||||
if let Some(mut diag) = self.demand_eqtype_diag(init.span, local_ty, init_ty) {
|
||||
self.emit_type_mismatch_suggestions(
|
||||
&mut diag,
|
||||
init.peel_drop_temps(),
|
||||
init_ty,
|
||||
local_ty,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
diag.emit();
|
||||
}
|
||||
init_ty
|
||||
} else {
|
||||
self.check_expr_coercible_to_type(init, local_ty, None)
|
||||
|
|
@ -1631,7 +1650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
hir::Stmt {
|
||||
kind:
|
||||
hir::StmtKind::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Assign(..),
|
||||
kind: hir::ExprKind::Assign(lhs, ..),
|
||||
..
|
||||
}),
|
||||
..
|
||||
|
|
@ -1641,7 +1660,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} = blk
|
||||
{
|
||||
self.comes_from_while_condition(blk.hir_id, |_| {
|
||||
err.downgrade_to_delayed_bug();
|
||||
// We cannot suppress the error if the LHS of assignment
|
||||
// is a syntactic place expression because E0070 would
|
||||
// not be emitted by `check_lhs_assignable`.
|
||||
let res = self.typeck_results.borrow().expr_ty_opt(lhs);
|
||||
|
||||
if !lhs.is_syntactic_place_expr()
|
||||
|| res.references_error()
|
||||
{
|
||||
err.downgrade_to_delayed_bug();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use super::FnCtxt;
|
||||
|
||||
use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing};
|
||||
use crate::errors::{
|
||||
AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing, SuggestConvertViaMethod,
|
||||
};
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
|
||||
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
|
||||
|
|
@ -275,6 +277,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||
) -> bool {
|
||||
let expr = expr.peel_blocks();
|
||||
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
|
||||
|
||||
if let Some((suggestion, msg, applicability, verbose, annotation)) =
|
||||
self.suggest_deref_or_ref(expr, found, expected)
|
||||
{
|
||||
|
|
@ -325,9 +329,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
return true;
|
||||
} else if self.suggest_else_fn_with_closure(err, expr, found, expected) {
|
||||
}
|
||||
|
||||
if self.suggest_else_fn_with_closure(err, expr, found, expected) {
|
||||
return true;
|
||||
} else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
|
||||
}
|
||||
|
||||
if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
|
||||
&& let ty::FnDef(def_id, ..) = *found.kind()
|
||||
&& let Some(sp) = self.tcx.hir().span_if_local(def_id)
|
||||
{
|
||||
|
|
@ -343,97 +351,156 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err.span_label(sp, format!("{descr} `{name}` defined here"));
|
||||
}
|
||||
return true;
|
||||
} else if self.suggest_cast(err, expr, found, expected, expected_ty_expr) {
|
||||
return true;
|
||||
} else {
|
||||
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
|
||||
if !methods.is_empty() {
|
||||
let mut suggestions = methods.iter()
|
||||
.filter_map(|conversion_method| {
|
||||
let receiver_method_ident = expr.method_ident();
|
||||
if let Some(method_ident) = receiver_method_ident
|
||||
&& method_ident.name == conversion_method.name
|
||||
{
|
||||
return None // do not suggest code that is already there (#53348)
|
||||
}
|
||||
}
|
||||
|
||||
let method_call_list = [sym::to_vec, sym::to_string];
|
||||
let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
|
||||
&& receiver_method.ident.name == sym::clone
|
||||
&& method_call_list.contains(&conversion_method.name)
|
||||
// If receiver is `.clone()` and found type has one of those methods,
|
||||
// we guess that the user wants to convert from a slice type (`&[]` or `&str`)
|
||||
// to an owned type (`Vec` or `String`). These conversions clone internally,
|
||||
// so we remove the user's `clone` call.
|
||||
{
|
||||
vec![(
|
||||
receiver_method.ident.span,
|
||||
conversion_method.name.to_string()
|
||||
)]
|
||||
} else if expr.precedence().order()
|
||||
< ExprPrecedence::MethodCall.order()
|
||||
{
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), "(".to_string()),
|
||||
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
|
||||
]
|
||||
} else {
|
||||
vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))]
|
||||
};
|
||||
let struct_pat_shorthand_field = self.maybe_get_struct_pattern_shorthand_field(expr);
|
||||
if let Some(name) = struct_pat_shorthand_field {
|
||||
sugg.insert(
|
||||
0,
|
||||
(expr.span.shrink_to_lo(), format!("{}: ", name)),
|
||||
);
|
||||
}
|
||||
Some(sugg)
|
||||
})
|
||||
.peekable();
|
||||
if suggestions.peek().is_some() {
|
||||
err.multipart_suggestions(
|
||||
"try using a conversion method",
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
} else if let ty::Adt(found_adt, found_substs) = found.kind()
|
||||
&& self.tcx.is_diagnostic_item(sym::Option, found_adt.did())
|
||||
&& let ty::Adt(expected_adt, expected_substs) = expected.kind()
|
||||
&& self.tcx.is_diagnostic_item(sym::Option, expected_adt.did())
|
||||
&& let ty::Ref(_, inner_ty, _) = expected_substs.type_at(0).kind()
|
||||
&& inner_ty.is_str()
|
||||
{
|
||||
let ty = found_substs.type_at(0);
|
||||
let mut peeled = ty;
|
||||
let mut ref_cnt = 0;
|
||||
while let ty::Ref(_, inner, _) = peeled.kind() {
|
||||
peeled = *inner;
|
||||
ref_cnt += 1;
|
||||
}
|
||||
if let ty::Adt(adt, _) = peeled.kind()
|
||||
&& Some(adt.did()) == self.tcx.lang_items().string()
|
||||
{
|
||||
let sugg = if ref_cnt == 0 {
|
||||
".as_deref()"
|
||||
if self.suggest_cast(err, expr, found, expected, expected_ty_expr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if !methods.is_empty() {
|
||||
let mut suggestions = methods
|
||||
.iter()
|
||||
.filter_map(|conversion_method| {
|
||||
let receiver_method_ident = expr.method_ident();
|
||||
if let Some(method_ident) = receiver_method_ident
|
||||
&& method_ident.name == conversion_method.name
|
||||
{
|
||||
return None // do not suggest code that is already there (#53348)
|
||||
}
|
||||
|
||||
let method_call_list = [sym::to_vec, sym::to_string];
|
||||
let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
|
||||
&& receiver_method.ident.name == sym::clone
|
||||
&& method_call_list.contains(&conversion_method.name)
|
||||
// If receiver is `.clone()` and found type has one of those methods,
|
||||
// we guess that the user wants to convert from a slice type (`&[]` or `&str`)
|
||||
// to an owned type (`Vec` or `String`). These conversions clone internally,
|
||||
// so we remove the user's `clone` call.
|
||||
{
|
||||
vec![(
|
||||
receiver_method.ident.span,
|
||||
conversion_method.name.to_string()
|
||||
)]
|
||||
} else if expr.precedence().order()
|
||||
< ExprPrecedence::MethodCall.order()
|
||||
{
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), "(".to_string()),
|
||||
(expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
|
||||
]
|
||||
} else {
|
||||
".map(|x| x.as_str())"
|
||||
vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))]
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_hi(),
|
||||
fluent::hir_typeck_convert_to_str,
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
let struct_pat_shorthand_field =
|
||||
self.maybe_get_struct_pattern_shorthand_field(expr);
|
||||
if let Some(name) = struct_pat_shorthand_field {
|
||||
sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name)));
|
||||
}
|
||||
Some(sugg)
|
||||
})
|
||||
.peekable();
|
||||
if suggestions.peek().is_some() {
|
||||
err.multipart_suggestions(
|
||||
"try using a conversion method",
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((found_ty_inner, expected_ty_inner, error_tys)) =
|
||||
self.deconstruct_option_or_result(found, expected)
|
||||
&& let ty::Ref(_, peeled, hir::Mutability::Not) = *expected_ty_inner.kind()
|
||||
{
|
||||
// Suggest removing any stray borrows (unless there's macro shenanigans involved).
|
||||
let inner_expr = expr.peel_borrows();
|
||||
if !inner_expr.span.eq_ctxt(expr.span) {
|
||||
return false;
|
||||
}
|
||||
let borrow_removal_span = if inner_expr.hir_id == expr.hir_id {
|
||||
None
|
||||
} else {
|
||||
Some(expr.span.shrink_to_lo().until(inner_expr.span))
|
||||
};
|
||||
// Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for
|
||||
// `as_ref` and `as_deref` compatibility.
|
||||
let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| {
|
||||
self.can_eq(self.param_env, self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, found), expected)
|
||||
});
|
||||
// FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`,
|
||||
// but those checks need to be a bit more delicate and the benefit is diminishing.
|
||||
if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref {
|
||||
err.subdiagnostic(SuggestConvertViaMethod {
|
||||
span: expr.span.shrink_to_hi(),
|
||||
sugg: ".as_ref()",
|
||||
expected,
|
||||
found,
|
||||
borrow_removal_span,
|
||||
});
|
||||
return true;
|
||||
} else if let Some((deref_ty, _)) =
|
||||
self.autoderef(expr.span, found_ty_inner).silence_errors().nth(1)
|
||||
&& self.can_eq(self.param_env, deref_ty, peeled)
|
||||
&& error_tys_equate_as_ref
|
||||
{
|
||||
err.subdiagnostic(SuggestConvertViaMethod {
|
||||
span: expr.span.shrink_to_hi(),
|
||||
sugg: ".as_deref()",
|
||||
expected,
|
||||
found,
|
||||
borrow_removal_span,
|
||||
});
|
||||
return true;
|
||||
} else if let ty::Adt(adt, _) = found_ty_inner.peel_refs().kind()
|
||||
&& Some(adt.did()) == self.tcx.lang_items().string()
|
||||
&& peeled.is_str()
|
||||
// `Result::map`, conversely, does not take ref of the error type.
|
||||
&& error_tys.map_or(true, |(found, expected)| {
|
||||
self.can_eq(self.param_env, found, expected)
|
||||
})
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
expr.span.shrink_to_hi(),
|
||||
fluent::hir_typeck_convert_to_str,
|
||||
".map(|x| x.as_str())",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn deconstruct_option_or_result(
|
||||
&self,
|
||||
found_ty: Ty<'tcx>,
|
||||
expected_ty: Ty<'tcx>,
|
||||
) -> Option<(Ty<'tcx>, Ty<'tcx>, Option<(Ty<'tcx>, Ty<'tcx>)>)> {
|
||||
let ty::Adt(found_adt, found_substs) = found_ty.peel_refs().kind() else {
|
||||
return None;
|
||||
};
|
||||
let ty::Adt(expected_adt, expected_substs) = expected_ty.kind() else {
|
||||
return None;
|
||||
};
|
||||
if self.tcx.is_diagnostic_item(sym::Option, found_adt.did())
|
||||
&& self.tcx.is_diagnostic_item(sym::Option, expected_adt.did())
|
||||
{
|
||||
Some((found_substs.type_at(0), expected_substs.type_at(0), None))
|
||||
} else if self.tcx.is_diagnostic_item(sym::Result, found_adt.did())
|
||||
&& self.tcx.is_diagnostic_item(sym::Result, expected_adt.did())
|
||||
{
|
||||
Some((
|
||||
found_substs.type_at(0),
|
||||
expected_substs.type_at(0),
|
||||
Some((found_substs.type_at(1), expected_substs.type_at(1))),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// When encountering the expected boxed value allocated in the stack, suggest allocating it
|
||||
/// in the heap by calling `Box::new()`.
|
||||
pub(in super::super) fn suggest_boxing_when_appropriate(
|
||||
|
|
|
|||
|
|
@ -129,7 +129,17 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
|
|||
self.fcx.require_type_is_sized(
|
||||
var_ty,
|
||||
p.span,
|
||||
traits::SizedArgumentType(Some(ty_span)),
|
||||
// ty_span == ident.span iff this is a closure parameter with no type
|
||||
// ascription, or if it's an implicit `self` parameter
|
||||
traits::SizedArgumentType(
|
||||
if ty_span == ident.span
|
||||
&& self.fcx.tcx.is_closure(self.fcx.body_id.into())
|
||||
{
|
||||
None
|
||||
} else {
|
||||
Some(ty_span)
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -270,6 +270,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
|
|||
| hir::Node::Variant(..)
|
||||
| hir::Node::Field(..)
|
||||
| hir::Node::AnonConst(..)
|
||||
| hir::Node::ConstBlock(..)
|
||||
| hir::Node::Stmt(..)
|
||||
| hir::Node::PathSegment(..)
|
||||
| hir::Node::Ty(..)
|
||||
|
|
|
|||
|
|
@ -86,8 +86,8 @@ impl<'tcx> Inherited<'tcx> {
|
|||
|
||||
Inherited {
|
||||
typeck_results,
|
||||
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(&infcx)),
|
||||
infcx,
|
||||
fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(tcx)),
|
||||
locals: RefCell::new(Default::default()),
|
||||
deferred_sized_obligations: RefCell::new(Vec::new()),
|
||||
deferred_call_resolutions: RefCell::new(Default::default()),
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ use rustc_data_structures::fx::FxHashSet;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir_analysis::astconv::InferCtxtExt as _;
|
||||
use rustc_hir_analysis::autoderef::{self, Autoderef};
|
||||
use rustc_infer::infer::canonical::OriginalQueryValues;
|
||||
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
||||
|
|
@ -954,7 +953,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
trait_def_id: DefId,
|
||||
) {
|
||||
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
|
||||
let trait_substs = self.fresh_item_substs(trait_def_id);
|
||||
let trait_substs = self.fresh_substs_for_item(self.span, trait_def_id);
|
||||
let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_substs);
|
||||
|
||||
if self.tcx.is_trait_alias(trait_def_id) {
|
||||
|
|
@ -1899,7 +1898,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
&self,
|
||||
impl_def_id: DefId,
|
||||
) -> (ty::EarlyBinder<Ty<'tcx>>, SubstsRef<'tcx>) {
|
||||
(self.tcx.type_of(impl_def_id), self.fresh_item_substs(impl_def_id))
|
||||
(self.tcx.type_of(impl_def_id), self.fresh_substs_for_item(self.span, impl_def_id))
|
||||
}
|
||||
|
||||
/// Replaces late-bound-regions bound by `value` with `'static` using
|
||||
|
|
|
|||
|
|
@ -2110,20 +2110,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| sym::Hash
|
||||
| sym::Debug => true,
|
||||
_ => false,
|
||||
} && match trait_pred.trait_ref.substs.as_slice() {
|
||||
// Only suggest deriving if lhs == rhs...
|
||||
[lhs, rhs] => {
|
||||
if let Some(lhs) = lhs.as_type()
|
||||
&& let Some(rhs) = rhs.as_type()
|
||||
{
|
||||
self.can_eq(self.param_env, lhs, rhs)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
// Unary ops can always be derived
|
||||
[_] => true,
|
||||
_ => false,
|
||||
};
|
||||
if can_derive {
|
||||
let self_name = trait_pred.self_ty().to_string();
|
||||
|
|
|
|||
|
|
@ -393,9 +393,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// They can denote both statically and dynamically-sized byte arrays.
|
||||
let mut pat_ty = ty;
|
||||
if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(..), .. }) = lt.kind {
|
||||
let expected = self.structurally_resolved_type(span, expected);
|
||||
if let ty::Ref(_, inner_ty, _) = expected.kind()
|
||||
&& matches!(inner_ty.kind(), ty::Slice(_))
|
||||
if let ty::Ref(_, inner_ty, _) = *self.structurally_resolved_type(span, expected).kind()
|
||||
&& self.structurally_resolved_type(span, inner_ty).is_slice()
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ use rustc_middle::mir::FakeReadCause;
|
|||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
|
||||
use rustc_middle::ty::TypeckResults;
|
||||
use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
|
@ -148,31 +147,25 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr<'_>) {
|
||||
match e.kind {
|
||||
hir::ExprKind::Unary(hir::UnOp::Neg | hir::UnOp::Not, inner) => {
|
||||
let inner_ty = self.fcx.node_ty(inner.hir_id);
|
||||
let inner_ty = self.fcx.resolve_vars_if_possible(inner_ty);
|
||||
let inner_ty = self.typeck_results.node_type(inner.hir_id);
|
||||
|
||||
if inner_ty.is_scalar() {
|
||||
let mut typeck_results = self.fcx.typeck_results.borrow_mut();
|
||||
typeck_results.type_dependent_defs_mut().remove(e.hir_id);
|
||||
typeck_results.node_substs_mut().remove(e.hir_id);
|
||||
self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
|
||||
self.typeck_results.node_substs_mut().remove(e.hir_id);
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Binary(ref op, lhs, rhs) | hir::ExprKind::AssignOp(ref op, lhs, rhs) => {
|
||||
let lhs_ty = self.fcx.node_ty(lhs.hir_id);
|
||||
let lhs_ty = self.fcx.resolve_vars_if_possible(lhs_ty);
|
||||
|
||||
let rhs_ty = self.fcx.node_ty(rhs.hir_id);
|
||||
let rhs_ty = self.fcx.resolve_vars_if_possible(rhs_ty);
|
||||
let lhs_ty = self.typeck_results.node_type(lhs.hir_id);
|
||||
let rhs_ty = self.typeck_results.node_type(rhs.hir_id);
|
||||
|
||||
if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
|
||||
let mut typeck_results = self.fcx.typeck_results.borrow_mut();
|
||||
typeck_results.type_dependent_defs_mut().remove(e.hir_id);
|
||||
typeck_results.node_substs_mut().remove(e.hir_id);
|
||||
self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
|
||||
self.typeck_results.node_substs_mut().remove(e.hir_id);
|
||||
|
||||
match e.kind {
|
||||
hir::ExprKind::Binary(..) => {
|
||||
if !op.node.is_by_value() {
|
||||
let mut adjustments = typeck_results.adjustments_mut();
|
||||
let mut adjustments = self.typeck_results.adjustments_mut();
|
||||
if let Some(a) = adjustments.get_mut(lhs.hir_id) {
|
||||
a.pop();
|
||||
}
|
||||
|
|
@ -182,7 +175,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
hir::ExprKind::AssignOp(..)
|
||||
if let Some(a) = typeck_results.adjustments_mut().get_mut(lhs.hir_id) =>
|
||||
if let Some(a) = self.typeck_results.adjustments_mut().get_mut(lhs.hir_id) =>
|
||||
{
|
||||
a.pop();
|
||||
}
|
||||
|
|
@ -200,16 +193,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
// if they are not we don't modify the expr, hence we bypass the ICE
|
||||
fn is_builtin_index(
|
||||
&mut self,
|
||||
typeck_results: &TypeckResults<'tcx>,
|
||||
e: &hir::Expr<'_>,
|
||||
base_ty: Ty<'tcx>,
|
||||
index_ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
if let Some(elem_ty) = base_ty.builtin_index() {
|
||||
let Some(exp_ty) = typeck_results.expr_ty_opt(e) else {return false;};
|
||||
let resolved_exp_ty = self.resolve(exp_ty, &e.span);
|
||||
|
||||
elem_ty == resolved_exp_ty && index_ty == self.fcx.tcx.types.usize
|
||||
if let Some(elem_ty) = base_ty.builtin_index()
|
||||
&& let Some(exp_ty) = self.typeck_results.expr_ty_opt(e)
|
||||
{
|
||||
elem_ty == exp_ty && index_ty == self.fcx.tcx.types.usize
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
@ -221,38 +212,34 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
// usize-ish
|
||||
fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) {
|
||||
if let hir::ExprKind::Index(ref base, ref index) = e.kind {
|
||||
let mut typeck_results = self.fcx.typeck_results.borrow_mut();
|
||||
|
||||
// All valid indexing looks like this; might encounter non-valid indexes at this point.
|
||||
let base_ty = typeck_results
|
||||
.expr_ty_adjusted_opt(base)
|
||||
.map(|t| self.fcx.resolve_vars_if_possible(t).kind());
|
||||
let base_ty = self.typeck_results.expr_ty_adjusted_opt(base);
|
||||
if base_ty.is_none() {
|
||||
// When encountering `return [0][0]` outside of a `fn` body we can encounter a base
|
||||
// that isn't in the type table. We assume more relevant errors have already been
|
||||
// emitted, so we delay an ICE if none have. (#64638)
|
||||
self.tcx().sess.delay_span_bug(e.span, format!("bad base: `{:?}`", base));
|
||||
}
|
||||
if let Some(ty::Ref(_, base_ty, _)) = base_ty {
|
||||
let index_ty = typeck_results.expr_ty_adjusted_opt(index).unwrap_or_else(|| {
|
||||
// When encountering `return [0][0]` outside of a `fn` body we would attempt
|
||||
// to access an nonexistent index. We assume that more relevant errors will
|
||||
// already have been emitted, so we only gate on this with an ICE if no
|
||||
// error has been emitted. (#64638)
|
||||
self.fcx.tcx.ty_error_with_message(
|
||||
e.span,
|
||||
format!("bad index {:?} for base: `{:?}`", index, base),
|
||||
)
|
||||
});
|
||||
let index_ty = self.fcx.resolve_vars_if_possible(index_ty);
|
||||
let resolved_base_ty = self.resolve(*base_ty, &base.span);
|
||||
|
||||
if self.is_builtin_index(&typeck_results, e, resolved_base_ty, index_ty) {
|
||||
if let Some(base_ty) = base_ty
|
||||
&& let ty::Ref(_, base_ty_inner, _) = *base_ty.kind()
|
||||
{
|
||||
let index_ty =
|
||||
self.typeck_results.expr_ty_adjusted_opt(index).unwrap_or_else(|| {
|
||||
// When encountering `return [0][0]` outside of a `fn` body we would attempt
|
||||
// to access an nonexistent index. We assume that more relevant errors will
|
||||
// already have been emitted, so we only gate on this with an ICE if no
|
||||
// error has been emitted. (#64638)
|
||||
self.fcx.tcx.ty_error_with_message(
|
||||
e.span,
|
||||
format!("bad index {:?} for base: `{:?}`", index, base),
|
||||
)
|
||||
});
|
||||
if self.is_builtin_index(e, base_ty_inner, index_ty) {
|
||||
// Remove the method call record
|
||||
typeck_results.type_dependent_defs_mut().remove(e.hir_id);
|
||||
typeck_results.node_substs_mut().remove(e.hir_id);
|
||||
self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
|
||||
self.typeck_results.node_substs_mut().remove(e.hir_id);
|
||||
|
||||
if let Some(a) = typeck_results.adjustments_mut().get_mut(base.hir_id) {
|
||||
if let Some(a) = self.typeck_results.adjustments_mut().get_mut(base.hir_id) {
|
||||
// Discard the need for a mutable borrow
|
||||
|
||||
// Extra adjustment made when indexing causes a drop
|
||||
|
|
@ -283,9 +270,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
|
||||
impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
||||
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
|
||||
self.fix_scalar_builtin_expr(e);
|
||||
self.fix_index_builtin_expr(e);
|
||||
|
||||
match e.kind {
|
||||
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
|
||||
let body = self.fcx.tcx.hir().body(body);
|
||||
|
|
@ -314,6 +298,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
|||
|
||||
self.visit_node_id(e.span, e.hir_id);
|
||||
intravisit::walk_expr(self, e);
|
||||
|
||||
self.fix_scalar_builtin_expr(e);
|
||||
self.fix_index_builtin_expr(e);
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
|
||||
|
|
@ -591,7 +578,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
.insert(opaque_type_key, hidden_type)
|
||||
&& last_opaque_ty.ty != hidden_type.ty
|
||||
{
|
||||
assert!(!self.tcx().trait_solver_next());
|
||||
assert!(!self.fcx.next_trait_solver());
|
||||
hidden_type
|
||||
.report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx())
|
||||
.stash(
|
||||
|
|
@ -812,7 +799,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
|
|||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match self.fcx.fully_resolve(t) {
|
||||
Ok(t) if self.fcx.tcx.trait_solver_next() => {
|
||||
Ok(t) if self.fcx.next_trait_solver() => {
|
||||
// We must normalize erasing regions here, since later lints
|
||||
// expect that types that show up in the typeck are fully
|
||||
// normalized.
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
use crate::errors;
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::graph::implementation::{Direction, NodeIndex, INCOMING, OUTGOING};
|
||||
use rustc_graphviz as dot;
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -258,7 +258,7 @@ fn dump_graph(query: &DepGraphQuery) {
|
|||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub struct GraphvizDepGraph(FxHashSet<DepKind>, Vec<(DepKind, DepKind)>);
|
||||
pub struct GraphvizDepGraph(FxIndexSet<DepKind>, Vec<(DepKind, DepKind)>);
|
||||
|
||||
impl<'a> dot::GraphWalk<'a> for GraphvizDepGraph {
|
||||
type Node = DepKind;
|
||||
|
|
@ -303,7 +303,7 @@ impl<'a> dot::Labeller<'a> for GraphvizDepGraph {
|
|||
fn node_set<'q>(
|
||||
query: &'q DepGraphQuery,
|
||||
filter: &DepNodeFilter,
|
||||
) -> Option<FxHashSet<&'q DepNode>> {
|
||||
) -> Option<FxIndexSet<&'q DepNode>> {
|
||||
debug!("node_set(filter={:?})", filter);
|
||||
|
||||
if filter.accepts_all() {
|
||||
|
|
@ -315,9 +315,9 @@ fn node_set<'q>(
|
|||
|
||||
fn filter_nodes<'q>(
|
||||
query: &'q DepGraphQuery,
|
||||
sources: &Option<FxHashSet<&'q DepNode>>,
|
||||
targets: &Option<FxHashSet<&'q DepNode>>,
|
||||
) -> FxHashSet<DepKind> {
|
||||
sources: &Option<FxIndexSet<&'q DepNode>>,
|
||||
targets: &Option<FxIndexSet<&'q DepNode>>,
|
||||
) -> FxIndexSet<DepKind> {
|
||||
if let Some(sources) = sources {
|
||||
if let Some(targets) = targets {
|
||||
walk_between(query, sources, targets)
|
||||
|
|
@ -333,10 +333,10 @@ fn filter_nodes<'q>(
|
|||
|
||||
fn walk_nodes<'q>(
|
||||
query: &'q DepGraphQuery,
|
||||
starts: &FxHashSet<&'q DepNode>,
|
||||
starts: &FxIndexSet<&'q DepNode>,
|
||||
direction: Direction,
|
||||
) -> FxHashSet<DepKind> {
|
||||
let mut set = FxHashSet::default();
|
||||
) -> FxIndexSet<DepKind> {
|
||||
let mut set = FxIndexSet::default();
|
||||
for &start in starts {
|
||||
debug!("walk_nodes: start={:?} outgoing?={:?}", start, direction == OUTGOING);
|
||||
if set.insert(start.kind) {
|
||||
|
|
@ -357,9 +357,9 @@ fn walk_nodes<'q>(
|
|||
|
||||
fn walk_between<'q>(
|
||||
query: &'q DepGraphQuery,
|
||||
sources: &FxHashSet<&'q DepNode>,
|
||||
targets: &FxHashSet<&'q DepNode>,
|
||||
) -> FxHashSet<DepKind> {
|
||||
sources: &FxIndexSet<&'q DepNode>,
|
||||
targets: &FxIndexSet<&'q DepNode>,
|
||||
) -> FxIndexSet<DepKind> {
|
||||
// This is a bit tricky. We want to include a node only if it is:
|
||||
// (a) reachable from a source and (b) will reach a target. And we
|
||||
// have to be careful about cycles etc. Luckily efficiency is not
|
||||
|
|
@ -426,8 +426,8 @@ fn walk_between<'q>(
|
|||
}
|
||||
}
|
||||
|
||||
fn filter_edges(query: &DepGraphQuery, nodes: &FxHashSet<DepKind>) -> Vec<(DepKind, DepKind)> {
|
||||
let uniq: FxHashSet<_> = query
|
||||
fn filter_edges(query: &DepGraphQuery, nodes: &FxIndexSet<DepKind>) -> Vec<(DepKind, DepKind)> {
|
||||
let uniq: FxIndexSet<_> = query
|
||||
.edges()
|
||||
.into_iter()
|
||||
.map(|(s, t)| (s.kind, t.kind))
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
use crate::errors;
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_middle::mir::mono::CodegenUnitNameBuilder;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
|
@ -52,7 +52,7 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) {
|
|||
|
||||
struct AssertModuleSource<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
available_cgus: FxHashSet<Symbol>,
|
||||
available_cgus: UnordSet<Symbol>,
|
||||
}
|
||||
|
||||
impl<'tcx> AssertModuleSource<'tcx> {
|
||||
|
|
@ -118,9 +118,8 @@ impl<'tcx> AssertModuleSource<'tcx> {
|
|||
debug!("mapping '{}' to cgu name '{}'", self.field(attr, sym::module), cgu_name);
|
||||
|
||||
if !self.available_cgus.contains(&cgu_name) {
|
||||
let mut cgu_names: Vec<&str> =
|
||||
self.available_cgus.iter().map(|cgu| cgu.as_str()).collect();
|
||||
cgu_names.sort();
|
||||
let cgu_names: Vec<&str> =
|
||||
self.available_cgus.items().map(|cgu| cgu.as_str()).into_sorted_stable_ord();
|
||||
self.tcx.sess.emit_err(errors::NoModuleNamed {
|
||||
span: attr.span,
|
||||
user_path,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![feature(never_type)]
|
||||
#![recursion_limit = "256"]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
use crate::errors;
|
||||
use rustc_ast::{self as ast, Attribute, NestedMetaItem};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::Node as HirNode;
|
||||
|
|
@ -125,7 +126,7 @@ const LABELS_ADT: &[&[&str]] = &[BASE_HIR, BASE_STRUCT];
|
|||
//
|
||||
// type_of for these.
|
||||
|
||||
type Labels = FxHashSet<String>;
|
||||
type Labels = UnordSet<String>;
|
||||
|
||||
/// Represents the requested configuration by rustc_clean/dirty
|
||||
struct Assertion {
|
||||
|
|
@ -197,7 +198,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
|
|||
let (name, mut auto) = self.auto_labels(item_id, attr);
|
||||
let except = self.except(attr);
|
||||
let loaded_from_disk = self.loaded_from_disk(attr);
|
||||
for e in except.iter() {
|
||||
for e in except.items().map(|x| x.as_str()).into_sorted_stable_ord() {
|
||||
if !auto.remove(e) {
|
||||
self.tcx.sess.emit_fatal(errors::AssertionAuto { span: attr.span, name, e });
|
||||
}
|
||||
|
|
@ -376,15 +377,17 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
|
|||
continue;
|
||||
};
|
||||
self.checked_attrs.insert(attr.id);
|
||||
for label in assertion.clean {
|
||||
for label in assertion.clean.items().map(|x| x.as_str()).into_sorted_stable_ord() {
|
||||
let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
|
||||
self.assert_clean(item_span, dep_node);
|
||||
}
|
||||
for label in assertion.dirty {
|
||||
for label in assertion.dirty.items().map(|x| x.as_str()).into_sorted_stable_ord() {
|
||||
let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
|
||||
self.assert_dirty(item_span, dep_node);
|
||||
}
|
||||
for label in assertion.loaded_from_disk {
|
||||
for label in
|
||||
assertion.loaded_from_disk.items().map(|x| x.as_str()).into_sorted_stable_ord()
|
||||
{
|
||||
let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
|
||||
self.assert_loaded_from_disk(item_span, dep_node);
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue