Merge ref 'f4665ab836' from rust-lang/rust

Pull recent changes from https://github.com/rust-lang/rust via Josh.

Upstream ref: f4665ab836
Filtered ref: d2e3c00d12fb613c03777e620c50528112247ad2
Upstream diff: a09fbe2c83...f4665ab836

This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
The Miri Cronjob Bot 2025-09-11 05:01:01 +00:00
commit 3790e37ca2
408 changed files with 5321 additions and 3046 deletions

View file

@ -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]]

View file

@ -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

View file

@ -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();

View file

@ -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 {

View file

@ -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(

View file

@ -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",

View file

@ -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

View file

@ -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) {

View file

@ -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)]

View file

@ -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}

View file

@ -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

View file

@ -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,
})
}
}

View file

@ -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;

View file

@ -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 })
}
}

View file

@ -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(),
}

View file

@ -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,
}

View file

@ -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((

View file

@ -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),

View file

@ -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

View file

@ -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();
}

View file

@ -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,

View file

@ -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);

View file

@ -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 {

View file

@ -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);

View file

@ -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);

View file

@ -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 {

View file

@ -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"

View file

@ -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};

View file

@ -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);

View file

@ -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

View file

@ -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));

View file

@ -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:?}"),
}
}

View file

@ -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

View 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());
}

View file

@ -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()
}

View file

@ -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};

View file

@ -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)]

View file

@ -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,

View file

@ -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);

View file

@ -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));

View file

@ -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"),

View file

@ -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.

View file

@ -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),

View file

@ -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,

View file

@ -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,

View file

@ -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,
..
)
),

View file

@ -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;

View file

@ -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;

View 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)
}
}

View file

@ -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;

View file

@ -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(&region)
&& !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())
}

View file

@ -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))
}

View file

@ -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);

View file

@ -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`)

View file

@ -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,
}

View file

@ -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(

View file

@ -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

View file

@ -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 {

View file

@ -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| {

View file

@ -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()

View file

@ -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)
}
}

View file

@ -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,

View file

@ -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.

View file

@ -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() }
}
}

View file

@ -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]),

View file

@ -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 };

View file

@ -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

View file

@ -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);
}

View file

@ -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
}

View file

@ -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

View file

@ -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)))
}));

View file

@ -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.

View file

@ -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>>),

View file

@ -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;

View file

@ -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

View file

@ -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,
}

View file

@ -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,

View file

@ -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))
}

View file

@ -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())
}

View file

@ -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(

View file

@ -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,
);

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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-")

View file

@ -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

View file

@ -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)]

View file

@ -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;

View file

@ -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;

View file

@ -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.

View file

@ -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) => {

View file

@ -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.

View file

@ -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 {

View file

@ -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))
}
}

View file

@ -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);
}

View file

@ -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

View file

@ -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)
}
}

View file

@ -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)

View file

@ -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(

View file

@ -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