Merge ref 'f4665ab836' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh. Upstream ref:f4665ab836Filtered ref: d2e3c00d12fb613c03777e620c50528112247ad2 Upstream diff:a09fbe2c83...f4665ab836This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
commit
3790e37ca2
408 changed files with 5321 additions and 3046 deletions
79
Cargo.lock
79
Cargo.lock
|
|
@ -674,7 +674,7 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
|
|||
dependencies = [
|
||||
"serde",
|
||||
"termcolor",
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1458,9 +1458,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.23"
|
||||
version = "0.2.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1"
|
||||
checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df"
|
||||
dependencies = [
|
||||
"unicode-width 0.2.1",
|
||||
]
|
||||
|
|
@ -2167,6 +2167,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"html5ever",
|
||||
"regex",
|
||||
"urlencoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3248,6 +3249,7 @@ dependencies = [
|
|||
"rustc_driver_impl",
|
||||
"rustc_public",
|
||||
"rustc_public_bridge",
|
||||
"rustc_windows_rc",
|
||||
"tikv-jemalloc-sys",
|
||||
]
|
||||
|
||||
|
|
@ -3623,6 +3625,7 @@ name = "rustc_driver"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_driver_impl",
|
||||
"rustc_windows_rc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4409,7 +4412,6 @@ dependencies = [
|
|||
"rustc_middle",
|
||||
"rustc_query_system",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"tracing",
|
||||
]
|
||||
|
|
@ -4681,6 +4683,7 @@ dependencies = [
|
|||
name = "rustc_type_ir"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"derive-where",
|
||||
"ena",
|
||||
|
|
@ -4718,6 +4721,13 @@ dependencies = [
|
|||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_windows_rc"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustdoc"
|
||||
version = "0.0.0"
|
||||
|
|
@ -5518,11 +5528,10 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
|||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.37"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
|
|
@ -5825,6 +5834,12 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urlencoding"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
|
|
@ -5969,9 +5984,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-component-ld"
|
||||
version = "0.5.16"
|
||||
version = "0.5.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14cd35d6cae91109a0ffd207b573cf3c741cab7e921dd376ea7aaf2c52a3408c"
|
||||
checksum = "1c9208f87cac2332fd80dcf36d54e9163d3446e28301e0c6e424984425738984"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
|
|
@ -5979,9 +5994,9 @@ dependencies = [
|
|||
"libc",
|
||||
"tempfile",
|
||||
"wasi-preview1-component-adapter-provider",
|
||||
"wasmparser 0.237.0",
|
||||
"wasmparser 0.239.0",
|
||||
"wat",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.60.2",
|
||||
"winsplit",
|
||||
"wit-component",
|
||||
"wit-parser",
|
||||
|
|
@ -6006,24 +6021,24 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.237.0"
|
||||
version = "0.239.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efe92d1321afa53ffc88a57c497bb7330c3cf84c98ffdba4a4caf6a0684fad3c"
|
||||
checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c"
|
||||
dependencies = [
|
||||
"leb128fmt",
|
||||
"wasmparser 0.237.0",
|
||||
"wasmparser 0.239.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.237.0"
|
||||
version = "0.239.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cc0b0a0c4f35ca6efa7a797671372915d4e9659dba2d59edc6fafc931d19997"
|
||||
checksum = "20b3ec880a9ac69ccd92fbdbcf46ee833071cf09f82bb005b2327c7ae6025ae2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"wasm-encoder 0.237.0",
|
||||
"wasmparser 0.237.0",
|
||||
"wasm-encoder 0.239.0",
|
||||
"wasmparser 0.239.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6048,9 +6063,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.237.0"
|
||||
version = "0.239.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d2a40ca0d2bdf4b0bf36c13a737d0b2c58e4c8aaefe1c57f336dd75369ca250"
|
||||
checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"hashbrown",
|
||||
|
|
@ -6061,22 +6076,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "237.0.0"
|
||||
version = "239.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcf66f545acbd55082485cb9a6daab54579cb8628a027162253e8e9f5963c767"
|
||||
checksum = "9139176fe8a2590e0fb174cdcaf373b224cb93c3dde08e4297c1361d2ba1ea5d"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"leb128fmt",
|
||||
"memchr",
|
||||
"unicode-width 0.2.1",
|
||||
"wasm-encoder 0.237.0",
|
||||
"wasm-encoder 0.239.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wat"
|
||||
version = "1.237.0"
|
||||
version = "1.239.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27975186f549e4b8d6878b627be732863883c72f7bf4dcf8f96e5f8242f73da9"
|
||||
checksum = "3e1c941927d34709f255558166f8901a2005f8ab4a9650432e9281b7cc6f3b75"
|
||||
dependencies = [
|
||||
"wast",
|
||||
]
|
||||
|
|
@ -6565,9 +6580,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.237.0"
|
||||
version = "0.239.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfb7674f76c10e82fe00b256a9d4ffb2b8d037d42ab8e9a83ebb3be35c9d0bf6"
|
||||
checksum = "88a866b19dba2c94d706ec58c92a4c62ab63e482b4c935d2a085ac94caecb136"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
|
|
@ -6576,17 +6591,17 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder 0.237.0",
|
||||
"wasm-encoder 0.239.0",
|
||||
"wasm-metadata",
|
||||
"wasmparser 0.237.0",
|
||||
"wasmparser 0.239.0",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.237.0"
|
||||
version = "0.239.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce2596a5bc7c24cc965b56ad6ff9e32394c4e401764f89620a888519c6e849ab"
|
||||
checksum = "55c92c939d667b7bf0c6bf2d1f67196529758f99a2a45a3355cc56964fd5315d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
|
|
@ -6597,7 +6612,7 @@ dependencies = [
|
|||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser 0.237.0",
|
||||
"wasmparser 0.239.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -33,3 +33,8 @@ llvm = ['rustc_driver_impl/llvm']
|
|||
max_level_info = ['rustc_driver_impl/max_level_info']
|
||||
rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts']
|
||||
# tidy-alphabetical-end
|
||||
|
||||
[build-dependencies]
|
||||
# tidy-alphabetical-start
|
||||
rustc_windows_rc = { path = "../rustc_windows_rc" }
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use std::env;
|
||||
use std::{env, path};
|
||||
|
||||
use rustc_windows_rc::{VersionInfoFileType, compile_windows_resource_file};
|
||||
|
||||
fn main() {
|
||||
let target_os = env::var("CARGO_CFG_TARGET_OS");
|
||||
|
|
@ -13,6 +15,18 @@ fn main() {
|
|||
|
||||
// Add a manifest file to rustc.exe.
|
||||
fn set_windows_exe_options() {
|
||||
set_windows_resource();
|
||||
set_windows_manifest();
|
||||
}
|
||||
|
||||
fn set_windows_resource() {
|
||||
let stem = path::PathBuf::from("rustc_main_resource");
|
||||
let file_description = "rustc";
|
||||
let res_file = compile_windows_resource_file(&stem, file_description, VersionInfoFileType::App);
|
||||
println!("cargo:rustc-link-arg={}", res_file.display());
|
||||
}
|
||||
|
||||
fn set_windows_manifest() {
|
||||
static WINDOWS_MANIFEST_FILE: &str = "Windows Manifest.xml";
|
||||
|
||||
let mut manifest = env::current_dir().unwrap();
|
||||
|
|
|
|||
|
|
@ -2284,6 +2284,54 @@ pub struct FnSig {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
impl FnSig {
|
||||
/// Return a span encompassing the header, or where to insert it if empty.
|
||||
pub fn header_span(&self) -> Span {
|
||||
match self.header.ext {
|
||||
Extern::Implicit(span) | Extern::Explicit(_, span) => {
|
||||
return self.span.with_hi(span.hi());
|
||||
}
|
||||
Extern::None => {}
|
||||
}
|
||||
|
||||
match self.header.safety {
|
||||
Safety::Unsafe(span) | Safety::Safe(span) => return self.span.with_hi(span.hi()),
|
||||
Safety::Default => {}
|
||||
};
|
||||
|
||||
if let Some(coroutine_kind) = self.header.coroutine_kind {
|
||||
return self.span.with_hi(coroutine_kind.span().hi());
|
||||
}
|
||||
|
||||
if let Const::Yes(span) = self.header.constness {
|
||||
return self.span.with_hi(span.hi());
|
||||
}
|
||||
|
||||
self.span.shrink_to_lo()
|
||||
}
|
||||
|
||||
/// The span of the header's safety, or where to insert it if empty.
|
||||
pub fn safety_span(&self) -> Span {
|
||||
match self.header.safety {
|
||||
Safety::Unsafe(span) | Safety::Safe(span) => span,
|
||||
Safety::Default => {
|
||||
// Insert after the `coroutine_kind` if available.
|
||||
if let Some(extern_span) = self.header.ext.span() {
|
||||
return extern_span.shrink_to_lo();
|
||||
}
|
||||
|
||||
// Insert right at the front of the signature.
|
||||
self.header_span().shrink_to_hi()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The span of the header's extern, or where to insert it if empty.
|
||||
pub fn extern_span(&self) -> Span {
|
||||
self.header.ext.span().unwrap_or(self.safety_span().shrink_to_hi())
|
||||
}
|
||||
}
|
||||
|
||||
/// A constraint on an associated item.
|
||||
///
|
||||
/// ### Examples
|
||||
|
|
@ -3526,6 +3574,13 @@ impl Extern {
|
|||
None => Extern::Implicit(span),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(self) -> Option<Span> {
|
||||
match self {
|
||||
Extern::None => None,
|
||||
Extern::Implicit(span) | Extern::Explicit(_, span) => Some(span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A function header.
|
||||
|
|
@ -3534,12 +3589,12 @@ impl Extern {
|
|||
/// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
|
||||
#[derive(Clone, Copy, Encodable, Decodable, Debug, Walkable)]
|
||||
pub struct FnHeader {
|
||||
/// Whether this is `unsafe`, or has a default safety.
|
||||
pub safety: Safety,
|
||||
/// Whether this is `async`, `gen`, or nothing.
|
||||
pub coroutine_kind: Option<CoroutineKind>,
|
||||
/// The `const` keyword, if any
|
||||
pub constness: Const,
|
||||
/// Whether this is `async`, `gen`, or nothing.
|
||||
pub coroutine_kind: Option<CoroutineKind>,
|
||||
/// Whether this is `unsafe`, or has a default safety.
|
||||
pub safety: Safety,
|
||||
/// The `extern` keyword and corresponding ABI string, if any.
|
||||
pub ext: Extern,
|
||||
}
|
||||
|
|
@ -3553,38 +3608,6 @@ impl FnHeader {
|
|||
|| matches!(constness, Const::Yes(_))
|
||||
|| !matches!(ext, Extern::None)
|
||||
}
|
||||
|
||||
/// Return a span encompassing the header, or none if all options are default.
|
||||
pub fn span(&self) -> Option<Span> {
|
||||
fn append(a: &mut Option<Span>, b: Span) {
|
||||
*a = match a {
|
||||
None => Some(b),
|
||||
Some(x) => Some(x.to(b)),
|
||||
}
|
||||
}
|
||||
|
||||
let mut full_span = None;
|
||||
|
||||
match self.safety {
|
||||
Safety::Unsafe(span) | Safety::Safe(span) => append(&mut full_span, span),
|
||||
Safety::Default => {}
|
||||
};
|
||||
|
||||
if let Some(coroutine_kind) = self.coroutine_kind {
|
||||
append(&mut full_span, coroutine_kind.span());
|
||||
}
|
||||
|
||||
if let Const::Yes(span) = self.constness {
|
||||
append(&mut full_span, span);
|
||||
}
|
||||
|
||||
match self.ext {
|
||||
Extern::Implicit(span) | Extern::Explicit(_, span) => append(&mut full_span, span),
|
||||
Extern::None => {}
|
||||
}
|
||||
|
||||
full_span
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FnHeader {
|
||||
|
|
|
|||
|
|
@ -1536,7 +1536,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::LangItem::Range
|
||||
}
|
||||
}
|
||||
(None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
|
||||
(None, Some(..), Closed) => {
|
||||
if self.tcx.features().new_range() {
|
||||
hir::LangItem::RangeToInclusiveCopy
|
||||
} else {
|
||||
hir::LangItem::RangeToInclusive
|
||||
}
|
||||
}
|
||||
(Some(e1), Some(e2), Closed) => {
|
||||
if self.tcx.features().new_range() {
|
||||
hir::LangItem::RangeInclusiveCopy
|
||||
|
|
@ -1560,13 +1566,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
};
|
||||
|
||||
let fields = self.arena.alloc_from_iter(
|
||||
e1.iter().map(|e| (sym::start, e)).chain(e2.iter().map(|e| (sym::end, e))).map(
|
||||
|(s, e)| {
|
||||
e1.iter()
|
||||
.map(|e| (sym::start, e))
|
||||
.chain(e2.iter().map(|e| {
|
||||
(
|
||||
if matches!(
|
||||
lang_item,
|
||||
hir::LangItem::RangeInclusiveCopy | hir::LangItem::RangeToInclusiveCopy
|
||||
) {
|
||||
sym::last
|
||||
} else {
|
||||
sym::end
|
||||
},
|
||||
e,
|
||||
)
|
||||
}))
|
||||
.map(|(s, e)| {
|
||||
let expr = self.lower_expr(e);
|
||||
let ident = Ident::new(s, self.lower_span(e.span));
|
||||
self.expr_field(ident, expr, e.span)
|
||||
},
|
||||
),
|
||||
}),
|
||||
);
|
||||
|
||||
hir::ExprKind::Struct(
|
||||
|
|
|
|||
|
|
@ -2101,17 +2101,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
{
|
||||
return;
|
||||
}
|
||||
if self.tcx.features().more_maybe_bounds() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
RelaxedBoundPolicy::Forbidden(reason) => {
|
||||
if self.tcx.features().more_maybe_bounds() {
|
||||
return;
|
||||
}
|
||||
|
||||
match reason {
|
||||
RelaxedBoundForbiddenReason::TraitObjectTy => {
|
||||
if self.tcx.features().more_maybe_bounds() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.dcx().span_err(
|
||||
span,
|
||||
"relaxed bounds are not permitted in trait object types",
|
||||
|
|
@ -2119,6 +2116,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
return;
|
||||
}
|
||||
RelaxedBoundForbiddenReason::SuperTrait => {
|
||||
if self.tcx.features().more_maybe_bounds() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut diag = self.dcx().struct_span_err(
|
||||
span,
|
||||
"relaxed bounds are not permitted in supertrait bounds",
|
||||
|
|
|
|||
|
|
@ -57,8 +57,6 @@ ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetim
|
|||
.label = {ast_passes_auto_super_lifetime}
|
||||
.suggestion = remove the super traits or lifetime bounds
|
||||
|
||||
ast_passes_bad_c_variadic = defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
|
||||
|
||||
ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
|
||||
.cannot_have = cannot have a body
|
||||
.invalid = the invalid body
|
||||
|
|
@ -66,6 +64,19 @@ ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
|
|||
|
||||
ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
|
||||
|
||||
ast_passes_c_variadic_associated_function = associated functions cannot have a C variable argument list
|
||||
|
||||
ast_passes_c_variadic_bad_extern = `...` is not supported for `extern "{$abi}"` functions
|
||||
.label = `extern "{$abi}"` because of this
|
||||
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||
|
||||
ast_passes_c_variadic_must_be_unsafe =
|
||||
functions with a C variable argument list must be unsafe
|
||||
.suggestion = add the `unsafe` keyword to this definition
|
||||
|
||||
ast_passes_c_variadic_no_extern = `...` is not supported for non-extern functions
|
||||
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||
|
||||
ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic
|
||||
.const = `const` because of this
|
||||
.variadic = C-variadic because of this
|
||||
|
|
@ -84,6 +95,10 @@ ast_passes_const_without_body =
|
|||
ast_passes_constraint_on_negative_bound =
|
||||
associated type constraints not allowed on negative bounds
|
||||
|
||||
ast_passes_coroutine_and_c_variadic = functions cannot be both `{$coroutine_kind}` and C-variadic
|
||||
.const = `{$coroutine_kind}` because of this
|
||||
.variadic = C-variadic because of this
|
||||
|
||||
ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
|
||||
.label = not supported
|
||||
.suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
|
||||
if !spans.is_empty() {
|
||||
let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo());
|
||||
let header_span = sig.header_span();
|
||||
let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span());
|
||||
let padding = if header_span.is_empty() { "" } else { " " };
|
||||
|
||||
|
|
@ -665,46 +665,73 @@ impl<'a> AstValidator<'a> {
|
|||
/// - Non-const
|
||||
/// - Either foreign, or free and `unsafe extern "C"` semantically
|
||||
fn check_c_variadic_type(&self, fk: FnKind<'a>) {
|
||||
let variadic_spans: Vec<_> = fk
|
||||
.decl()
|
||||
.inputs
|
||||
.iter()
|
||||
.filter(|arg| matches!(arg.ty.kind, TyKind::CVarArgs))
|
||||
.map(|arg| arg.span)
|
||||
.collect();
|
||||
// `...` is already rejected when it is not the final parameter.
|
||||
let variadic_param = match fk.decl().inputs.last() {
|
||||
Some(param) if matches!(param.ty.kind, TyKind::CVarArgs) => param,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
if variadic_spans.is_empty() {
|
||||
return;
|
||||
}
|
||||
let FnKind::Fn(fn_ctxt, _, Fn { sig, .. }) = fk else {
|
||||
// Unreachable because the parser already rejects `...` in closures.
|
||||
unreachable!("C variable argument list cannot be used in closures")
|
||||
};
|
||||
|
||||
if let Some(header) = fk.header()
|
||||
&& let Const::Yes(const_span) = header.constness
|
||||
{
|
||||
let mut spans = variadic_spans.clone();
|
||||
spans.push(const_span);
|
||||
// C-variadics are not yet implemented in const evaluation.
|
||||
if let Const::Yes(const_span) = sig.header.constness {
|
||||
self.dcx().emit_err(errors::ConstAndCVariadic {
|
||||
spans,
|
||||
spans: vec![const_span, variadic_param.span],
|
||||
const_span,
|
||||
variadic_spans: variadic_spans.clone(),
|
||||
variadic_span: variadic_param.span,
|
||||
});
|
||||
}
|
||||
|
||||
match (fk.ctxt(), fk.header()) {
|
||||
(Some(FnCtxt::Foreign), _) => return,
|
||||
(Some(FnCtxt::Free), Some(header)) => match header.ext {
|
||||
Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
|
||||
| Extern::Explicit(StrLit { symbol_unescaped: sym::C_dash_unwind, .. }, _)
|
||||
| Extern::Implicit(_)
|
||||
if matches!(header.safety, Safety::Unsafe(_)) =>
|
||||
{
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
if let Some(coroutine_kind) = sig.header.coroutine_kind {
|
||||
self.dcx().emit_err(errors::CoroutineAndCVariadic {
|
||||
spans: vec![coroutine_kind.span(), variadic_param.span],
|
||||
coroutine_kind: coroutine_kind.as_str(),
|
||||
coroutine_span: coroutine_kind.span(),
|
||||
variadic_span: variadic_param.span,
|
||||
});
|
||||
}
|
||||
|
||||
self.dcx().emit_err(errors::BadCVariadic { span: variadic_spans });
|
||||
match fn_ctxt {
|
||||
FnCtxt::Foreign => return,
|
||||
FnCtxt::Free => match sig.header.ext {
|
||||
Extern::Implicit(_) => {
|
||||
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
|
||||
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
|
||||
span: variadic_param.span,
|
||||
unsafe_span: sig.safety_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
|
||||
if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) {
|
||||
self.dcx().emit_err(errors::CVariadicBadExtern {
|
||||
span: variadic_param.span,
|
||||
abi: symbol_unescaped,
|
||||
extern_span: sig.extern_span(),
|
||||
});
|
||||
}
|
||||
|
||||
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
|
||||
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
|
||||
span: variadic_param.span,
|
||||
unsafe_span: sig.safety_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Extern::None => {
|
||||
let err = errors::CVariadicNoExtern { span: variadic_param.span };
|
||||
self.dcx().emit_err(err);
|
||||
}
|
||||
},
|
||||
FnCtxt::Assoc(_) => {
|
||||
// For now, C variable argument lists are unsupported in associated functions.
|
||||
let err = errors::CVariadicAssociatedFunction { span: variadic_param.span };
|
||||
self.dcx().emit_err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_item_named(&self, ident: Ident, kind: &str) {
|
||||
|
|
|
|||
|
|
@ -319,10 +319,44 @@ pub(crate) struct ExternItemAscii {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_bad_c_variadic)]
|
||||
pub(crate) struct BadCVariadic {
|
||||
#[diag(ast_passes_c_variadic_associated_function)]
|
||||
pub(crate) struct CVariadicAssociatedFunction {
|
||||
#[primary_span]
|
||||
pub span: Vec<Span>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_c_variadic_no_extern)]
|
||||
#[help]
|
||||
pub(crate) struct CVariadicNoExtern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_c_variadic_must_be_unsafe)]
|
||||
pub(crate) struct CVariadicMustBeUnsafe {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "unsafe ",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub unsafe_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_c_variadic_bad_extern)]
|
||||
#[help]
|
||||
pub(crate) struct CVariadicBadExtern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub abi: Symbol,
|
||||
#[label]
|
||||
pub extern_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
@ -656,7 +690,19 @@ pub(crate) struct ConstAndCVariadic {
|
|||
#[label(ast_passes_const)]
|
||||
pub const_span: Span,
|
||||
#[label(ast_passes_variadic)]
|
||||
pub variadic_spans: Vec<Span>,
|
||||
pub variadic_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_coroutine_and_c_variadic)]
|
||||
pub(crate) struct CoroutineAndCVariadic {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
pub coroutine_kind: &'static str,
|
||||
#[label(ast_passes_const)]
|
||||
pub coroutine_span: Span,
|
||||
#[label(ast_passes_variadic)]
|
||||
pub variadic_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -247,3 +247,7 @@ attr_parsing_raw_dylib_only_windows =
|
|||
|
||||
attr_parsing_whole_archive_needs_static =
|
||||
linking modifier `whole-archive` is only compatible with `static` linking kind
|
||||
|
||||
attr_parsing_limit_invalid =
|
||||
`limit` must be a non-negative integer
|
||||
.label = {$error_str}
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
|
|||
sym::rustc_std_internal_symbol,
|
||||
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
|
||||
sym::rustc_align,
|
||||
sym::rustc_align_static,
|
||||
// obviously compatible with self
|
||||
sym::naked,
|
||||
// documentation
|
||||
|
|
|
|||
|
|
@ -1,6 +1,40 @@
|
|||
use rustc_feature::AttributeType;
|
||||
use std::num::IntErrorKind;
|
||||
|
||||
use rustc_hir::limit::Limit;
|
||||
|
||||
use super::prelude::*;
|
||||
use crate::session_diagnostics::LimitInvalid;
|
||||
|
||||
impl<S: Stage> AcceptContext<'_, '_, S> {
|
||||
fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> {
|
||||
let Some(limit) = nv.value_as_str() else {
|
||||
self.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
||||
return None;
|
||||
};
|
||||
|
||||
let error_str = match limit.as_str().parse() {
|
||||
Ok(i) => return Some(Limit::new(i)),
|
||||
Err(e) => match e.kind() {
|
||||
IntErrorKind::PosOverflow => "`limit` is too large",
|
||||
IntErrorKind::Empty => "`limit` must be a non-negative integer",
|
||||
IntErrorKind::InvalidDigit => "not a valid integer",
|
||||
IntErrorKind::NegOverflow => {
|
||||
panic!(
|
||||
"`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
|
||||
)
|
||||
}
|
||||
IntErrorKind::Zero => {
|
||||
panic!("zero is a valid `limit` so should have returned Ok() when parsing")
|
||||
}
|
||||
kind => panic!("unimplemented IntErrorKind variant: {:?}", kind),
|
||||
},
|
||||
};
|
||||
|
||||
self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CrateNameParser;
|
||||
|
||||
|
|
@ -11,8 +45,8 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
|
|||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||
const TYPE: AttributeType = AttributeType::CrateLevel;
|
||||
|
||||
// FIXME: crate name is allowed on all targets and ignored,
|
||||
// even though it should only be valid on crates of course
|
||||
// because it's a crate-level attribute, we already warn about it.
|
||||
// Putting target limitations here would give duplicate warnings
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
|
|
@ -34,3 +68,111 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RecursionLimitParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
|
||||
const PATH: &[Symbol] = &[sym::recursion_limit];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute");
|
||||
const TYPE: AttributeType = AttributeType::CrateLevel;
|
||||
|
||||
// because it's a crate-level attribute, we already warn about it.
|
||||
// Putting target limitations here would give duplicate warnings
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(nv) = args else {
|
||||
cx.expected_name_value(cx.attr_span, None);
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(AttributeKind::RecursionLimit {
|
||||
limit: cx.parse_limit_int(nv)?,
|
||||
attr_span: cx.attr_span,
|
||||
limit_span: nv.value_span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct MoveSizeLimitParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
|
||||
const PATH: &[Symbol] = &[sym::move_size_limit];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
const TYPE: AttributeType = AttributeType::CrateLevel;
|
||||
|
||||
// because it's a crate-level attribute, we already warn about it.
|
||||
// Putting target limitations here would give duplicate warnings
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(nv) = args else {
|
||||
cx.expected_name_value(cx.attr_span, None);
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(AttributeKind::MoveSizeLimit {
|
||||
limit: cx.parse_limit_int(nv)?,
|
||||
attr_span: cx.attr_span,
|
||||
limit_span: nv.value_span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TypeLengthLimitParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
|
||||
const PATH: &[Symbol] = &[sym::type_length_limit];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
const TYPE: AttributeType = AttributeType::CrateLevel;
|
||||
|
||||
// because it's a crate-level attribute, we already warn about it.
|
||||
// Putting target limitations here would give duplicate warnings
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(nv) = args else {
|
||||
cx.expected_name_value(cx.attr_span, None);
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(AttributeKind::TypeLengthLimit {
|
||||
limit: cx.parse_limit_int(nv)?,
|
||||
attr_span: cx.attr_span,
|
||||
limit_span: nv.value_span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct PatternComplexityLimitParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
|
||||
const PATH: &[Symbol] = &[sym::pattern_complexity_limit];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
const TYPE: AttributeType = AttributeType::CrateLevel;
|
||||
|
||||
// because it's a crate-level attribute, we already warn about it.
|
||||
// Putting target limitations here would give duplicate warnings
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(nv) = args else {
|
||||
cx.expected_name_value(cx.attr_span, None);
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(AttributeKind::PatternComplexityLimit {
|
||||
limit: cx.parse_limit_int(nv)?,
|
||||
attr_span: cx.attr_span,
|
||||
limit_span: nv.value_span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
// templates
|
||||
#[doc(hidden)]
|
||||
pub(super) use rustc_feature::{AttributeTemplate, template};
|
||||
// data structures
|
||||
#[doc(hidden)]
|
||||
pub(super) use rustc_feature::{AttributeTemplate, AttributeType, template};
|
||||
#[doc(hidden)]
|
||||
pub(super) use rustc_hir::attrs::AttributeKind;
|
||||
#[doc(hidden)]
|
||||
pub(super) use rustc_hir::lints::AttributeLintKind;
|
||||
|
|
|
|||
|
|
@ -331,3 +331,30 @@ impl<S: Stage> AttributeParser<S> for AlignParser {
|
|||
Some(AttributeKind::Align { align, span })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct AlignStaticParser(AlignParser);
|
||||
|
||||
impl AlignStaticParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_align_static];
|
||||
const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE;
|
||||
|
||||
fn parse<'c, S: Stage>(
|
||||
&mut self,
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) {
|
||||
self.0.parse(cx, args)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Stage> AttributeParser<S> for AlignStaticParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)];
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
let (align, span) = self.0.0?;
|
||||
Some(AttributeKind::Align { align, span })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@ use crate::attributes::codegen_attrs::{
|
|||
UsedParser,
|
||||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::crate_level::CrateNameParser;
|
||||
use crate::attributes::crate_level::{
|
||||
CrateNameParser, MoveSizeLimitParser, PatternComplexityLimitParser, RecursionLimitParser,
|
||||
TypeLengthLimitParser,
|
||||
};
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
use crate::attributes::dummy::DummyParser;
|
||||
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
|
||||
|
|
@ -47,7 +50,7 @@ use crate::attributes::proc_macro_attrs::{
|
|||
ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
|
||||
};
|
||||
use crate::attributes::prototype::CustomMirParser;
|
||||
use crate::attributes::repr::{AlignParser, ReprParser};
|
||||
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
|
||||
use crate::attributes::rustc_internal::{
|
||||
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
|
||||
RustcObjectLifetimeDefaultParser,
|
||||
|
|
@ -149,6 +152,7 @@ attribute_parsers!(
|
|||
pub(crate) static ATTRIBUTE_PARSERS = [
|
||||
// tidy-alphabetical-start
|
||||
AlignParser,
|
||||
AlignStaticParser,
|
||||
BodyStabilityParser,
|
||||
ConfusablesParser,
|
||||
ConstStabilityParser,
|
||||
|
|
@ -181,10 +185,13 @@ attribute_parsers!(
|
|||
Single<LinkOrdinalParser>,
|
||||
Single<LinkSectionParser>,
|
||||
Single<LinkageParser>,
|
||||
Single<MoveSizeLimitParser>,
|
||||
Single<MustUseParser>,
|
||||
Single<OptimizeParser>,
|
||||
Single<PathAttributeParser>,
|
||||
Single<PatternComplexityLimitParser>,
|
||||
Single<ProcMacroDeriveParser>,
|
||||
Single<RecursionLimitParser>,
|
||||
Single<RustcBuiltinMacroParser>,
|
||||
Single<RustcForceInlineParser>,
|
||||
Single<RustcLayoutScalarValidRangeEnd>,
|
||||
|
|
@ -194,6 +201,7 @@ attribute_parsers!(
|
|||
Single<ShouldPanicParser>,
|
||||
Single<SkipDuringMethodDispatchParser>,
|
||||
Single<TransparencyParser>,
|
||||
Single<TypeLengthLimitParser>,
|
||||
Single<WithoutArgs<AllowIncoherentImplParser>>,
|
||||
Single<WithoutArgs<AllowInternalUnsafeParser>>,
|
||||
Single<WithoutArgs<AsPtrParser>>,
|
||||
|
|
@ -346,7 +354,10 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
|
|||
/// must be delayed until after HIR is built. This method will take care of the details of
|
||||
/// that.
|
||||
pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
|
||||
if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
|
||||
if !matches!(
|
||||
self.stage.should_emit(),
|
||||
ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true }
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let id = self.target_id;
|
||||
|
|
@ -670,20 +681,20 @@ pub enum ShouldEmit {
|
|||
///
|
||||
/// Only relevant when early parsing, in late parsing equivalent to `ErrorsAndLints`.
|
||||
/// Late parsing is never fatal, and instead tries to emit as many diagnostics as possible.
|
||||
EarlyFatal,
|
||||
EarlyFatal { also_emit_lints: bool },
|
||||
/// The operation will emit errors and lints.
|
||||
/// This is usually what you need.
|
||||
ErrorsAndLints,
|
||||
/// The operation will emit *not* errors and lints.
|
||||
/// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::Emit`.
|
||||
/// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::ErrorsAndLints`.
|
||||
Nothing,
|
||||
}
|
||||
|
||||
impl ShouldEmit {
|
||||
pub(crate) fn emit_err(&self, diag: Diag<'_>) -> ErrorGuaranteed {
|
||||
match self {
|
||||
ShouldEmit::EarlyFatal if diag.level() == Level::DelayedBug => diag.emit(),
|
||||
ShouldEmit::EarlyFatal => diag.upgrade_to_fatal().emit(),
|
||||
ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
|
||||
ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
|
||||
ShouldEmit::ErrorsAndLints => diag.emit(),
|
||||
ShouldEmit::Nothing => diag.delay_as_bug(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -930,3 +930,13 @@ pub(crate) struct ImportNameTypeRaw {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_limit_invalid)]
|
||||
pub(crate) struct LimitInvalid<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub value_span: Span,
|
||||
pub error_str: &'a str,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -615,7 +615,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
|
||||
// Type-test failed. Report the error.
|
||||
let erased_generic_kind = infcx.tcx.erase_regions(type_test.generic_kind);
|
||||
let erased_generic_kind = infcx.tcx.erase_and_anonymize_regions(type_test.generic_kind);
|
||||
|
||||
// Skip duplicate-ish errors.
|
||||
if deduplicate_errors.insert((
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ fn compute_concrete_types_from_defining_uses<'tcx>(
|
|||
//
|
||||
// FIXME(-Znext-solver): This isn't necessary after all. We can remove this check again.
|
||||
if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
|
||||
rcx.infcx.tcx.erase_regions(opaque_type_key),
|
||||
rcx.infcx.tcx.erase_and_anonymize_regions(opaque_type_key),
|
||||
(opaque_type_key, hidden_type.span),
|
||||
) && let Some((arg1, arg2)) = std::iter::zip(
|
||||
prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
|
||||
|
|
|
|||
|
|
@ -1892,7 +1892,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
if is_diverging {
|
||||
// The signature in this call can reference region variables,
|
||||
// so erase them before calling a query.
|
||||
let output_ty = self.tcx().erase_regions(sig.output());
|
||||
let output_ty = self.tcx().erase_and_anonymize_regions(sig.output());
|
||||
if !output_ty
|
||||
.is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.infcx.param_env))
|
||||
{
|
||||
|
|
@ -1986,7 +1986,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
|
||||
let op_arg_ty = self.normalize(op_arg_ty, term_location);
|
||||
let category = if call_source.from_hir_call() {
|
||||
ConstraintCategory::CallArgument(Some(self.infcx.tcx.erase_regions(func_ty)))
|
||||
ConstraintCategory::CallArgument(Some(
|
||||
self.infcx.tcx.erase_and_anonymize_regions(func_ty),
|
||||
))
|
||||
} else {
|
||||
ConstraintCategory::Boring
|
||||
};
|
||||
|
|
@ -2120,7 +2122,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// Erase the regions from `ty` to get a global type. The
|
||||
// `Sized` bound in no way depends on precise regions, so this
|
||||
// shouldn't affect `is_sized`.
|
||||
let erased_ty = tcx.erase_regions(ty);
|
||||
let erased_ty = tcx.erase_and_anonymize_regions(ty);
|
||||
// FIXME(#132279): Using `Ty::is_sized` causes us to incorrectly handle opaques here.
|
||||
if !erased_ty.is_sized(tcx, self.infcx.typing_env(self.infcx.param_env)) {
|
||||
// in current MIR construction, all non-control-flow rvalue
|
||||
|
|
|
|||
|
|
@ -565,6 +565,7 @@ fn make_format_args(
|
|||
&used,
|
||||
&args,
|
||||
&pieces,
|
||||
&invalid_refs,
|
||||
detect_foreign_fmt,
|
||||
str_style,
|
||||
fmt_str,
|
||||
|
|
@ -645,6 +646,7 @@ fn report_missing_placeholders(
|
|||
used: &[bool],
|
||||
args: &FormatArguments,
|
||||
pieces: &[parse::Piece<'_>],
|
||||
invalid_refs: &[(usize, Option<Span>, PositionUsedAs, FormatArgPositionKind)],
|
||||
detect_foreign_fmt: bool,
|
||||
str_style: Option<usize>,
|
||||
fmt_str: &str,
|
||||
|
|
@ -762,6 +764,31 @@ fn report_missing_placeholders(
|
|||
diag.span_label(fmt_span, "formatting specifier missing");
|
||||
}
|
||||
|
||||
if !found_foreign && invalid_refs.is_empty() {
|
||||
// Show example if user didn't use any format specifiers
|
||||
let show_example = used.iter().all(|used| !used);
|
||||
|
||||
if !show_example {
|
||||
if unused.len() > 1 {
|
||||
diag.note(format!("consider adding {} format specifiers", unused.len()));
|
||||
}
|
||||
} else {
|
||||
let original_fmt_str =
|
||||
if fmt_str.len() >= 1 { &fmt_str[..fmt_str.len() - 1] } else { "" };
|
||||
|
||||
let msg = if unused.len() == 1 {
|
||||
"a format specifier".to_string()
|
||||
} else {
|
||||
format!("{} format specifiers", unused.len())
|
||||
};
|
||||
|
||||
let sugg = format!("\"{}{}\"", original_fmt_str, "{}".repeat(unused.len()));
|
||||
let msg = format!("format specifiers use curly braces, consider adding {msg}");
|
||||
|
||||
diag.span_suggestion_verbose(fmt_span, msg, sugg, Applicability::MaybeIncorrect);
|
||||
}
|
||||
}
|
||||
|
||||
diag.emit();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! The implementation of built-in macros which relate to the file system.
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
|
@ -11,9 +13,11 @@ use rustc_expand::base::{
|
|||
};
|
||||
use rustc_expand::module::DirOwnership;
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_parse::lexer::StripTokens;
|
||||
use rustc_parse::parser::ForceCollect;
|
||||
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error};
|
||||
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{ByteSymbol, Pos, Span, Symbol};
|
||||
use smallvec::SmallVec;
|
||||
|
|
@ -23,11 +27,7 @@ use crate::util::{
|
|||
check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
|
||||
};
|
||||
|
||||
// These macros all relate to the file system; they either return
|
||||
// the column/row/filename of the expression, or they include
|
||||
// a given file into the current one.
|
||||
|
||||
/// line!(): expands to the current line number
|
||||
/// Expand `line!()` to the current line number.
|
||||
pub(crate) fn expand_line(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
|
|
@ -42,7 +42,7 @@ pub(crate) fn expand_line(
|
|||
ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.line as u32)))
|
||||
}
|
||||
|
||||
/* column!(): expands to the current column number */
|
||||
/// Expand `column!()` to the current column number.
|
||||
pub(crate) fn expand_column(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
|
|
@ -57,9 +57,7 @@ pub(crate) fn expand_column(
|
|||
ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1)))
|
||||
}
|
||||
|
||||
/// file!(): expands to the current filename */
|
||||
/// The source_file (`loc.file`) contains a bunch more information we could spit
|
||||
/// out if we wanted.
|
||||
/// Expand `file!()` to the current filename.
|
||||
pub(crate) fn expand_file(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
|
|
@ -81,6 +79,7 @@ pub(crate) fn expand_file(
|
|||
)))
|
||||
}
|
||||
|
||||
/// Expand `stringify!($input)`.
|
||||
pub(crate) fn expand_stringify(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
|
|
@ -91,6 +90,7 @@ pub(crate) fn expand_stringify(
|
|||
ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))))
|
||||
}
|
||||
|
||||
/// Expand `module_path!()` to (a textual representation of) the current module path.
|
||||
pub(crate) fn expand_mod(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
|
|
@ -104,9 +104,9 @@ pub(crate) fn expand_mod(
|
|||
ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string))))
|
||||
}
|
||||
|
||||
/// include! : parse the given file as an expr
|
||||
/// This is generally a bad idea because it's going to behave
|
||||
/// unhygienically.
|
||||
/// Expand `include!($input)`.
|
||||
///
|
||||
/// This works in item and expression position. Notably, it doesn't work in pattern position.
|
||||
pub(crate) fn expand_include<'cx>(
|
||||
cx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
|
|
@ -116,39 +116,48 @@ pub(crate) fn expand_include<'cx>(
|
|||
let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include!") else {
|
||||
return ExpandResult::Retry(());
|
||||
};
|
||||
let file = match mac {
|
||||
Ok(file) => file,
|
||||
let path = match mac {
|
||||
Ok(path) => path,
|
||||
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
|
||||
};
|
||||
// The file will be added to the code map by the parser
|
||||
let file = match resolve_path(&cx.sess, file.as_str(), sp) {
|
||||
Ok(f) => f,
|
||||
let path = match resolve_path(&cx.sess, path.as_str(), sp) {
|
||||
Ok(path) => path,
|
||||
Err(err) => {
|
||||
let guar = err.emit();
|
||||
return ExpandResult::Ready(DummyResult::any(sp, guar));
|
||||
}
|
||||
};
|
||||
let p = unwrap_or_emit_fatal(new_parser_from_file(cx.psess(), &file, Some(sp)));
|
||||
|
||||
// If in the included file we have e.g., `mod bar;`,
|
||||
// then the path of `bar.rs` should be relative to the directory of `file`.
|
||||
// then the path of `bar.rs` should be relative to the directory of `path`.
|
||||
// See https://github.com/rust-lang/rust/pull/69838/files#r395217057 for a discussion.
|
||||
// `MacroExpander::fully_expand_fragment` later restores, so "stack discipline" is maintained.
|
||||
let dir_path = file.parent().unwrap_or(&file).to_owned();
|
||||
let dir_path = path.parent().unwrap_or(&path).to_owned();
|
||||
cx.current_expansion.module = Rc::new(cx.current_expansion.module.with_dir_path(dir_path));
|
||||
cx.current_expansion.dir_ownership = DirOwnership::Owned { relative: None };
|
||||
|
||||
struct ExpandInclude<'a> {
|
||||
p: Parser<'a>,
|
||||
psess: &'a ParseSess,
|
||||
path: PathBuf,
|
||||
node_id: ast::NodeId,
|
||||
span: Span,
|
||||
}
|
||||
impl<'a> MacResult for ExpandInclude<'a> {
|
||||
fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<Box<ast::Expr>> {
|
||||
let expr = parse_expr(&mut self.p).ok()?;
|
||||
if self.p.token != token::Eof {
|
||||
self.p.psess.buffer_lint(
|
||||
fn make_expr(self: Box<ExpandInclude<'a>>) -> Option<Box<ast::Expr>> {
|
||||
let mut p = unwrap_or_emit_fatal(new_parser_from_file(
|
||||
self.psess,
|
||||
&self.path,
|
||||
// Don't strip frontmatter for backward compatibility, `---` may be the start of a
|
||||
// manifold negation. FIXME: Ideally, we wouldn't strip shebangs here either.
|
||||
StripTokens::Shebang,
|
||||
Some(self.span),
|
||||
));
|
||||
let expr = parse_expr(&mut p).ok()?;
|
||||
if p.token != token::Eof {
|
||||
p.psess.buffer_lint(
|
||||
INCOMPLETE_INCLUDE,
|
||||
self.p.token.span,
|
||||
p.token.span,
|
||||
self.node_id,
|
||||
BuiltinLintDiag::IncompleteInclude,
|
||||
);
|
||||
|
|
@ -156,24 +165,27 @@ pub(crate) fn expand_include<'cx>(
|
|||
Some(expr)
|
||||
}
|
||||
|
||||
fn make_items(mut self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[Box<ast::Item>; 1]>> {
|
||||
fn make_items(self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[Box<ast::Item>; 1]>> {
|
||||
let mut p = unwrap_or_emit_fatal(new_parser_from_file(
|
||||
self.psess,
|
||||
&self.path,
|
||||
StripTokens::ShebangAndFrontmatter,
|
||||
Some(self.span),
|
||||
));
|
||||
let mut ret = SmallVec::new();
|
||||
loop {
|
||||
match self.p.parse_item(ForceCollect::No) {
|
||||
match p.parse_item(ForceCollect::No) {
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
break;
|
||||
}
|
||||
Ok(Some(item)) => ret.push(item),
|
||||
Ok(None) => {
|
||||
if self.p.token != token::Eof {
|
||||
self.p
|
||||
.dcx()
|
||||
.create_err(errors::ExpectedItem {
|
||||
span: self.p.token.span,
|
||||
token: &pprust::token_to_string(&self.p.token),
|
||||
})
|
||||
.emit();
|
||||
if p.token != token::Eof {
|
||||
p.dcx().emit_err(errors::ExpectedItem {
|
||||
span: p.token.span,
|
||||
token: &pprust::token_to_string(&p.token),
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -184,10 +196,17 @@ pub(crate) fn expand_include<'cx>(
|
|||
}
|
||||
}
|
||||
|
||||
ExpandResult::Ready(Box::new(ExpandInclude { p, node_id: cx.current_expansion.lint_node_id }))
|
||||
ExpandResult::Ready(Box::new(ExpandInclude {
|
||||
psess: cx.psess(),
|
||||
path,
|
||||
node_id: cx.current_expansion.lint_node_id,
|
||||
span: sp,
|
||||
}))
|
||||
}
|
||||
|
||||
/// `include_str!`: read the given file, insert it as a literal string expr
|
||||
/// Expand `include_str!($input)` to the content of the UTF-8-encoded file given by path `$input` as a string literal.
|
||||
///
|
||||
/// This works in expression, pattern and statement position.
|
||||
pub(crate) fn expand_include_str(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
|
|
@ -206,6 +225,7 @@ pub(crate) fn expand_include_str(
|
|||
Ok((bytes, bsp)) => match std::str::from_utf8(&bytes) {
|
||||
Ok(src) => {
|
||||
let interned_src = Symbol::intern(src);
|
||||
// MacEager converts the expr into a pat if need be.
|
||||
MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src))
|
||||
}
|
||||
Err(utf8err) => {
|
||||
|
|
@ -218,6 +238,9 @@ pub(crate) fn expand_include_str(
|
|||
})
|
||||
}
|
||||
|
||||
/// Expand `include_bytes!($input)` to the content of the file given by path `$input`.
|
||||
///
|
||||
/// This works in expression, pattern and statement position.
|
||||
pub(crate) fn expand_include_bytes(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
|
|
@ -237,6 +260,7 @@ pub(crate) fn expand_include_bytes(
|
|||
// Don't care about getting the span for the raw bytes,
|
||||
// because the console can't really show them anyway.
|
||||
let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(ByteSymbol::intern(&bytes)));
|
||||
// MacEager converts the expr into a pat if need be.
|
||||
MacEager::expr(expr)
|
||||
}
|
||||
Err(dummy) => dummy,
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> {
|
|||
if global.to_rvalue().get_type() != val_llty {
|
||||
global.to_rvalue().set_type(val_llty);
|
||||
}
|
||||
|
||||
// NOTE: Alignment from attributes has already been applied to the allocation.
|
||||
set_global_alignment(self, global, alloc.align);
|
||||
|
||||
global.global_set_initializer_rvalue(value);
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
|||
|
||||
// Make sure lifetimes are erased, to avoid generating distinct LLVM
|
||||
// types for Rust types that only differ in the choice of lifetimes.
|
||||
let normal_ty = cx.tcx.erase_regions(self.ty);
|
||||
let normal_ty = cx.tcx.erase_and_anonymize_regions(self.ty);
|
||||
|
||||
let mut defer = None;
|
||||
let ty = if self.ty != normal_ty {
|
||||
|
|
|
|||
|
|
@ -452,6 +452,8 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
self.statics_to_rauw.borrow_mut().push((g, new_g));
|
||||
new_g
|
||||
};
|
||||
|
||||
// NOTE: Alignment from attributes has already been applied to the allocation.
|
||||
set_global_alignment(self, g, alloc.align);
|
||||
llvm::set_initializer(g, v);
|
||||
|
||||
|
|
|
|||
|
|
@ -103,16 +103,17 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>(
|
|||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
unique_type_id: UniqueTypeId<'tcx>,
|
||||
array_type: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> DINodeCreationResult<'ll> {
|
||||
let ty::Array(element_type, len) = array_type.kind() else {
|
||||
bug!("build_fixed_size_array_di_node() called with non-ty::Array type `{:?}`", array_type)
|
||||
};
|
||||
|
||||
let element_type_di_node = type_di_node(cx, *element_type);
|
||||
let element_type_di_node = spanned_type_di_node(cx, *element_type, span);
|
||||
|
||||
return_if_di_node_created_in_meantime!(cx, unique_type_id);
|
||||
|
||||
let (size, align) = cx.size_and_align_of(array_type);
|
||||
let (size, align) = cx.spanned_size_and_align_of(array_type, span);
|
||||
|
||||
let upper_bound = len
|
||||
.try_to_target_usize(cx.tcx)
|
||||
|
|
@ -447,7 +448,7 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>(
|
|||
build_basic_type_di_node(cx, t)
|
||||
}
|
||||
ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t),
|
||||
ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t),
|
||||
ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t, span),
|
||||
ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id),
|
||||
ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id),
|
||||
ty::Foreign(..) => build_foreign_type_di_node(cx, t, unique_type_id),
|
||||
|
|
@ -1435,7 +1436,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
|
|||
|
||||
let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
|
||||
let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
|
||||
let trait_ref = tcx.erase_regions(trait_ref);
|
||||
let trait_ref = tcx.erase_and_anonymize_regions(trait_ref);
|
||||
|
||||
tcx.vtable_entries(trait_ref)
|
||||
} else {
|
||||
|
|
@ -1562,7 +1563,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
|
|||
// Unwrap potential addrspacecast
|
||||
let vtable = find_vtable_behind_cast(vtable);
|
||||
let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty);
|
||||
let trait_ref_self = cx.tcx.erase_regions(trait_ref_self);
|
||||
let trait_ref_self = cx.tcx.erase_and_anonymize_regions(trait_ref_self);
|
||||
let trait_def_id = trait_ref_self.def_id;
|
||||
let trait_vis = cx.tcx.visibility(trait_def_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use rustc_middle::bug;
|
|||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||
use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt};
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::common::*;
|
||||
|
|
@ -149,7 +150,11 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub(crate) fn size_and_align_of(&self, ty: Ty<'tcx>) -> (Size, Align) {
|
||||
let layout = self.layout_of(ty);
|
||||
self.spanned_size_and_align_of(ty, DUMMY_SP)
|
||||
}
|
||||
|
||||
pub(crate) fn spanned_size_and_align_of(&self, ty: Ty<'tcx>, span: Span) -> (Size, Align) {
|
||||
let layout = self.spanned_layout_of(ty, span);
|
||||
(layout.size, layout.align.abi)
|
||||
}
|
||||
}
|
||||
|
|
@ -226,7 +231,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
|
|||
|
||||
// Make sure lifetimes are erased, to avoid generating distinct LLVM
|
||||
// types for Rust types that only differ in the choice of lifetimes.
|
||||
let normal_ty = cx.tcx.erase_regions(self.ty);
|
||||
let normal_ty = cx.tcx.erase_and_anonymize_regions(self.ty);
|
||||
|
||||
let mut defer = None;
|
||||
let llty = if self.ty != normal_ty {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ ar_archive_writer = "0.5"
|
|||
bitflags = "2.4.1"
|
||||
bstr = "1.11.3"
|
||||
# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version
|
||||
# per crate", so if you change this, you need to also change it in `rustc_llvm`.
|
||||
# per crate", so if you change this, you need to also change it in `rustc_llvm` and `rustc_windows_rc`.
|
||||
cc = "=1.2.16"
|
||||
itertools = "0.12"
|
||||
pathdiff = "0.2.0"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use either::{Left, Right};
|
|||
use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout};
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::ty::layout::{
|
||||
|
|
@ -12,7 +13,6 @@ use rustc_middle::ty::layout::{
|
|||
};
|
||||
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance};
|
||||
use rustc_middle::{mir, span_bug};
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::callconv::FnAbi;
|
||||
use tracing::{debug, trace};
|
||||
|
|
|
|||
|
|
@ -953,6 +953,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
|
||||
// # Global allocations
|
||||
if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) {
|
||||
// NOTE: `static` alignment from attributes has already been applied to the allocation.
|
||||
let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env);
|
||||
let mutbl = global_alloc.mutability(*self.tcx, self.typing_env);
|
||||
let kind = match global_alloc {
|
||||
|
|
@ -1501,8 +1502,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
// `get_bytes_mut` will clear the provenance, which is correct,
|
||||
// since we don't want to keep any provenance at the target.
|
||||
// This will also error if copying partial provenance is not supported.
|
||||
let provenance =
|
||||
src_alloc.provenance().prepare_copy(src_range, dest_offset, num_copies, self);
|
||||
let provenance = src_alloc
|
||||
.provenance()
|
||||
.prepare_copy(src_range, dest_offset, num_copies, self)
|
||||
.map_err(|e| e.to_interp_error(src_alloc_id))?;
|
||||
// Prepare a copy of the initialization mask.
|
||||
let init = src_alloc.init_mask().prepare_copy(src_range);
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
|
||||
trace!("get_vtable(ty={ty:?}, dyn_ty={dyn_ty:?})");
|
||||
|
||||
let (ty, dyn_ty) = self.tcx.erase_regions((ty, dyn_ty));
|
||||
let (ty, dyn_ty) = self.tcx.erase_and_anonymize_regions((ty, dyn_ty));
|
||||
|
||||
// All vtables must be monomorphic, bail out otherwise.
|
||||
ensure_monomorphic_enough(*self.tcx, ty)?;
|
||||
|
|
@ -53,8 +53,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
) -> &'tcx [VtblEntry<'tcx>] {
|
||||
if let Some(trait_) = trait_ {
|
||||
let trait_ref = trait_.with_self_ty(*self.tcx, dyn_ty);
|
||||
let trait_ref =
|
||||
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
|
||||
let trait_ref = self.tcx.erase_and_anonymize_regions(
|
||||
self.tcx.instantiate_bound_regions_with_erased(trait_ref),
|
||||
);
|
||||
self.tcx.vtable_entries(trait_ref)
|
||||
} else {
|
||||
TyCtxt::COMMON_VTABLE_ENTRIES
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer};
|
||||
use rustc_middle::mir::interpret::{AllocInit, Allocation, GlobalAlloc, InterpResult, Pointer};
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{TyCtxt, TypeVisitable, TypeVisitableExt};
|
||||
use tracing::debug;
|
||||
|
|
@ -38,7 +38,14 @@ pub(crate) fn create_static_alloc<'tcx>(
|
|||
static_def_id: LocalDefId,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
|
||||
let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit, ())?;
|
||||
// Inherit size and align from the `GlobalAlloc::Static` so we can avoid duplicating
|
||||
// the alignment attribute logic.
|
||||
let (size, align) =
|
||||
GlobalAlloc::Static(static_def_id.into()).size_and_align(*ecx.tcx, ecx.typing_env);
|
||||
assert_eq!(size, layout.size);
|
||||
assert!(align >= layout.align.abi);
|
||||
|
||||
let alloc = Allocation::try_new(size, align, AllocInit::Uninit, ())?;
|
||||
let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into());
|
||||
assert_eq!(ecx.machine.static_root_ids, None);
|
||||
ecx.machine.static_root_ids = Some((alloc_id, static_def_id));
|
||||
|
|
|
|||
|
|
@ -168,10 +168,11 @@ impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> {
|
|||
// Bound regions are always printed (as `'_`), which gives some idea that they are special,
|
||||
// even though the `for` is omitted by the pretty printer.
|
||||
// E.g. `for<'a, 'b> fn(&'a u32, &'b u32)` is printed as "fn(&'_ u32, &'_ u32)".
|
||||
let kind = region.kind();
|
||||
match region.kind() {
|
||||
ty::ReErased | ty::ReEarlyParam(_) => false,
|
||||
ty::ReErased | ty::ReEarlyParam(_) | ty::ReStatic => false,
|
||||
ty::ReBound(..) => true,
|
||||
_ => unreachable!(),
|
||||
_ => panic!("type_name unhandled region: {kind:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,3 +10,8 @@ crate-type = ["dylib"]
|
|||
# tidy-alphabetical-start
|
||||
rustc_driver_impl = { path = "../rustc_driver_impl" }
|
||||
# tidy-alphabetical-end
|
||||
|
||||
[build-dependencies]
|
||||
# tidy-alphabetical-start
|
||||
rustc_windows_rc = { path = "../rustc_windows_rc" }
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
21
compiler/rustc_driver/build.rs
Normal file
21
compiler/rustc_driver/build.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
use std::{env, path};
|
||||
|
||||
use rustc_windows_rc::{VersionInfoFileType, compile_windows_resource_file};
|
||||
|
||||
fn main() {
|
||||
let target_os = env::var("CARGO_CFG_TARGET_OS");
|
||||
let target_env = env::var("CARGO_CFG_TARGET_ENV");
|
||||
if Ok("windows") == target_os.as_deref() && Ok("msvc") == target_env.as_deref() {
|
||||
set_windows_dll_options();
|
||||
} else {
|
||||
// Avoid rerunning the build script every time.
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
||||
}
|
||||
|
||||
fn set_windows_dll_options() {
|
||||
let stem = path::PathBuf::from("rustc_driver_resource");
|
||||
let file_description = "rustc_driver";
|
||||
let res_file = compile_windows_resource_file(&stem, file_description, VersionInfoFileType::Dll);
|
||||
println!("cargo:rustc-link-arg={}", res_file.display());
|
||||
}
|
||||
|
|
@ -51,6 +51,7 @@ use rustc_lint::unerased_lint_store;
|
|||
use rustc_metadata::creader::MetadataLoader;
|
||||
use rustc_metadata::locator;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_parse::lexer::StripTokens;
|
||||
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
|
||||
use rustc_session::config::{
|
||||
CG_OPTIONS, CrateType, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, Sysroot,
|
||||
|
|
@ -1288,10 +1289,15 @@ fn warn_on_confusing_output_filename_flag(
|
|||
|
||||
fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> {
|
||||
let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
|
||||
Input::File(file) => new_parser_from_file(&sess.psess, file, None),
|
||||
Input::Str { name, input } => {
|
||||
new_parser_from_source_str(&sess.psess, name.clone(), input.clone())
|
||||
Input::File(file) => {
|
||||
new_parser_from_file(&sess.psess, file, StripTokens::ShebangAndFrontmatter, None)
|
||||
}
|
||||
Input::Str { name, input } => new_parser_from_source_str(
|
||||
&sess.psess,
|
||||
name.clone(),
|
||||
input.clone(),
|
||||
StripTokens::ShebangAndFrontmatter,
|
||||
),
|
||||
});
|
||||
parser.parse_inner_attributes()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,13 +18,14 @@ use rustc_feature::Features;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::{AttributeKind, CfgEntry, Deprecation};
|
||||
use rustc_hir::def::MacroKinds;
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_hir::{Stability, find_attr};
|
||||
use rustc_lint_defs::RegisteredTools;
|
||||
use rustc_parse::MACRO_ARGUMENTS;
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::CollapseMacroDebuginfo;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_session::{Limit, Session};
|
||||
use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind};
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use std::borrow::Cow;
|
|||
|
||||
use rustc_ast::ast;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol};
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -19,14 +19,15 @@ use rustc_errors::PResult;
|
|||
use rustc_feature::Features;
|
||||
use rustc_hir::Target;
|
||||
use rustc_hir::def::MacroKinds;
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_parse::parser::{
|
||||
AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma,
|
||||
token_descr,
|
||||
};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::{Limit, Session};
|
||||
use rustc_span::hygiene::SyntaxContext;
|
||||
use rustc_span::{ErrorGuaranteed, FileName, Ident, LocalExpnId, Span, Symbol, sym};
|
||||
use smallvec::SmallVec;
|
||||
|
|
@ -2529,6 +2530,7 @@ impl ExpansionConfig<'_> {
|
|||
ExpansionConfig {
|
||||
crate_name,
|
||||
features,
|
||||
// FIXME should this limit be configurable?
|
||||
recursion_limit: Limit::new(1024),
|
||||
trace_mac: false,
|
||||
should_test: false,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use std::path::{self, Path, PathBuf};
|
|||
use rustc_ast::{AttrVec, Attribute, Inline, Item, ModSpans};
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_errors::{Diag, ErrorGuaranteed};
|
||||
use rustc_parse::lexer::StripTokens;
|
||||
use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::parse::ParseSess;
|
||||
|
|
@ -67,8 +68,12 @@ pub(crate) fn parse_external_mod(
|
|||
}
|
||||
|
||||
// Actually parse the external file as a module.
|
||||
let mut parser =
|
||||
unwrap_or_emit_fatal(new_parser_from_file(&sess.psess, &mp.file_path, Some(span)));
|
||||
let mut parser = unwrap_or_emit_fatal(new_parser_from_file(
|
||||
&sess.psess,
|
||||
&mp.file_path,
|
||||
StripTokens::ShebangAndFrontmatter,
|
||||
Some(span),
|
||||
));
|
||||
let (inner_attrs, items, inner_span) =
|
||||
parser.parse_mod(exp!(Eof)).map_err(|err| ModError::ParserError(err))?;
|
||||
attrs.extend(inner_attrs);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_ast::util::literal::escape_byte_str_symbol;
|
|||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{Diag, ErrorGuaranteed, MultiSpan, PResult};
|
||||
use rustc_parse::lexer::nfc_normalize;
|
||||
use rustc_parse::lexer::{StripTokens, nfc_normalize};
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_parse::{exp, new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal};
|
||||
use rustc_proc_macro::bridge::{
|
||||
|
|
@ -485,8 +485,13 @@ impl server::FreeFunctions for Rustc<'_, '_> {
|
|||
|
||||
fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span, Self::Symbol>, ()> {
|
||||
let name = FileName::proc_macro_source_code(s);
|
||||
let mut parser =
|
||||
unwrap_or_emit_fatal(new_parser_from_source_str(self.psess(), name, s.to_owned()));
|
||||
|
||||
let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str(
|
||||
self.psess(),
|
||||
name,
|
||||
s.to_owned(),
|
||||
StripTokens::Nothing,
|
||||
));
|
||||
|
||||
let first_span = parser.token.span.data();
|
||||
let minus_present = parser.eat(exp!(Minus));
|
||||
|
|
|
|||
|
|
@ -621,6 +621,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
|
||||
gated!(rustc_align, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(rustc_align)),
|
||||
gated!(rustc_align_static, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, static_align, experimental!(rustc_align_static)),
|
||||
ungated!(
|
||||
unsafe(Edition2024) export_name, Normal,
|
||||
template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute"),
|
||||
|
|
|
|||
|
|
@ -632,6 +632,8 @@ declare_features! (
|
|||
(unstable, simd_ffi, "1.0.0", Some(27731)),
|
||||
/// Allows specialization of implementations (RFC 1210).
|
||||
(incomplete, specialization, "1.7.0", Some(31844)),
|
||||
/// Allows using `#[rustc_align_static(...)]` on static items.
|
||||
(unstable, static_align, "CURRENT_RUSTC_VERSION", Some(146177)),
|
||||
/// Allows attributes on expressions and non-item statements.
|
||||
(unstable, stmt_expr_attributes, "1.6.0", Some(15701)),
|
||||
/// Allows lints part of the strict provenance effort.
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ pub use rustc_target::spec::SanitizerSet;
|
|||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::attrs::pretty_printing::PrintAttribute;
|
||||
use crate::limit::Limit;
|
||||
use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
|
||||
|
|
@ -565,6 +566,9 @@ pub enum AttributeKind {
|
|||
/// Represents [`#[may_dangle]`](https://std-dev-guide.rust-lang.org/tricky/may-dangle.html).
|
||||
MayDangle(Span),
|
||||
|
||||
/// Represents `#[move_size_limit]`
|
||||
MoveSizeLimit { attr_span: Span, limit_span: Span, limit: Limit },
|
||||
|
||||
/// Represents `#[must_use]`.
|
||||
MustUse {
|
||||
span: Span,
|
||||
|
|
@ -596,6 +600,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[path]`
|
||||
Path(Symbol, Span),
|
||||
|
||||
/// Represents `#[pattern_complexity_limit]`
|
||||
PatternComplexityLimit { attr_span: Span, limit_span: Span, limit: Limit },
|
||||
|
||||
/// Represents `#[pointee]`
|
||||
Pointee(Span),
|
||||
|
||||
|
|
@ -611,6 +618,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
|
||||
PubTransparent(Span),
|
||||
|
||||
/// Represents [`#[recursion_limit]`](https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute)
|
||||
RecursionLimit { attr_span: Span, limit_span: Span, limit: Limit },
|
||||
|
||||
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
|
||||
Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span },
|
||||
|
||||
|
|
@ -661,6 +671,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[type_const]`.
|
||||
TypeConst(Span),
|
||||
|
||||
/// Represents `#[type_length_limit]`
|
||||
TypeLengthLimit { attr_span: Span, limit_span: Span, limit: Limit },
|
||||
|
||||
/// Represents `#[rustc_unsafe_specialization_marker]`.
|
||||
UnsafeSpecializationMarker(Span),
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ impl AttributeKind {
|
|||
MacroUse { .. } => No,
|
||||
Marker(..) => No,
|
||||
MayDangle(..) => No,
|
||||
MoveSizeLimit { .. } => No,
|
||||
MustUse { .. } => Yes,
|
||||
Naked(..) => No,
|
||||
NoImplicitPrelude(..) => No,
|
||||
|
|
@ -70,11 +71,13 @@ impl AttributeKind {
|
|||
ParenSugar(..) => No,
|
||||
PassByValue(..) => Yes,
|
||||
Path(..) => No,
|
||||
PatternComplexityLimit { .. } => No,
|
||||
Pointee(..) => No,
|
||||
ProcMacro(..) => No,
|
||||
ProcMacroAttribute(..) => No,
|
||||
ProcMacroDerive { .. } => No,
|
||||
PubTransparent(..) => Yes,
|
||||
RecursionLimit { .. } => No,
|
||||
Repr { .. } => No,
|
||||
RustcBuiltinMacro { .. } => Yes,
|
||||
RustcLayoutScalarValidRangeEnd(..) => Yes,
|
||||
|
|
@ -89,6 +92,7 @@ impl AttributeKind {
|
|||
TargetFeature { .. } => No,
|
||||
TrackCaller(..) => Yes,
|
||||
TypeConst(..) => Yes,
|
||||
TypeLengthLimit { .. } => No,
|
||||
UnsafeSpecializationMarker(..) => No,
|
||||
UnstableFeatureBound(..) => No,
|
||||
Used { .. } => No,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
|
|||
use rustc_target::spec::SanitizerSet;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::limit::Limit;
|
||||
|
||||
/// This trait is used to print attributes in `rustc_hir_pretty`.
|
||||
///
|
||||
/// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`].
|
||||
|
|
@ -146,7 +148,7 @@ macro_rules! print_tup {
|
|||
|
||||
print_tup!(A B C D E F G H);
|
||||
print_skip!(Span, (), ErrorGuaranteed);
|
||||
print_disp!(u16, bool, NonZero<u32>);
|
||||
print_disp!(u16, bool, NonZero<u32>, Limit);
|
||||
print_debug!(
|
||||
Symbol,
|
||||
Ident,
|
||||
|
|
|
|||
|
|
@ -2614,6 +2614,18 @@ impl Expr<'_> {
|
|||
StructTailExpr::None,
|
||||
),
|
||||
)
|
||||
| (
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeToInclusiveCopy, _),
|
||||
[val1],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeToInclusiveCopy, _),
|
||||
[val2],
|
||||
StructTailExpr::None,
|
||||
),
|
||||
)
|
||||
| (
|
||||
ExprKind::Struct(
|
||||
QPath::LangItem(LangItem::RangeFrom, _),
|
||||
|
|
@ -2705,7 +2717,8 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
|
|||
| LangItem::RangeToInclusive
|
||||
| LangItem::RangeCopy
|
||||
| LangItem::RangeFromCopy
|
||||
| LangItem::RangeInclusiveCopy,
|
||||
| LangItem::RangeInclusiveCopy
|
||||
| LangItem::RangeToInclusiveCopy,
|
||||
..
|
||||
)
|
||||
),
|
||||
|
|
|
|||
|
|
@ -422,6 +422,7 @@ language_item_table! {
|
|||
RangeFromCopy, sym::RangeFromCopy, range_from_copy_struct, Target::Struct, GenericRequirement::None;
|
||||
RangeCopy, sym::RangeCopy, range_copy_struct, Target::Struct, GenericRequirement::None;
|
||||
RangeInclusiveCopy, sym::RangeInclusiveCopy, range_inclusive_copy_struct, Target::Struct, GenericRequirement::None;
|
||||
RangeToInclusiveCopy, sym::RangeToInclusiveCopy, range_to_inclusive_copy_struct, Target::Struct, GenericRequirement::None;
|
||||
|
||||
String, sym::String, string, Target::Struct, GenericRequirement::None;
|
||||
CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ mod hir;
|
|||
pub use rustc_hir_id::{self as hir_id, *};
|
||||
pub mod intravisit;
|
||||
pub mod lang_items;
|
||||
pub mod limit;
|
||||
pub mod lints;
|
||||
pub mod pat_util;
|
||||
mod stability;
|
||||
|
|
|
|||
63
compiler/rustc_hir/src/limit.rs
Normal file
63
compiler/rustc_hir/src/limit.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use std::fmt;
|
||||
use std::ops::{Div, Mul};
|
||||
|
||||
use rustc_error_messages::{DiagArgValue, IntoDiagArg};
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
|
||||
/// New-type wrapper around `usize` for representing limits. Ensures that comparisons against
|
||||
/// limits are consistent throughout the compiler.
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic, Encodable, Decodable)]
|
||||
pub struct Limit(pub usize);
|
||||
|
||||
impl Limit {
|
||||
/// Create a new limit from a `usize`.
|
||||
pub fn new(value: usize) -> Self {
|
||||
Limit(value)
|
||||
}
|
||||
|
||||
/// Create a new unlimited limit.
|
||||
pub fn unlimited() -> Self {
|
||||
Limit(usize::MAX)
|
||||
}
|
||||
|
||||
/// Check that `value` is within the limit. Ensures that the same comparisons are used
|
||||
/// throughout the compiler, as mismatches can cause ICEs, see #72540.
|
||||
#[inline]
|
||||
pub fn value_within_limit(&self, value: usize) -> bool {
|
||||
value <= self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Limit {
|
||||
fn from(value: usize) -> Self {
|
||||
Self::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Limit {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for Limit {
|
||||
type Output = Limit;
|
||||
|
||||
fn div(self, rhs: usize) -> Self::Output {
|
||||
Limit::new(self.0 / rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<usize> for Limit {
|
||||
type Output = Limit;
|
||||
|
||||
fn mul(self, rhs: usize) -> Self::Output {
|
||||
Limit::new(self.0 * rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoDiagArg for Limit {
|
||||
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
|
||||
self.to_string().into_diag_arg(&mut None)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_hir::limit::Limit;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::PredicateObligations;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_session::Limit;
|
||||
use rustc_span::def_id::{LOCAL_CRATE, LocalDefId};
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ pub mod intrinsic;
|
|||
mod region;
|
||||
pub mod wfcheck;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::num::NonZero;
|
||||
|
||||
pub use check::{check_abi, check_custom_abi};
|
||||
|
|
@ -85,7 +86,9 @@ use rustc_infer::traits::ObligationCause;
|
|||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::print::with_types_for_signature;
|
||||
use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode};
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgs, GenericArgsRef, OutlivesPredicate, Region, Ty, TyCtxt, TypingMode,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
|
|
@ -233,8 +236,7 @@ fn missing_items_err(
|
|||
};
|
||||
|
||||
// Obtain the level of indentation ending in `sugg_sp`.
|
||||
let padding =
|
||||
tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new());
|
||||
let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new);
|
||||
let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) =
|
||||
(Vec::new(), Vec::new(), Vec::new());
|
||||
|
||||
|
|
@ -331,8 +333,10 @@ fn default_body_is_unstable(
|
|||
fn bounds_from_generic_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
|
||||
assoc: ty::AssocItem,
|
||||
) -> (String, String) {
|
||||
let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default();
|
||||
let mut regions: FxIndexMap<Region<'tcx>, Vec<Region<'tcx>>> = FxIndexMap::default();
|
||||
let mut projections = vec![];
|
||||
for (predicate, _) in predicates {
|
||||
debug!("predicate {:?}", predicate);
|
||||
|
|
@ -349,39 +353,75 @@ fn bounds_from_generic_predicates<'tcx>(
|
|||
ty::ClauseKind::Projection(projection_pred) => {
|
||||
projections.push(bound_predicate.rebind(projection_pred));
|
||||
}
|
||||
ty::ClauseKind::RegionOutlives(OutlivesPredicate(a, b)) => {
|
||||
regions.entry(a).or_default().push(b);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let mut where_clauses = vec![];
|
||||
let mut types_str = vec![];
|
||||
for (ty, bounds) in types {
|
||||
if let ty::Param(_) = ty.kind() {
|
||||
let mut bounds_str = vec![];
|
||||
for bound in bounds {
|
||||
let mut projections_str = vec![];
|
||||
for projection in &projections {
|
||||
let p = projection.skip_binder();
|
||||
if bound == tcx.parent(p.projection_term.def_id)
|
||||
&& p.projection_term.self_ty() == ty
|
||||
{
|
||||
let name = tcx.item_name(p.projection_term.def_id);
|
||||
projections_str.push(format!("{} = {}", name, p.term));
|
||||
let generics = tcx.generics_of(assoc.def_id);
|
||||
let params = generics
|
||||
.own_params
|
||||
.iter()
|
||||
.filter(|p| !p.kind.is_synthetic())
|
||||
.map(|p| match tcx.mk_param_from_def(p).kind() {
|
||||
ty::GenericArgKind::Type(ty) => {
|
||||
let bounds =
|
||||
types.get(&ty).map(Cow::Borrowed).unwrap_or_else(|| Cow::Owned(Vec::new()));
|
||||
let mut bounds_str = vec![];
|
||||
for bound in bounds.iter().copied() {
|
||||
let mut projections_str = vec![];
|
||||
for projection in &projections {
|
||||
let p = projection.skip_binder();
|
||||
if bound == tcx.parent(p.projection_term.def_id)
|
||||
&& p.projection_term.self_ty() == ty
|
||||
{
|
||||
let name = tcx.item_name(p.projection_term.def_id);
|
||||
projections_str.push(format!("{} = {}", name, p.term));
|
||||
}
|
||||
}
|
||||
let bound_def_path = if tcx.is_lang_item(bound, LangItem::MetaSized) {
|
||||
String::from("?Sized")
|
||||
} else {
|
||||
tcx.def_path_str(bound)
|
||||
};
|
||||
if projections_str.is_empty() {
|
||||
where_clauses.push(format!("{}: {}", ty, bound_def_path));
|
||||
} else {
|
||||
bounds_str.push(format!(
|
||||
"{}<{}>",
|
||||
bound_def_path,
|
||||
projections_str.join(", ")
|
||||
));
|
||||
}
|
||||
}
|
||||
let bound_def_path = tcx.def_path_str(bound);
|
||||
if projections_str.is_empty() {
|
||||
where_clauses.push(format!("{}: {}", ty, bound_def_path));
|
||||
if bounds_str.is_empty() {
|
||||
ty.to_string()
|
||||
} else {
|
||||
bounds_str.push(format!("{}<{}>", bound_def_path, projections_str.join(", ")));
|
||||
format!("{}: {}", ty, bounds_str.join(" + "))
|
||||
}
|
||||
}
|
||||
if bounds_str.is_empty() {
|
||||
types_str.push(ty.to_string());
|
||||
} else {
|
||||
types_str.push(format!("{}: {}", ty, bounds_str.join(" + ")));
|
||||
ty::GenericArgKind::Const(ct) => {
|
||||
format!("const {ct}: {}", tcx.type_of(p.def_id).skip_binder())
|
||||
}
|
||||
} else {
|
||||
ty::GenericArgKind::Lifetime(region) => {
|
||||
if let Some(v) = regions.get(®ion)
|
||||
&& !v.is_empty()
|
||||
{
|
||||
format!(
|
||||
"{region}: {}",
|
||||
v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + ")
|
||||
)
|
||||
} else {
|
||||
region.to_string()
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
for (ty, bounds) in types.into_iter() {
|
||||
if !matches!(ty.kind(), ty::Param(_)) {
|
||||
// Avoid suggesting the following:
|
||||
// fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {}
|
||||
where_clauses.extend(
|
||||
|
|
@ -391,7 +431,7 @@ fn bounds_from_generic_predicates<'tcx>(
|
|||
}
|
||||
|
||||
let generics =
|
||||
if types_str.is_empty() { "".to_string() } else { format!("<{}>", types_str.join(", ")) };
|
||||
if params.is_empty() { "".to_string() } else { format!("<{}>", params.join(", ")) };
|
||||
|
||||
let where_clauses = if where_clauses.is_empty() {
|
||||
"".to_string()
|
||||
|
|
@ -473,10 +513,10 @@ fn fn_sig_suggestion<'tcx>(
|
|||
let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
|
||||
|
||||
let safety = sig.safety.prefix_str();
|
||||
let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
|
||||
let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates, assoc);
|
||||
|
||||
// FIXME: this is not entirely correct, as the lifetimes from borrowed params will
|
||||
// not be present in the `fn` definition, not will we account for renamed
|
||||
// not be present in the `fn` definition, nor will we account for renamed
|
||||
// lifetimes between the `impl` and the `trait`, but this should be good enough to
|
||||
// fill in a significant portion of the missing code, and other subsequent
|
||||
// suggestions can help the user fix the code.
|
||||
|
|
@ -512,6 +552,7 @@ fn suggestion_signature<'tcx>(
|
|||
let (generics, where_clauses) = bounds_from_generic_predicates(
|
||||
tcx,
|
||||
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
|
||||
assoc,
|
||||
);
|
||||
format!("type {}{generics} = /* Type */{where_clauses};", assoc.name())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1047,7 +1047,7 @@ fn check_type_defn<'tcx>(
|
|||
let needs_drop_copy = || {
|
||||
packed && {
|
||||
let ty = tcx.type_of(variant.tail().did).instantiate_identity();
|
||||
let ty = tcx.erase_regions(ty);
|
||||
let ty = tcx.erase_and_anonymize_regions(ty);
|
||||
assert!(!ty.has_infer());
|
||||
ty.needs_drop(tcx, wfcx.infcx.typing_env(wfcx.param_env))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -404,7 +404,7 @@ fn emit_orphan_check_error<'tcx>(
|
|||
of_trait.trait_ref.path.span
|
||||
};
|
||||
|
||||
ty = tcx.erase_regions(ty);
|
||||
ty = tcx.erase_and_anonymize_regions(ty);
|
||||
|
||||
let is_foreign =
|
||||
!trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No);
|
||||
|
|
|
|||
|
|
@ -174,12 +174,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
}
|
||||
};
|
||||
|
||||
if let Node::TraitItem(item) = node {
|
||||
let mut bounds = Vec::new();
|
||||
icx.lowerer().add_default_trait_item_bounds(item, &mut bounds);
|
||||
predicates.extend(bounds);
|
||||
}
|
||||
|
||||
let generics = tcx.generics_of(def_id);
|
||||
|
||||
// Below we'll consider the bounds on the type parameters (including `Self`)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use rustc_errors::{
|
|||
Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
|
||||
MultiSpan,
|
||||
};
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
|
@ -557,7 +558,7 @@ pub(crate) struct AutoDerefReachedRecursionLimit<'a> {
|
|||
#[label]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'a>,
|
||||
pub suggested_limit: rustc_session::Limit,
|
||||
pub suggested_limit: Limit,
|
||||
pub crate_name: Symbol,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use std::assert_matches::assert_matches;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::struct_span_code_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::PolyTraitRef;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
|
||||
use rustc_hir::{AmbigArg, PolyTraitRef};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{
|
||||
self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||
|
|
@ -230,122 +231,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds
|
||||
/// or associated items.
|
||||
///
|
||||
/// To keep backward compatibility with existing code, `experimental_default_bounds` bounds
|
||||
/// should be added everywhere, including super bounds. However this causes a huge performance
|
||||
/// costs. For optimization purposes instead of adding default supertraits, bounds
|
||||
/// are added to the associated items:
|
||||
///
|
||||
/// ```ignore(illustrative)
|
||||
/// // Default bounds are generated in the following way:
|
||||
/// trait Trait {
|
||||
/// fn foo(&self) where Self: Leak {}
|
||||
/// }
|
||||
///
|
||||
/// // instead of this:
|
||||
/// trait Trait: Leak {
|
||||
/// fn foo(&self) {}
|
||||
/// }
|
||||
/// ```
|
||||
/// It is not always possible to do this because of backward compatibility:
|
||||
///
|
||||
/// ```ignore(illustrative)
|
||||
/// pub trait Trait<Rhs = Self> {}
|
||||
/// pub trait Trait1 : Trait {}
|
||||
/// //~^ ERROR: `Rhs` requires `DefaultAutoTrait`, but `Self` is not `DefaultAutoTrait`
|
||||
/// ```
|
||||
///
|
||||
/// or:
|
||||
///
|
||||
/// ```ignore(illustrative)
|
||||
/// trait Trait {
|
||||
/// type Type where Self: Sized;
|
||||
/// }
|
||||
/// trait Trait2<T> : Trait<Type = T> {}
|
||||
/// //~^ ERROR: `DefaultAutoTrait` required for `Trait2`, by implicit `Self: DefaultAutoTrait` in `Trait::Type`
|
||||
/// ```
|
||||
///
|
||||
/// Therefore, `experimental_default_bounds` are still being added to supertraits if
|
||||
/// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header.
|
||||
fn requires_default_supertraits(
|
||||
&self,
|
||||
hir_bounds: &'tcx [hir::GenericBound<'tcx>],
|
||||
hir_generics: &'tcx hir::Generics<'tcx>,
|
||||
) -> bool {
|
||||
struct TraitInfoCollector;
|
||||
|
||||
impl<'tcx> hir::intravisit::Visitor<'tcx> for TraitInfoCollector {
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn visit_assoc_item_constraint(
|
||||
&mut self,
|
||||
_constraint: &'tcx hir::AssocItemConstraint<'tcx>,
|
||||
) -> Self::Result {
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
|
||||
if matches!(
|
||||
&t.kind,
|
||||
hir::TyKind::Path(hir::QPath::Resolved(
|
||||
_,
|
||||
hir::Path { res: hir::def::Res::SelfTyParam { .. }, .. },
|
||||
))
|
||||
) {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
hir::intravisit::walk_ty(self, t)
|
||||
}
|
||||
}
|
||||
|
||||
let mut found = false;
|
||||
for bound in hir_bounds {
|
||||
found |= hir::intravisit::walk_param_bound(&mut TraitInfoCollector, bound).is_break();
|
||||
}
|
||||
found |= hir::intravisit::walk_generics(&mut TraitInfoCollector, hir_generics).is_break();
|
||||
found
|
||||
}
|
||||
|
||||
/// Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if
|
||||
/// they are not added as super trait bounds to the trait itself. See
|
||||
/// `requires_default_supertraits` for more information.
|
||||
pub(crate) fn add_default_trait_item_bounds(
|
||||
&self,
|
||||
trait_item: &hir::TraitItem<'tcx>,
|
||||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
if !tcx.sess.opts.unstable_opts.experimental_default_bounds {
|
||||
return;
|
||||
}
|
||||
|
||||
let parent = tcx.local_parent(trait_item.hir_id().owner.def_id);
|
||||
let hir::Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
let (trait_generics, trait_bounds) = match parent_trait.kind {
|
||||
hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => (generics, supertraits),
|
||||
hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if !self.requires_default_supertraits(trait_bounds, trait_generics) {
|
||||
let self_ty_where_predicates = (parent, trait_item.generics.predicates);
|
||||
self.add_default_traits(
|
||||
bounds,
|
||||
tcx.types.self_param,
|
||||
&[],
|
||||
Some(self_ty_where_predicates),
|
||||
trait_item.span,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Lazily sets `experimental_default_bounds` to true on trait super bounds.
|
||||
/// See `requires_default_supertraits` for more information.
|
||||
/// Adds `experimental_default_bounds` bounds to the supertrait bounds.
|
||||
pub(crate) fn add_default_super_traits(
|
||||
&self,
|
||||
trait_def_id: LocalDefId,
|
||||
|
|
@ -354,21 +240,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir_generics: &'tcx hir::Generics<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
if !self.tcx().sess.opts.unstable_opts.experimental_default_bounds {
|
||||
assert_matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias);
|
||||
|
||||
// Supertraits for auto trait are unsound according to the unstable book:
|
||||
// https://doc.rust-lang.org/beta/unstable-book/language-features/auto-traits.html#supertraits
|
||||
if self.tcx().trait_is_auto(trait_def_id.to_def_id()) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias));
|
||||
if self.requires_default_supertraits(hir_bounds, hir_generics) {
|
||||
let self_ty_where_predicates = (trait_def_id, hir_generics.predicates);
|
||||
self.add_default_traits(
|
||||
bounds,
|
||||
self.tcx().types.self_param,
|
||||
hir_bounds,
|
||||
Some(self_ty_where_predicates),
|
||||
span,
|
||||
);
|
||||
}
|
||||
self.add_default_traits(
|
||||
bounds,
|
||||
self.tcx().types.self_param,
|
||||
hir_bounds,
|
||||
Some((trait_def_id, hir_generics.predicates)),
|
||||
span,
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn add_default_traits(
|
||||
|
|
|
|||
|
|
@ -482,7 +482,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.map(|header| header.trait_ref.instantiate_identity().self_ty())
|
||||
// We don't care about blanket impls.
|
||||
.filter(|self_ty| !self_ty.has_non_region_param())
|
||||
.map(|self_ty| tcx.erase_regions(self_ty).to_string())
|
||||
.map(|self_ty| tcx.erase_and_anonymize_regions(self_ty).to_string())
|
||||
.collect()
|
||||
};
|
||||
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
|
||||
|
|
|
|||
|
|
@ -851,8 +851,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
debug!("check_ptr_ptr_cast m_src={m_src:?} m_dst={m_dst:?}");
|
||||
// ptr-ptr cast. metadata must match.
|
||||
|
||||
let src_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_src.ty, self.span)?);
|
||||
let dst_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_dst.ty, self.span)?);
|
||||
let src_kind = fcx.tcx.erase_and_anonymize_regions(fcx.pointer_kind(m_src.ty, self.span)?);
|
||||
let dst_kind = fcx.tcx.erase_and_anonymize_regions(fcx.pointer_kind(m_dst.ty, self.span)?);
|
||||
|
||||
// We can't cast if target pointer kind is unknown
|
||||
let Some(dst_kind) = dst_kind else {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
|
|||
use rustc_session::Session;
|
||||
use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym};
|
||||
use rustc_trait_selection::error_reporting::TypeErrCtxt;
|
||||
use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations;
|
||||
use rustc_trait_selection::traits::{
|
||||
self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt,
|
||||
};
|
||||
|
|
@ -188,14 +187,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
///
|
||||
/// [`InferCtxtErrorExt::err_ctxt`]: rustc_trait_selection::error_reporting::InferCtxtErrorExt::err_ctxt
|
||||
pub(crate) fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
|
||||
let mut sub_relations = SubRelations::default();
|
||||
sub_relations.add_constraints(
|
||||
self,
|
||||
self.fulfillment_cx.borrow_mut().pending_obligations().iter().map(|o| o.predicate),
|
||||
);
|
||||
TypeErrCtxt {
|
||||
infcx: &self.infcx,
|
||||
sub_relations: RefCell::new(sub_relations),
|
||||
typeck_results: Some(self.typeck_results.borrow()),
|
||||
fallback_has_occurred: self.fallback_has_occurred.get(),
|
||||
normalize_fn_sig: Box::new(|fn_sig| {
|
||||
|
|
|
|||
|
|
@ -1358,7 +1358,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.infcx
|
||||
.type_implements_trait(
|
||||
clone_trait_def,
|
||||
[self.tcx.erase_regions(expected_ty)],
|
||||
[self.tcx.erase_and_anonymize_regions(expected_ty)],
|
||||
self.param_env,
|
||||
)
|
||||
.must_apply_modulo_regions()
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
|
|||
if ty.has_non_region_infer() {
|
||||
Ty::new_misc_error(self.tcx())
|
||||
} else {
|
||||
self.tcx().erase_regions(ty)
|
||||
self.tcx().erase_and_anonymize_regions(ty)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -403,15 +403,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// special handling for this "trivial case" is a good idea.
|
||||
|
||||
let infcx = &self.infcx;
|
||||
let (ParamEnvAnd { param_env: _, value: self_ty }, canonical_inference_vars) =
|
||||
let (ParamEnvAnd { param_env: _, value: self_ty }, var_values) =
|
||||
infcx.instantiate_canonical(span, &query_input.canonical);
|
||||
debug!(?self_ty, ?query_input, "probe_op: Mode::Path");
|
||||
MethodAutoderefStepsResult {
|
||||
steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
|
||||
self_ty: self.make_query_response_ignoring_pending_obligations(
|
||||
canonical_inference_vars,
|
||||
self_ty,
|
||||
),
|
||||
self_ty: self
|
||||
.make_query_response_ignoring_pending_obligations(var_values, self_ty),
|
||||
autoderefs: 0,
|
||||
from_unsafe_deref: false,
|
||||
unsize: false,
|
||||
|
|
|
|||
|
|
@ -802,7 +802,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
format!("unexpected inference variable after writeback: {predicate:?}"),
|
||||
);
|
||||
} else {
|
||||
let predicate = self.tcx().erase_regions(predicate);
|
||||
let predicate = self.tcx().erase_and_anonymize_regions(predicate);
|
||||
if cause.has_infer() || cause.has_placeholders() {
|
||||
// We can't use the the obligation cause as it references
|
||||
// information local to this query.
|
||||
|
|
@ -984,8 +984,8 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
|
|||
// borrowck, and specifically region constraints will be populated during
|
||||
// MIR typeck which is run on the new body.
|
||||
//
|
||||
// We're not using `tcx.erase_regions` as that also anonymizes bound variables,
|
||||
// regressing borrowck diagnostics.
|
||||
// We're not using `tcx.erase_and_anonymize_regions` as that also
|
||||
// anonymizes bound variables, regressing borrowck diagnostics.
|
||||
value = fold_regions(tcx, value, |_, _| tcx.lifetimes.re_erased);
|
||||
|
||||
// Normalize consts in writeback, because GCE doesn't normalize eagerly.
|
||||
|
|
|
|||
|
|
@ -130,7 +130,22 @@ impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeFrom<I> {
|
|||
impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeInclusive<I> {
|
||||
type Output = core::range::RangeInclusive<usize>;
|
||||
#[inline]
|
||||
#[cfg(bootstrap)]
|
||||
fn into_slice_idx(self) -> Self::Output {
|
||||
core::range::RangeInclusive { start: self.start.index(), end: self.end.index() }
|
||||
}
|
||||
#[inline]
|
||||
#[cfg(not(bootstrap))]
|
||||
fn into_slice_idx(self) -> Self::Output {
|
||||
core::range::RangeInclusive { start: self.start.index(), last: self.last.index() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "nightly", not(bootstrap)))]
|
||||
impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeToInclusive<I> {
|
||||
type Output = core::range::RangeToInclusive<usize>;
|
||||
#[inline]
|
||||
fn into_slice_idx(self) -> Self::Output {
|
||||
core::range::RangeToInclusive { last: self.last.index() }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sso::SsoHashMap;
|
||||
use rustc_index::Idx;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{
|
||||
|
|
@ -17,7 +18,7 @@ use tracing::debug;
|
|||
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::canonical::{
|
||||
Canonical, CanonicalQueryInput, CanonicalTyVarKind, CanonicalVarKind, OriginalQueryValues,
|
||||
Canonical, CanonicalQueryInput, CanonicalVarKind, OriginalQueryValues,
|
||||
};
|
||||
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
|
|
@ -293,6 +294,13 @@ struct Canonicalizer<'cx, 'tcx> {
|
|||
// Note that indices is only used once `var_values` is big enough to be
|
||||
// heap-allocated.
|
||||
indices: FxHashMap<GenericArg<'tcx>, BoundVar>,
|
||||
/// Maps each `sub_unification_table_root_var` to the index of the first
|
||||
/// variable which used it.
|
||||
///
|
||||
/// This means in case two type variables have the same sub relations root,
|
||||
/// we set the `sub_root` of the second variable to the position of the first.
|
||||
/// Otherwise the `sub_root` of each type variable is just its own position.
|
||||
sub_root_lookup_table: SsoHashMap<ty::TyVid, usize>,
|
||||
canonicalize_mode: &'cx dyn CanonicalizeMode,
|
||||
needs_canonical_flags: TypeFlags,
|
||||
|
||||
|
|
@ -361,10 +369,8 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
// FIXME: perf problem described in #55921.
|
||||
ui = ty::UniverseIndex::ROOT;
|
||||
}
|
||||
self.canonicalize_ty_var(
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
|
||||
t,
|
||||
)
|
||||
let sub_root = self.get_or_insert_sub_root(vid);
|
||||
self.canonicalize_ty_var(CanonicalVarKind::Ty { ui, sub_root }, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -374,7 +380,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
if nt != t {
|
||||
return self.fold_ty(nt);
|
||||
} else {
|
||||
self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Int), t)
|
||||
self.canonicalize_ty_var(CanonicalVarKind::Int, t)
|
||||
}
|
||||
}
|
||||
ty::Infer(ty::FloatVar(vid)) => {
|
||||
|
|
@ -382,7 +388,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
if nt != t {
|
||||
return self.fold_ty(nt);
|
||||
} else {
|
||||
self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Float), t)
|
||||
self.canonicalize_ty_var(CanonicalVarKind::Float, t)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -562,6 +568,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
variables: SmallVec::from_slice(base.variables),
|
||||
query_state,
|
||||
indices: FxHashMap::default(),
|
||||
sub_root_lookup_table: Default::default(),
|
||||
binder_index: ty::INNERMOST,
|
||||
};
|
||||
if canonicalizer.query_state.var_values.spilled() {
|
||||
|
|
@ -660,6 +667,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar {
|
||||
let root_vid = self.infcx.unwrap().sub_unification_table_root_var(vid);
|
||||
let idx =
|
||||
*self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len());
|
||||
ty::BoundVar::from(idx)
|
||||
}
|
||||
|
||||
/// Replaces the universe indexes used in `var_values` with their index in
|
||||
/// `query_state.universe_map`. This minimizes the maximum universe used in
|
||||
/// the canonicalized value.
|
||||
|
|
@ -679,11 +693,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
self.variables
|
||||
.iter()
|
||||
.map(|&kind| match kind {
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
|
||||
CanonicalVarKind::Int | CanonicalVarKind::Float => {
|
||||
return kind;
|
||||
}
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
|
||||
CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
|
||||
CanonicalVarKind::Ty { ui, sub_root } => {
|
||||
CanonicalVarKind::Ty { ui: reverse_universe_map[&ui], sub_root }
|
||||
}
|
||||
CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]),
|
||||
CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]),
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
pub use instantiate::CanonicalExt;
|
||||
use rustc_index::IndexVec;
|
||||
pub use rustc_middle::infer::canonical::*;
|
||||
use rustc_middle::ty::{self, GenericArg, List, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::infer::{InferCtxt, RegionVariableOrigin};
|
||||
|
|
@ -67,30 +67,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
.chain((1..=canonical.max_universe.as_u32()).map(|_| self.create_next_universe()))
|
||||
.collect();
|
||||
|
||||
let canonical_inference_vars =
|
||||
self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]);
|
||||
let result = canonical.instantiate(self.tcx, &canonical_inference_vars);
|
||||
(result, canonical_inference_vars)
|
||||
}
|
||||
|
||||
/// Given the "infos" about the canonical variables from some
|
||||
/// canonical, creates fresh variables with the same
|
||||
/// characteristics (see `instantiate_canonical_var` for
|
||||
/// details). You can then use `instantiate` to instantiate the
|
||||
/// canonical variable with these inference variables.
|
||||
fn instantiate_canonical_vars(
|
||||
&self,
|
||||
span: Span,
|
||||
variables: &List<CanonicalVarKind<'tcx>>,
|
||||
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
|
||||
) -> CanonicalVarValues<'tcx> {
|
||||
CanonicalVarValues {
|
||||
var_values: self.tcx.mk_args_from_iter(
|
||||
variables
|
||||
.iter()
|
||||
.map(|kind| self.instantiate_canonical_var(span, kind, &universe_map)),
|
||||
),
|
||||
}
|
||||
let var_values =
|
||||
CanonicalVarValues::instantiate(self.tcx, &canonical.variables, |var_values, info| {
|
||||
self.instantiate_canonical_var(span, info, &var_values, |ui| universes[ui])
|
||||
});
|
||||
let result = canonical.instantiate(self.tcx, &var_values);
|
||||
(result, var_values)
|
||||
}
|
||||
|
||||
/// Given the "info" about a canonical variable, creates a fresh
|
||||
|
|
@ -105,22 +87,28 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
&self,
|
||||
span: Span,
|
||||
kind: CanonicalVarKind<'tcx>,
|
||||
previous_var_values: &[GenericArg<'tcx>],
|
||||
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
|
||||
) -> GenericArg<'tcx> {
|
||||
match kind {
|
||||
CanonicalVarKind::Ty(ty_kind) => {
|
||||
let ty = match ty_kind {
|
||||
CanonicalTyVarKind::General(ui) => {
|
||||
self.next_ty_var_in_universe(span, universe_map(ui))
|
||||
CanonicalVarKind::Ty { ui, sub_root } => {
|
||||
let vid = self.next_ty_vid_in_universe(span, universe_map(ui));
|
||||
// If this inference variable is related to an earlier variable
|
||||
// via subtyping, we need to add that info to the inference context.
|
||||
if let Some(prev) = previous_var_values.get(sub_root.as_usize()) {
|
||||
if let &ty::Infer(ty::TyVar(sub_root)) = prev.expect_ty().kind() {
|
||||
self.sub_unify_ty_vids_raw(vid, sub_root);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
CanonicalTyVarKind::Int => self.next_int_var(),
|
||||
|
||||
CanonicalTyVarKind::Float => self.next_float_var(),
|
||||
};
|
||||
ty.into()
|
||||
}
|
||||
Ty::new_var(self.tcx, vid).into()
|
||||
}
|
||||
|
||||
CanonicalVarKind::Int => self.next_int_var().into(),
|
||||
|
||||
CanonicalVarKind::Float => self.next_float_var().into(),
|
||||
|
||||
CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound }) => {
|
||||
let universe_mapped = universe_map(universe);
|
||||
let placeholder_mapped = ty::PlaceholderType { universe: universe_mapped, bound };
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use std::iter;
|
|||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_middle::arena::ArenaAllocatable;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::infer::canonical::CanonicalVarKind;
|
||||
use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
|
|
@ -413,26 +414,27 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
let mut opt_values: IndexVec<BoundVar, Option<GenericArg<'tcx>>> =
|
||||
IndexVec::from_elem_n(None, query_response.variables.len());
|
||||
|
||||
// In terms of our example above, we are iterating over pairs like:
|
||||
// [(?A, Vec<?0>), ('static, '?1), (?B, ?0)]
|
||||
for (original_value, result_value) in iter::zip(&original_values.var_values, result_values)
|
||||
{
|
||||
match result_value.kind() {
|
||||
GenericArgKind::Type(result_value) => {
|
||||
// e.g., here `result_value` might be `?0` in the example above...
|
||||
if let ty::Bound(debruijn, b) = *result_value.kind() {
|
||||
// ...in which case we would set `canonical_vars[0]` to `Some(?U)`.
|
||||
|
||||
// We disable the instantiation guess for inference variables
|
||||
// and only use it for placeholders. We need to handle the
|
||||
// `sub_root` of type inference variables which would make this
|
||||
// more involved. They are also a lot rarer than region variables.
|
||||
if let ty::Bound(debruijn, b) = *result_value.kind()
|
||||
&& !matches!(
|
||||
query_response.variables[b.var.as_usize()],
|
||||
CanonicalVarKind::Ty { .. }
|
||||
)
|
||||
{
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
opt_values[b.var] = Some(*original_value);
|
||||
}
|
||||
}
|
||||
GenericArgKind::Lifetime(result_value) => {
|
||||
// e.g., here `result_value` might be `'?1` in the example above...
|
||||
if let ty::ReBound(debruijn, b) = result_value.kind() {
|
||||
// ... in which case we would set `canonical_vars[0]` to `Some('static)`.
|
||||
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
opt_values[b.var] = Some(*original_value);
|
||||
|
|
@ -440,8 +442,6 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
GenericArgKind::Const(result_value) => {
|
||||
if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() {
|
||||
// ...in which case we would set `canonical_vars[0]` to `Some(const X)`.
|
||||
|
||||
// We only allow a `ty::INNERMOST` index in generic parameters.
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
opt_values[b.var] = Some(*original_value);
|
||||
|
|
@ -453,39 +453,36 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
// Create result arguments: if we found a value for a
|
||||
// given variable in the loop above, use that. Otherwise, use
|
||||
// a fresh inference variable.
|
||||
let result_args = CanonicalVarValues {
|
||||
var_values: self.tcx.mk_args_from_iter(
|
||||
query_response.variables.iter().enumerate().map(|(index, var_kind)| {
|
||||
if var_kind.universe() != ty::UniverseIndex::ROOT {
|
||||
// A variable from inside a binder of the query. While ideally these shouldn't
|
||||
// exist at all, we have to deal with them for now.
|
||||
self.instantiate_canonical_var(cause.span, var_kind, |u| {
|
||||
universe_map[u.as_usize()]
|
||||
})
|
||||
} else if var_kind.is_existential() {
|
||||
match opt_values[BoundVar::new(index)] {
|
||||
Some(k) => k,
|
||||
None => self.instantiate_canonical_var(cause.span, var_kind, |u| {
|
||||
universe_map[u.as_usize()]
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
// For placeholders which were already part of the input, we simply map this
|
||||
// universal bound variable back the placeholder of the input.
|
||||
opt_values[BoundVar::new(index)].expect(
|
||||
"expected placeholder to be unified with itself during response",
|
||||
)
|
||||
}
|
||||
}),
|
||||
),
|
||||
};
|
||||
let tcx = self.tcx;
|
||||
let variables = query_response.variables;
|
||||
let var_values = CanonicalVarValues::instantiate(tcx, variables, |var_values, kind| {
|
||||
if kind.universe() != ty::UniverseIndex::ROOT {
|
||||
// A variable from inside a binder of the query. While ideally these shouldn't
|
||||
// exist at all, we have to deal with them for now.
|
||||
self.instantiate_canonical_var(cause.span, kind, &var_values, |u| {
|
||||
universe_map[u.as_usize()]
|
||||
})
|
||||
} else if kind.is_existential() {
|
||||
match opt_values[BoundVar::new(var_values.len())] {
|
||||
Some(k) => k,
|
||||
None => self.instantiate_canonical_var(cause.span, kind, &var_values, |u| {
|
||||
universe_map[u.as_usize()]
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
// For placeholders which were already part of the input, we simply map this
|
||||
// universal bound variable back the placeholder of the input.
|
||||
opt_values[BoundVar::new(var_values.len())]
|
||||
.expect("expected placeholder to be unified with itself during response")
|
||||
}
|
||||
});
|
||||
|
||||
let mut obligations = PredicateObligations::new();
|
||||
|
||||
// Carry all newly resolved opaque types to the caller's scope
|
||||
for &(a, b) in &query_response.value.opaque_types {
|
||||
let a = instantiate_value(self.tcx, &result_args, a);
|
||||
let b = instantiate_value(self.tcx, &result_args, b);
|
||||
let a = instantiate_value(self.tcx, &var_values, a);
|
||||
let b = instantiate_value(self.tcx, &var_values, b);
|
||||
debug!(?a, ?b, "constrain opaque type");
|
||||
// We use equate here instead of, for example, just registering the
|
||||
// opaque type's hidden value directly, because the hidden type may have been an inference
|
||||
|
|
@ -502,7 +499,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
Ok(InferOk { value: result_args, obligations })
|
||||
Ok(InferOk { value: var_values, obligations })
|
||||
}
|
||||
|
||||
/// Given a "guess" at the values for the canonical variables in
|
||||
|
|
|
|||
|
|
@ -59,6 +59,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
|||
self.root_var(var)
|
||||
}
|
||||
|
||||
fn sub_unification_table_root_var(&self, var: ty::TyVid) -> ty::TyVid {
|
||||
self.sub_unification_table_root_var(var)
|
||||
}
|
||||
|
||||
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
|
||||
self.root_const_var(var)
|
||||
}
|
||||
|
|
@ -179,6 +183,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
|||
self.inner.borrow_mut().type_variables().equate(a, b);
|
||||
}
|
||||
|
||||
fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
|
||||
self.sub_unify_ty_vids_raw(a, b);
|
||||
}
|
||||
|
||||
fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid) {
|
||||
self.inner.borrow_mut().int_unification_table().union(a, b);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -764,6 +764,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
let r_b = self.shallow_resolve(predicate.skip_binder().b);
|
||||
match (r_a.kind(), r_b.kind()) {
|
||||
(&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
|
||||
self.sub_unify_ty_vids_raw(a_vid, b_vid);
|
||||
return Err((a_vid, b_vid));
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -1128,6 +1129,14 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
self.inner.borrow_mut().type_variables().root_var(var)
|
||||
}
|
||||
|
||||
pub fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
|
||||
self.inner.borrow_mut().type_variables().sub_unify(a, b);
|
||||
}
|
||||
|
||||
pub fn sub_unification_table_root_var(&self, var: ty::TyVid) -> ty::TyVid {
|
||||
self.inner.borrow_mut().type_variables().sub_unification_table_root_var(var)
|
||||
}
|
||||
|
||||
pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
|
||||
self.inner.borrow_mut().const_unification_table().find(var).vid
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ pub(super) fn can_match_erased_ty<'tcx>(
|
|||
erased_ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
assert!(!outlives_predicate.has_escaping_bound_vars());
|
||||
let erased_outlives_predicate = tcx.erase_regions(outlives_predicate);
|
||||
let erased_outlives_predicate = tcx.erase_and_anonymize_regions(outlives_predicate);
|
||||
let outlives_ty = erased_outlives_predicate.skip_binder().0;
|
||||
if outlives_ty == erased_ty {
|
||||
// pointless micro-optimization
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
&self,
|
||||
alias_ty: ty::AliasTy<'tcx>,
|
||||
) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
|
||||
let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx));
|
||||
let erased_alias_ty = self.tcx.erase_and_anonymize_regions(alias_ty.to_ty(self.tcx));
|
||||
self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty)
|
||||
}
|
||||
|
||||
|
|
@ -241,7 +241,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
let p_ty = p.to_ty(tcx);
|
||||
let erased_p_ty = self.tcx.erase_regions(p_ty);
|
||||
let erased_p_ty = self.tcx.erase_and_anonymize_regions(p_ty);
|
||||
(erased_p_ty == erased_ty).then_some(ty::Binder::dummy(ty::OutlivesPredicate(p_ty, r)))
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::{
|
||||
self, AliasRelationDirection, InferConst, MaxUniverse, Term, Ty, TyCtxt, TypeVisitable,
|
||||
TypeVisitableExt, TypingMode,
|
||||
self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt, TypeVisitor, TypingMode,
|
||||
};
|
||||
use rustc_span::Span;
|
||||
use tracing::{debug, instrument, warn};
|
||||
|
|
@ -290,6 +290,45 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Finds the max universe present
|
||||
struct MaxUniverse {
|
||||
max_universe: ty::UniverseIndex,
|
||||
}
|
||||
|
||||
impl MaxUniverse {
|
||||
fn new() -> Self {
|
||||
MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
|
||||
}
|
||||
|
||||
fn max_universe(self) -> ty::UniverseIndex {
|
||||
self.max_universe
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxUniverse {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) {
|
||||
if let ty::Placeholder(placeholder) = t.kind() {
|
||||
self.max_universe = self.max_universe.max(placeholder.universe);
|
||||
}
|
||||
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) {
|
||||
if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
|
||||
self.max_universe = self.max_universe.max(placeholder.universe);
|
||||
}
|
||||
|
||||
c.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) {
|
||||
if let ty::RePlaceholder(placeholder) = r.kind() {
|
||||
self.max_universe = self.max_universe.max(placeholder.universe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The "generalizer" is used when handling inference variables.
|
||||
///
|
||||
/// The basic strategy for handling a constraint like `?A <: B` is to
|
||||
|
|
@ -519,6 +558,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
|
|||
let origin = inner.type_variables().var_origin(vid);
|
||||
let new_var_id =
|
||||
inner.type_variables().new_var(self.for_universe, origin);
|
||||
// Record that `vid` and `new_var_id` have to be subtypes
|
||||
// of each other. This is currently only used for diagnostics.
|
||||
// To see why, see the docs in the `type_variables` module.
|
||||
inner.type_variables().sub_unify(vid, new_var_id);
|
||||
// If we're in the new solver and create a new inference
|
||||
// variable inside of an alias we eagerly constrain that
|
||||
// inference variable to prevent unexpected ambiguity errors.
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ pub struct Snapshot<'tcx> {
|
|||
pub(crate) enum UndoLog<'tcx> {
|
||||
DuplicateOpaqueType,
|
||||
OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
|
||||
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
|
||||
TypeVariables(type_variable::UndoLog<'tcx>),
|
||||
ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
|
||||
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
|
||||
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
|
||||
|
|
@ -49,6 +49,8 @@ impl_from! {
|
|||
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
|
||||
|
||||
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
|
||||
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidSubKey>>),
|
||||
TypeVariables(type_variable::UndoLog<'tcx>),
|
||||
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
|
||||
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
|
||||
|
||||
|
|
|
|||
|
|
@ -13,12 +13,48 @@ use tracing::debug;
|
|||
|
||||
use crate::infer::InferCtxtUndoLogs;
|
||||
|
||||
/// Represents a single undo-able action that affects a type inference variable.
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum UndoLog<'tcx> {
|
||||
EqRelation(sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>),
|
||||
SubRelation(sv::UndoLog<ut::Delegate<TyVidSubKey>>),
|
||||
}
|
||||
|
||||
/// Convert from a specific kind of undo to the more general UndoLog
|
||||
impl<'tcx> From<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for UndoLog<'tcx> {
|
||||
fn from(l: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) -> Self {
|
||||
UndoLog::EqRelation(l)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert from a specific kind of undo to the more general UndoLog
|
||||
impl<'tcx> From<sv::UndoLog<ut::Delegate<TyVidSubKey>>> for UndoLog<'tcx> {
|
||||
fn from(l: sv::UndoLog<ut::Delegate<TyVidSubKey>>) -> Self {
|
||||
UndoLog::SubRelation(l)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Rollback<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for TypeVariableStorage<'tcx> {
|
||||
fn reverse(&mut self, undo: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) {
|
||||
self.eq_relations.reverse(undo)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Rollback<sv::UndoLog<ut::Delegate<TyVidSubKey>>> for TypeVariableStorage<'tcx> {
|
||||
fn reverse(&mut self, undo: sv::UndoLog<ut::Delegate<TyVidSubKey>>) {
|
||||
self.sub_unification_table.reverse(undo)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Rollback<UndoLog<'tcx>> for TypeVariableStorage<'tcx> {
|
||||
fn reverse(&mut self, undo: UndoLog<'tcx>) {
|
||||
match undo {
|
||||
UndoLog::EqRelation(undo) => self.eq_relations.reverse(undo),
|
||||
UndoLog::SubRelation(undo) => self.sub_unification_table.reverse(undo),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct TypeVariableStorage<'tcx> {
|
||||
/// The origins of each type variable.
|
||||
|
|
@ -27,6 +63,25 @@ pub(crate) struct TypeVariableStorage<'tcx> {
|
|||
/// constraint `?X == ?Y`. This table also stores, for each key,
|
||||
/// the known value.
|
||||
eq_relations: ut::UnificationTableStorage<TyVidEqKey<'tcx>>,
|
||||
/// Only used by `-Znext-solver` and for diagnostics. Tracks whether
|
||||
/// type variables are related via subtyping at all, ignoring which of
|
||||
/// the two is the subtype.
|
||||
///
|
||||
/// When reporting ambiguity errors, we sometimes want to
|
||||
/// treat all inference vars which are subtypes of each
|
||||
/// others as if they are equal. For this case we compute
|
||||
/// the transitive closure of our subtype obligations here.
|
||||
///
|
||||
/// E.g. when encountering ambiguity errors, we want to suggest
|
||||
/// specifying some method argument or to add a type annotation
|
||||
/// to a local variable. Because subtyping cannot change the
|
||||
/// shape of a type, it's fine if the cause of the ambiguity error
|
||||
/// is only related to the suggested variable via subtyping.
|
||||
///
|
||||
/// Even for something like `let x = returns_arg(); x.method();` the
|
||||
/// type of `x` is only a supertype of the argument of `returns_arg`. We
|
||||
/// still want to suggest specifying the type of the argument.
|
||||
sub_unification_table: ut::UnificationTableStorage<TyVidSubKey>,
|
||||
}
|
||||
|
||||
pub(crate) struct TypeVariableTable<'a, 'tcx> {
|
||||
|
|
@ -102,13 +157,24 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
|
|||
self.storage.values[vid].origin
|
||||
}
|
||||
|
||||
/// Records that `a == b`, depending on `dir`.
|
||||
/// Records that `a == b`.
|
||||
///
|
||||
/// Precondition: neither `a` nor `b` are known.
|
||||
pub(crate) fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) {
|
||||
debug_assert!(self.probe(a).is_unknown());
|
||||
debug_assert!(self.probe(b).is_unknown());
|
||||
self.eq_relations().union(a, b);
|
||||
self.sub_unification_table().union(a, b);
|
||||
}
|
||||
|
||||
/// Records that `a` and `b` are related via subtyping. We don't track
|
||||
/// which of the two is the subtype.
|
||||
///
|
||||
/// Precondition: neither `a` nor `b` are known.
|
||||
pub(crate) fn sub_unify(&mut self, a: ty::TyVid, b: ty::TyVid) {
|
||||
debug_assert!(self.probe(a).is_unknown());
|
||||
debug_assert!(self.probe(b).is_unknown());
|
||||
self.sub_unification_table().union(a, b);
|
||||
}
|
||||
|
||||
/// Instantiates `vid` with the type `ty`.
|
||||
|
|
@ -142,6 +208,10 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
|
|||
origin: TypeVariableOrigin,
|
||||
) -> ty::TyVid {
|
||||
let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe });
|
||||
|
||||
let sub_key = self.sub_unification_table().new_key(());
|
||||
debug_assert_eq!(eq_key.vid, sub_key.vid);
|
||||
|
||||
let index = self.storage.values.push(TypeVariableData { origin });
|
||||
debug_assert_eq!(eq_key.vid, index);
|
||||
|
||||
|
|
@ -164,6 +234,18 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
|
|||
self.eq_relations().find(vid).vid
|
||||
}
|
||||
|
||||
/// Returns the "root" variable of `vid` in the `sub_unification_table`
|
||||
/// equivalence table. All type variables that have been are related via
|
||||
/// equality or subtyping will yield the same root variable (per the
|
||||
/// union-find algorithm), so `sub_unification_table_root_var(a)
|
||||
/// == sub_unification_table_root_var(b)` implies that:
|
||||
/// ```text
|
||||
/// exists X. (a <: X || X <: a) && (b <: X || X <: b)
|
||||
/// ```
|
||||
pub(crate) fn sub_unification_table_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
|
||||
self.sub_unification_table().find(vid).vid
|
||||
}
|
||||
|
||||
/// Retrieves the type to which `vid` has been instantiated, if
|
||||
/// any.
|
||||
pub(crate) fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> {
|
||||
|
|
@ -181,6 +263,11 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
|
|||
self.storage.eq_relations.with_log(self.undo_log)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sub_unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidSubKey> {
|
||||
self.storage.sub_unification_table.with_log(self.undo_log)
|
||||
}
|
||||
|
||||
/// Returns a range of the type variables created during the snapshot.
|
||||
pub(crate) fn vars_since_snapshot(
|
||||
&mut self,
|
||||
|
|
@ -243,6 +330,33 @@ impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct TyVidSubKey {
|
||||
vid: ty::TyVid,
|
||||
}
|
||||
|
||||
impl From<ty::TyVid> for TyVidSubKey {
|
||||
#[inline] // make this function eligible for inlining - it is quite hot.
|
||||
fn from(vid: ty::TyVid) -> Self {
|
||||
TyVidSubKey { vid }
|
||||
}
|
||||
}
|
||||
|
||||
impl ut::UnifyKey for TyVidSubKey {
|
||||
type Value = ();
|
||||
#[inline]
|
||||
fn index(&self) -> u32 {
|
||||
self.vid.as_u32()
|
||||
}
|
||||
#[inline]
|
||||
fn from_index(i: u32) -> TyVidSubKey {
|
||||
TyVidSubKey { vid: ty::TyVid::from_u32(i) }
|
||||
}
|
||||
fn tag() -> &'static str {
|
||||
"TyVidSubKey"
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> {
|
||||
type Error = ut::NoError;
|
||||
|
||||
|
|
|
|||
|
|
@ -30,10 +30,6 @@ interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag
|
|||
interface_input_file_would_be_overwritten =
|
||||
the input file "{$path}" would be overwritten by the generated executable
|
||||
|
||||
interface_limit_invalid =
|
||||
`limit` must be a non-negative integer
|
||||
.label = {$error_str}
|
||||
|
||||
interface_mixed_bin_crate =
|
||||
cannot mix `bin` crate type with others
|
||||
|
||||
|
|
|
|||
|
|
@ -108,13 +108,3 @@ pub(crate) struct AbiRequiredTargetFeature<'a> {
|
|||
pub feature: &'a str,
|
||||
pub enabled: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(interface_limit_invalid)]
|
||||
pub(crate) struct LimitInvalid<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub value_span: Span,
|
||||
pub error_str: &'a str,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ use rustc_lint::LintStore;
|
|||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::CurrentGcx;
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_parse::new_parser_from_simple_source_str;
|
||||
use rustc_parse::lexer::StripTokens;
|
||||
use rustc_parse::new_parser_from_source_str;
|
||||
use rustc_parse::parser::attr::AllowLeadingUnsafe;
|
||||
use rustc_query_impl::QueryCtxt;
|
||||
use rustc_query_system::query::print_query_stack;
|
||||
|
|
@ -68,7 +69,8 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg {
|
|||
};
|
||||
}
|
||||
|
||||
match new_parser_from_simple_source_str(&psess, filename, s.to_string()) {
|
||||
match new_parser_from_source_str(&psess, filename, s.to_string(), StripTokens::Nothing)
|
||||
{
|
||||
Ok(mut parser) => match parser.parse_meta_item(AllowLeadingUnsafe::No) {
|
||||
Ok(meta_item) if parser.token == token::Eof => {
|
||||
if meta_item.path.segments.len() != 1 {
|
||||
|
|
@ -166,13 +168,15 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
|
|||
error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`")
|
||||
};
|
||||
|
||||
let mut parser = match new_parser_from_simple_source_str(&psess, filename, s.to_string()) {
|
||||
Ok(parser) => parser,
|
||||
Err(errs) => {
|
||||
errs.into_iter().for_each(|err| err.cancel());
|
||||
expected_error();
|
||||
}
|
||||
};
|
||||
let mut parser =
|
||||
match new_parser_from_source_str(&psess, filename, s.to_string(), StripTokens::Nothing)
|
||||
{
|
||||
Ok(parser) => parser,
|
||||
Err(errs) => {
|
||||
errs.into_iter().for_each(|err| err.cancel());
|
||||
expected_error();
|
||||
}
|
||||
};
|
||||
|
||||
let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::No) {
|
||||
Ok(meta_item) if parser.token == token::Eof => meta_item,
|
||||
|
|
|
|||
|
|
@ -8,78 +8,32 @@
|
|||
//! Users can override these limits via an attribute on the crate like
|
||||
//! `#![recursion_limit="22"]`. This pass just looks for those attributes.
|
||||
|
||||
use std::num::IntErrorKind;
|
||||
|
||||
use rustc_ast::attr::AttributeExt;
|
||||
use rustc_middle::bug;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_hir::{Attribute, find_attr};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_session::{Limit, Limits, Session};
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::errors::LimitInvalid;
|
||||
use rustc_session::Limits;
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
providers.limits = |tcx, ()| Limits {
|
||||
recursion_limit: get_recursion_limit(tcx.hir_krate_attrs(), tcx.sess),
|
||||
move_size_limit: get_limit(
|
||||
tcx.hir_krate_attrs(),
|
||||
tcx.sess,
|
||||
sym::move_size_limit,
|
||||
Limit::new(tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0)),
|
||||
),
|
||||
type_length_limit: get_limit(
|
||||
tcx.hir_krate_attrs(),
|
||||
tcx.sess,
|
||||
sym::type_length_limit,
|
||||
Limit::new(2usize.pow(24)),
|
||||
),
|
||||
pattern_complexity_limit: get_limit(
|
||||
tcx.hir_krate_attrs(),
|
||||
tcx.sess,
|
||||
sym::pattern_complexity_limit,
|
||||
Limit::unlimited(),
|
||||
),
|
||||
providers.limits = |tcx, ()| {
|
||||
let attrs = tcx.hir_krate_attrs();
|
||||
Limits {
|
||||
recursion_limit: get_recursion_limit(tcx.hir_krate_attrs()),
|
||||
move_size_limit:
|
||||
find_attr!(attrs, AttributeKind::MoveSizeLimit { limit, .. } => *limit)
|
||||
.unwrap_or(Limit::new(tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0))),
|
||||
type_length_limit:
|
||||
find_attr!(attrs, AttributeKind::TypeLengthLimit { limit, .. } => *limit)
|
||||
.unwrap_or(Limit::new(2usize.pow(24))),
|
||||
pattern_complexity_limit:
|
||||
find_attr!(attrs, AttributeKind::PatternComplexityLimit { limit, .. } => *limit)
|
||||
.unwrap_or(Limit::unlimited()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This one is separate because it must be read prior to macro expansion.
|
||||
pub(crate) fn get_recursion_limit(krate_attrs: &[impl AttributeExt], sess: &Session) -> Limit {
|
||||
get_limit(krate_attrs, sess, sym::recursion_limit, Limit::new(128))
|
||||
}
|
||||
|
||||
fn get_limit(
|
||||
krate_attrs: &[impl AttributeExt],
|
||||
sess: &Session,
|
||||
name: Symbol,
|
||||
default: Limit,
|
||||
) -> Limit {
|
||||
for attr in krate_attrs {
|
||||
if !attr.has_name(name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(sym) = attr.value_str() {
|
||||
match sym.as_str().parse() {
|
||||
Ok(n) => return Limit::new(n),
|
||||
Err(e) => {
|
||||
let error_str = match e.kind() {
|
||||
IntErrorKind::PosOverflow => "`limit` is too large",
|
||||
IntErrorKind::Empty => "`limit` must be a non-negative integer",
|
||||
IntErrorKind::InvalidDigit => "not a valid integer",
|
||||
IntErrorKind::NegOverflow => {
|
||||
bug!("`limit` should never negatively overflow")
|
||||
}
|
||||
IntErrorKind::Zero => bug!("zero is a valid `limit`"),
|
||||
kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
|
||||
};
|
||||
sess.dcx().emit_err(LimitInvalid {
|
||||
span: attr.span(),
|
||||
value_span: attr.value_span().unwrap(),
|
||||
error_str,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default
|
||||
pub(crate) fn get_recursion_limit(attrs: &[Attribute]) -> Limit {
|
||||
find_attr!(attrs, AttributeKind::RecursionLimit { limit, .. } => *limit)
|
||||
.unwrap_or(Limit::new(128))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::sync::{Arc, LazyLock, OnceLock};
|
|||
use std::{env, fs, iter};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr_parsing::{AttributeParser, ShouldEmit, validate_attr};
|
||||
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_data_structures::jobserver::Proxy;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
|
|
@ -19,6 +19,7 @@ use rustc_fs_util::try_canonicalize;
|
|||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap};
|
||||
use rustc_hir::definitions::Definitions;
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_incremental::setup_dep_graph;
|
||||
use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
|
|
@ -27,15 +28,16 @@ use rustc_middle::arena::Arena;
|
|||
use rustc_middle::dep_graph::DepsType;
|
||||
use rustc_middle::ty::{self, CurrentGcx, GlobalCtxt, RegisteredTools, TyCtxt};
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_parse::lexer::StripTokens;
|
||||
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
|
||||
use rustc_passes::{abi_test, input_stats, layout_test};
|
||||
use rustc_resolve::{Resolver, ResolverOutputs};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
|
||||
use rustc_session::cstore::Untracked;
|
||||
use rustc_session::output::{collect_crate_types, filename_for_input};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::search_paths::PathKind;
|
||||
use rustc_session::{Limit, Session};
|
||||
use rustc_span::{
|
||||
DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span,
|
||||
Symbol, sym,
|
||||
|
|
@ -51,10 +53,18 @@ pub fn parse<'a>(sess: &'a Session) -> ast::Crate {
|
|||
let mut krate = sess
|
||||
.time("parse_crate", || {
|
||||
let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
|
||||
Input::File(file) => new_parser_from_file(&sess.psess, file, None),
|
||||
Input::Str { input, name } => {
|
||||
new_parser_from_source_str(&sess.psess, name.clone(), input.clone())
|
||||
}
|
||||
Input::File(file) => new_parser_from_file(
|
||||
&sess.psess,
|
||||
file,
|
||||
StripTokens::ShebangAndFrontmatter,
|
||||
None,
|
||||
),
|
||||
Input::Str { input, name } => new_parser_from_source_str(
|
||||
&sess.psess,
|
||||
name.clone(),
|
||||
input.clone(),
|
||||
StripTokens::ShebangAndFrontmatter,
|
||||
),
|
||||
});
|
||||
parser.parse_crate_mod()
|
||||
})
|
||||
|
|
@ -1246,7 +1256,8 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol
|
|||
// in all code paths that require the crate name very early on, namely before
|
||||
// macro expansion.
|
||||
|
||||
let attr_crate_name = parse_crate_name(sess, krate_attrs, ShouldEmit::EarlyFatal);
|
||||
let attr_crate_name =
|
||||
parse_crate_name(sess, krate_attrs, ShouldEmit::EarlyFatal { also_emit_lints: true });
|
||||
|
||||
let validate = |name, span| {
|
||||
rustc_session::output::validate_crate_name(sess, name, span);
|
||||
|
|
@ -1307,36 +1318,18 @@ pub(crate) fn parse_crate_name(
|
|||
}
|
||||
|
||||
fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
|
||||
// We don't permit macro calls inside of the attribute (e.g., #![recursion_limit = `expand!()`])
|
||||
// because that would require expanding this while in the middle of expansion, which needs to
|
||||
// know the limit before expanding.
|
||||
let _ = validate_and_find_value_str_builtin_attr(sym::recursion_limit, sess, krate_attrs);
|
||||
crate::limits::get_recursion_limit(krate_attrs, sess)
|
||||
}
|
||||
|
||||
/// Validate *all* occurrences of the given "[value-str]" built-in attribute and return the first find.
|
||||
///
|
||||
/// This validator is intended for built-in attributes whose value needs to be known very early
|
||||
/// during compilation (namely, before macro expansion) and it mainly exists to reject macro calls
|
||||
/// inside of the attributes, such as in `#![name = expand!()]`. Normal attribute validation happens
|
||||
/// during semantic analysis via [`TyCtxt::check_mod_attrs`] which happens *after* macro expansion
|
||||
/// when such macro calls (here: `expand`) have already been expanded and we can no longer check for
|
||||
/// their presence.
|
||||
///
|
||||
/// [value-str]: ast::Attribute::value_str
|
||||
fn validate_and_find_value_str_builtin_attr(
|
||||
name: Symbol,
|
||||
sess: &Session,
|
||||
krate_attrs: &[ast::Attribute],
|
||||
) -> Option<(Symbol, Span)> {
|
||||
let mut result = None;
|
||||
// Validate *all* relevant attributes, not just the first occurrence.
|
||||
for attr in ast::attr::filter_by_name(krate_attrs, name) {
|
||||
let Some(value) = attr.value_str() else {
|
||||
validate_attr::emit_fatal_malformed_builtin_attribute(&sess.psess, attr, name)
|
||||
};
|
||||
// Choose the first occurrence as our result.
|
||||
result.get_or_insert((value, attr.span));
|
||||
}
|
||||
result
|
||||
let attr = AttributeParser::parse_limited_should_emit(
|
||||
sess,
|
||||
&krate_attrs,
|
||||
sym::recursion_limit,
|
||||
DUMMY_SP,
|
||||
rustc_ast::node_id::CRATE_NODE_ID,
|
||||
None,
|
||||
// errors are fatal here, but lints aren't.
|
||||
// If things aren't fatal we continue, and will parse this again.
|
||||
// That makes the same lint trigger again.
|
||||
// So, no lints here to avoid duplicates.
|
||||
ShouldEmit::EarlyFatal { also_emit_lints: false },
|
||||
);
|
||||
crate::limits::get_recursion_limit(attr.as_slice())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
|
|||
{
|
||||
// erase regions in self type for better diagnostic presentation
|
||||
let (self_ty, target_principal, supertrait_principal) =
|
||||
tcx.erase_regions((self_ty, target_principal, supertrait_principal));
|
||||
tcx.erase_and_anonymize_regions((self_ty, target_principal, supertrait_principal));
|
||||
let label2 = tcx
|
||||
.associated_items(item.owner_id)
|
||||
.find_by_ident_and_kind(
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ fn suggest_question_mark<'tcx>(
|
|||
cause,
|
||||
param_env,
|
||||
// Erase any region vids from the type, which may not be resolved
|
||||
infcx.tcx.erase_regions(ty),
|
||||
infcx.tcx.erase_and_anonymize_regions(ty),
|
||||
into_iterator_did,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
|
|||
.explicit_super_predicates_of(def_id)
|
||||
.iter_identity_copied()
|
||||
.filter_map(|(pred, _)| pred.as_trait_clause())
|
||||
.filter(|pred| !cx.tcx.is_lang_item(pred.def_id(), hir::LangItem::MetaSized));
|
||||
.filter(|pred| !cx.tcx.is_lang_item(pred.def_id(), hir::LangItem::MetaSized))
|
||||
.filter(|pred| !cx.tcx.is_default_trait(pred.def_id()));
|
||||
if direct_super_traits_iter.count() > 1 {
|
||||
cx.emit_span_lint(
|
||||
MULTIPLE_SUPERTRAIT_UPCASTABLE,
|
||||
|
|
|
|||
|
|
@ -935,7 +935,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
|
|||
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
|
||||
if let hir::ItemKind::Enum(_, _, ref enum_definition) = it.kind {
|
||||
let t = cx.tcx.type_of(it.owner_id).instantiate_identity();
|
||||
let ty = cx.tcx.erase_regions(t);
|
||||
let ty = cx.tcx.erase_and_anonymize_regions(t);
|
||||
let Ok(layout) = cx.layout_of(ty) else { return };
|
||||
let Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, variants, .. } =
|
||||
&layout.variants
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ libc = "0.2.73"
|
|||
[build-dependencies]
|
||||
# tidy-alphabetical-start
|
||||
# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version
|
||||
# per crate", so if you change this, you need to also change it in `rustc_codegen_ssa`.
|
||||
# per crate", so if you change this, you need to also change it in `rustc_codegen_ssa` and `rustc_windows_rc`.
|
||||
cc = "=1.2.16"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
|
|
|
|||
|
|
@ -254,7 +254,10 @@ fn main() {
|
|||
println!("cargo:rustc-link-lib=kstat");
|
||||
}
|
||||
|
||||
if (target.starts_with("arm") && !target.contains("freebsd") && !target.contains("ohos"))
|
||||
if (target.starts_with("arm")
|
||||
&& !target.starts_with("arm64")
|
||||
&& !target.contains("freebsd")
|
||||
&& !target.contains("ohos"))
|
||||
|| target.starts_with("mips-")
|
||||
|| target.starts_with("mipsel-")
|
||||
|| target.starts_with("powerpc-")
|
||||
|
|
|
|||
|
|
@ -5,13 +5,12 @@ edition = "2024"
|
|||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
# tracing > 0.1.37 have huge binary size / instructions regression
|
||||
tracing = "=0.1.37"
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
|
||||
tracing-tree = "0.3.1"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
[features]
|
||||
# tidy-alphabetical-start
|
||||
max_level_info = ['tracing/max_level_info']
|
||||
max_level_info = ['tracing/max_level_info', 'tracing/release_max_level_info']
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ pub enum TypeMismatchReason {
|
|||
#[help]
|
||||
pub(crate) struct RecursionLimitReached<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
pub suggested_limit: rustc_session::Limit,
|
||||
pub suggested_limit: rustc_hir::limit::Limit,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ use rustc_data_structures::fx::FxHashMap;
|
|||
use rustc_data_structures::sync::Lock;
|
||||
use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
|
||||
pub use rustc_type_ir as ir;
|
||||
pub use rustc_type_ir::CanonicalTyVarKind;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::mir::ConstraintCategory;
|
||||
|
|
|
|||
|
|
@ -724,6 +724,11 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
|
|||
}
|
||||
// If we get here, we have to check per-byte provenance, and join them together.
|
||||
let prov = 'prov: {
|
||||
if !Prov::OFFSET_IS_ADDR {
|
||||
// FIXME(#146291): We need to ensure that we don't mix different pointers with
|
||||
// the same provenance.
|
||||
return Err(AllocError::ReadPartialPointer(range.start));
|
||||
}
|
||||
// Initialize with first fragment. Must have index 0.
|
||||
let Some((mut joint_prov, 0)) = self.provenance.get_byte(range.start, cx) else {
|
||||
break 'prov None;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
|||
use tracing::trace;
|
||||
|
||||
use super::{AllocRange, CtfeProvenance, Provenance, alloc_range};
|
||||
use crate::mir::interpret::{AllocError, AllocResult};
|
||||
|
||||
/// Stores the provenance information of pointers stored in memory.
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
|
|
@ -137,6 +138,11 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
|
|||
let Some(bytes) = self.bytes.as_deref_mut() else {
|
||||
return true;
|
||||
};
|
||||
if !Prov::OFFSET_IS_ADDR {
|
||||
// FIXME(#146291): We need to ensure that we don't mix different pointers with
|
||||
// the same provenance.
|
||||
return false;
|
||||
}
|
||||
let ptr_size = cx.data_layout().pointer_size();
|
||||
while let Some((offset, (prov, _))) = bytes.iter().next().copied() {
|
||||
// Check if this fragment starts a pointer.
|
||||
|
|
@ -285,7 +291,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
|
|||
dest: Size,
|
||||
count: u64,
|
||||
cx: &impl HasDataLayout,
|
||||
) -> ProvenanceCopy<Prov> {
|
||||
) -> AllocResult<ProvenanceCopy<Prov>> {
|
||||
let shift_offset = move |idx, offset| {
|
||||
// compute offset for current repetition
|
||||
let dest_offset = dest + src.size * idx; // `Size` operations
|
||||
|
|
@ -363,6 +369,12 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
|
|||
}
|
||||
trace!("byte provenances: {bytes:?}");
|
||||
|
||||
if !bytes.is_empty() && !Prov::OFFSET_IS_ADDR {
|
||||
// FIXME(#146291): We need to ensure that we don't mix different pointers with
|
||||
// the same provenance.
|
||||
return Err(AllocError::ReadPartialPointer(src.start));
|
||||
}
|
||||
|
||||
// And again a buffer for the new list on the target side.
|
||||
let mut dest_bytes = Vec::with_capacity(bytes.len() * (count as usize));
|
||||
for i in 0..count {
|
||||
|
|
@ -373,7 +385,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
|
|||
dest_bytes_box = Some(dest_bytes.into_boxed_slice());
|
||||
}
|
||||
|
||||
ProvenanceCopy { dest_ptrs: dest_ptrs_box, dest_bytes: dest_bytes_box }
|
||||
Ok(ProvenanceCopy { dest_ptrs: dest_ptrs_box, dest_bytes: dest_bytes_box })
|
||||
}
|
||||
|
||||
/// Applies a provenance copy.
|
||||
|
|
|
|||
|
|
@ -386,7 +386,16 @@ impl<'tcx> GlobalAlloc<'tcx> {
|
|||
.expect("statics should not have generic parameters");
|
||||
let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap();
|
||||
assert!(layout.is_sized());
|
||||
(layout.size, layout.align.abi)
|
||||
|
||||
// Take over-alignment from attributes into account.
|
||||
let align = match tcx.codegen_fn_attrs(def_id).alignment {
|
||||
Some(align_from_attribute) => {
|
||||
Ord::max(align_from_attribute, layout.align.abi)
|
||||
}
|
||||
None => layout.align.abi,
|
||||
};
|
||||
|
||||
(layout.size, align)
|
||||
}
|
||||
}
|
||||
GlobalAlloc::Memory(alloc) => {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
let instance = ty::Instance::new_raw(def_id, args);
|
||||
let cid = GlobalId { instance, promoted: None };
|
||||
let typing_env = ty::TypingEnv::post_analysis(self, def_id);
|
||||
let inputs = self.erase_regions(typing_env.as_query_input(cid));
|
||||
let inputs = self.erase_and_anonymize_regions(typing_env.as_query_input(cid));
|
||||
self.eval_to_allocation_raw(inputs)
|
||||
}
|
||||
|
||||
|
|
@ -172,8 +172,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
) -> EvalToConstValueResult<'tcx> {
|
||||
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
|
||||
// improve caching of queries.
|
||||
let inputs =
|
||||
self.erase_regions(typing_env.with_post_analysis_normalized(self).as_query_input(cid));
|
||||
let inputs = self.erase_and_anonymize_regions(
|
||||
typing_env.with_post_analysis_normalized(self).as_query_input(cid),
|
||||
);
|
||||
if !span.is_dummy() {
|
||||
// The query doesn't know where it is being invoked, so we need to fix the span.
|
||||
self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span))
|
||||
|
|
@ -192,8 +193,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
) -> ConstToValTreeResult<'tcx> {
|
||||
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
|
||||
// improve caching of queries.
|
||||
let inputs =
|
||||
self.erase_regions(typing_env.with_post_analysis_normalized(self).as_query_input(cid));
|
||||
let inputs = self.erase_and_anonymize_regions(
|
||||
typing_env.with_post_analysis_normalized(self).as_query_input(cid),
|
||||
);
|
||||
debug!(?inputs);
|
||||
let res = if !span.is_dummy() {
|
||||
// The query doesn't know where it is being invoked, so we need to fix the span.
|
||||
|
|
|
|||
|
|
@ -78,8 +78,9 @@ impl<'dis, 'de, 'tcx> MirDumper<'dis, 'de, 'tcx> {
|
|||
pub fn new(tcx: TyCtxt<'tcx>, pass_name: &'static str, body: &Body<'tcx>) -> Option<Self> {
|
||||
let dump_enabled = if let Some(ref filters) = tcx.sess.opts.unstable_opts.dump_mir {
|
||||
// see notes on #41697 below
|
||||
let node_path =
|
||||
ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id()));
|
||||
let node_path = ty::print::with_no_trimmed_paths!(
|
||||
ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id()))
|
||||
);
|
||||
filters.split('|').any(|or_filter| {
|
||||
or_filter.split('&').all(|and_filter| {
|
||||
let and_filter_trimmed = and_filter.trim();
|
||||
|
|
@ -173,9 +174,10 @@ impl<'dis, 'de, 'tcx> MirDumper<'dis, 'de, 'tcx> {
|
|||
// trigger `type_of`, and this can run while we are already attempting to evaluate `type_of`.
|
||||
pub fn dump_mir_to_writer(&self, body: &Body<'tcx>, w: &mut dyn io::Write) -> io::Result<()> {
|
||||
// see notes on #41697 above
|
||||
let def_path = ty::print::with_forced_impl_filename_line!(
|
||||
self.tcx().def_path_str(body.source.def_id())
|
||||
);
|
||||
let def_path =
|
||||
ty::print::with_no_trimmed_paths!(ty::print::with_forced_impl_filename_line!(
|
||||
self.tcx().def_path_str(body.source.def_id())
|
||||
));
|
||||
// ignore-tidy-odd-backticks the literal below is fine
|
||||
write!(w, "// MIR for `{def_path}")?;
|
||||
match body.source.promoted {
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ use crate::traits::{
|
|||
};
|
||||
use crate::ty::fast_reject::SimplifiedType;
|
||||
use crate::ty::layout::ValidityRequirement;
|
||||
use crate::ty::print::{PrintTraitRefExt, describe_as_module};
|
||||
use crate::ty::print::PrintTraitRefExt;
|
||||
use crate::ty::util::AlwaysRequiresDrop;
|
||||
use crate::ty::{
|
||||
self, CrateInherentImpls, GenericArg, GenericArgsRef, PseudoCanonicalInput, SizedTraitKind, Ty,
|
||||
|
|
@ -761,9 +761,9 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
/// Erases regions from `ty` to yield a new type.
|
||||
/// Normally you would just use `tcx.erase_regions(value)`,
|
||||
/// Normally you would just use `tcx.erase_and_anonymize_regions(value)`,
|
||||
/// however, which uses this query as a kind of cache.
|
||||
query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
query erase_and_anonymize_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
// This query is not expected to have input -- as a result, it
|
||||
// is not a good candidates for "replay" because it is essentially a
|
||||
// pure function of its input (and hence the expectation is that
|
||||
|
|
@ -2731,3 +2731,12 @@ rustc_queries! {
|
|||
|
||||
rustc_with_all_queries! { define_callbacks! }
|
||||
rustc_feedable_queries! { define_feedable! }
|
||||
|
||||
fn describe_as_module(def_id: impl Into<LocalDefId>, tcx: TyCtxt<'_>) -> String {
|
||||
let def_id = def_id.into();
|
||||
if def_id.is_top_level_module() {
|
||||
"top-level module".to_string()
|
||||
} else {
|
||||
format!("module `{}`", tcx.def_path_str(def_id))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
ty::ConstKind::Unevaluated(uv) => match self.tcx.thir_abstract_const(uv.def) {
|
||||
Err(e) => ty::Const::new_error(self.tcx, e),
|
||||
Ok(Some(bac)) => {
|
||||
let args = self.tcx.erase_regions(uv.args);
|
||||
let args = self.tcx.erase_and_anonymize_regions(uv.args);
|
||||
let bac = bac.instantiate(self.tcx, args);
|
||||
return bac.fold_with(self);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
|
|||
use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState};
|
||||
use rustc_hir::intravisit::VisitorExt;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate, find_attr};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||
|
|
@ -45,14 +46,14 @@ use rustc_query_system::cache::WithDepNode;
|
|||
use rustc_query_system::dep_graph::DepNodeIndex;
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::CrateType;
|
||||
use rustc_session::cstore::{CrateStoreDyn, Untracked};
|
||||
use rustc_session::lint::Lint;
|
||||
use rustc_session::{Limit, Session};
|
||||
use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId};
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
|
||||
use rustc_type_ir::TyKind::*;
|
||||
use rustc_type_ir::lang_items::{SolverLangItem, SolverTraitLangItem};
|
||||
use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem};
|
||||
pub use rustc_type_ir::lift::Lift;
|
||||
use rustc_type_ir::{
|
||||
CollectAndApply, Interner, TypeFlags, TypeFoldable, WithCachedTypeInfo, elaborate, search_graph,
|
||||
|
|
@ -94,6 +95,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
type DefId = DefId;
|
||||
type LocalDefId = LocalDefId;
|
||||
type TraitId = DefId;
|
||||
type ForeignId = DefId;
|
||||
type FunctionId = DefId;
|
||||
type ClosureId = DefId;
|
||||
type CoroutineClosureId = DefId;
|
||||
type CoroutineId = DefId;
|
||||
type AdtId = DefId;
|
||||
type ImplId = DefId;
|
||||
type Span = Span;
|
||||
|
||||
type GenericArgs = ty::GenericArgsRef<'tcx>;
|
||||
|
|
@ -492,6 +500,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
self.require_lang_item(solver_trait_lang_item_to_lang_item(lang_item), DUMMY_SP)
|
||||
}
|
||||
|
||||
fn require_adt_lang_item(self, lang_item: SolverAdtLangItem) -> DefId {
|
||||
self.require_lang_item(solver_adt_lang_item_to_lang_item(lang_item), DUMMY_SP)
|
||||
}
|
||||
|
||||
fn is_lang_item(self, def_id: DefId, lang_item: SolverLangItem) -> bool {
|
||||
self.is_lang_item(def_id, solver_lang_item_to_lang_item(lang_item))
|
||||
}
|
||||
|
|
@ -500,6 +512,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
self.is_lang_item(def_id, solver_trait_lang_item_to_lang_item(lang_item))
|
||||
}
|
||||
|
||||
fn is_adt_lang_item(self, def_id: DefId, lang_item: SolverAdtLangItem) -> bool {
|
||||
self.is_lang_item(def_id, solver_adt_lang_item_to_lang_item(lang_item))
|
||||
}
|
||||
|
||||
fn is_default_trait(self, def_id: DefId) -> bool {
|
||||
self.is_default_trait(def_id)
|
||||
}
|
||||
|
|
@ -512,6 +528,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
lang_item_to_solver_trait_lang_item(self.lang_items().from_def_id(def_id)?)
|
||||
}
|
||||
|
||||
fn as_adt_lang_item(self, def_id: DefId) -> Option<SolverAdtLangItem> {
|
||||
lang_item_to_solver_adt_lang_item(self.lang_items().from_def_id(def_id)?)
|
||||
}
|
||||
|
||||
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
|
||||
self.associated_items(def_id)
|
||||
.in_definition_order()
|
||||
|
|
@ -783,6 +803,13 @@ bidirectional_lang_item_map! {
|
|||
DynMetadata,
|
||||
FutureOutput,
|
||||
Metadata,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
bidirectional_lang_item_map! {
|
||||
SolverAdtLangItem, lang_item_to_solver_adt_lang_item, solver_adt_lang_item_to_lang_item;
|
||||
|
||||
// tidy-alphabetical-start
|
||||
Option,
|
||||
Poll,
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -6,20 +6,20 @@ use crate::ty::{
|
|||
};
|
||||
|
||||
pub(super) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { erase_regions_ty, ..*providers };
|
||||
*providers = Providers { erase_and_anonymize_regions_ty, ..*providers };
|
||||
}
|
||||
|
||||
fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
fn erase_and_anonymize_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
// N.B., use `super_fold_with` here. If we used `fold_with`, it
|
||||
// could invoke the `erase_regions_ty` query recursively.
|
||||
ty.super_fold_with(&mut RegionEraserVisitor { tcx })
|
||||
// could invoke the `erase_and_anonymize_regions_ty` query recursively.
|
||||
ty.super_fold_with(&mut RegionEraserAndAnonymizerVisitor { tcx })
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Returns an equivalent value with all free regions removed (note
|
||||
/// that late-bound regions remain, because they are important for
|
||||
/// subtyping, but they are anonymized and normalized as well)..
|
||||
pub fn erase_regions<T>(self, value: T) -> T
|
||||
/// Returns an equivalent value with all free regions removed and
|
||||
/// bound regions anonymized. (note that bound regions are important
|
||||
/// for subtyping and generally type equality so *cannot* be removed)
|
||||
pub fn erase_and_anonymize_regions<T>(self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
|
|
@ -27,18 +27,18 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
if !value.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) {
|
||||
return value;
|
||||
}
|
||||
debug!("erase_regions({:?})", value);
|
||||
let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
|
||||
debug!("erase_regions = {:?}", value1);
|
||||
debug!("erase_and_anonymize_regions({:?})", value);
|
||||
let value1 = value.fold_with(&mut RegionEraserAndAnonymizerVisitor { tcx: self });
|
||||
debug!("erase_and_anonymize_regions = {:?}", value1);
|
||||
value1
|
||||
}
|
||||
}
|
||||
|
||||
struct RegionEraserVisitor<'tcx> {
|
||||
struct RegionEraserAndAnonymizerVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> {
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserAndAnonymizerVisitor<'tcx> {
|
||||
fn cx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> {
|
|||
} else if ty.has_infer() {
|
||||
ty.super_fold_with(self)
|
||||
} else {
|
||||
self.tcx.erase_regions_ty(ty)
|
||||
self.tcx.erase_and_anonymize_regions_ty(ty)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use std::path::PathBuf;
|
|||
use rustc_errors::pluralize;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind};
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_macros::extension;
|
||||
pub use rustc_type_ir::error::ExpectedFound;
|
||||
|
||||
|
|
@ -233,7 +234,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
loop {
|
||||
// Look for the longest properly trimmed path that still fits in length_limit.
|
||||
short = with_forced_trimmed_paths!({
|
||||
let mut p = FmtPrinter::new_with_limit(self, ns, rustc_session::Limit(type_limit));
|
||||
let mut p = FmtPrinter::new_with_limit(self, ns, Limit(type_limit));
|
||||
self.lift(t)
|
||||
.expect("could not lift for printing")
|
||||
.print(&mut p)
|
||||
|
|
|
|||
|
|
@ -544,7 +544,9 @@ impl<'tcx> Instance<'tcx> {
|
|||
|
||||
// All regions in the result of this query are erased, so it's
|
||||
// fine to erase all of the input regions.
|
||||
tcx.resolve_instance_raw(tcx.erase_regions(typing_env.as_query_input((def_id, args))))
|
||||
tcx.resolve_instance_raw(
|
||||
tcx.erase_and_anonymize_regions(typing_env.as_query_input((def_id, args))),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn expect_resolve(
|
||||
|
|
|
|||
|
|
@ -401,7 +401,10 @@ impl<'tcx> SizeSkeleton<'tcx> {
|
|||
match tail.kind() {
|
||||
ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => {
|
||||
debug_assert!(tail.has_non_region_param());
|
||||
Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
|
||||
Ok(SizeSkeleton::Pointer {
|
||||
non_zero,
|
||||
tail: tcx.erase_and_anonymize_regions(tail),
|
||||
})
|
||||
}
|
||||
ty::Error(guar) => {
|
||||
// Fixes ICE #124031
|
||||
|
|
|
|||
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