Merge from rustc
This commit is contained in:
commit
f0ea91c60f
517 changed files with 5033 additions and 3792 deletions
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
|
@ -38,6 +38,8 @@ concurrency:
|
|||
cancel-in-progress: true
|
||||
env:
|
||||
TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
|
||||
# This will be empty in PR jobs.
|
||||
TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
|
||||
jobs:
|
||||
# The job matrix for `calculate_matrix` is defined in src/ci/github-actions/jobs.yml.
|
||||
# It calculates which jobs should be executed, based on the data of the ${{ github }} context.
|
||||
|
|
@ -242,6 +244,5 @@ jobs:
|
|||
shell: bash
|
||||
if: needs.calculate_matrix.outputs.run_type == 'auto'
|
||||
env:
|
||||
TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
|
||||
TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
|
||||
TOOLSTATE_PUBLISH: 1
|
||||
|
|
|
|||
148
Cargo.lock
148
Cargo.lock
|
|
@ -372,7 +372,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"regex-automata 0.3.9",
|
||||
"regex-automata 0.3.7",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
|
@ -2206,6 +2206,21 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "line-wrap"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd1bc4d24ad230d21fb898d1116b1801d7adfc449d42026475862ab48b11e70e"
|
||||
|
||||
[[package]]
|
||||
name = "linereader"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d921fea6860357575519aca014c6e22470585accdd543b370c404a8a72d0dd1d"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linkchecker"
|
||||
version = "0.1.0"
|
||||
|
|
@ -2214,6 +2229,12 @@ dependencies = [
|
|||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "lint-docs"
|
||||
version = "0.1.0"
|
||||
|
|
@ -2364,6 +2385,25 @@ dependencies = [
|
|||
"topological-sort",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdbook-i18n-helpers"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1f71f5961d6f3376e1ff3e5989c2e3ecccc3e8a00f3a3acde446847f84852e4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"mdbook",
|
||||
"polib",
|
||||
"pulldown-cmark 0.10.3",
|
||||
"pulldown-cmark-to-cmark",
|
||||
"regex",
|
||||
"semver",
|
||||
"serde_json",
|
||||
"syntect",
|
||||
"textwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdbook-trpl-listing"
|
||||
version = "0.1.0"
|
||||
|
|
@ -2650,6 +2690,28 @@ version = "1.19.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "onig"
|
||||
version = "6.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"onig_sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "onig_sys"
|
||||
version = "69.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opener"
|
||||
version = "0.6.1"
|
||||
|
|
@ -2968,6 +3030,29 @@ version = "0.3.30"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||
|
||||
[[package]]
|
||||
name = "plist"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9d34169e64b3c7a80c8621a48adaf44e0cf62c78a9b25dd9dd35f1881a17cf9"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"indexmap",
|
||||
"line-wrap",
|
||||
"quick-xml",
|
||||
"serde",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polib"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b393b155cf9be86249cba1b56cc81be0e6212c66d94ac0d76d37a1761f3bb1b"
|
||||
dependencies = [
|
||||
"linereader",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polonius-engine"
|
||||
version = "0.13.0"
|
||||
|
|
@ -3126,6 +3211,15 @@ version = "0.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9e1dcb320d6839f6edb64f7a4a59d39b30480d4d1765b56873f7c858538a5fe"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quine-mc_cluskey"
|
||||
version = "0.2.4"
|
||||
|
|
@ -3261,12 +3355,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.8.4"
|
||||
version = "1.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
|
||||
checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.3.7",
|
||||
"regex-syntax 0.7.5",
|
||||
]
|
||||
|
||||
|
|
@ -3290,9 +3385,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.3.9"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9"
|
||||
checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.7.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-lite"
|
||||
|
|
@ -3367,6 +3467,7 @@ dependencies = [
|
|||
"clap",
|
||||
"env_logger",
|
||||
"mdbook",
|
||||
"mdbook-i18n-helpers",
|
||||
"mdbook-trpl-listing",
|
||||
"mdbook-trpl-note",
|
||||
]
|
||||
|
|
@ -5372,6 +5473,28 @@ dependencies = [
|
|||
"syn 2.0.64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syntect"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags 1.3.2",
|
||||
"flate2",
|
||||
"fnv",
|
||||
"once_cell",
|
||||
"onig",
|
||||
"plist",
|
||||
"regex-syntax 0.8.3",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.30.12"
|
||||
|
|
@ -5497,6 +5620,12 @@ dependencies = [
|
|||
"std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
|
||||
|
||||
[[package]]
|
||||
name = "thin-vec"
|
||||
version = "0.2.13"
|
||||
|
|
@ -6476,6 +6605,15 @@ dependencies = [
|
|||
"lzma-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi-term"
|
||||
version = "0.1.2"
|
||||
|
|
|
|||
|
|
@ -2501,6 +2501,8 @@ pub enum IsAuto {
|
|||
pub enum Safety {
|
||||
/// `unsafe` an item is explicitly marked as `unsafe`.
|
||||
Unsafe(Span),
|
||||
/// `safe` an item is explicitly marked as `safe`.
|
||||
Safe(Span),
|
||||
/// Default means no value was provided, it will take a default value given the context in
|
||||
/// which is used.
|
||||
Default,
|
||||
|
|
@ -3162,6 +3164,7 @@ pub struct DelegationMac {
|
|||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct StaticItem {
|
||||
pub ty: P<Ty>,
|
||||
pub safety: Safety,
|
||||
pub mutability: Mutability,
|
||||
pub expr: Option<P<Expr>>,
|
||||
}
|
||||
|
|
@ -3171,6 +3174,7 @@ pub struct StaticItem {
|
|||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct StaticForeignItem {
|
||||
pub ty: P<Ty>,
|
||||
pub safety: Safety,
|
||||
pub mutability: Mutability,
|
||||
pub expr: Option<P<Expr>>,
|
||||
}
|
||||
|
|
@ -3179,6 +3183,7 @@ impl From<StaticItem> for StaticForeignItem {
|
|||
fn from(static_item: StaticItem) -> StaticForeignItem {
|
||||
StaticForeignItem {
|
||||
ty: static_item.ty,
|
||||
safety: static_item.safety,
|
||||
mutability: static_item.mutability,
|
||||
expr: static_item.expr,
|
||||
}
|
||||
|
|
@ -3189,6 +3194,7 @@ impl From<StaticForeignItem> for StaticItem {
|
|||
fn from(static_item: StaticForeignItem) -> StaticItem {
|
||||
StaticItem {
|
||||
ty: static_item.ty,
|
||||
safety: static_item.safety,
|
||||
mutability: static_item.mutability,
|
||||
expr: static_item.expr,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -862,6 +862,7 @@ fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T)
|
|||
fn visit_safety<T: MutVisitor>(safety: &mut Safety, vis: &mut T) {
|
||||
match safety {
|
||||
Safety::Unsafe(span) => vis.visit_span(span),
|
||||
Safety::Safe(span) => vis.visit_span(span),
|
||||
Safety::Default => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -1079,7 +1080,7 @@ impl NoopVisitItemKind for ItemKind {
|
|||
match self {
|
||||
ItemKind::ExternCrate(_orig_name) => {}
|
||||
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
|
||||
ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
|
||||
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
|
||||
vis.visit_ty(ty);
|
||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
}
|
||||
|
|
@ -1289,7 +1290,12 @@ pub fn noop_flat_map_item<K: NoopVisitItemKind>(
|
|||
impl NoopVisitItemKind for ForeignItemKind {
|
||||
fn noop_visit(&mut self, visitor: &mut impl MutVisitor) {
|
||||
match self {
|
||||
ForeignItemKind::Static(box StaticForeignItem { ty, mutability: _, expr }) => {
|
||||
ForeignItemKind::Static(box StaticForeignItem {
|
||||
ty,
|
||||
mutability: _,
|
||||
expr,
|
||||
safety: _,
|
||||
}) => {
|
||||
visitor.visit_ty(ty);
|
||||
visit_opt(expr, |expr| visitor.visit_expr(expr));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,6 +210,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: IdentIsRaw) -> boo
|
|||
kw::Unsafe,
|
||||
kw::While,
|
||||
kw::Yield,
|
||||
kw::Safe,
|
||||
kw::Static,
|
||||
]
|
||||
.contains(&name)
|
||||
|
|
@ -577,6 +578,7 @@ impl Token {
|
|||
kw::Impl,
|
||||
kw::Unsafe,
|
||||
kw::Const,
|
||||
kw::Safe,
|
||||
kw::Static,
|
||||
kw::Union,
|
||||
kw::Macro,
|
||||
|
|
|
|||
|
|
@ -334,7 +334,7 @@ impl WalkItemKind for ItemKind {
|
|||
match self {
|
||||
ItemKind::ExternCrate(_) => {}
|
||||
ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, item.id, false)),
|
||||
ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
|
||||
ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => {
|
||||
try_visit!(visitor.visit_ty(ty));
|
||||
visit_opt!(visitor, visit_expr, expr);
|
||||
}
|
||||
|
|
@ -658,7 +658,12 @@ impl WalkItemKind for ForeignItemKind {
|
|||
) -> V::Result {
|
||||
let &Item { id, span, ident, ref vis, .. } = item;
|
||||
match self {
|
||||
ForeignItemKind::Static(box StaticForeignItem { ty, mutability: _, expr }) => {
|
||||
ForeignItemKind::Static(box StaticForeignItem {
|
||||
ty,
|
||||
mutability: _,
|
||||
expr,
|
||||
safety: _,
|
||||
}) => {
|
||||
try_visit!(visitor.visit_ty(ty));
|
||||
visit_opt!(visitor, visit_expr, expr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs)
|
||||
}
|
||||
ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => {
|
||||
ItemKind::Static(box ast::StaticItem { ty: t, safety: _, mutability: m, expr: e }) => {
|
||||
let (ty, body_id) =
|
||||
self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy);
|
||||
hir::ItemKind::Static(ty, *m, body_id)
|
||||
|
|
@ -388,7 +388,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)),
|
||||
};
|
||||
hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
|
||||
safety: self.lower_safety(*safety),
|
||||
safety: self.lower_safety(*safety, hir::Safety::Safe),
|
||||
polarity,
|
||||
defaultness,
|
||||
defaultness_span,
|
||||
|
|
@ -418,7 +418,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let items = this.arena.alloc_from_iter(
|
||||
items.iter().map(|item| this.lower_trait_item_ref(item)),
|
||||
);
|
||||
let safety = this.lower_safety(*safety);
|
||||
let safety = this.lower_safety(*safety, hir::Safety::Safe);
|
||||
(safety, items, bounds)
|
||||
},
|
||||
);
|
||||
|
|
@ -660,13 +660,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
this.lower_fn_params_to_names(fdec),
|
||||
)
|
||||
});
|
||||
let safety = self.lower_safety(sig.header.safety, hir::Safety::Unsafe);
|
||||
|
||||
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
|
||||
hir::ForeignItemKind::Fn(fn_dec, fn_args, generics, safety)
|
||||
}
|
||||
ForeignItemKind::Static(box StaticForeignItem { ty, mutability, expr: _ }) => {
|
||||
ForeignItemKind::Static(box StaticForeignItem {
|
||||
ty,
|
||||
mutability,
|
||||
expr: _,
|
||||
safety,
|
||||
}) => {
|
||||
let ty = self
|
||||
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
hir::ForeignItemKind::Static(ty, *mutability)
|
||||
let safety = self.lower_safety(*safety, hir::Safety::Unsafe);
|
||||
|
||||
hir::ForeignItemKind::Static(ty, *mutability, safety)
|
||||
}
|
||||
ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
|
||||
ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"),
|
||||
|
|
@ -1360,7 +1368,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::IsAsync::NotAsync
|
||||
};
|
||||
hir::FnHeader {
|
||||
safety: self.lower_safety(h.safety),
|
||||
safety: self.lower_safety(h.safety, hir::Safety::Safe),
|
||||
asyncness: asyncness,
|
||||
constness: self.lower_constness(h.constness),
|
||||
abi: self.lower_extern(h.ext),
|
||||
|
|
@ -1410,10 +1418,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn lower_safety(&mut self, s: Safety) -> hir::Safety {
|
||||
pub(super) fn lower_safety(&mut self, s: Safety, default: hir::Safety) -> hir::Safety {
|
||||
match s {
|
||||
Safety::Unsafe(_) => hir::Safety::Unsafe,
|
||||
Safety::Default => hir::Safety::Safe,
|
||||
Safety::Default => default,
|
||||
Safety::Safe(_) => hir::Safety::Safe,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1321,7 +1321,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
|
||||
hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy {
|
||||
generic_params,
|
||||
safety: self.lower_safety(f.safety),
|
||||
safety: self.lower_safety(f.safety, hir::Safety::Safe),
|
||||
abi: self.lower_extern(f.ext),
|
||||
decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None),
|
||||
param_names: self.lower_fn_params_to_names(&f.decl),
|
||||
|
|
|
|||
|
|
@ -67,6 +67,9 @@ ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have quali
|
|||
.label = in this `extern` block
|
||||
.suggestion = remove this qualifier
|
||||
|
||||
ast_passes_extern_invalid_safety = items in unadorned `extern` blocks cannot have safety qualifiers
|
||||
.suggestion = add unsafe to this `extern` block
|
||||
|
||||
ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
|
||||
.label = in this `extern` block
|
||||
.note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information
|
||||
|
|
@ -174,6 +177,8 @@ ast_passes_match_arm_with_no_body =
|
|||
`match` arm with no body
|
||||
.suggestion = add a body after the pattern
|
||||
|
||||
ast_passes_missing_unsafe_on_extern = extern blocks must be unsafe
|
||||
|
||||
ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
|
||||
.help = consider using the `#[path]` attribute to specify filesystem path
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ use rustc_data_structures::fx::FxIndexMap;
|
|||
use rustc_feature::Features;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::lint::builtin::{
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
|
||||
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
};
|
||||
use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
|
||||
use rustc_session::Session;
|
||||
|
|
@ -86,6 +87,9 @@ struct AstValidator<'a> {
|
|||
/// or `Foo::Bar<impl Trait>`
|
||||
is_impl_trait_banned: bool,
|
||||
|
||||
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
|
||||
extern_mod_safety: Option<Safety>,
|
||||
|
||||
lint_buffer: &'a mut LintBuffer,
|
||||
}
|
||||
|
||||
|
|
@ -116,6 +120,12 @@ impl<'a> AstValidator<'a> {
|
|||
self.outer_trait_or_trait_impl = old;
|
||||
}
|
||||
|
||||
fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
|
||||
f(self);
|
||||
self.extern_mod_safety = old;
|
||||
}
|
||||
|
||||
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.is_impl_trait_banned, true);
|
||||
f(self);
|
||||
|
|
@ -429,6 +439,18 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_foreign_item_safety(&self, item_span: Span, safety: Safety) {
|
||||
if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_))
|
||||
&& (self.extern_mod_safety == Some(Safety::Default)
|
||||
|| !self.features.unsafe_extern_blocks)
|
||||
{
|
||||
self.dcx().emit_err(errors::InvalidSafetyOnExtern {
|
||||
item_span,
|
||||
block: self.current_extern_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
|
||||
if let Defaultness::Default(def_span) = defaultness {
|
||||
let span = self.session.source_map().guess_head_span(span);
|
||||
|
|
@ -518,7 +540,7 @@ impl<'a> AstValidator<'a> {
|
|||
fn check_foreign_fn_headerless(
|
||||
&self,
|
||||
// Deconstruct to ensure exhaustiveness
|
||||
FnHeader { safety, coroutine_kind, constness, ext }: FnHeader,
|
||||
FnHeader { safety: _, coroutine_kind, constness, ext }: FnHeader,
|
||||
) {
|
||||
let report_err = |span| {
|
||||
self.dcx().emit_err(errors::FnQualifierInExtern {
|
||||
|
|
@ -526,10 +548,6 @@ impl<'a> AstValidator<'a> {
|
|||
block: self.current_extern_span(),
|
||||
});
|
||||
};
|
||||
match safety {
|
||||
Safety::Unsafe(span) => report_err(span),
|
||||
Safety::Default => (),
|
||||
}
|
||||
match coroutine_kind {
|
||||
Some(knd) => report_err(knd.span()),
|
||||
None => (),
|
||||
|
|
@ -1017,19 +1035,39 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
return; // Avoid visiting again.
|
||||
}
|
||||
ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => {
|
||||
let old_item = mem::replace(&mut self.extern_mod, Some(item));
|
||||
self.visibility_not_permitted(
|
||||
&item.vis,
|
||||
errors::VisibilityNotPermittedNote::IndividualForeignItems,
|
||||
);
|
||||
if let &Safety::Unsafe(span) = safety {
|
||||
self.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" });
|
||||
}
|
||||
if abi.is_none() {
|
||||
self.maybe_lint_missing_abi(item.span, item.id);
|
||||
}
|
||||
visit::walk_item(self, item);
|
||||
self.extern_mod = old_item;
|
||||
self.with_in_extern_mod(*safety, |this| {
|
||||
let old_item = mem::replace(&mut this.extern_mod, Some(item));
|
||||
this.visibility_not_permitted(
|
||||
&item.vis,
|
||||
errors::VisibilityNotPermittedNote::IndividualForeignItems,
|
||||
);
|
||||
|
||||
if this.features.unsafe_extern_blocks {
|
||||
if &Safety::Default == safety {
|
||||
if item.span.at_least_rust_2024() {
|
||||
this.dcx()
|
||||
.emit_err(errors::MissingUnsafeOnExtern { span: item.span });
|
||||
} else {
|
||||
this.lint_buffer.buffer_lint(
|
||||
MISSING_UNSAFE_ON_EXTERN,
|
||||
item.id,
|
||||
item.span,
|
||||
BuiltinLintDiag::MissingUnsafeOnExtern {
|
||||
suggestion: item.span.shrink_to_lo(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if let &Safety::Unsafe(span) = safety {
|
||||
this.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" });
|
||||
}
|
||||
|
||||
if abi.is_none() {
|
||||
this.maybe_lint_missing_abi(item.span, item.id);
|
||||
}
|
||||
visit::walk_item(this, item);
|
||||
this.extern_mod = old_item;
|
||||
});
|
||||
return; // Avoid visiting again.
|
||||
}
|
||||
ItemKind::Enum(def, _) => {
|
||||
|
|
@ -1161,6 +1199,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||
match &fi.kind {
|
||||
ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
|
||||
self.check_foreign_item_safety(fi.span, sig.header.safety);
|
||||
self.check_defaultness(fi.span, *defaultness);
|
||||
self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
|
||||
self.check_foreign_fn_headerless(sig.header);
|
||||
|
|
@ -1180,7 +1219,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_foreign_ty_genericless(generics, where_clauses);
|
||||
self.check_foreign_item_ascii_only(fi.ident);
|
||||
}
|
||||
ForeignItemKind::Static(box StaticForeignItem { ty: _, mutability: _, expr }) => {
|
||||
ForeignItemKind::Static(box StaticForeignItem { expr, safety, .. }) => {
|
||||
self.check_foreign_item_safety(fi.span, *safety);
|
||||
self.check_foreign_kind_bodyless(fi.ident, "static", expr.as_ref().map(|b| b.span));
|
||||
self.check_foreign_item_ascii_only(fi.ident);
|
||||
}
|
||||
|
|
@ -1736,6 +1776,7 @@ pub fn check_crate(
|
|||
outer_impl_trait: None,
|
||||
disallow_tilde_const: Some(DisallowTildeConstContext::Item),
|
||||
is_impl_trait_banned: false,
|
||||
extern_mod_safety: None,
|
||||
lint_buffer: lints,
|
||||
};
|
||||
visit::walk_crate(&mut validator, krate);
|
||||
|
|
|
|||
|
|
@ -216,6 +216,15 @@ pub enum ExternBlockSuggestion {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_extern_invalid_safety)]
|
||||
pub struct InvalidSafetyOnExtern {
|
||||
#[primary_span]
|
||||
pub item_span: Span,
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||
pub block: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_bound_in_context)]
|
||||
pub struct BoundInContext<'a> {
|
||||
|
|
@ -485,6 +494,13 @@ pub struct UnsafeItem {
|
|||
pub kind: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_missing_unsafe_on_extern)]
|
||||
pub struct MissingUnsafeOnExtern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_fieldless_union)]
|
||||
pub struct FieldlessUnion {
|
||||
|
|
|
|||
|
|
@ -1973,6 +1973,7 @@ impl<'a> State<'a> {
|
|||
fn print_safety(&mut self, s: ast::Safety) {
|
||||
match s {
|
||||
ast::Safety::Default => {}
|
||||
ast::Safety::Safe(_) => self.word_nbsp("safe"),
|
||||
ast::Safety::Unsafe(_) => self.word_nbsp("unsafe"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,13 @@ impl<'a> State<'a> {
|
|||
ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
|
||||
self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
|
||||
}
|
||||
ast::ForeignItemKind::Static(box ast::StaticForeignItem { ty, mutability, expr }) => {
|
||||
ast::ForeignItemKind::Static(box ast::StaticForeignItem {
|
||||
ty,
|
||||
mutability,
|
||||
expr,
|
||||
safety,
|
||||
}) => {
|
||||
self.print_safety(*safety);
|
||||
self.print_item_const(
|
||||
ident,
|
||||
Some(*mutability),
|
||||
|
|
@ -165,7 +171,8 @@ impl<'a> State<'a> {
|
|||
self.print_use_tree(tree);
|
||||
self.word(";");
|
||||
}
|
||||
ast::ItemKind::Static(box StaticItem { ty, mutability: mutbl, expr: body }) => {
|
||||
ast::ItemKind::Static(box StaticItem { ty, safety, mutability: mutbl, expr: body }) => {
|
||||
self.print_safety(*safety);
|
||||
self.print_item_const(
|
||||
item.ident,
|
||||
Some(*mutbl),
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
} else {
|
||||
let tcx = self.tcx();
|
||||
let maybe_uneval = match constant.const_ {
|
||||
Const::Ty(ct) => match ct.kind() {
|
||||
Const::Ty(_, ct) => match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(_) => {
|
||||
bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct)
|
||||
}
|
||||
|
|
@ -1856,7 +1856,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
|
||||
if let Operand::Constant(constant) = op {
|
||||
let maybe_uneval = match constant.const_ {
|
||||
Const::Val(..) | Const::Ty(_) => None,
|
||||
Const::Val(..) | Const::Ty(_, _) => None,
|
||||
Const::Unevaluated(uv, _) => Some(uv),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
types: &mut |_bound_ty: ty::BoundTy| {
|
||||
unreachable!("we only replace regions in nll_relate, not types")
|
||||
},
|
||||
consts: &mut |_bound_var: ty::BoundVar, _ty| {
|
||||
consts: &mut |_bound_var: ty::BoundVar| {
|
||||
unreachable!("we only replace regions in nll_relate, not consts")
|
||||
},
|
||||
};
|
||||
|
|
@ -231,7 +231,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
types: &mut |_bound_ty: ty::BoundTy| {
|
||||
unreachable!("we only replace regions in nll_relate, not types")
|
||||
},
|
||||
consts: &mut |_bound_var: ty::BoundVar, _ty| {
|
||||
consts: &mut |_bound_var: ty::BoundVar| {
|
||||
unreachable!("we only replace regions in nll_relate, not consts")
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ impl<'cx, 'a> Context<'cx, 'a> {
|
|||
/// Builds the whole `assert!` expression. For example, `let elem = 1; assert!(elem == 1);` expands to:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(generic_assert_internals)]
|
||||
/// let elem = 1;
|
||||
/// {
|
||||
/// #[allow(unused_imports)]
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ impl CfgEval<'_, '_> {
|
|||
// Re-parse the tokens, setting the `capture_cfg` flag to save extra information
|
||||
// to the captured `AttrTokenStream` (specifically, we capture
|
||||
// `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`)
|
||||
let mut parser = rustc_parse::stream_to_parser(&self.cfg.sess.psess, orig_tokens, None);
|
||||
let mut parser = Parser::new(&self.cfg.sess.psess, orig_tokens, None);
|
||||
parser.capture_cfg = true;
|
||||
match parse_annotatable_with(&mut parser) {
|
||||
Ok(a) => annotatable = a,
|
||||
|
|
|
|||
|
|
@ -4,16 +4,17 @@ use crate::errors;
|
|||
use rustc_ast::attr::mk_attr;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::{self as ast, AttrItem, AttrStyle};
|
||||
use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::FileName;
|
||||
|
||||
pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
|
||||
for raw_attr in attrs {
|
||||
let mut parser = rustc_parse::new_parser_from_source_str(
|
||||
let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str(
|
||||
psess,
|
||||
FileName::cli_crate_attr_source_code(raw_attr),
|
||||
raw_attr.clone(),
|
||||
);
|
||||
));
|
||||
|
||||
let start_span = parser.token.span;
|
||||
let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) {
|
||||
|
|
|
|||
|
|
@ -412,6 +412,15 @@ fn find_type_parameters(
|
|||
|
||||
impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> {
|
||||
fn visit_ty(&mut self, ty: &'a ast::Ty) {
|
||||
let stack_len = self.bound_generic_params_stack.len();
|
||||
if let ast::TyKind::BareFn(bare_fn) = &ty.kind
|
||||
&& !bare_fn.generic_params.is_empty()
|
||||
{
|
||||
// Given a field `x: for<'a> fn(T::SomeType<'a>)`, we wan't to account for `'a` so
|
||||
// that we generate `where for<'a> T::SomeType<'a>: ::core::clone::Clone`. #122622
|
||||
self.bound_generic_params_stack.extend(bare_fn.generic_params.iter().cloned());
|
||||
}
|
||||
|
||||
if let ast::TyKind::Path(_, path) = &ty.kind
|
||||
&& let Some(segment) = path.segments.first()
|
||||
&& self.ty_param_names.contains(&segment.ident.name)
|
||||
|
|
@ -422,7 +431,8 @@ fn find_type_parameters(
|
|||
});
|
||||
}
|
||||
|
||||
visit::walk_ty(self, ty)
|
||||
visit::walk_ty(self, ty);
|
||||
self.bound_generic_params_stack.truncate(stack_len);
|
||||
}
|
||||
|
||||
// Place bound generic params on a stack, to extract them when a type is encountered.
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ use rustc_expand::base::{
|
|||
};
|
||||
use rustc_expand::module::DirOwnership;
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_parse::new_parser_from_file;
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal};
|
||||
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::Symbol;
|
||||
|
|
@ -126,7 +126,7 @@ pub(crate) fn expand_include<'cx>(
|
|||
return ExpandResult::Ready(DummyResult::any(sp, guar));
|
||||
}
|
||||
};
|
||||
let p = new_parser_from_file(cx.psess(), &file, Some(sp));
|
||||
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`.
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
.expect_const()
|
||||
.eval(fx.tcx, ty::ParamEnv::reveal_all(), span)
|
||||
.unwrap()
|
||||
.1
|
||||
.unwrap_branch();
|
||||
|
||||
assert_eq!(x.layout(), y.layout());
|
||||
|
|
|
|||
|
|
@ -128,11 +128,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
|
|||
is_direct_dependency: bool,
|
||||
) -> PathBuf {
|
||||
let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
|
||||
let output_path = {
|
||||
let mut output_path: PathBuf = tmpdir.to_path_buf();
|
||||
output_path.push(format!("{lib_name}{name_suffix}"));
|
||||
output_path.with_extension("lib")
|
||||
};
|
||||
let output_path = tmpdir.join(format!("{lib_name}{name_suffix}.lib"));
|
||||
|
||||
let target = &sess.target;
|
||||
let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target);
|
||||
|
|
@ -157,8 +153,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
|
|||
// that loaded but crashed with an AV upon calling one of the imported
|
||||
// functions. Therefore, use binutils to create the import library instead,
|
||||
// by writing a .DEF file to the temp dir and calling binutils's dlltool.
|
||||
let def_file_path =
|
||||
tmpdir.join(format!("{lib_name}{name_suffix}")).with_extension("def");
|
||||
let def_file_path = tmpdir.join(format!("{lib_name}{name_suffix}.def"));
|
||||
|
||||
let def_file_content = format!(
|
||||
"EXPORTS\n{}",
|
||||
|
|
|
|||
|
|
@ -1201,6 +1201,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
.expect_const()
|
||||
.eval(tcx, ty::ParamEnv::reveal_all(), span)
|
||||
.unwrap()
|
||||
.1
|
||||
.unwrap_branch();
|
||||
let n = idx.len() as u64;
|
||||
|
||||
|
|
|
|||
|
|
@ -85,6 +85,11 @@ fn get_rpath_relative_to_output(config: &RPathConfig<'_>, lib: &Path) -> OsStrin
|
|||
// Strip filenames
|
||||
let lib = lib.parent().unwrap();
|
||||
let output = config.out_filename.parent().unwrap();
|
||||
|
||||
// If output or lib is empty, just assume it locates in current path
|
||||
let lib = if lib == Path::new("") { Path::new(".") } else { lib };
|
||||
let output = if output == Path::new("") { Path::new(".") } else { output };
|
||||
|
||||
let lib = try_canonicalize(lib).unwrap();
|
||||
let output = try_canonicalize(output).unwrap();
|
||||
let relative = path_relative_from(&lib, &output)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,22 @@ fn test_rpath_relative() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rpath_relative_issue_119571() {
|
||||
let config = &mut RPathConfig {
|
||||
libs: &[],
|
||||
out_filename: PathBuf::from("rustc"),
|
||||
has_rpath: true,
|
||||
is_like_osx: false,
|
||||
linker_is_gnu: true,
|
||||
};
|
||||
// Should not panic when out_filename only contains filename.
|
||||
// Issue 119571
|
||||
let _ = get_rpath_relative_to_output(config, Path::new("lib/libstd.so"));
|
||||
// Should not panic when lib only contains filename.
|
||||
let _ = get_rpath_relative_to_output(config, Path::new("libstd.so"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_xlinker() {
|
||||
let args = rpaths_to_flags(vec!["a/normal/path".into(), "a,comma,path".into()]);
|
||||
|
|
|
|||
|
|
@ -400,7 +400,7 @@ fn upstream_monomorphizations_provider(
|
|||
tcx: TyCtxt<'_>,
|
||||
(): (),
|
||||
) -> DefIdMap<UnordMap<GenericArgsRef<'_>, CrateNum>> {
|
||||
let cnums = tcx.used_crates(());
|
||||
let cnums = tcx.crates(());
|
||||
|
||||
let mut instances: DefIdMap<UnordMap<_, _>> = Default::default();
|
||||
|
||||
|
|
|
|||
|
|
@ -541,7 +541,7 @@ pub fn collect_debugger_visualizers_transitive(
|
|||
tcx.debugger_visualizers(LOCAL_CRATE)
|
||||
.iter()
|
||||
.chain(
|
||||
tcx.used_crates(())
|
||||
tcx.crates(())
|
||||
.iter()
|
||||
.filter(|&cnum| {
|
||||
let used_crate_source = tcx.used_crate_source(*cnum);
|
||||
|
|
@ -851,7 +851,7 @@ impl CrateInfo {
|
|||
// `compiler_builtins` are always placed last to ensure that they're linked correctly.
|
||||
used_crates.extend(compiler_builtins);
|
||||
|
||||
let crates = tcx.used_crates(());
|
||||
let crates = tcx.crates(());
|
||||
let n_crates = crates.len();
|
||||
let mut info = CrateInfo {
|
||||
target_cpu,
|
||||
|
|
|
|||
|
|
@ -324,21 +324,22 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
|
||||
if tcx.is_foreign_item(did) {
|
||||
codegen_fn_attrs.import_linkage = linkage;
|
||||
|
||||
if tcx.is_mutable_static(did.into()) {
|
||||
let mut diag = tcx.dcx().struct_span_err(
|
||||
attr.span,
|
||||
"extern mutable statics are not allowed with `#[linkage]`",
|
||||
);
|
||||
diag.note(
|
||||
"marking the extern static mutable would allow changing which symbol \
|
||||
the static references rather than make the target of the symbol \
|
||||
mutable",
|
||||
);
|
||||
diag.emit();
|
||||
}
|
||||
} else {
|
||||
codegen_fn_attrs.linkage = linkage;
|
||||
}
|
||||
if tcx.is_mutable_static(did.into()) {
|
||||
let mut diag = tcx.dcx().struct_span_err(
|
||||
attr.span,
|
||||
"mutable statics are not allowed with `#[linkage]`",
|
||||
);
|
||||
diag.note(
|
||||
"making the static mutable would allow changing which symbol the \
|
||||
static references rather than make the target of the symbol \
|
||||
mutable",
|
||||
);
|
||||
diag.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
sym::link_section => {
|
||||
|
|
|
|||
|
|
@ -693,41 +693,46 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
|
|||
ty::ConstKind::Param(param) => {
|
||||
write!(output, "{}", param.name)
|
||||
}
|
||||
_ => match ct.ty().kind() {
|
||||
ty::Int(ity) => {
|
||||
let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
|
||||
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
|
||||
write!(output, "{val}")
|
||||
}
|
||||
ty::Uint(_) => {
|
||||
let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
|
||||
write!(output, "{val}")
|
||||
}
|
||||
ty::Bool => {
|
||||
let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap();
|
||||
write!(output, "{val}")
|
||||
}
|
||||
_ => {
|
||||
// If we cannot evaluate the constant to a known type, we fall back
|
||||
// to emitting a stable hash value of the constant. This isn't very pretty
|
||||
// but we get a deterministic, virtually unique value for the constant.
|
||||
//
|
||||
// Let's only emit 64 bits of the hash value. That should be plenty for
|
||||
// avoiding collisions and will make the emitted type names shorter.
|
||||
let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
|
||||
let mut hasher = StableHasher::new();
|
||||
let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP).unwrap();
|
||||
hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher));
|
||||
hasher.finish::<Hash64>()
|
||||
});
|
||||
ty::ConstKind::Value(ty, _) => {
|
||||
match ty.kind() {
|
||||
ty::Int(ity) => {
|
||||
// FIXME: directly extract the bits from a valtree instead of evaluating an
|
||||
// alreay evaluated `Const` in order to get the bits.
|
||||
let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
|
||||
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
|
||||
write!(output, "{val}")
|
||||
}
|
||||
ty::Uint(_) => {
|
||||
let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
|
||||
write!(output, "{val}")
|
||||
}
|
||||
ty::Bool => {
|
||||
let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap();
|
||||
write!(output, "{val}")
|
||||
}
|
||||
_ => {
|
||||
// If we cannot evaluate the constant to a known type, we fall back
|
||||
// to emitting a stable hash value of the constant. This isn't very pretty
|
||||
// but we get a deterministic, virtually unique value for the constant.
|
||||
//
|
||||
// Let's only emit 64 bits of the hash value. That should be plenty for
|
||||
// avoiding collisions and will make the emitted type names shorter.
|
||||
let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
|
||||
let mut hasher = StableHasher::new();
|
||||
let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP).unwrap();
|
||||
hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher));
|
||||
hasher.finish::<Hash64>()
|
||||
});
|
||||
|
||||
if cpp_like_debuginfo(tcx) {
|
||||
write!(output, "CONST${hash_short:x}")
|
||||
} else {
|
||||
write!(output, "{{CONST#{hash_short:x}}}")
|
||||
if cpp_like_debuginfo(tcx) {
|
||||
write!(output, "CONST${hash_short:x}")
|
||||
} else {
|
||||
write!(output, "{{CONST#{hash_short:x}}}")
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => bug!("Invalid `Const` during codegen: {:?}", ct),
|
||||
}
|
||||
.unwrap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,10 +40,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
) -> Result<Option<ty::ValTree<'tcx>>, ErrorHandled> {
|
||||
let uv = match self.monomorphize(constant.const_) {
|
||||
mir::Const::Unevaluated(uv, _) => uv.shrink(),
|
||||
mir::Const::Ty(c) => match c.kind() {
|
||||
mir::Const::Ty(_, c) => match c.kind() {
|
||||
// A constant that came from a const generic but was then used as an argument to old-style
|
||||
// simd_shuffle (passing as argument instead of as a generic param).
|
||||
rustc_type_ir::ConstKind::Value(valtree) => return Ok(Some(valtree)),
|
||||
rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Some(valtree)),
|
||||
other => span_bug!(constant.span, "{other:#?}"),
|
||||
},
|
||||
// We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate
|
||||
|
|
|
|||
|
|
@ -357,15 +357,15 @@ where
|
|||
|
||||
// Check the qualifs of the value of `const` items.
|
||||
let uneval = match constant.const_ {
|
||||
Const::Ty(ct)
|
||||
Const::Ty(_, ct)
|
||||
if matches!(
|
||||
ct.kind(),
|
||||
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_)
|
||||
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_, _)
|
||||
) =>
|
||||
{
|
||||
None
|
||||
}
|
||||
Const::Ty(c) => {
|
||||
Const::Ty(_, c) => {
|
||||
bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c)
|
||||
}
|
||||
Const::Unevaluated(uv, _) => Some(uv),
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ fn intern_as_new_static<'tcx>(
|
|||
let feed = tcx.create_def(
|
||||
static_id,
|
||||
sym::nested,
|
||||
DefKind::Static { mutability: alloc.0.mutability, nested: true },
|
||||
DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true },
|
||||
);
|
||||
tcx.set_nested_alloc_id_static(alloc_id, feed.def_id());
|
||||
|
||||
|
|
|
|||
|
|
@ -294,17 +294,30 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
|
||||
/// Unwrap types that are guaranteed a null-pointer-optimization
|
||||
fn unfold_npo(&self, layout: TyAndLayout<'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
|
||||
// Check if this is `Option` wrapping some type.
|
||||
let inner = match layout.ty.kind() {
|
||||
ty::Adt(def, args) if self.tcx.is_diagnostic_item(sym::Option, def.did()) => {
|
||||
args[0].as_type().unwrap()
|
||||
}
|
||||
_ => {
|
||||
// Not an `Option`.
|
||||
return Ok(layout);
|
||||
}
|
||||
// Check if this is `Option` wrapping some type or if this is `Result` wrapping a 1-ZST and
|
||||
// another type.
|
||||
let ty::Adt(def, args) = layout.ty.kind() else {
|
||||
// Not an ADT, so definitely no NPO.
|
||||
return Ok(layout);
|
||||
};
|
||||
let inner = self.layout_of(inner)?;
|
||||
let inner = if self.tcx.is_diagnostic_item(sym::Option, def.did()) {
|
||||
// The wrapped type is the only arg.
|
||||
self.layout_of(args[0].as_type().unwrap())?
|
||||
} else if self.tcx.is_diagnostic_item(sym::Result, def.did()) {
|
||||
// We want to extract which (if any) of the args is not a 1-ZST.
|
||||
let lhs = self.layout_of(args[0].as_type().unwrap())?;
|
||||
let rhs = self.layout_of(args[1].as_type().unwrap())?;
|
||||
if lhs.is_1zst() {
|
||||
rhs
|
||||
} else if rhs.is_1zst() {
|
||||
lhs
|
||||
} else {
|
||||
return Ok(layout); // no NPO
|
||||
}
|
||||
} else {
|
||||
return Ok(layout); // no NPO
|
||||
};
|
||||
|
||||
// Check if the inner type is one of the NPO-guaranteed ones.
|
||||
// For that we first unpeel transparent *structs* (but not unions).
|
||||
let is_npo = |def: AdtDef<'tcx>| {
|
||||
|
|
|
|||
|
|
@ -711,7 +711,9 @@ fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId)
|
|||
// We're not using `try_global_alloc` since dangling pointers have already been handled.
|
||||
match ecx.tcx.global_alloc(alloc_id) {
|
||||
GlobalAlloc::Static(did) => {
|
||||
let DefKind::Static { mutability, nested } = ecx.tcx.def_kind(did) else { bug!() };
|
||||
let DefKind::Static { safety: _, mutability, nested } = ecx.tcx.def_kind(did) else {
|
||||
bug!()
|
||||
};
|
||||
if nested {
|
||||
assert!(
|
||||
ecx.memory.alloc_map.get(alloc_id).is_none(),
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ use rustc_interface::{interface, Queries};
|
|||
use rustc_lint::unerased_lint_store;
|
||||
use rustc_metadata::creader::MetadataLoader;
|
||||
use rustc_metadata::locator;
|
||||
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
|
||||
use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
|
||||
use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType};
|
||||
use rustc_session::getopts::{self, Matches};
|
||||
|
|
@ -1264,12 +1265,13 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
|
|||
}
|
||||
|
||||
fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> {
|
||||
match &sess.io.input {
|
||||
Input::File(ifile) => rustc_parse::parse_crate_attrs_from_file(ifile, &sess.psess),
|
||||
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 } => {
|
||||
rustc_parse::parse_crate_attrs_from_source_str(name.clone(), input.clone(), &sess.psess)
|
||||
new_parser_from_source_str(&sess.psess, name.clone(), input.clone())
|
||||
}
|
||||
}
|
||||
});
|
||||
parser.parse_inner_attributes()
|
||||
}
|
||||
|
||||
/// Runs a closure and catches unwinds triggered by fatal errors.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,40 @@ fn bar<F, G>(t: F, u: G)
|
|||
fn main() { }
|
||||
```
|
||||
|
||||
This error also includes the use of associated types with lifetime parameters.
|
||||
```compile_fail,E0582
|
||||
trait Foo {
|
||||
type Assoc<'a>;
|
||||
}
|
||||
|
||||
struct Bar<X, F>
|
||||
where
|
||||
X: Foo,
|
||||
F: for<'a> Fn(X::Assoc<'a>) -> &'a i32
|
||||
{
|
||||
x: X,
|
||||
f: F
|
||||
}
|
||||
```
|
||||
The latter scenario encounters this error because `Foo::Assoc<'a>` could be
|
||||
implemented by a type that does not use the `'a` parameter, so there is no
|
||||
guarentee that `X::Assoc<'a>` actually uses `'a`.
|
||||
|
||||
To fix this we can pass a dummy parameter:
|
||||
```
|
||||
# trait Foo {
|
||||
# type Assoc<'a>;
|
||||
# }
|
||||
struct Bar<X, F>
|
||||
where
|
||||
X: Foo,
|
||||
F: for<'a> Fn(X::Assoc<'a>, /* dummy */ &'a ()) -> &'a i32
|
||||
{
|
||||
x: X,
|
||||
f: F
|
||||
}
|
||||
```
|
||||
|
||||
Note: The examples above used to be (erroneously) accepted by the
|
||||
compiler, but this was since corrected. See [issue #33685] for more
|
||||
details.
|
||||
|
|
|
|||
|
|
@ -124,6 +124,9 @@ expand_not_a_meta_item =
|
|||
expand_only_one_word =
|
||||
must only be one word
|
||||
|
||||
expand_proc_macro_back_compat = using an old version of `{$crate_name}`
|
||||
.note = older versions of the `{$crate_name}` crate no longer compile; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives
|
||||
|
||||
expand_proc_macro_derive_panicked =
|
||||
proc-macro derive panicked
|
||||
.help = message: {$message}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,8 @@ use rustc_data_structures::fx::FxIndexMap;
|
|||
use rustc_data_structures::sync::{self, Lrc};
|
||||
use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult};
|
||||
use rustc_feature::Features;
|
||||
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
|
||||
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, RegisteredTools};
|
||||
use rustc_parse::{parser, MACRO_ARGUMENTS};
|
||||
use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools};
|
||||
use rustc_parse::{parser::Parser, MACRO_ARGUMENTS};
|
||||
use rustc_session::config::CollapseMacroDebuginfo;
|
||||
use rustc_session::{parse::ParseSess, Limit, Session};
|
||||
use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
|
||||
|
|
@ -1150,8 +1149,8 @@ impl<'a> ExtCtxt<'a> {
|
|||
pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
|
||||
expand::MacroExpander::new(self, true)
|
||||
}
|
||||
pub fn new_parser_from_tts(&self, stream: TokenStream) -> parser::Parser<'a> {
|
||||
rustc_parse::stream_to_parser(&self.sess.psess, stream, MACRO_ARGUMENTS)
|
||||
pub fn new_parser_from_tts(&self, stream: TokenStream) -> Parser<'a> {
|
||||
Parser::new(&self.sess.psess, stream, MACRO_ARGUMENTS)
|
||||
}
|
||||
pub fn source_map(&self) -> &'a SourceMap {
|
||||
self.sess.psess.source_map()
|
||||
|
|
@ -1330,80 +1329,63 @@ pub fn parse_macro_name_and_helper_attrs(
|
|||
Some((trait_ident.name, proc_attrs))
|
||||
}
|
||||
|
||||
/// This nonterminal looks like some specific enums from
|
||||
/// `proc-macro-hack` and `procedural-masquerade` crates.
|
||||
/// We need to maintain some special pretty-printing behavior for them due to incorrect
|
||||
/// asserts in old versions of those crates and their wide use in the ecosystem.
|
||||
/// See issue #73345 for more details.
|
||||
/// If this item looks like a specific enums from `rental`, emit a fatal error.
|
||||
/// See #73345 and #83125 for more details.
|
||||
/// FIXME(#73933): Remove this eventually.
|
||||
fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) -> bool {
|
||||
fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) {
|
||||
let name = item.ident.name;
|
||||
if name == sym::ProceduralMasqueradeDummyType {
|
||||
if let ast::ItemKind::Enum(enum_def, _) = &item.kind {
|
||||
if let [variant] = &*enum_def.variants {
|
||||
if variant.ident.name == sym::Input {
|
||||
let filename = sess.source_map().span_to_filename(item.ident.span);
|
||||
if let FileName::Real(real) = filename {
|
||||
if let Some(c) = real
|
||||
.local_path()
|
||||
.unwrap_or(Path::new(""))
|
||||
.components()
|
||||
.flat_map(|c| c.as_os_str().to_str())
|
||||
.find(|c| c.starts_with("rental") || c.starts_with("allsorts-rental"))
|
||||
{
|
||||
let crate_matches = if c.starts_with("allsorts-rental") {
|
||||
true
|
||||
} else {
|
||||
let mut version = c.trim_start_matches("rental-").split('.');
|
||||
version.next() == Some("0")
|
||||
&& version.next() == Some("5")
|
||||
&& version
|
||||
.next()
|
||||
.and_then(|c| c.parse::<u32>().ok())
|
||||
.is_some_and(|v| v < 6)
|
||||
};
|
||||
if name == sym::ProceduralMasqueradeDummyType
|
||||
&& let ast::ItemKind::Enum(enum_def, _) = &item.kind
|
||||
&& let [variant] = &*enum_def.variants
|
||||
&& variant.ident.name == sym::Input
|
||||
&& let FileName::Real(real) = sess.source_map().span_to_filename(item.ident.span)
|
||||
&& let Some(c) = real
|
||||
.local_path()
|
||||
.unwrap_or(Path::new(""))
|
||||
.components()
|
||||
.flat_map(|c| c.as_os_str().to_str())
|
||||
.find(|c| c.starts_with("rental") || c.starts_with("allsorts-rental"))
|
||||
{
|
||||
let crate_matches = if c.starts_with("allsorts-rental") {
|
||||
true
|
||||
} else {
|
||||
let mut version = c.trim_start_matches("rental-").split('.');
|
||||
version.next() == Some("0")
|
||||
&& version.next() == Some("5")
|
||||
&& version.next().and_then(|c| c.parse::<u32>().ok()).is_some_and(|v| v < 6)
|
||||
};
|
||||
|
||||
if crate_matches {
|
||||
sess.psess.buffer_lint(
|
||||
PROC_MACRO_BACK_COMPAT,
|
||||
item.ident.span,
|
||||
ast::CRATE_NODE_ID,
|
||||
BuiltinLintDiag::ProcMacroBackCompat {
|
||||
crate_name: "rental".to_string(),
|
||||
fixed_version: "0.5.6".to_string(),
|
||||
},
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if crate_matches {
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
sess.psess.dcx.emit_fatal(errors::ProcMacroBackCompat {
|
||||
crate_name: "rental".to_string(),
|
||||
fixed_version: "0.5.6".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &Session) -> bool {
|
||||
pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &Session) {
|
||||
let item = match ann {
|
||||
Annotatable::Item(item) => item,
|
||||
Annotatable::Stmt(stmt) => match &stmt.kind {
|
||||
ast::StmtKind::Item(item) => item,
|
||||
_ => return false,
|
||||
_ => return,
|
||||
},
|
||||
_ => return false,
|
||||
_ => return,
|
||||
};
|
||||
pretty_printing_compatibility_hack(item, sess)
|
||||
}
|
||||
|
||||
pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &Session) -> bool {
|
||||
pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &Session) {
|
||||
let item = match nt {
|
||||
Nonterminal::NtItem(item) => item,
|
||||
Nonterminal::NtStmt(stmt) => match &stmt.kind {
|
||||
ast::StmtKind::Item(item) => item,
|
||||
_ => return false,
|
||||
_ => return,
|
||||
},
|
||||
_ => return false,
|
||||
_ => return,
|
||||
};
|
||||
pretty_printing_compatibility_hack(item, sess)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -631,7 +631,10 @@ impl<'a> ExtCtxt<'a> {
|
|||
span,
|
||||
name,
|
||||
AttrVec::new(),
|
||||
ast::ItemKind::Static(ast::StaticItem { ty, mutability, expr: Some(expr) }.into()),
|
||||
ast::ItemKind::Static(
|
||||
ast::StaticItem { ty, safety: ast::Safety::Default, mutability, expr: Some(expr) }
|
||||
.into(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -440,3 +440,13 @@ pub(crate) struct EmptyDelegationList {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
// This used to be the `proc_macro_back_compat` lint (#83125). It was later
|
||||
// turned into a hard error.
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(expand_proc_macro_back_compat)]
|
||||
#[note]
|
||||
pub struct ProcMacroBackCompat {
|
||||
pub crate_name: String,
|
||||
pub fixed_version: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -267,7 +267,6 @@ pub(super) fn transcribe<'a>(
|
|||
// some of the unnecessary whitespace.
|
||||
let ident = MacroRulesNormalizedIdent::new(original_ident);
|
||||
if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
|
||||
// njn: explain the use of alone here
|
||||
let tt = match cur_matched {
|
||||
MatchedSingle(ParseNtResult::Tt(tt)) => {
|
||||
// `tt`s are emitted into the output stream directly as "raw tokens",
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ use crate::errors::{
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{token, AttrVec, Attribute, Inline, Item, ModSpans};
|
||||
use rustc_errors::{Diag, ErrorGuaranteed};
|
||||
use rustc_parse::new_parser_from_file;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
|
|
@ -66,7 +66,8 @@ pub(crate) fn parse_external_mod(
|
|||
}
|
||||
|
||||
// Actually parse the external file as a module.
|
||||
let mut parser = 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, Some(span)));
|
||||
let (inner_attrs, items, inner_span) =
|
||||
parser.parse_mod(&token::Eof).map_err(|err| ModError::ParserError(err))?;
|
||||
attrs.extend(inner_attrs);
|
||||
|
|
|
|||
|
|
@ -4,14 +4,12 @@ use crate::proc_macro_server;
|
|||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_parse::parser::ForceCollect;
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_session::config::ProcMacroExecutionStrategy;
|
||||
use rustc_span::profiling::SpannedEventArgRecorder;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_span::Span;
|
||||
|
||||
struct MessagePipe<T> {
|
||||
tx: std::sync::mpsc::SyncSender<T>,
|
||||
|
|
@ -120,18 +118,13 @@ impl MultiItemModifier for DeriveProcMacro {
|
|||
// We need special handling for statement items
|
||||
// (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
|
||||
let is_stmt = matches!(item, Annotatable::Stmt(..));
|
||||
let hack = crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess);
|
||||
let input = if hack {
|
||||
let nt = match item {
|
||||
Annotatable::Item(item) => token::NtItem(item),
|
||||
Annotatable::Stmt(stmt) => token::NtStmt(stmt),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
TokenStream::token_alone(token::Interpolated(Lrc::new(nt)), DUMMY_SP)
|
||||
} else {
|
||||
item.to_tokens()
|
||||
};
|
||||
|
||||
// We used to have an alternative behaviour for crates that needed it.
|
||||
// We had a lint for a long time, but now we just emit a hard error.
|
||||
// Eventually we might remove the special case hard error check
|
||||
// altogether. See #73345.
|
||||
crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess);
|
||||
let input = item.to_tokens();
|
||||
let stream = {
|
||||
let _timer =
|
||||
ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
|
||||
|
|
@ -161,8 +154,7 @@ impl MultiItemModifier for DeriveProcMacro {
|
|||
};
|
||||
|
||||
let error_count_before = ecx.dcx().err_count();
|
||||
let mut parser =
|
||||
rustc_parse::stream_to_parser(&ecx.sess.psess, stream, Some("proc-macro derive"));
|
||||
let mut parser = Parser::new(&ecx.sess.psess, stream, Some("proc-macro derive"));
|
||||
let mut items = vec![];
|
||||
|
||||
loop {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ use rustc_data_structures::fx::FxHashMap;
|
|||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Diag, ErrorGuaranteed, MultiSpan, PResult};
|
||||
use rustc_parse::lexer::nfc_normalize;
|
||||
use rustc_parse::parse_stream_from_source_str;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_parse::{new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::def_id::CrateNum;
|
||||
use rustc_span::symbol::{self, sym, Symbol};
|
||||
|
|
@ -276,21 +277,20 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
|||
|
||||
Interpolated(nt) => {
|
||||
let stream = TokenStream::from_nonterminal_ast(&nt);
|
||||
// A hack used to pass AST fragments to attribute and derive
|
||||
// macros as a single nonterminal token instead of a token
|
||||
// stream. Such token needs to be "unwrapped" and not
|
||||
// represented as a delimited group.
|
||||
// FIXME: It needs to be removed, but there are some
|
||||
// compatibility issues (see #73345).
|
||||
if crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.ecx.sess) {
|
||||
trees.extend(Self::from_internal((stream, rustc)));
|
||||
} else {
|
||||
trees.push(TokenTree::Group(Group {
|
||||
delimiter: pm::Delimiter::None,
|
||||
stream: Some(stream),
|
||||
span: DelimSpan::from_single(span),
|
||||
}))
|
||||
}
|
||||
// We used to have an alternative behaviour for crates that
|
||||
// needed it: a hack used to pass AST fragments to
|
||||
// attribute and derive macros as a single nonterminal
|
||||
// token instead of a token stream. Such token needs to be
|
||||
// "unwrapped" and not represented as a delimited group. We
|
||||
// had a lint for a long time, but now we just emit a hard
|
||||
// error. Eventually we might remove the special case hard
|
||||
// error check altogether. See #73345.
|
||||
crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.ecx.sess);
|
||||
trees.push(TokenTree::Group(Group {
|
||||
delimiter: pm::Delimiter::None,
|
||||
stream: Some(stream),
|
||||
span: DelimSpan::from_single(span),
|
||||
}))
|
||||
}
|
||||
|
||||
OpenDelim(..) | CloseDelim(..) => unreachable!(),
|
||||
|
|
@ -467,7 +467,8 @@ 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 = rustc_parse::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()));
|
||||
|
||||
let first_span = parser.token.span.data();
|
||||
let minus_present = parser.eat(&token::BinOp(token::Minus));
|
||||
|
|
@ -539,12 +540,12 @@ impl server::TokenStream for Rustc<'_, '_> {
|
|||
}
|
||||
|
||||
fn from_str(&mut self, src: &str) -> Self::TokenStream {
|
||||
parse_stream_from_source_str(
|
||||
unwrap_or_emit_fatal(source_str_to_stream(
|
||||
self.psess(),
|
||||
FileName::proc_macro_source_code(src),
|
||||
src.to_string(),
|
||||
self.psess(),
|
||||
Some(self.call_site),
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
fn to_string(&mut self, stream: &Self::TokenStream) -> String {
|
||||
|
|
@ -554,11 +555,7 @@ impl server::TokenStream for Rustc<'_, '_> {
|
|||
fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
|
||||
// Parse the expression from our tokenstream.
|
||||
let expr: PResult<'_, _> = try {
|
||||
let mut p = rustc_parse::stream_to_parser(
|
||||
self.psess(),
|
||||
stream.clone(),
|
||||
Some("proc_macro expand expr"),
|
||||
);
|
||||
let mut p = Parser::new(self.psess(), stream.clone(), Some("proc_macro expand expr"));
|
||||
let expr = p.parse_expr()?;
|
||||
if p.token != token::Eof {
|
||||
p.unexpected()?;
|
||||
|
|
|
|||
|
|
@ -128,6 +128,8 @@ declare_features! (
|
|||
/// Allows the use of type alias impl trait in function return positions
|
||||
(removed, min_type_alias_impl_trait, "1.56.0", Some(63063),
|
||||
Some("removed in favor of full type_alias_impl_trait")),
|
||||
/// Make `mut` not reset the binding mode on edition >= 2024.
|
||||
(removed, mut_preserve_binding_mode_2024, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024`")),
|
||||
(removed, needs_allocator, "1.4.0", Some(27389),
|
||||
Some("subsumed by `#![feature(allocator_internals)]`")),
|
||||
/// Allows use of unary negate on unsigned integers, e.g., -e for e: u8
|
||||
|
|
@ -181,6 +183,7 @@ declare_features! (
|
|||
(removed, pushpop_unsafe, "1.2.0", None, None),
|
||||
(removed, quad_precision_float, "1.0.0", None, None),
|
||||
(removed, quote, "1.33.0", Some(29601), None),
|
||||
(removed, ref_pat_everywhere, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024")),
|
||||
(removed, reflect, "1.0.0", Some(27749), None),
|
||||
/// Allows using the `#[register_attr]` attribute.
|
||||
(removed, register_attr, "1.65.0", Some(66080),
|
||||
|
|
|
|||
|
|
@ -529,8 +529,6 @@ declare_features! (
|
|||
(unstable, more_qualified_paths, "1.54.0", Some(86935)),
|
||||
/// Allows the `#[must_not_suspend]` attribute.
|
||||
(unstable, must_not_suspend, "1.57.0", Some(83310)),
|
||||
/// Make `mut` not reset the binding mode on edition >= 2024.
|
||||
(incomplete, mut_preserve_binding_mode_2024, "1.79.0", Some(123076)),
|
||||
/// Allows `mut ref` and `mut ref mut` identifier patterns.
|
||||
(incomplete, mut_ref, "1.79.0", Some(123076)),
|
||||
/// Allows using `#[naked]` on functions.
|
||||
|
|
@ -573,8 +571,6 @@ declare_features! (
|
|||
(unstable, raw_ref_op, "1.41.0", Some(64490)),
|
||||
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
|
||||
(incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)),
|
||||
/// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references.
|
||||
(incomplete, ref_pat_everywhere, "1.79.0", Some(123076)),
|
||||
/// Allows using the `#[register_tool]` attribute.
|
||||
(unstable, register_tool, "1.41.0", Some(66079)),
|
||||
/// Allows the `#[repr(i128)]` attribute for enums.
|
||||
|
|
@ -624,6 +620,8 @@ declare_features! (
|
|||
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
|
||||
/// Allows unnamed fields of struct and union type
|
||||
(incomplete, unnamed_fields, "1.74.0", Some(49804)),
|
||||
/// Allows unsafe on extern declarations and safety qualifiers over internal items.
|
||||
(unstable, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)),
|
||||
/// Allows unsized fn parameters.
|
||||
(unstable, unsized_fn_params, "1.49.0", Some(48055)),
|
||||
/// Allows unsized rvalues at arguments and parameters.
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ pub enum DefKind {
|
|||
/// Constant generic parameter: `struct Foo<const N: usize> { ... }`
|
||||
ConstParam,
|
||||
Static {
|
||||
/// Whether it's a `unsafe static`, `safe static` (inside extern only) or just a `static`.
|
||||
safety: hir::Safety,
|
||||
/// Whether it's a `static mut` or just a `static`.
|
||||
mutability: ast::Mutability,
|
||||
/// Whether it's an anonymous static generated for nested allocations.
|
||||
|
|
|
|||
|
|
@ -3475,9 +3475,9 @@ impl ForeignItem<'_> {
|
|||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub enum ForeignItemKind<'hir> {
|
||||
/// A foreign function.
|
||||
Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>),
|
||||
Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>, Safety),
|
||||
/// A foreign static item (`static ext: u8`).
|
||||
Static(&'hir Ty<'hir>, Mutability),
|
||||
Static(&'hir Ty<'hir>, Mutability, Safety),
|
||||
/// A foreign type.
|
||||
Type,
|
||||
}
|
||||
|
|
@ -3545,7 +3545,7 @@ impl<'hir> OwnerNode<'hir> {
|
|||
| OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
|
||||
| OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl),
|
||||
OwnerNode::ForeignItem(ForeignItem {
|
||||
kind: ForeignItemKind::Fn(fn_decl, _, _),
|
||||
kind: ForeignItemKind::Fn(fn_decl, _, _, _),
|
||||
..
|
||||
}) => Some(fn_decl),
|
||||
_ => None,
|
||||
|
|
@ -3728,9 +3728,9 @@ impl<'hir> Node<'hir> {
|
|||
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
|
||||
| Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl),
|
||||
Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. })
|
||||
| Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
|
||||
Some(fn_decl)
|
||||
}
|
||||
| Node::ForeignItem(ForeignItem {
|
||||
kind: ForeignItemKind::Fn(fn_decl, _, _, _), ..
|
||||
}) => Some(fn_decl),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -3813,7 +3813,7 @@ impl<'hir> Node<'hir> {
|
|||
pub fn generics(self) -> Option<&'hir Generics<'hir>> {
|
||||
match self {
|
||||
Node::ForeignItem(ForeignItem {
|
||||
kind: ForeignItemKind::Fn(_, _, generics), ..
|
||||
kind: ForeignItemKind::Fn(_, _, generics, _), ..
|
||||
})
|
||||
| Node::TraitItem(TraitItem { generics, .. })
|
||||
| Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
|
||||
|
|
|
|||
|
|
@ -608,12 +608,14 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(
|
|||
try_visit!(visitor.visit_ident(foreign_item.ident));
|
||||
|
||||
match foreign_item.kind {
|
||||
ForeignItemKind::Fn(ref function_declaration, param_names, ref generics) => {
|
||||
ForeignItemKind::Fn(ref function_declaration, param_names, ref generics, _) => {
|
||||
try_visit!(visitor.visit_generics(generics));
|
||||
try_visit!(visitor.visit_fn_decl(function_declaration));
|
||||
walk_list!(visitor, visit_ident, param_names.iter().copied());
|
||||
}
|
||||
ForeignItemKind::Static(ref typ, _) => try_visit!(visitor.visit_ty(typ)),
|
||||
ForeignItemKind::Static(ref typ, _, _) => {
|
||||
try_visit!(visitor.visit_ty(typ));
|
||||
}
|
||||
ForeignItemKind::Type => (),
|
||||
}
|
||||
V::Result::output()
|
||||
|
|
|
|||
|
|
@ -801,7 +801,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||
|
||||
let item = tcx.hir().foreign_item(item.id);
|
||||
match &item.kind {
|
||||
hir::ForeignItemKind::Fn(fn_decl, _, _) => {
|
||||
hir::ForeignItemKind::Fn(fn_decl, _, _, _) => {
|
||||
require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span);
|
||||
}
|
||||
hir::ForeignItemKind::Static(..) => {
|
||||
|
|
|
|||
|
|
@ -2198,9 +2198,6 @@ fn param_env_with_gat_bounds<'tcx>(
|
|||
tcx,
|
||||
ty::INNERMOST,
|
||||
ty::BoundVar::from_usize(bound_vars.len() - 1),
|
||||
tcx.type_of(param.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic"),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ fn path_if_static_mut(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> Option<String> {
|
|||
if let hir::ExprKind::Path(qpath) = expr.kind
|
||||
&& let hir::QPath::Resolved(_, path) = qpath
|
||||
&& let hir::def::Res::Def(def_kind, _) = path.res
|
||||
&& let hir::def::DefKind::Static { mutability: Mutability::Mut, nested: false } = def_kind
|
||||
&& let hir::def::DefKind::Static { safety: _, mutability: Mutability::Mut, nested: false } =
|
||||
def_kind
|
||||
{
|
||||
return Some(qpath_to_string(&tcx, &qpath));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ fn equate_intrinsic_type<'tcx>(
|
|||
let (own_counts, span) = match tcx.hir_node_by_def_id(def_id) {
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })
|
||||
| hir::Node::ForeignItem(hir::ForeignItem {
|
||||
kind: hir::ForeignItemKind::Fn(.., generics),
|
||||
kind: hir::ForeignItemKind::Fn(.., generics, _),
|
||||
..
|
||||
}) => {
|
||||
let own_counts = tcx.generics_of(def_id).own_counts();
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@ use rustc_ast::Recovered;
|
|||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_errors::{struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, E0228};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::intravisit::{self, walk_generics, Visitor};
|
||||
use rustc_hir::{self as hir};
|
||||
use rustc_hir::{GenericParamKind, Node};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
|
|
@ -44,7 +44,7 @@ use std::ops::Bound;
|
|||
|
||||
use crate::check::intrinsic::intrinsic_operation_unsafety;
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::HirTyLowerer;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
|
||||
pub use type_of::test_opaque_hidden_types;
|
||||
|
||||
mod generics_of;
|
||||
|
|
@ -370,32 +370,34 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
|||
self.tcx
|
||||
}
|
||||
|
||||
fn item_def_id(&self) -> DefId {
|
||||
self.item_def_id.to_def_id()
|
||||
fn item_def_id(&self) -> LocalDefId {
|
||||
self.item_def_id
|
||||
}
|
||||
|
||||
fn allow_infer(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option<ty::Region<'tcx>> {
|
||||
None
|
||||
fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
|
||||
if let RegionInferReason::BorrowedObjectLifetimeDefault = reason {
|
||||
let e = struct_span_code_err!(
|
||||
self.tcx().dcx(),
|
||||
span,
|
||||
E0228,
|
||||
"the lifetime bound for this object type cannot be deduced \
|
||||
from context; please supply an explicit bound"
|
||||
)
|
||||
.emit();
|
||||
self.set_tainted_by_errors(e);
|
||||
ty::Region::new_error(self.tcx(), e)
|
||||
} else {
|
||||
// This indicates an illegal lifetime in a non-assoc-trait position
|
||||
ty::Region::new_error_with_message(self.tcx(), span, "unelided lifetime in signature")
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
|
||||
Ty::new_error_with_message(self.tcx(), span, "bad placeholder type")
|
||||
}
|
||||
|
||||
fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
|
||||
let ty = self.tcx.fold_regions(ty, |r, _| match *r {
|
||||
rustc_type_ir::RegionKind::ReStatic => r,
|
||||
|
||||
// This is never reached in practice. If it ever is reached,
|
||||
// `ReErased` should be changed to `ReStatic`, and any other region
|
||||
// left alone.
|
||||
r => bug!("unexpected region: {r:?}"),
|
||||
});
|
||||
ty::Const::new_error_with_message(self.tcx(), ty, span, "bad placeholder constant")
|
||||
fn ct_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
|
||||
ty::Const::new_error_with_message(self.tcx(), span, "bad placeholder constant")
|
||||
}
|
||||
|
||||
fn probe_ty_param_bounds(
|
||||
|
|
@ -510,6 +512,89 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
|||
fn set_tainted_by_errors(&self, err: ErrorGuaranteed) {
|
||||
self.tainted_by_errors.set(Some(err));
|
||||
}
|
||||
|
||||
fn lower_fn_sig(
|
||||
&self,
|
||||
decl: &hir::FnDecl<'tcx>,
|
||||
generics: Option<&hir::Generics<'_>>,
|
||||
hir_id: rustc_hir::HirId,
|
||||
hir_ty: Option<&hir::Ty<'_>>,
|
||||
) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
|
||||
let tcx = self.tcx();
|
||||
// We proactively collect all the inferred type params to emit a single error per fn def.
|
||||
let mut visitor = HirPlaceholderCollector::default();
|
||||
let mut infer_replacements = vec![];
|
||||
|
||||
if let Some(generics) = generics {
|
||||
walk_generics(&mut visitor, generics);
|
||||
}
|
||||
|
||||
let input_tys = decl
|
||||
.inputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, a)| {
|
||||
if let hir::TyKind::Infer = a.kind {
|
||||
if let Some(suggested_ty) =
|
||||
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
|
||||
{
|
||||
infer_replacements.push((a.span, suggested_ty.to_string()));
|
||||
return Ty::new_error_with_message(tcx, a.span, suggested_ty.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Only visit the type looking for `_` if we didn't fix the type above
|
||||
visitor.visit_ty(a);
|
||||
self.lowerer().lower_arg_ty(a, None)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let output_ty = match decl.output {
|
||||
hir::FnRetTy::Return(output) => {
|
||||
if let hir::TyKind::Infer = output.kind
|
||||
&& let Some(suggested_ty) =
|
||||
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
|
||||
{
|
||||
infer_replacements.push((output.span, suggested_ty.to_string()));
|
||||
Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string())
|
||||
} else {
|
||||
visitor.visit_ty(output);
|
||||
self.lower_ty(output)
|
||||
}
|
||||
}
|
||||
hir::FnRetTy::DefaultReturn(..) => tcx.types.unit,
|
||||
};
|
||||
|
||||
if !(visitor.0.is_empty() && infer_replacements.is_empty()) {
|
||||
// We check for the presence of
|
||||
// `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
|
||||
|
||||
let mut diag = crate::collect::placeholder_type_error_diag(
|
||||
tcx,
|
||||
generics,
|
||||
visitor.0,
|
||||
infer_replacements.iter().map(|(s, _)| *s).collect(),
|
||||
true,
|
||||
hir_ty,
|
||||
"function",
|
||||
);
|
||||
|
||||
if !infer_replacements.is_empty() {
|
||||
diag.multipart_suggestion(
|
||||
format!(
|
||||
"try replacing `_` with the type{} in the corresponding trait method signature",
|
||||
rustc_errors::pluralize!(infer_replacements.len()),
|
||||
),
|
||||
infer_replacements,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
self.set_tainted_by_errors(diag.emit());
|
||||
}
|
||||
|
||||
(input_tys, output_ty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.
|
||||
|
|
@ -1321,9 +1406,11 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
|
|||
icx.lowerer().lower_fn_ty(hir_id, header.safety, header.abi, decl, Some(generics), None)
|
||||
}
|
||||
|
||||
ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
|
||||
ForeignItem(&hir::ForeignItem {
|
||||
kind: ForeignItemKind::Fn(fn_decl, _, _, safety), ..
|
||||
}) => {
|
||||
let abi = tcx.hir().get_foreign_abi(hir_id);
|
||||
compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
|
||||
compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi, safety)
|
||||
}
|
||||
|
||||
Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => {
|
||||
|
|
@ -1695,11 +1782,12 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
|
|||
def_id: LocalDefId,
|
||||
decl: &'tcx hir::FnDecl<'tcx>,
|
||||
abi: abi::Abi,
|
||||
safety: hir::Safety,
|
||||
) -> ty::PolyFnSig<'tcx> {
|
||||
let safety = if abi == abi::Abi::RustIntrinsic {
|
||||
intrinsic_operation_unsafety(tcx, def_id)
|
||||
} else {
|
||||
hir::Safety::Unsafe
|
||||
safety
|
||||
};
|
||||
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||
let fty =
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::bounds::Bounds;
|
||||
use crate::collect::ItemCtxt;
|
||||
use crate::constrained_generic_params as cgp;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter};
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason};
|
||||
use hir::{HirId, Node};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -117,7 +117,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
let mut is_trait = None;
|
||||
let mut is_default_impl_trait = None;
|
||||
|
||||
// FIXME: Should ItemCtxt take a LocalDefId?
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
|
||||
const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
|
||||
|
|
@ -197,7 +196,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
.type_of(param.def_id.to_def_id())
|
||||
.no_bound_vars()
|
||||
.expect("const parameters cannot be generic");
|
||||
let ct = icx.lowerer().lower_const_param(param.hir_id, ct_ty);
|
||||
let ct = icx.lowerer().lower_const_param(param.hir_id);
|
||||
predicates
|
||||
.insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span));
|
||||
}
|
||||
|
|
@ -244,12 +243,15 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
|||
}
|
||||
|
||||
hir::WherePredicate::RegionPredicate(region_pred) => {
|
||||
let r1 = icx.lowerer().lower_lifetime(region_pred.lifetime, None);
|
||||
let r1 = icx
|
||||
.lowerer()
|
||||
.lower_lifetime(region_pred.lifetime, RegionInferReason::RegionPredicate);
|
||||
predicates.extend(region_pred.bounds.iter().map(|bound| {
|
||||
let (r2, span) = match bound {
|
||||
hir::GenericBound::Outlives(lt) => {
|
||||
(icx.lowerer().lower_lifetime(lt, None), lt.ident.span)
|
||||
}
|
||||
hir::GenericBound::Outlives(lt) => (
|
||||
icx.lowerer().lower_lifetime(lt, RegionInferReason::RegionPredicate),
|
||||
lt.ident.span,
|
||||
),
|
||||
bound => {
|
||||
span_bug!(
|
||||
bound.span(),
|
||||
|
|
|
|||
|
|
@ -603,7 +603,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
|
||||
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
|
||||
match item.kind {
|
||||
hir::ForeignItemKind::Fn(_, _, generics) => {
|
||||
hir::ForeignItemKind::Fn(_, _, generics, _) => {
|
||||
self.visit_early_late(item.hir_id(), generics, |this| {
|
||||
intravisit::walk_foreign_item(this, item);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -464,7 +464,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
|
|||
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
|
||||
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
|
||||
}
|
||||
ForeignItemKind::Static(t, _) => icx.lower_ty(t),
|
||||
ForeignItemKind::Static(t, _, _) => icx.lower_ty(t),
|
||||
ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()),
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ use crate::bounds::Bounds;
|
|||
use crate::errors;
|
||||
use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter};
|
||||
|
||||
use super::RegionInferReason;
|
||||
|
||||
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
/// Add a `Sized` bound to the `bounds` if appropriate.
|
||||
///
|
||||
|
|
@ -166,7 +168,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
);
|
||||
}
|
||||
hir::GenericBound::Outlives(lifetime) => {
|
||||
let region = self.lower_lifetime(lifetime, None);
|
||||
let region = self.lower_lifetime(lifetime, RegionInferReason::OutlivesBound);
|
||||
bounds.push_region_bound(
|
||||
self.tcx(),
|
||||
ty::Binder::bind_with_vars(
|
||||
|
|
@ -366,11 +368,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
},
|
||||
)
|
||||
});
|
||||
let ty = tcx
|
||||
.type_of(param.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("ct params cannot have early bound vars");
|
||||
ty::Const::new_error(tcx, guar, ty).into()
|
||||
ty::Const::new_error(tcx, guar).into()
|
||||
}
|
||||
};
|
||||
num_bound_vars += 1;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ mod lint;
|
|||
mod object_safety;
|
||||
|
||||
use crate::bounds::Bounds;
|
||||
use crate::collect::HirPlaceholderCollector;
|
||||
use crate::errors::{AmbiguousLifetimeBound, WildPatTy};
|
||||
use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend};
|
||||
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
|
||||
|
|
@ -34,7 +33,6 @@ use rustc_errors::{
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{walk_generics, Visitor as _};
|
||||
use rustc_hir::{GenericArg, GenericArgs, HirId};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
|
|
@ -82,6 +80,20 @@ pub enum PredicateFilter {
|
|||
SelfAndAssociatedTypeBounds,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RegionInferReason<'a> {
|
||||
/// Lifetime on a trait object behind a reference.
|
||||
/// This allows inferring information from the reference.
|
||||
BorrowedObjectLifetimeDefault,
|
||||
/// A trait object's lifetime.
|
||||
ObjectLifetimeDefault,
|
||||
/// Generic lifetime parameter
|
||||
Param(&'a ty::GenericParamDef),
|
||||
RegionPredicate,
|
||||
Reference,
|
||||
OutlivesBound,
|
||||
}
|
||||
|
||||
/// A context which can lower type-system entities from the [HIR][hir] to
|
||||
/// the [`rustc_middle::ty`] representation.
|
||||
///
|
||||
|
|
@ -89,26 +101,17 @@ pub enum PredicateFilter {
|
|||
pub trait HirTyLowerer<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx>;
|
||||
|
||||
/// Returns the [`DefId`] of the overarching item whose constituents get lowered.
|
||||
fn item_def_id(&self) -> DefId;
|
||||
|
||||
/// Returns `true` if the current context allows the use of inference variables.
|
||||
fn allow_infer(&self) -> bool;
|
||||
/// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered.
|
||||
fn item_def_id(&self) -> LocalDefId;
|
||||
|
||||
/// Returns the region to use when a lifetime is omitted (and not elided).
|
||||
fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span)
|
||||
-> Option<ty::Region<'tcx>>;
|
||||
fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx>;
|
||||
|
||||
/// Returns the type to use when a type is omitted.
|
||||
fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>;
|
||||
|
||||
/// Returns the const to use when a const is omitted.
|
||||
fn ct_infer(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
param: Option<&ty::GenericParamDef>,
|
||||
span: Span,
|
||||
) -> Const<'tcx>;
|
||||
fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx>;
|
||||
|
||||
/// Probe bounds in scope where the bounded type coincides with the given type parameter.
|
||||
///
|
||||
|
|
@ -151,6 +154,14 @@ pub trait HirTyLowerer<'tcx> {
|
|||
poly_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Ty<'tcx>;
|
||||
|
||||
fn lower_fn_sig(
|
||||
&self,
|
||||
decl: &hir::FnDecl<'tcx>,
|
||||
generics: Option<&hir::Generics<'_>>,
|
||||
hir_id: HirId,
|
||||
hir_ty: Option<&hir::Ty<'_>>,
|
||||
) -> (Vec<Ty<'tcx>>, Ty<'tcx>);
|
||||
|
||||
/// Returns `AdtDef` if `ty` is an ADT.
|
||||
///
|
||||
/// Note that `ty` might be a alias type that needs normalization.
|
||||
|
|
@ -258,7 +269,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
pub fn lower_lifetime(
|
||||
&self,
|
||||
lifetime: &hir::Lifetime,
|
||||
def: Option<&ty::GenericParamDef>,
|
||||
reason: RegionInferReason<'_>,
|
||||
) -> ty::Region<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id));
|
||||
|
|
@ -292,21 +303,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar),
|
||||
|
||||
None => {
|
||||
self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| {
|
||||
debug!(?lifetime, "unelided lifetime in signature");
|
||||
|
||||
// This indicates an illegal lifetime
|
||||
// elision. `resolve_lifetime` should have
|
||||
// reported an error in this case -- but if
|
||||
// not, let's error out.
|
||||
ty::Region::new_error_with_message(
|
||||
tcx,
|
||||
lifetime.ident.span,
|
||||
"unelided lifetime in signature",
|
||||
)
|
||||
})
|
||||
}
|
||||
None => self.re_infer(lifetime.ident.span, reason),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -421,7 +418,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
def_id: DefId,
|
||||
generic_args: &'a GenericArgs<'tcx>,
|
||||
span: Span,
|
||||
inferred_params: Vec<Span>,
|
||||
infer_args: bool,
|
||||
incorrect_args: &'a Result<(), GenericArgCountMismatch>,
|
||||
}
|
||||
|
|
@ -438,7 +434,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
fn provided_kind(
|
||||
&mut self,
|
||||
preceding_args: &[ty::GenericArg<'tcx>],
|
||||
_preceding_args: &[ty::GenericArg<'tcx>],
|
||||
param: &ty::GenericParamDef,
|
||||
arg: &GenericArg<'tcx>,
|
||||
) -> ty::GenericArg<'tcx> {
|
||||
|
|
@ -446,11 +442,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
if let Err(incorrect) = self.incorrect_args {
|
||||
if incorrect.invalid_args.contains(&(param.index as usize)) {
|
||||
return param.to_error(tcx, preceding_args);
|
||||
return param.to_error(tcx);
|
||||
}
|
||||
}
|
||||
|
||||
let mut handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| {
|
||||
let handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| {
|
||||
if has_default {
|
||||
tcx.check_optional_stability(
|
||||
param.def_id,
|
||||
|
|
@ -467,17 +463,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
},
|
||||
);
|
||||
}
|
||||
if let (hir::TyKind::Infer, false) = (&ty.kind, self.lowerer.allow_infer()) {
|
||||
self.inferred_params.push(ty.span);
|
||||
Ty::new_misc_error(tcx).into()
|
||||
} else {
|
||||
self.lowerer.lower_ty(ty).into()
|
||||
}
|
||||
self.lowerer.lower_ty(ty).into()
|
||||
};
|
||||
|
||||
match (¶m.kind, arg) {
|
||||
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
|
||||
self.lowerer.lower_lifetime(lt, Some(param)).into()
|
||||
self.lowerer.lower_lifetime(lt, RegionInferReason::Param(param)).into()
|
||||
}
|
||||
(&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
|
||||
handle_ty_args(has_default, ty)
|
||||
|
|
@ -491,17 +482,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
ty::Const::from_anon_const(tcx, did).into()
|
||||
}
|
||||
(&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => {
|
||||
let ty = tcx
|
||||
.at(self.span)
|
||||
.type_of(param.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic");
|
||||
if self.lowerer.allow_infer() {
|
||||
self.lowerer.ct_infer(ty, Some(param), inf.span).into()
|
||||
} else {
|
||||
self.inferred_params.push(inf.span);
|
||||
ty::Const::new_misc_error(tcx, ty).into()
|
||||
}
|
||||
self.lowerer.ct_infer(Some(param), inf.span).into()
|
||||
}
|
||||
(kind, arg) => span_bug!(
|
||||
self.span,
|
||||
|
|
@ -520,24 +501,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
if let Err(incorrect) = self.incorrect_args {
|
||||
if incorrect.invalid_args.contains(&(param.index as usize)) {
|
||||
return param.to_error(tcx, preceding_args);
|
||||
return param.to_error(tcx);
|
||||
}
|
||||
}
|
||||
match param.kind {
|
||||
GenericParamDefKind::Lifetime => self
|
||||
.lowerer
|
||||
.re_infer(Some(param), self.span)
|
||||
.unwrap_or_else(|| {
|
||||
debug!(?param, "unelided lifetime in signature");
|
||||
|
||||
// This indicates an illegal lifetime in a non-assoc-trait position
|
||||
ty::Region::new_error_with_message(
|
||||
tcx,
|
||||
self.span,
|
||||
"unelided lifetime in signature",
|
||||
)
|
||||
})
|
||||
.into(),
|
||||
GenericParamDefKind::Lifetime => {
|
||||
self.lowerer.re_infer(self.span, RegionInferReason::Param(param)).into()
|
||||
}
|
||||
GenericParamDefKind::Type { has_default, .. } => {
|
||||
if !infer_args && has_default {
|
||||
// No type parameter provided, but a default exists.
|
||||
|
|
@ -568,7 +538,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic");
|
||||
if let Err(guar) = ty.error_reported() {
|
||||
return ty::Const::new_error(tcx, guar, ty).into();
|
||||
return ty::Const::new_error(tcx, guar).into();
|
||||
}
|
||||
// FIXME(effects) see if we should special case effect params here
|
||||
if !infer_args && has_default {
|
||||
|
|
@ -577,10 +547,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.into()
|
||||
} else {
|
||||
if infer_args {
|
||||
self.lowerer.ct_infer(ty, Some(param), self.span).into()
|
||||
self.lowerer.ct_infer(Some(param), self.span).into()
|
||||
} else {
|
||||
// We've already errored above about the mismatch.
|
||||
ty::Const::new_misc_error(tcx, ty).into()
|
||||
ty::Const::new_misc_error(tcx).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -604,7 +574,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
def_id,
|
||||
span,
|
||||
generic_args: segment.args(),
|
||||
inferred_params: vec![],
|
||||
infer_args: segment.infer_args,
|
||||
incorrect_args: &arg_count.correct,
|
||||
};
|
||||
|
|
@ -1493,16 +1462,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let def_id = self.item_def_id();
|
||||
debug!(item_def_id = ?def_id);
|
||||
|
||||
let parent_def_id = def_id
|
||||
.as_local()
|
||||
.map(|def_id| tcx.local_def_id_to_hir_id(def_id))
|
||||
.map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id());
|
||||
// FIXME: document why/how this is different from `tcx.local_parent(def_id)`
|
||||
let parent_def_id =
|
||||
tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id();
|
||||
debug!(?parent_def_id);
|
||||
|
||||
// If the trait in segment is the same as the trait defining the item,
|
||||
// use the `<Self as ..>` syntax in the error.
|
||||
let is_part_of_self_trait_constraints = def_id == trait_def_id;
|
||||
let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
|
||||
let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id;
|
||||
let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id;
|
||||
|
||||
let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
|
||||
vec!["Self".to_string()]
|
||||
|
|
@ -1930,7 +1898,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
///
|
||||
/// Early-bound const parameters get lowered to [`ty::ConstKind::Param`]
|
||||
/// and late-bound ones to [`ty::ConstKind::Bound`].
|
||||
pub(crate) fn lower_const_param(&self, hir_id: HirId, param_ty: Ty<'tcx>) -> Const<'tcx> {
|
||||
pub(crate) fn lower_const_param(&self, hir_id: HirId) -> Const<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
match tcx.named_bound_var(hir_id) {
|
||||
Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
|
||||
|
|
@ -1940,12 +1908,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let generics = tcx.generics_of(item_def_id);
|
||||
let index = generics.param_def_id_to_index[&def_id];
|
||||
let name = tcx.item_name(def_id);
|
||||
ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty)
|
||||
ty::Const::new_param(tcx, ty::ParamConst::new(index, name))
|
||||
}
|
||||
Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
|
||||
ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index), param_ty)
|
||||
ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index))
|
||||
}
|
||||
Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar, param_ty),
|
||||
Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar),
|
||||
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id),
|
||||
}
|
||||
}
|
||||
|
|
@ -1983,7 +1951,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
|
||||
let sig_generics = self.tcx().generics_of(sig_id);
|
||||
let parent = self.tcx().parent(self.item_def_id());
|
||||
let parent = self.tcx().local_parent(self.item_def_id());
|
||||
let parent_generics = self.tcx().generics_of(parent);
|
||||
|
||||
let parent_is_trait = (self.tcx().def_kind(parent) == DefKind::Trait) as usize;
|
||||
|
|
@ -2022,7 +1990,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let sig = self.tcx().fn_sig(sig_id);
|
||||
let sig_generics = self.tcx().generics_of(sig_id);
|
||||
|
||||
let parent = self.tcx().parent(self.item_def_id());
|
||||
let parent = self.tcx().local_parent(self.item_def_id());
|
||||
let parent_def_kind = self.tcx().def_kind(parent);
|
||||
|
||||
let sig = if let DefKind::Impl { .. } = parent_def_kind
|
||||
|
|
@ -2070,7 +2038,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)),
|
||||
hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl),
|
||||
hir::TyKind::Ref(region, mt) => {
|
||||
let r = self.lower_lifetime(region, None);
|
||||
let r = self.lower_lifetime(region, RegionInferReason::Reference);
|
||||
debug!(?r);
|
||||
let t = self.lower_ty_common(mt.ty, true, false);
|
||||
Ty::new_ref(tcx, r, t, mt.mutbl)
|
||||
|
|
@ -2161,7 +2129,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
hir::TyKind::Array(ty, length) => {
|
||||
let length = match length {
|
||||
hir::ArrayLen::Infer(inf) => self.ct_infer(tcx.types.usize, None, inf.span),
|
||||
hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
|
||||
hir::ArrayLen::Body(constant) => {
|
||||
ty::Const::from_anon_const(tcx, constant.def_id)
|
||||
}
|
||||
|
|
@ -2192,17 +2160,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
_ => (expr, None),
|
||||
};
|
||||
let c = match &expr.kind {
|
||||
let (c, c_ty) = match &expr.kind {
|
||||
hir::ExprKind::Lit(lit) => {
|
||||
let lit_input =
|
||||
LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() };
|
||||
match tcx.lit_to_const(lit_input) {
|
||||
let ct = match tcx.lit_to_const(lit_input) {
|
||||
Ok(c) => c,
|
||||
Err(LitToConstError::Reported(err)) => {
|
||||
ty::Const::new_error(tcx, err, ty)
|
||||
ty::Const::new_error(tcx, err)
|
||||
}
|
||||
Err(LitToConstError::TypeError) => todo!(),
|
||||
}
|
||||
};
|
||||
(ct, ty)
|
||||
}
|
||||
|
||||
hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
|
|
@ -2220,19 +2189,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.type_of(def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic");
|
||||
self.lower_const_param(expr.hir_id, ty)
|
||||
let ct = self.lower_const_param(expr.hir_id);
|
||||
(ct, ty)
|
||||
}
|
||||
|
||||
_ => {
|
||||
let err = tcx
|
||||
.dcx()
|
||||
.emit_err(crate::errors::NonConstRange { span: expr.span });
|
||||
ty::Const::new_error(tcx, err, ty)
|
||||
(ty::Const::new_error(tcx, err), Ty::new_error(tcx, err))
|
||||
}
|
||||
};
|
||||
self.record_ty(expr.hir_id, c.ty(), expr.span);
|
||||
self.record_ty(expr.hir_id, c_ty, expr.span);
|
||||
if let Some((id, span)) = neg {
|
||||
self.record_ty(id, c.ty(), span);
|
||||
self.record_ty(id, c_ty, span);
|
||||
}
|
||||
c
|
||||
};
|
||||
|
|
@ -2299,7 +2269,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
&lifetimes[i]
|
||||
)
|
||||
};
|
||||
self.lower_lifetime(lifetime, None).into()
|
||||
self.lower_lifetime(lifetime, RegionInferReason::Param(¶m)).into()
|
||||
} else {
|
||||
tcx.mk_param_from_def(param)
|
||||
}
|
||||
|
|
@ -2338,92 +2308,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let bound_vars = tcx.late_bound_vars(hir_id);
|
||||
debug!(?bound_vars);
|
||||
|
||||
// We proactively collect all the inferred type params to emit a single error per fn def.
|
||||
let mut visitor = HirPlaceholderCollector::default();
|
||||
let mut infer_replacements = vec![];
|
||||
|
||||
if let Some(generics) = generics {
|
||||
walk_generics(&mut visitor, generics);
|
||||
}
|
||||
|
||||
let input_tys: Vec<_> = decl
|
||||
.inputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, a)| {
|
||||
if let hir::TyKind::Infer = a.kind
|
||||
&& !self.allow_infer()
|
||||
{
|
||||
if let Some(suggested_ty) =
|
||||
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
|
||||
{
|
||||
infer_replacements.push((a.span, suggested_ty.to_string()));
|
||||
return Ty::new_error_with_message(
|
||||
self.tcx(),
|
||||
a.span,
|
||||
suggested_ty.to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Only visit the type looking for `_` if we didn't fix the type above
|
||||
visitor.visit_ty(a);
|
||||
self.lower_arg_ty(a, None)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let output_ty = match decl.output {
|
||||
hir::FnRetTy::Return(output) => {
|
||||
if let hir::TyKind::Infer = output.kind
|
||||
&& !self.allow_infer()
|
||||
&& let Some(suggested_ty) =
|
||||
self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
|
||||
{
|
||||
infer_replacements.push((output.span, suggested_ty.to_string()));
|
||||
Ty::new_error_with_message(self.tcx(), output.span, suggested_ty.to_string())
|
||||
} else {
|
||||
visitor.visit_ty(output);
|
||||
self.lower_ty(output)
|
||||
}
|
||||
}
|
||||
hir::FnRetTy::DefaultReturn(..) => tcx.types.unit,
|
||||
};
|
||||
let (input_tys, output_ty) = self.lower_fn_sig(decl, generics, hir_id, hir_ty);
|
||||
|
||||
debug!(?output_ty);
|
||||
|
||||
let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi);
|
||||
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
|
||||
|
||||
if !self.allow_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) {
|
||||
// We always collect the spans for placeholder types when evaluating `fn`s, but we
|
||||
// only want to emit an error complaining about them if infer types (`_`) are not
|
||||
// allowed. `allow_infer` gates this behavior. We check for the presence of
|
||||
// `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
|
||||
|
||||
let mut diag = crate::collect::placeholder_type_error_diag(
|
||||
tcx,
|
||||
generics,
|
||||
visitor.0,
|
||||
infer_replacements.iter().map(|(s, _)| *s).collect(),
|
||||
true,
|
||||
hir_ty,
|
||||
"function",
|
||||
);
|
||||
|
||||
if !infer_replacements.is_empty() {
|
||||
diag.multipart_suggestion(
|
||||
format!(
|
||||
"try replacing `_` with the type{} in the corresponding trait method signature",
|
||||
rustc_errors::pluralize!(infer_replacements.len()),
|
||||
),
|
||||
infer_replacements,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
self.set_tainted_by_errors(diag.emit());
|
||||
}
|
||||
|
||||
// Find any late-bound regions declared in return type that do
|
||||
// not appear in the arguments. These are not well-formed.
|
||||
//
|
||||
|
|
@ -2453,7 +2344,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
/// corresponding function in the trait that the impl implements, if it exists.
|
||||
/// If arg_idx is Some, then it corresponds to an input type index, otherwise it
|
||||
/// corresponds to the return type.
|
||||
fn suggest_trait_fn_ty_for_impl_fn_infer(
|
||||
pub(super) fn suggest_trait_fn_ty_for_impl_fn_infer(
|
||||
&self,
|
||||
fn_hir_id: HirId,
|
||||
arg_idx: Option<usize>,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use crate::bounds::Bounds;
|
||||
use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
|
||||
use crate::hir_ty_lowering::{
|
||||
GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds, RegionInferReason,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::{codes::*, struct_span_code_err};
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -141,9 +143,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// `trait_object_dummy_self`, so check for that.
|
||||
let references_self = match pred.skip_binder().term.unpack() {
|
||||
ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
|
||||
ty::TermKind::Const(c) => {
|
||||
c.ty().walk().any(|arg| arg == dummy_self.into())
|
||||
}
|
||||
// FIXME(associated_const_equality): We should walk the const instead of not doing anything
|
||||
ty::TermKind::Const(_) => false,
|
||||
};
|
||||
|
||||
// If the projection output contains `Self`, force the user to
|
||||
|
|
@ -321,30 +322,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
// Use explicitly-specified region bound.
|
||||
let region_bound = if !lifetime.is_elided() {
|
||||
self.lower_lifetime(lifetime, None)
|
||||
self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault)
|
||||
} else {
|
||||
self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
|
||||
if tcx.named_bound_var(lifetime.hir_id).is_some() {
|
||||
self.lower_lifetime(lifetime, None)
|
||||
self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault)
|
||||
} else {
|
||||
self.re_infer(None, span).unwrap_or_else(|| {
|
||||
let err = struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
span,
|
||||
E0228,
|
||||
"the lifetime bound for this object type cannot be deduced \
|
||||
from context; please supply an explicit bound"
|
||||
);
|
||||
let e = if borrowed {
|
||||
// We will have already emitted an error E0106 complaining about a
|
||||
// missing named lifetime in `&dyn Trait`, so we elide this one.
|
||||
err.delay_as_bug()
|
||||
self.re_infer(
|
||||
span,
|
||||
if borrowed {
|
||||
RegionInferReason::ObjectLifetimeDefault
|
||||
} else {
|
||||
err.emit()
|
||||
};
|
||||
self.set_tainted_by_errors(e);
|
||||
ty::Region::new_error(tcx, e)
|
||||
})
|
||||
RegionInferReason::BorrowedObjectLifetimeDefault
|
||||
},
|
||||
)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
},
|
||||
hir::Node::Field(field) => vec![field.ty],
|
||||
hir::Node::ForeignItem(ForeignItem {
|
||||
kind: ForeignItemKind::Static(ty, _), ..
|
||||
kind: ForeignItemKind::Static(ty, _, _), ..
|
||||
}) => vec![*ty],
|
||||
hir::Node::GenericParam(hir::GenericParam {
|
||||
kind: hir::GenericParamKind::Type { default: Some(ty), .. },
|
||||
|
|
|
|||
|
|
@ -345,12 +345,12 @@ impl<'a> State<'a> {
|
|||
self.maybe_print_comment(item.span.lo());
|
||||
self.print_outer_attributes(self.attrs(item.hir_id()));
|
||||
match item.kind {
|
||||
hir::ForeignItemKind::Fn(decl, arg_names, generics) => {
|
||||
hir::ForeignItemKind::Fn(decl, arg_names, generics, safety) => {
|
||||
self.head("");
|
||||
self.print_fn(
|
||||
decl,
|
||||
hir::FnHeader {
|
||||
safety: hir::Safety::Safe,
|
||||
safety,
|
||||
constness: hir::Constness::NotConst,
|
||||
abi: Abi::Rust,
|
||||
asyncness: hir::IsAsync::NotAsync,
|
||||
|
|
@ -364,7 +364,8 @@ impl<'a> State<'a> {
|
|||
self.word(";");
|
||||
self.end() // end the outer fn box
|
||||
}
|
||||
hir::ForeignItemKind::Static(t, m) => {
|
||||
hir::ForeignItemKind::Static(t, m, safety) => {
|
||||
self.print_safety(safety);
|
||||
self.head("static");
|
||||
if m.is_mut() {
|
||||
self.word_space("mut");
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
lt_op: |_| self.tcx.lifetimes.re_erased,
|
||||
ct_op: |ct| {
|
||||
if let ty::ConstKind::Infer(_) = ct.kind() {
|
||||
self.next_const_var(ct.ty(), DUMMY_SP)
|
||||
self.next_const_var(DUMMY_SP)
|
||||
} else {
|
||||
ct
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ use crate::errors::{
|
|||
YieldExprOutsideOfCoroutine,
|
||||
};
|
||||
use crate::fatally_break_rust;
|
||||
use crate::method::SelfSource;
|
||||
use crate::type_error_struct;
|
||||
use crate::CoroutineTypes;
|
||||
use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
|
||||
|
|
@ -223,7 +222,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let ty = ensure_sufficient_stack(|| match &expr.kind {
|
||||
hir::ExprKind::Path(
|
||||
qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)),
|
||||
) => self.check_expr_path(qpath, expr, args, call),
|
||||
) => self.check_expr_path(qpath, expr, Some(args), call),
|
||||
_ => self.check_expr_kind(expr, expected),
|
||||
});
|
||||
let ty = self.resolve_vars_if_possible(ty);
|
||||
|
|
@ -290,7 +289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ExprKind::Path(QPath::LangItem(lang_item, _)) => {
|
||||
self.check_lang_item_path(lang_item, expr)
|
||||
}
|
||||
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[], None),
|
||||
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None, None),
|
||||
ExprKind::InlineAsm(asm) => {
|
||||
// We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars).
|
||||
self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id));
|
||||
|
|
@ -502,12 +501,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
qpath: &'tcx hir::QPath<'tcx>,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
args: &'tcx [hir::Expr<'tcx>],
|
||||
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
||||
call: Option<&'tcx hir::Expr<'tcx>>,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let (res, opt_ty, segs) =
|
||||
self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span, Some(args));
|
||||
self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span);
|
||||
let ty = match res {
|
||||
Res::Err => {
|
||||
self.suggest_assoc_method_call(segs);
|
||||
|
|
@ -564,7 +563,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// We just want to check sizedness, so instead of introducing
|
||||
// placeholder lifetimes with probing, we just replace higher lifetimes
|
||||
// with fresh vars.
|
||||
let span = args.get(i).map(|a| a.span).unwrap_or(expr.span);
|
||||
let span = args.and_then(|args| args.get(i)).map_or(expr.span, |arg| arg.span);
|
||||
let input = self.instantiate_binder_with_fresh_vars(
|
||||
span,
|
||||
infer::BoundRegionConversionTime::FnCall,
|
||||
|
|
@ -1331,9 +1330,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let rcvr_t = self.check_expr(rcvr);
|
||||
// no need to check for bot/err -- callee does that
|
||||
let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t);
|
||||
let span = segment.ident.span;
|
||||
|
||||
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) {
|
||||
let method = match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args)
|
||||
{
|
||||
Ok(method) => {
|
||||
// We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to
|
||||
// trigger this codepath causing `structurally_resolve_type` to emit an error.
|
||||
|
|
@ -1342,18 +1341,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
Err(error) => {
|
||||
if segment.ident.name != kw::Empty {
|
||||
if let Some(err) = self.report_method_error(
|
||||
span,
|
||||
Some(rcvr),
|
||||
rcvr_t,
|
||||
segment.ident,
|
||||
expr.hir_id,
|
||||
SelfSource::MethodCall(rcvr),
|
||||
error,
|
||||
Some(args),
|
||||
expected,
|
||||
false,
|
||||
) {
|
||||
if let Some(err) =
|
||||
self.report_method_error(expr.hir_id, rcvr_t, error, expected, false)
|
||||
{
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
|
@ -1362,7 +1352,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
|
||||
// Call the generic checker.
|
||||
self.check_method_argument_types(span, expr, method, args, DontTupleArguments, expected)
|
||||
self.check_method_argument_types(
|
||||
segment.ident.span,
|
||||
expr,
|
||||
method,
|
||||
args,
|
||||
DontTupleArguments,
|
||||
expected,
|
||||
)
|
||||
}
|
||||
|
||||
fn check_expr_cast(
|
||||
|
|
@ -1674,6 +1671,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let mut error_happened = false;
|
||||
|
||||
if variant.fields.len() != remaining_fields.len() {
|
||||
// Some field is defined more than once. Make sure we don't try to
|
||||
// instantiate this struct in static/const context.
|
||||
let guar =
|
||||
self.dcx().span_delayed_bug(expr.span, "struct fields have non-unique names");
|
||||
self.set_tainted_by_errors(guar);
|
||||
error_happened = true;
|
||||
}
|
||||
|
||||
// Type-check each field.
|
||||
for (idx, field) in hir_fields.iter().enumerate() {
|
||||
let ident = tcx.adjust_ident(field.ident, variant.def_id);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::callee::{self, DeferredCallResolution};
|
||||
use crate::errors::{self, CtorIsPrivate};
|
||||
use crate::method::{self, MethodCallee, SelfSource};
|
||||
use crate::method::{self, MethodCallee};
|
||||
use crate::rvalue_scopes;
|
||||
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
|
@ -16,7 +16,7 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{
|
|||
};
|
||||
use rustc_hir_analysis::hir_ty_lowering::{
|
||||
ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer,
|
||||
GenericPathSegment, HirTyLowerer, IsMethodCall,
|
||||
GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason,
|
||||
};
|
||||
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
||||
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
|
||||
|
|
@ -436,7 +436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
pub fn lower_array_length(&self, length: &hir::ArrayLen<'tcx>) -> ty::Const<'tcx> {
|
||||
match length {
|
||||
hir::ArrayLen::Infer(inf) => self.ct_infer(self.tcx.types.usize, None, inf.span),
|
||||
hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
|
||||
hir::ArrayLen::Body(anon_const) => {
|
||||
let span = self.tcx.def_span(anon_const.def_id);
|
||||
let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id);
|
||||
|
|
@ -735,7 +735,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
qpath: &'tcx QPath<'tcx>,
|
||||
hir_id: HirId,
|
||||
span: Span,
|
||||
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
||||
) -> (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) {
|
||||
debug!(
|
||||
"resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}",
|
||||
|
|
@ -828,14 +827,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
if item_name.name != kw::Empty {
|
||||
if let Some(e) = self.report_method_error(
|
||||
span,
|
||||
None,
|
||||
ty.normalized,
|
||||
item_name,
|
||||
hir_id,
|
||||
SelfSource::QPath(qself),
|
||||
ty.normalized,
|
||||
error,
|
||||
args,
|
||||
Expectation::NoExpectation,
|
||||
trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021
|
||||
) {
|
||||
|
|
@ -1072,7 +1066,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ty::ImplContainer => {
|
||||
if segments.len() == 1 {
|
||||
// `<T>::assoc` will end up here, and so
|
||||
// can `T::assoc`. It this came from an
|
||||
// can `T::assoc`. If this came from an
|
||||
// inherent impl, we need to record the
|
||||
// `T` for posterity (see `UserSelfTy` for
|
||||
// details).
|
||||
|
|
@ -1280,9 +1274,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
arg: &GenericArg<'tcx>,
|
||||
) -> ty::GenericArg<'tcx> {
|
||||
match (¶m.kind, arg) {
|
||||
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
|
||||
self.fcx.lowerer().lower_lifetime(lt, Some(param)).into()
|
||||
}
|
||||
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self
|
||||
.fcx
|
||||
.lowerer()
|
||||
.lower_lifetime(lt, RegionInferReason::Param(param))
|
||||
.into(),
|
||||
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
|
||||
self.fcx.lower_ty(ty).raw.into()
|
||||
}
|
||||
|
|
@ -1296,20 +1292,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&GenericParamDefKind::Const { has_default, is_host_effect },
|
||||
GenericArg::Infer(inf),
|
||||
) => {
|
||||
let tcx = self.fcx.tcx();
|
||||
|
||||
if has_default && is_host_effect {
|
||||
self.fcx.var_for_effect(param)
|
||||
} else {
|
||||
self.fcx
|
||||
.ct_infer(
|
||||
tcx.type_of(param.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic"),
|
||||
Some(param),
|
||||
inf.span,
|
||||
)
|
||||
.into()
|
||||
self.fcx.ct_infer(Some(param), inf.span).into()
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
|
|
@ -1324,9 +1310,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) -> ty::GenericArg<'tcx> {
|
||||
let tcx = self.fcx.tcx();
|
||||
match param.kind {
|
||||
GenericParamDefKind::Lifetime => {
|
||||
self.fcx.re_infer(Some(param), self.span).unwrap().into()
|
||||
}
|
||||
GenericParamDefKind::Lifetime => self
|
||||
.fcx
|
||||
.re_infer(
|
||||
self.span,
|
||||
rustc_hir_analysis::hir_ty_lowering::RegionInferReason::Param(param),
|
||||
)
|
||||
.into(),
|
||||
GenericParamDefKind::Type { has_default, .. } => {
|
||||
if !infer_args && has_default {
|
||||
// If we have a default, then it doesn't matter that we're not
|
||||
|
|
@ -1416,11 +1406,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) {
|
||||
Ok(ok) => self.register_infer_ok_obligations(ok),
|
||||
Err(_) => {
|
||||
self.dcx().span_delayed_bug(
|
||||
self.dcx().span_bug(
|
||||
span,
|
||||
format!(
|
||||
"instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?",
|
||||
),
|
||||
"instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use hir::def_id::CRATE_DEF_ID;
|
|||
use rustc_errors::DiagCtxt;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::infer::error_reporting::sub_relations::SubRelations;
|
||||
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
||||
|
|
@ -213,25 +213,21 @@ impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> {
|
||||
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
|
||||
impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn item_def_id(&self) -> DefId {
|
||||
self.body_id.to_def_id()
|
||||
fn item_def_id(&self) -> LocalDefId {
|
||||
self.body_id
|
||||
}
|
||||
|
||||
fn allow_infer(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
|
||||
let v = match def {
|
||||
Some(def) => infer::RegionParameterDefinition(span, def.name),
|
||||
None => infer::MiscVariable(span),
|
||||
fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
|
||||
let v = match reason {
|
||||
RegionInferReason::Param(def) => infer::RegionParameterDefinition(span, def.name),
|
||||
_ => infer::MiscVariable(span),
|
||||
};
|
||||
Some(self.next_region_var(v))
|
||||
self.next_region_var(v)
|
||||
}
|
||||
|
||||
fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
|
||||
|
|
@ -241,12 +237,7 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn ct_infer(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
param: Option<&ty::GenericParamDef>,
|
||||
span: Span,
|
||||
) -> Const<'tcx> {
|
||||
fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
|
||||
// FIXME ideally this shouldn't use unwrap
|
||||
match param {
|
||||
Some(
|
||||
|
|
@ -256,7 +247,7 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> {
|
|||
},
|
||||
) => self.var_for_effect(param).as_const().unwrap(),
|
||||
Some(param) => self.var_for_def(span, param).as_const().unwrap(),
|
||||
None => self.next_const_var(ty, span),
|
||||
None => self.next_const_var(span),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -350,6 +341,22 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> {
|
|||
fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
|
||||
self.infcx.set_tainted_by_errors(e)
|
||||
}
|
||||
|
||||
fn lower_fn_sig(
|
||||
&self,
|
||||
decl: &rustc_hir::FnDecl<'tcx>,
|
||||
_generics: Option<&rustc_hir::Generics<'_>>,
|
||||
_hir_id: rustc_hir::HirId,
|
||||
_hir_ty: Option<&hir::Ty<'_>>,
|
||||
) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
|
||||
let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_arg_ty(a, None)).collect();
|
||||
|
||||
let output_ty = match decl.output {
|
||||
hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output),
|
||||
hir::FnRetTy::DefaultReturn(..) => self.tcx().types.unit,
|
||||
};
|
||||
(input_tys, output_ty)
|
||||
}
|
||||
}
|
||||
|
||||
/// The `ty` representation of a user-provided type. Depending on the use-site
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ use rustc_hir::GenericArg;
|
|||
use rustc_hir_analysis::hir_ty_lowering::generics::{
|
||||
check_generic_arg_count_for_call, lower_generic_args,
|
||||
};
|
||||
use rustc_hir_analysis::hir_ty_lowering::{GenericArgsLowerer, HirTyLowerer, IsMethodCall};
|
||||
use rustc_hir_analysis::hir_ty_lowering::{
|
||||
GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason,
|
||||
};
|
||||
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
|
||||
use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
|
||||
|
|
@ -388,9 +390,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
arg: &GenericArg<'tcx>,
|
||||
) -> ty::GenericArg<'tcx> {
|
||||
match (¶m.kind, arg) {
|
||||
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
|
||||
self.cfcx.fcx.lowerer().lower_lifetime(lt, Some(param)).into()
|
||||
}
|
||||
(GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self
|
||||
.cfcx
|
||||
.fcx
|
||||
.lowerer()
|
||||
.lower_lifetime(lt, RegionInferReason::Param(param))
|
||||
.into(),
|
||||
(GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
|
||||
self.cfcx.lower_ty(ty).raw.into()
|
||||
}
|
||||
|
|
@ -401,16 +406,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
self.cfcx.ty_infer(Some(param), inf.span).into()
|
||||
}
|
||||
(GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
|
||||
let tcx = self.cfcx.tcx();
|
||||
self.cfcx
|
||||
.ct_infer(
|
||||
tcx.type_of(param.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic"),
|
||||
Some(param),
|
||||
inf.span,
|
||||
)
|
||||
.into()
|
||||
self.cfcx.ct_infer(Some(param), inf.span).into()
|
||||
}
|
||||
(kind, arg) => {
|
||||
bug!("mismatched method arg kind {kind:?} in turbofish: {arg:?}")
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ mod prelude_edition_lints;
|
|||
pub mod probe;
|
||||
mod suggest;
|
||||
|
||||
pub use self::suggest::SelfSource;
|
||||
pub use self::MethodError::*;
|
||||
|
||||
use crate::FnCtxt;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{
|
|||
use rustc_trait_selection::traits::query::CanonicalTyGoal;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause};
|
||||
use std::cell::Cell;
|
||||
use std::cell::RefCell;
|
||||
use std::cmp::max;
|
||||
use std::iter;
|
||||
|
|
@ -76,8 +77,12 @@ pub(crate) struct ProbeContext<'a, 'tcx> {
|
|||
/// requested name (by edit distance)
|
||||
allow_similar_names: bool,
|
||||
|
||||
/// List of potential private candidates. Will be trimmed to ones that
|
||||
/// actually apply and then the result inserted into `private_candidate`
|
||||
private_candidates: Vec<Candidate<'tcx>>,
|
||||
|
||||
/// Some(candidate) if there is a private candidate
|
||||
private_candidate: Option<(DefKind, DefId)>,
|
||||
private_candidate: Cell<Option<(DefKind, DefId)>>,
|
||||
|
||||
/// Collects near misses when the candidate functions are missing a `self` keyword and is only
|
||||
/// used for error reporting
|
||||
|
|
@ -581,7 +586,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
orig_steps_var_values,
|
||||
steps,
|
||||
allow_similar_names: false,
|
||||
private_candidate: None,
|
||||
private_candidates: Vec::new(),
|
||||
private_candidate: Cell::new(None),
|
||||
static_candidates: RefCell::new(Vec::new()),
|
||||
unsatisfied_predicates: RefCell::new(Vec::new()),
|
||||
scope_expr_id,
|
||||
|
|
@ -593,7 +599,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
self.inherent_candidates.clear();
|
||||
self.extension_candidates.clear();
|
||||
self.impl_dups.clear();
|
||||
self.private_candidate = None;
|
||||
self.private_candidates.clear();
|
||||
self.private_candidate.set(None);
|
||||
self.static_candidates.borrow_mut().clear();
|
||||
self.unsatisfied_predicates.borrow_mut().clear();
|
||||
}
|
||||
|
|
@ -617,9 +624,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
} else {
|
||||
self.extension_candidates.push(candidate);
|
||||
}
|
||||
} else if self.private_candidate.is_none() {
|
||||
self.private_candidate =
|
||||
Some((candidate.item.kind.as_def_kind(), candidate.item.def_id));
|
||||
} else {
|
||||
self.private_candidates.push(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1171,7 +1177,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
let mut possibly_unsatisfied_predicates = Vec::new();
|
||||
|
||||
for (kind, candidates) in
|
||||
&[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
|
||||
[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
|
||||
{
|
||||
debug!("searching {} candidates", kind);
|
||||
let res = self.consider_candidates(
|
||||
|
|
@ -1185,6 +1191,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if self.private_candidate.get().is_none() {
|
||||
if let Some(Ok(pick)) =
|
||||
self.consider_candidates(self_ty, &self.private_candidates, &mut vec![], None)
|
||||
{
|
||||
self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id)));
|
||||
}
|
||||
}
|
||||
|
||||
// `pick_method` may be called twice for the same self_ty if no stable methods
|
||||
// match. Only extend once.
|
||||
if unstable_candidates.is_some() {
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@ use rustc_data_structures::unord::UnordSet;
|
|||
use rustc_errors::{
|
||||
codes::*, pluralize, struct_span_code_err, Applicability, Diag, MultiSpan, StashKey,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::PathSegment;
|
||||
use rustc_hir::{self as hir, HirId};
|
||||
use rustc_hir::{ExprKind, Node, QPath};
|
||||
use rustc_infer::infer::{self, RegionVariableOrigin};
|
||||
use rustc_middle::bug;
|
||||
|
|
@ -187,37 +187,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
#[instrument(level = "debug", skip(self))]
|
||||
pub fn report_method_error(
|
||||
&self,
|
||||
span: Span,
|
||||
rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
|
||||
call_id: HirId,
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
item_name: Ident,
|
||||
expr_id: hir::HirId,
|
||||
source: SelfSource<'tcx>,
|
||||
error: MethodError<'tcx>,
|
||||
args: Option<&'tcx [hir::Expr<'tcx>]>,
|
||||
expected: Expectation<'tcx>,
|
||||
trait_missing_method: bool,
|
||||
) -> Option<Diag<'_>> {
|
||||
let (span, sugg_span, source, item_name, args) = match self.tcx.hir_node(call_id) {
|
||||
hir::Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::MethodCall(segment, rcvr, args, _),
|
||||
span,
|
||||
..
|
||||
}) => {
|
||||
(segment.ident.span, span, SelfSource::MethodCall(rcvr), segment.ident, Some(args))
|
||||
}
|
||||
hir::Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Path(QPath::TypeRelative(rcvr, segment)),
|
||||
span,
|
||||
..
|
||||
})
|
||||
| hir::Node::Pat(&hir::Pat {
|
||||
kind:
|
||||
hir::PatKind::Path(QPath::TypeRelative(rcvr, segment))
|
||||
| hir::PatKind::Struct(QPath::TypeRelative(rcvr, segment), ..)
|
||||
| hir::PatKind::TupleStruct(QPath::TypeRelative(rcvr, segment), ..),
|
||||
span,
|
||||
..
|
||||
}) => {
|
||||
let args = match self.tcx.parent_hir_node(call_id) {
|
||||
hir::Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Call(callee, args), ..
|
||||
}) if callee.hir_id == call_id => Some(args),
|
||||
_ => None,
|
||||
};
|
||||
(segment.ident.span, span, SelfSource::QPath(rcvr), segment.ident, args)
|
||||
}
|
||||
node => unreachable!("{node:?}"),
|
||||
};
|
||||
|
||||
// Avoid suggestions when we don't know what's going on.
|
||||
if rcvr_ty.references_error() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let sugg_span = if let SelfSource::MethodCall(expr) = source {
|
||||
// Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
|
||||
self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id)).span
|
||||
} else {
|
||||
span
|
||||
};
|
||||
|
||||
match error {
|
||||
MethodError::NoMatch(mut no_match_data) => {
|
||||
return self.report_no_match_method_error(
|
||||
span,
|
||||
rcvr_opt,
|
||||
rcvr_ty,
|
||||
item_name,
|
||||
expr_id,
|
||||
call_id,
|
||||
source,
|
||||
args,
|
||||
sugg_span,
|
||||
|
|
@ -362,7 +381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
pub fn suggest_use_shadowed_binding_with_method(
|
||||
&self,
|
||||
rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
|
||||
self_source: SelfSource<'tcx>,
|
||||
method_name: Ident,
|
||||
ty_str_reported: &str,
|
||||
err: &mut Diag<'_>,
|
||||
|
|
@ -502,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(rcvr) = rcvr_opt
|
||||
if let SelfSource::MethodCall(rcvr) = self_source
|
||||
&& let hir::ExprKind::Path(QPath::Resolved(_, path)) = rcvr.kind
|
||||
&& let hir::def::Res::Local(recv_id) = path.res
|
||||
&& let Some(segment) = path.segments.first()
|
||||
|
|
@ -548,7 +567,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pub fn report_no_match_method_error(
|
||||
&self,
|
||||
mut span: Span,
|
||||
rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
item_name: Ident,
|
||||
expr_id: hir::HirId,
|
||||
|
|
@ -658,7 +676,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
if is_method {
|
||||
self.suggest_use_shadowed_binding_with_method(
|
||||
rcvr_opt,
|
||||
source,
|
||||
item_name,
|
||||
&ty_str_reported,
|
||||
&mut err,
|
||||
|
|
@ -2078,9 +2096,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
|
||||
.into(),
|
||||
GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(),
|
||||
GenericArgKind::Const(arg) => {
|
||||
self.next_const_var(arg.ty(), DUMMY_SP).into()
|
||||
}
|
||||
GenericArgKind::Const(_) => self.next_const_var(DUMMY_SP).into(),
|
||||
}
|
||||
} else {
|
||||
arg
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_infer::infer;
|
|||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
||||
use rustc_session::{lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS, parse::feature_err};
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::source_map::Spanned;
|
||||
|
|
@ -223,9 +223,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info;
|
||||
|
||||
let path_res = match &pat.kind {
|
||||
PatKind::Path(qpath) => Some(
|
||||
self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None),
|
||||
),
|
||||
PatKind::Path(qpath) => {
|
||||
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
|
||||
|
|
@ -335,9 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
match adjust_mode {
|
||||
AdjustMode::Pass => (expected, def_br, max_ref_mutbl),
|
||||
AdjustMode::Reset => (expected, ByRef::No, MutblCap::Mut),
|
||||
AdjustMode::Peel => {
|
||||
self.peel_off_references(pat, expected, def_br, Mutability::Mut, max_ref_mutbl)
|
||||
}
|
||||
AdjustMode::Peel => self.peel_off_references(pat, expected, def_br, max_ref_mutbl),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -408,8 +406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pat: &'tcx Pat<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
mut def_br: ByRef,
|
||||
max_peelable_mutability: Mutability,
|
||||
mut max_ref_mutability: MutblCap,
|
||||
mut max_ref_mutbl: MutblCap,
|
||||
) -> (Ty<'tcx>, ByRef, MutblCap) {
|
||||
let mut expected = self.try_structurally_resolve_type(pat.span, expected);
|
||||
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
|
||||
|
|
@ -421,9 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
//
|
||||
// See the examples in `ui/match-defbm*.rs`.
|
||||
let mut pat_adjustments = vec![];
|
||||
while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind()
|
||||
&& inner_mutability <= max_peelable_mutability
|
||||
{
|
||||
while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() {
|
||||
debug!("inspecting {:?}", expected);
|
||||
|
||||
debug!("current discriminant is Ref, inserting implicit deref");
|
||||
|
|
@ -443,10 +438,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
|
||||
def_br = def_br.cap_ref_mutability(max_ref_mutability.as_mutbl());
|
||||
if self.tcx.features().ref_pat_eat_one_layer_2024 {
|
||||
def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl());
|
||||
if def_br == ByRef::Yes(Mutability::Not) {
|
||||
max_ref_mutability = MutblCap::Not;
|
||||
max_ref_mutbl = MutblCap::Not;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -458,7 +453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.insert(pat.hir_id, pat_adjustments);
|
||||
}
|
||||
|
||||
(expected, def_br, max_ref_mutability)
|
||||
(expected, def_br, max_ref_mutbl)
|
||||
}
|
||||
|
||||
fn check_pat_lit(
|
||||
|
|
@ -674,17 +669,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Determine the binding mode...
|
||||
let bm = match user_bind_annot {
|
||||
// `mut` resets binding mode on edition <= 2021
|
||||
BindingMode(ByRef::No, Mutability::Mut)
|
||||
if !(pat.span.at_least_rust_2024()
|
||||
&& self.tcx.features().mut_preserve_binding_mode_2024)
|
||||
&& matches!(def_br, ByRef::Yes(_)) =>
|
||||
{
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.rust_2024_migration_desugared_pats_mut()
|
||||
.insert(pat_info.top_info.hir_id);
|
||||
BindingMode(ByRef::No, Mutability::Mut)
|
||||
BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
|
||||
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
|
||||
if !self.tcx.features().mut_ref {
|
||||
feature_err(
|
||||
&self.tcx.sess,
|
||||
sym::mut_ref,
|
||||
pat.span.until(ident.span),
|
||||
"binding cannot be both mutable and by-reference",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
BindingMode(def_br, Mutability::Mut)
|
||||
} else {
|
||||
// `mut` resets binding mode on edition <= 2021
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.rust_2024_migration_desugared_pats_mut()
|
||||
.insert(pat_info.top_info.hir_id);
|
||||
BindingMode(ByRef::No, Mutability::Mut)
|
||||
}
|
||||
}
|
||||
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
|
||||
BindingMode(ByRef::Yes(_), _) => user_bind_annot,
|
||||
|
|
@ -1184,7 +1189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Resolve the path and check the definition for errors.
|
||||
let (res, opt_ty, segments) =
|
||||
self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None);
|
||||
self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
|
||||
if res == Res::Err {
|
||||
let e = tcx.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
|
||||
self.set_tainted_by_errors(e);
|
||||
|
|
@ -2126,57 +2131,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
mut expected: Ty<'tcx>,
|
||||
mut pat_info: PatInfo<'tcx, '_>,
|
||||
) -> Ty<'tcx> {
|
||||
// FIXME: repace with `bool` once final decision on 1 vs 2 layers is made
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum MatchErgonomicsMode {
|
||||
EatOneLayer,
|
||||
EatTwoLayers,
|
||||
Legacy,
|
||||
}
|
||||
let no_ref_mut_behind_and = self.tcx.features().ref_pat_eat_one_layer_2024;
|
||||
let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and;
|
||||
|
||||
let match_ergonomics_mode =
|
||||
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
|
||||
MatchErgonomicsMode::EatOneLayer
|
||||
} else if self.tcx.features().ref_pat_everywhere {
|
||||
MatchErgonomicsMode::EatTwoLayers
|
||||
} else {
|
||||
MatchErgonomicsMode::Legacy
|
||||
};
|
||||
let pat_prefix_span =
|
||||
inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end));
|
||||
|
||||
let mut inherited_ref_mutbl_match = false;
|
||||
if match_ergonomics_mode != MatchErgonomicsMode::Legacy {
|
||||
if no_ref_mut_behind_and {
|
||||
if pat_mutbl == Mutability::Not {
|
||||
// Prevent the inner pattern from binding with `ref mut`.
|
||||
pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(
|
||||
inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)),
|
||||
);
|
||||
pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span);
|
||||
}
|
||||
} else {
|
||||
pat_info.max_ref_mutbl = MutblCap::Mut;
|
||||
}
|
||||
|
||||
if new_match_ergonomics {
|
||||
if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
|
||||
inherited_ref_mutbl_match = pat_mutbl <= inh_mut;
|
||||
}
|
||||
// ref pattern consumes inherited reference
|
||||
|
||||
if inherited_ref_mutbl_match {
|
||||
pat_info.binding_mode = ByRef::No;
|
||||
if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer {
|
||||
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
|
||||
self.check_pat(inner, expected, pat_info);
|
||||
return expected;
|
||||
if pat_mutbl > inh_mut {
|
||||
// Tried to match inherited `ref` with `&mut`, which is an error
|
||||
let err_msg = "cannot match inherited `&` with `&mut` pattern";
|
||||
let err = if let Some(span) = pat_prefix_span {
|
||||
let mut err = self.dcx().struct_span_err(span, err_msg);
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
"replace this `&mut` pattern with `&`",
|
||||
"&",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err
|
||||
} else {
|
||||
self.dcx().struct_span_err(pat.span, err_msg)
|
||||
};
|
||||
err.emit();
|
||||
}
|
||||
} else if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer
|
||||
&& pat_mutbl == Mutability::Mut
|
||||
{
|
||||
// `&mut` patterns pell off `&` references
|
||||
let (new_expected, new_bm, max_ref_mutbl) = self.peel_off_references(
|
||||
pat,
|
||||
expected,
|
||||
pat_info.binding_mode,
|
||||
Mutability::Not,
|
||||
pat_info.max_ref_mutbl,
|
||||
);
|
||||
expected = new_expected;
|
||||
pat_info.binding_mode = new_bm;
|
||||
pat_info.max_ref_mutbl = max_ref_mutbl;
|
||||
|
||||
pat_info.binding_mode = ByRef::No;
|
||||
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
|
||||
self.check_pat(inner, expected, pat_info);
|
||||
return expected;
|
||||
}
|
||||
} else {
|
||||
// Reset binding mode on old editions
|
||||
|
|
@ -2189,8 +2184,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.rust_2024_migration_desugared_pats_mut()
|
||||
.insert(pat_info.top_info.hir_id);
|
||||
}
|
||||
|
||||
pat_info.max_ref_mutbl = MutblCap::Mut;
|
||||
}
|
||||
|
||||
let tcx = self.tcx;
|
||||
|
|
@ -2205,34 +2198,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// the bad interactions of the given hack detailed in (note_1).
|
||||
debug!("check_pat_ref: expected={:?}", expected);
|
||||
match *expected.kind() {
|
||||
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == pat_mutbl => {
|
||||
if r_mutbl == Mutability::Not
|
||||
&& match_ergonomics_mode != MatchErgonomicsMode::Legacy
|
||||
{
|
||||
ty::Ref(_, r_ty, r_mutbl)
|
||||
if (new_match_ergonomics && r_mutbl >= pat_mutbl)
|
||||
|| r_mutbl == pat_mutbl =>
|
||||
{
|
||||
if no_ref_mut_behind_and && r_mutbl == Mutability::Not {
|
||||
pat_info.max_ref_mutbl = MutblCap::Not;
|
||||
}
|
||||
|
||||
(expected, r_ty)
|
||||
}
|
||||
|
||||
// `&` pattern eats `&mut` reference
|
||||
ty::Ref(_, r_ty, Mutability::Mut)
|
||||
if pat_mutbl == Mutability::Not
|
||||
&& match_ergonomics_mode != MatchErgonomicsMode::Legacy =>
|
||||
{
|
||||
(expected, r_ty)
|
||||
}
|
||||
|
||||
_ if inherited_ref_mutbl_match
|
||||
&& match_ergonomics_mode == MatchErgonomicsMode::EatTwoLayers =>
|
||||
{
|
||||
// We already matched against a match-ergonmics inserted reference,
|
||||
// so we don't need to match against a reference from the original type.
|
||||
// Save this info for use in lowering later
|
||||
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
|
||||
(expected, expected)
|
||||
}
|
||||
|
||||
_ => {
|
||||
let inner_ty = self.next_ty_var(inner.span);
|
||||
let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty);
|
||||
|
|
@ -2409,7 +2385,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
min_len: u64,
|
||||
) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
|
||||
let len = match len.eval(self.tcx, self.param_env, span) {
|
||||
Ok(val) => val
|
||||
// FIXME(BoxyUwU): Assert the `Ty` is a `usize`?
|
||||
Ok((_, val)) => val
|
||||
.try_to_scalar()
|
||||
.and_then(|scalar| scalar.try_to_int().ok())
|
||||
.and_then(|int| int.try_to_target_usize(self.tcx).ok()),
|
||||
|
|
|
|||
|
|
@ -863,7 +863,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
|
|||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
self.handle_term(ct, ty::Const::outer_exclusive_binder, |tcx, guar| {
|
||||
ty::Const::new_error(tcx, guar, ct.ty())
|
||||
ty::Const::new_error(tcx, guar)
|
||||
})
|
||||
.super_fold_with(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -462,7 +462,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
// any equated inference vars correctly!
|
||||
let root_vid = self.infcx.unwrap().root_const_var(vid);
|
||||
if root_vid != vid {
|
||||
ct = ty::Const::new_var(self.tcx, root_vid, ct.ty());
|
||||
ct = ty::Const::new_var(self.tcx, root_vid);
|
||||
vid = root_vid;
|
||||
}
|
||||
|
||||
|
|
@ -481,7 +481,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
ui = ty::UniverseIndex::ROOT;
|
||||
}
|
||||
return self.canonicalize_const_var(
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty()) },
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
|
||||
ct,
|
||||
);
|
||||
}
|
||||
|
|
@ -510,9 +510,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
}
|
||||
ty::ConstKind::Placeholder(placeholder) => {
|
||||
return self.canonicalize_const_var(
|
||||
CanonicalVarInfo {
|
||||
kind: CanonicalVarKind::PlaceholderConst(placeholder, ct.ty()),
|
||||
},
|
||||
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) },
|
||||
ct,
|
||||
);
|
||||
}
|
||||
|
|
@ -719,9 +717,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
CanonicalVarKind::Region(u) => {
|
||||
CanonicalVarKind::Region(reverse_universe_map[&u])
|
||||
}
|
||||
CanonicalVarKind::Const(u, t) => {
|
||||
CanonicalVarKind::Const(reverse_universe_map[&u], t)
|
||||
}
|
||||
CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]),
|
||||
CanonicalVarKind::PlaceholderTy(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderTy(ty::Placeholder {
|
||||
universe: reverse_universe_map[&placeholder.universe],
|
||||
|
|
@ -734,14 +730,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
..placeholder
|
||||
})
|
||||
}
|
||||
CanonicalVarKind::PlaceholderConst(placeholder, t) => {
|
||||
CanonicalVarKind::PlaceholderConst(
|
||||
ty::Placeholder {
|
||||
universe: reverse_universe_map[&placeholder.universe],
|
||||
..placeholder
|
||||
},
|
||||
t,
|
||||
)
|
||||
CanonicalVarKind::PlaceholderConst(placeholder) => {
|
||||
CanonicalVarKind::PlaceholderConst(ty::Placeholder {
|
||||
universe: reverse_universe_map[&placeholder.universe],
|
||||
..placeholder
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
|
|
@ -806,6 +799,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
|||
!self.infcx.is_some_and(|infcx| const_var != infcx.shallow_resolve_const(const_var))
|
||||
);
|
||||
let var = self.canonical_var(info, const_var.into());
|
||||
ty::Const::new_bound(self.tcx, self.binder_index, var, self.fold_ty(const_var.ty()))
|
||||
ty::Const::new_bound(self.tcx, self.binder_index, var)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ where
|
|||
GenericArgKind::Type(ty) => ty,
|
||||
r => bug!("{:?} is a type but value is {:?}", bound_ty, r),
|
||||
},
|
||||
consts: &mut |bound_ct: ty::BoundVar, _| match var_values[bound_ct].unpack() {
|
||||
consts: &mut |bound_ct: ty::BoundVar| match var_values[bound_ct].unpack() {
|
||||
GenericArgKind::Const(ct) => ct,
|
||||
c => bug!("{:?} is a const but value is {:?}", bound_ct, c),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -143,8 +143,8 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
ty::Region::new_placeholder(self.tcx, placeholder_mapped).into()
|
||||
}
|
||||
|
||||
CanonicalVarKind::Const(ui, ty) => {
|
||||
self.next_const_var_in_universe(ty, span, universe_map(ui)).into()
|
||||
CanonicalVarKind::Const(ui) => {
|
||||
self.next_const_var_in_universe(span, universe_map(ui)).into()
|
||||
}
|
||||
CanonicalVarKind::Effect => {
|
||||
let vid = self
|
||||
|
|
@ -153,13 +153,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
.effect_unification_table()
|
||||
.new_key(EffectVarValue::Unknown)
|
||||
.vid;
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool)
|
||||
.into()
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid)).into()
|
||||
}
|
||||
CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }, ty) => {
|
||||
CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }) => {
|
||||
let universe_mapped = universe_map(universe);
|
||||
let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound };
|
||||
ty::Const::new_placeholder(self.tcx, placeholder_mapped, ty).into()
|
||||
ty::Const::new_placeholder(self.tcx, placeholder_mapped).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -543,9 +543,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
match arg.unpack() {
|
||||
GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
|
||||
GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(),
|
||||
GenericArgKind::Const(arg) => {
|
||||
self.next_const_var(arg.ty(), DUMMY_SP).into()
|
||||
}
|
||||
GenericArgKind::Const(_) => self.next_const_var(DUMMY_SP).into(),
|
||||
}
|
||||
}))
|
||||
.unwrap();
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
|
|||
&mut self,
|
||||
input: Result<ty::Const<'tcx>, ty::InferConst>,
|
||||
freshener: F,
|
||||
ty: Ty<'tcx>,
|
||||
) -> ty::Const<'tcx>
|
||||
where
|
||||
F: FnOnce(u32) -> ty::InferConst,
|
||||
|
|
@ -91,7 +90,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
|
|||
Entry::Vacant(entry) => {
|
||||
let index = self.const_freshen_count;
|
||||
self.const_freshen_count += 1;
|
||||
let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index), ty);
|
||||
let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index));
|
||||
entry.insert(ct);
|
||||
ct
|
||||
}
|
||||
|
|
@ -149,7 +148,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
|
|||
ty::InferConst::Var(inner.const_unification_table().find(v).vid)
|
||||
});
|
||||
drop(inner);
|
||||
self.freshen_const(input, ty::InferConst::Fresh, ct.ty())
|
||||
self.freshen_const(input, ty::InferConst::Fresh)
|
||||
}
|
||||
ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
|
|
@ -158,7 +157,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
|
|||
ty::InferConst::EffectVar(inner.effect_unification_table().find(v).vid)
|
||||
});
|
||||
drop(inner);
|
||||
self.freshen_const(input, ty::InferConst::Fresh, ct.ty())
|
||||
self.freshen_const(input, ty::InferConst::Fresh)
|
||||
}
|
||||
ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
|
||||
if i >= self.const_freshen_count {
|
||||
|
|
@ -177,7 +176,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
|
|||
}
|
||||
|
||||
ty::ConstKind::Param(_)
|
||||
| ty::ConstKind::Value(_)
|
||||
| ty::ConstKind::Value(_, _)
|
||||
| ty::ConstKind::Unevaluated(..)
|
||||
| ty::ConstKind::Expr(..)
|
||||
| ty::ConstKind::Error(_) => ct.super_fold_with(self),
|
||||
|
|
|
|||
|
|
@ -392,18 +392,18 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
|
|||
self.opportunistic_resolve_float_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ct_var(&self, vid: ConstVid, ty: Ty<'tcx>) -> ty::Const<'tcx> {
|
||||
fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> ty::Const<'tcx> {
|
||||
match self.probe_const_var(vid) {
|
||||
Ok(ct) => ct,
|
||||
Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid), ty),
|
||||
Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_effect_var(&self, vid: EffectVid, ty: Ty<'tcx>) -> ty::Const<'tcx> {
|
||||
fn opportunistic_resolve_effect_var(&self, vid: EffectVid) -> ty::Const<'tcx> {
|
||||
match self.probe_effect_var(vid) {
|
||||
Some(ct) => ct,
|
||||
None => {
|
||||
ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid)), ty)
|
||||
ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -832,9 +832,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
(0..table.len())
|
||||
.map(|i| ty::EffectVid::from_usize(i))
|
||||
.filter(|&vid| table.probe_value(vid).is_unknown())
|
||||
.map(|v| {
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool)
|
||||
})
|
||||
.map(|v| ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
|
@ -993,27 +991,22 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
Ty::new_var(self.tcx, vid)
|
||||
}
|
||||
|
||||
pub fn next_const_var(&self, ty: Ty<'tcx>, span: Span) -> ty::Const<'tcx> {
|
||||
self.next_const_var_with_origin(ty, ConstVariableOrigin { span, param_def_id: None })
|
||||
pub fn next_const_var(&self, span: Span) -> ty::Const<'tcx> {
|
||||
self.next_const_var_with_origin(ConstVariableOrigin { span, param_def_id: None })
|
||||
}
|
||||
|
||||
pub fn next_const_var_with_origin(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
origin: ConstVariableOrigin,
|
||||
) -> ty::Const<'tcx> {
|
||||
pub fn next_const_var_with_origin(&self, origin: ConstVariableOrigin) -> ty::Const<'tcx> {
|
||||
let vid = self
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.const_unification_table()
|
||||
.new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
|
||||
.vid;
|
||||
ty::Const::new_var(self.tcx, vid, ty)
|
||||
ty::Const::new_var(self.tcx, vid)
|
||||
}
|
||||
|
||||
pub fn next_const_var_in_universe(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
universe: ty::UniverseIndex,
|
||||
) -> ty::Const<'tcx> {
|
||||
|
|
@ -1024,7 +1017,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
.const_unification_table()
|
||||
.new_key(ConstVariableValue::Unknown { origin, universe })
|
||||
.vid;
|
||||
ty::Const::new_var(self.tcx, vid, ty)
|
||||
ty::Const::new_var(self.tcx, vid)
|
||||
}
|
||||
|
||||
pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid {
|
||||
|
|
@ -1135,15 +1128,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
.const_unification_table()
|
||||
.new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
|
||||
.vid;
|
||||
ty::Const::new_var(
|
||||
self.tcx,
|
||||
const_var_id,
|
||||
self.tcx
|
||||
.type_of(param.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic"),
|
||||
)
|
||||
.into()
|
||||
ty::Const::new_var(self.tcx, const_var_id).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1157,7 +1142,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic");
|
||||
debug_assert_eq!(self.tcx.types.bool, ty);
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid), ty).into()
|
||||
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid)).into()
|
||||
}
|
||||
|
||||
/// Given a set of generics defined on a type or impl, returns the generic parameters mapping each
|
||||
|
|
@ -1314,7 +1299,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
| ty::ConstKind::Bound(_, _)
|
||||
| ty::ConstKind::Placeholder(_)
|
||||
| ty::ConstKind::Unevaluated(_)
|
||||
| ty::ConstKind::Value(_)
|
||||
| ty::ConstKind::Value(_, _)
|
||||
| ty::ConstKind::Error(_)
|
||||
| ty::ConstKind::Expr(_) => ct,
|
||||
}
|
||||
|
|
@ -1469,10 +1454,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
.or_insert_with(|| self.infcx.next_ty_var(self.span).into())
|
||||
.expect_ty()
|
||||
}
|
||||
fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> {
|
||||
fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> {
|
||||
self.map
|
||||
.entry(bv)
|
||||
.or_insert_with(|| self.infcx.next_const_var(ty, self.span).into())
|
||||
.or_insert_with(|| self.infcx.next_const_var(self.span).into())
|
||||
.expect_const()
|
||||
}
|
||||
}
|
||||
|
|
@ -1526,11 +1511,14 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
unevaluated: ty::UnevaluatedConst<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Result<ty::Const<'tcx>, ErrorHandled> {
|
||||
match self.const_eval_resolve(param_env, unevaluated, span) {
|
||||
Ok(Some(val)) => Ok(ty::Const::new_value(self.tcx, val, ty)),
|
||||
Ok(Some(val)) => Ok(ty::Const::new_value(
|
||||
self.tcx,
|
||||
val,
|
||||
self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args),
|
||||
)),
|
||||
Ok(None) => {
|
||||
let tcx = self.tcx;
|
||||
let def_id = unevaluated.def;
|
||||
|
|
@ -1964,11 +1952,6 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>(
|
|||
|
||||
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
if let ty::ConstKind::Infer(_) = c.kind() {
|
||||
let ty = c.ty();
|
||||
// If the type references param or infer then ICE ICE ICE
|
||||
if ty.has_non_region_param() || ty.has_non_region_infer() {
|
||||
bug!("const `{c}`'s type should not reference params or types");
|
||||
}
|
||||
ty::Const::new_placeholder(
|
||||
self.tcx,
|
||||
ty::PlaceholderConst {
|
||||
|
|
@ -1979,7 +1962,6 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>(
|
|||
idx
|
||||
}),
|
||||
},
|
||||
ty,
|
||||
)
|
||||
} else {
|
||||
c.super_fold_with(self)
|
||||
|
|
|
|||
|
|
@ -329,6 +329,14 @@ impl<'tcx> Generalizer<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a new type variable in the universe of the target when
|
||||
/// generalizing an alias. This has to set `has_unconstrained_ty_var`
|
||||
/// if we're currently in a bivariant context.
|
||||
fn next_ty_var_for_alias(&mut self) -> Ty<'tcx> {
|
||||
self.has_unconstrained_ty_var |= self.ambient_variance == ty::Bivariant;
|
||||
self.infcx.next_ty_var_in_universe(self.span, self.for_universe)
|
||||
}
|
||||
|
||||
/// An occurs check failure inside of an alias does not mean
|
||||
/// that the types definitely don't unify. We may be able
|
||||
/// to normalize the alias after all.
|
||||
|
|
@ -358,7 +366,7 @@ impl<'tcx> Generalizer<'_, 'tcx> {
|
|||
//
|
||||
// cc trait-system-refactor-initiative#110
|
||||
if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias {
|
||||
return Ok(self.infcx.next_ty_var_in_universe(self.span, self.for_universe));
|
||||
return Ok(self.next_ty_var_for_alias());
|
||||
}
|
||||
|
||||
let is_nested_alias = mem::replace(&mut self.in_alias, true);
|
||||
|
|
@ -378,7 +386,7 @@ impl<'tcx> Generalizer<'_, 'tcx> {
|
|||
}
|
||||
|
||||
debug!("generalization failure in alias");
|
||||
Ok(self.infcx.next_ty_var_in_universe(self.span, self.for_universe))
|
||||
Ok(self.next_ty_var_for_alias())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -645,7 +653,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||
{
|
||||
variable_table.union(vid, new_var_id);
|
||||
}
|
||||
Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty()))
|
||||
Ok(ty::Const::new_var(self.tcx(), new_var_id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -663,11 +671,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||
args,
|
||||
args,
|
||||
)?;
|
||||
Ok(ty::Const::new_unevaluated(
|
||||
self.tcx(),
|
||||
ty::UnevaluatedConst { def, args },
|
||||
c.ty(),
|
||||
))
|
||||
Ok(ty::Const::new_unevaluated(self.tcx(), ty::UnevaluatedConst { def, args }))
|
||||
}
|
||||
ty::ConstKind::Placeholder(placeholder) => {
|
||||
if self.for_universe.can_name(placeholder.universe) {
|
||||
|
|
|
|||
|
|
@ -43,11 +43,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
ty::PlaceholderType { universe: next_universe, bound: bound_ty },
|
||||
)
|
||||
},
|
||||
consts: &mut |bound_var: ty::BoundVar, ty| {
|
||||
consts: &mut |bound_var: ty::BoundVar| {
|
||||
ty::Const::new_placeholder(
|
||||
self.tcx,
|
||||
ty::PlaceholderConst { universe: next_universe, bound: bound_var },
|
||||
ty,
|
||||
)
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
|
|||
// Recreate it with a fresh variable here.
|
||||
let idx = vid.index() - self.const_vars.0.start.index();
|
||||
let origin = self.const_vars.1[idx];
|
||||
self.infcx.next_const_var_with_origin(ct.ty(), origin)
|
||||
self.infcx.next_const_var_with_origin(origin)
|
||||
} else {
|
||||
ct
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use rustc_lint::LintStore;
|
|||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::CurrentGcx;
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_parse::maybe_new_parser_from_source_str;
|
||||
use rustc_parse::new_parser_from_source_str;
|
||||
use rustc_query_impl::QueryCtxt;
|
||||
use rustc_query_system::query::print_query_stack;
|
||||
use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName};
|
||||
|
|
@ -67,7 +67,7 @@ pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg {
|
|||
};
|
||||
}
|
||||
|
||||
match maybe_new_parser_from_source_str(&psess, filename, s.to_string()) {
|
||||
match new_parser_from_source_str(&psess, filename, s.to_string()) {
|
||||
Ok(mut parser) => match parser.parse_meta_item() {
|
||||
Ok(meta_item) if parser.token == token::Eof => {
|
||||
if meta_item.path.segments.len() != 1 {
|
||||
|
|
@ -166,7 +166,7 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg {
|
|||
error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`")
|
||||
};
|
||||
|
||||
let mut parser = match maybe_new_parser_from_source_str(&psess, filename, s.to_string()) {
|
||||
let mut parser = match new_parser_from_source_str(&psess, filename, s.to_string()) {
|
||||
Ok(parser) => parser,
|
||||
Err(errs) => {
|
||||
errs.into_iter().for_each(|err| err.cancel());
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ use rustc_middle::arena::Arena;
|
|||
use rustc_middle::dep_graph::DepGraph;
|
||||
use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt};
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
|
||||
use rustc_parse::{
|
||||
new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr,
|
||||
};
|
||||
use rustc_passes::{abi_test, hir_stats, layout_test};
|
||||
use rustc_resolve::Resolver;
|
||||
use rustc_session::code_stats::VTableSizeInfo;
|
||||
|
|
@ -42,11 +44,14 @@ use std::{env, fs, iter};
|
|||
use tracing::{info, instrument};
|
||||
|
||||
pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> {
|
||||
let krate = sess.time("parse_crate", || match &sess.io.input {
|
||||
Input::File(file) => parse_crate_from_file(file, &sess.psess),
|
||||
Input::Str { input, name } => {
|
||||
parse_crate_from_source_str(name.clone(), input.clone(), &sess.psess)
|
||||
}
|
||||
let 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())
|
||||
}
|
||||
});
|
||||
parser.parse_crate_mod()
|
||||
})?;
|
||||
|
||||
if sess.opts.unstable_opts.input_stats {
|
||||
|
|
@ -459,7 +464,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||
}
|
||||
}
|
||||
|
||||
for &cnum in tcx.crates_including_speculative(()) {
|
||||
for &cnum in tcx.crates(()) {
|
||||
let source = tcx.used_crate_source(cnum);
|
||||
if let Some((path, _)) = &source.dylib {
|
||||
files.push(escape_dep_filename(&path.display().to_string()));
|
||||
|
|
|
|||
|
|
@ -462,6 +462,9 @@ lint_metavariable_wrong_operator = meta-variable repeats with different Kleene o
|
|||
|
||||
lint_missing_fragment_specifier = missing fragment specifier
|
||||
|
||||
lint_missing_unsafe_on_extern = extern blocks should be unsafe
|
||||
.suggestion = needs `unsafe` before the extern keyword
|
||||
|
||||
lint_mixed_script_confusables =
|
||||
the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables
|
||||
.includes_note = the usage includes {$includes}
|
||||
|
|
@ -635,9 +638,6 @@ lint_pattern_in_foreign = patterns aren't allowed in foreign function declaratio
|
|||
lint_private_extern_crate_reexport =
|
||||
extern crate `{$ident}` is private, and cannot be re-exported, consider declaring with `pub`
|
||||
|
||||
lint_proc_macro_back_compat = using an old version of `{$crate_name}`
|
||||
.note = older versions of the `{$crate_name}` crate will stop compiling in future versions of Rust; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives
|
||||
|
||||
lint_proc_macro_derive_resolution_fallback = cannot find {$ns} `{$ident}` in this scope
|
||||
.label = names from parent modules are not accessible without an explicit import
|
||||
|
||||
|
|
|
|||
|
|
@ -159,9 +159,6 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
|
|||
BuiltinLintDiag::LegacyDeriveHelpers(label_span) => {
|
||||
lints::LegacyDeriveHelpers { span: label_span }.decorate_lint(diag);
|
||||
}
|
||||
BuiltinLintDiag::ProcMacroBackCompat { crate_name, fixed_version } => {
|
||||
lints::ProcMacroBackCompat { crate_name, fixed_version }.decorate_lint(diag);
|
||||
}
|
||||
BuiltinLintDiag::OrPatternsBackCompat(suggestion_span, suggestion) => {
|
||||
lints::OrPatternsBackCompat { span: suggestion_span, suggestion }.decorate_lint(diag);
|
||||
}
|
||||
|
|
@ -205,6 +202,9 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
|
|||
};
|
||||
lints::DeprecatedWhereClauseLocation { suggestion }.decorate_lint(diag);
|
||||
}
|
||||
BuiltinLintDiag::MissingUnsafeOnExtern { suggestion } => {
|
||||
lints::MissingUnsafeOnExtern { suggestion }.decorate_lint(diag);
|
||||
}
|
||||
BuiltinLintDiag::SingleUseLifetime {
|
||||
param_span,
|
||||
use_span: Some((use_span, elide)),
|
||||
|
|
|
|||
|
|
@ -2649,14 +2649,6 @@ pub struct LegacyDeriveHelpers {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_proc_macro_back_compat)]
|
||||
#[note]
|
||||
pub struct ProcMacroBackCompat {
|
||||
pub crate_name: String,
|
||||
pub fixed_version: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_or_patterns_back_compat)]
|
||||
pub struct OrPatternsBackCompat {
|
||||
|
|
@ -2738,6 +2730,13 @@ pub enum DeprecatedWhereClauseLocationSugg {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_missing_unsafe_on_extern)]
|
||||
pub struct MissingUnsafeOnExtern {
|
||||
#[suggestion(code = "unsafe ", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_single_use_lifetime)]
|
||||
pub struct SingleUseLifetime {
|
||||
|
|
|
|||
|
|
@ -1741,13 +1741,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations {
|
|||
let abi = cx.tcx.hir().get_foreign_abi(it.hir_id());
|
||||
|
||||
match it.kind {
|
||||
hir::ForeignItemKind::Fn(decl, _, _) if !vis.is_internal_abi(abi) => {
|
||||
hir::ForeignItemKind::Fn(decl, _, _, _) if !vis.is_internal_abi(abi) => {
|
||||
vis.check_foreign_fn(it.owner_id.def_id, decl);
|
||||
}
|
||||
hir::ForeignItemKind::Static(ty, _) if !vis.is_internal_abi(abi) => {
|
||||
hir::ForeignItemKind::Static(ty, _, _) if !vis.is_internal_abi(abi) => {
|
||||
vis.check_foreign_static(it.owner_id, ty.span);
|
||||
}
|
||||
hir::ForeignItemKind::Fn(decl, _, _) => vis.check_fn(it.owner_id.def_id, decl),
|
||||
hir::ForeignItemKind::Fn(decl, _, _, _) => vis.check_fn(it.owner_id.def_id, decl),
|
||||
hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ declare_lint_pass! {
|
|||
META_VARIABLE_MISUSE,
|
||||
MISSING_ABI,
|
||||
MISSING_FRAGMENT_SPECIFIER,
|
||||
MISSING_UNSAFE_ON_EXTERN,
|
||||
MUST_NOT_SUSPEND,
|
||||
NAMED_ARGUMENTS_USED_POSITIONALLY,
|
||||
NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
|
||||
|
|
@ -76,7 +77,6 @@ declare_lint_pass! {
|
|||
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
PRIVATE_BOUNDS,
|
||||
PRIVATE_INTERFACES,
|
||||
PROC_MACRO_BACK_COMPAT,
|
||||
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
|
||||
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
||||
REDUNDANT_LIFETIMES,
|
||||
|
|
@ -3664,53 +3664,6 @@ declare_lint! {
|
|||
"detects invalid `#[doc(...)]` attributes",
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `proc_macro_back_compat` lint detects uses of old versions of certain
|
||||
/// proc-macro crates, which have hardcoded workarounds in the compiler.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,ignore (needs-dependency)
|
||||
///
|
||||
/// use time_macros_impl::impl_macros;
|
||||
/// struct Foo;
|
||||
/// impl_macros!(Foo);
|
||||
/// ```
|
||||
///
|
||||
/// This will produce:
|
||||
///
|
||||
/// ```text
|
||||
/// warning: using an old version of `time-macros-impl`
|
||||
/// ::: $DIR/group-compat-hack.rs:27:5
|
||||
/// |
|
||||
/// LL | impl_macros!(Foo);
|
||||
/// | ------------------ in this macro invocation
|
||||
/// |
|
||||
/// = note: `#[warn(proc_macro_back_compat)]` on by default
|
||||
/// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
/// = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
|
||||
/// = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
|
||||
/// = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
/// ```
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Eventually, the backwards-compatibility hacks present in the compiler will be removed,
|
||||
/// causing older versions of certain crates to stop compiling.
|
||||
/// This is a [future-incompatible] lint to ease the transition to an error.
|
||||
/// See [issue #83125] for more details.
|
||||
///
|
||||
/// [issue #83125]: https://github.com/rust-lang/rust/issues/83125
|
||||
/// [future-incompatible]: ../index.md#future-incompatible-lints
|
||||
pub PROC_MACRO_BACK_COMPAT,
|
||||
Deny,
|
||||
"detects usage of old versions of certain proc-macro crates",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
|
||||
reference: "issue #83125 <https://github.com/rust-lang/rust/issues/83125>",
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `rust_2021_incompatible_or_patterns` lint detects usage of old versions of or-patterns.
|
||||
///
|
||||
|
|
@ -4851,3 +4804,40 @@ declare_lint! {
|
|||
reference: "issue #27970 <https://github.com/rust-lang/rust/issues/27970>",
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `missing_unsafe_on_extern` lint detects missing unsafe keyword on extern declarations.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(unsafe_extern_blocks)]
|
||||
/// #![warn(missing_unsafe_on_extern)]
|
||||
/// #![allow(dead_code)]
|
||||
///
|
||||
/// extern "C" {
|
||||
/// fn foo(_: i32);
|
||||
/// }
|
||||
///
|
||||
/// fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Declaring extern items, even without ever using them, can cause Undefined Behavior. We
|
||||
/// should consider all sources of Undefined Behavior to be unsafe.
|
||||
///
|
||||
/// This is a [future-incompatible] lint to transition this to a
|
||||
/// hard error in the future.
|
||||
///
|
||||
/// [future-incompatible]: ../index.md#future-incompatible-lints
|
||||
pub MISSING_UNSAFE_ON_EXTERN,
|
||||
Allow,
|
||||
"detects missing unsafe keyword on extern declarations",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
|
||||
reference: "issue #123743 <https://github.com/rust-lang/rust/issues/123743>",
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -618,10 +618,6 @@ pub enum BuiltinLintDiag {
|
|||
is_foreign: bool,
|
||||
},
|
||||
LegacyDeriveHelpers(Span),
|
||||
ProcMacroBackCompat {
|
||||
crate_name: String,
|
||||
fixed_version: String,
|
||||
},
|
||||
OrPatternsBackCompat(Span, String),
|
||||
ReservedPrefix(Span, String),
|
||||
TrailingMacro(bool, Ident),
|
||||
|
|
@ -630,6 +626,9 @@ pub enum BuiltinLintDiag {
|
|||
UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
|
||||
UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
|
||||
DeprecatedWhereclauseLocation(Span, Option<(Span, String)>),
|
||||
MissingUnsafeOnExtern {
|
||||
suggestion: Span,
|
||||
},
|
||||
SingleUseLifetime {
|
||||
/// Span of the parameter which declares this lifetime.
|
||||
param_span: Span,
|
||||
|
|
|
|||
|
|
@ -314,6 +314,17 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
|||
let mut query_description_stream = quote! {};
|
||||
let mut query_cached_stream = quote! {};
|
||||
let mut feedable_queries = quote! {};
|
||||
let mut errors = quote! {};
|
||||
|
||||
macro_rules! assert {
|
||||
( $cond:expr, $span:expr, $( $tt:tt )+ ) => {
|
||||
if !$cond {
|
||||
errors.extend(
|
||||
Error::new($span, format!($($tt)+)).into_compile_error(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for query in queries.0 {
|
||||
let Query { name, arg, modifiers, .. } = &query;
|
||||
|
|
@ -369,10 +380,15 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
|||
[#attribute_stream] fn #name(#arg) #result,
|
||||
});
|
||||
|
||||
if modifiers.feedable.is_some() {
|
||||
assert!(modifiers.anon.is_none(), "Query {name} cannot be both `feedable` and `anon`.");
|
||||
if let Some(feedable) = &modifiers.feedable {
|
||||
assert!(
|
||||
modifiers.anon.is_none(),
|
||||
feedable.span(),
|
||||
"Query {name} cannot be both `feedable` and `anon`."
|
||||
);
|
||||
assert!(
|
||||
modifiers.eval_always.is_none(),
|
||||
feedable.span(),
|
||||
"Query {name} cannot be both `feedable` and `eval_always`."
|
||||
);
|
||||
feedable_queries.extend(quote! {
|
||||
|
|
@ -407,5 +423,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
|||
use super::*;
|
||||
#query_cached_stream
|
||||
}
|
||||
#errors
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
&& sess.crt_static(Some(ty))
|
||||
&& !sess.target.crt_static_allows_dylibs)
|
||||
{
|
||||
for &cnum in tcx.used_crates(()).iter() {
|
||||
for &cnum in tcx.crates(()).iter() {
|
||||
if tcx.dep_kind(cnum).macros_only() {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -165,7 +165,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
// Sweep all crates for found dylibs. Add all dylibs, as well as their
|
||||
// dependencies, ensuring there are no conflicts. The only valid case for a
|
||||
// dependency to be relied upon twice is for both cases to rely on a dylib.
|
||||
for &cnum in tcx.used_crates(()).iter() {
|
||||
for &cnum in tcx.crates(()).iter() {
|
||||
if tcx.dep_kind(cnum).macros_only() {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -183,7 +183,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
}
|
||||
|
||||
// Collect what we've got so far in the return vector.
|
||||
let last_crate = tcx.used_crates(()).len();
|
||||
let last_crate = tcx.crates(()).len();
|
||||
let mut ret = (1..last_crate + 1)
|
||||
.map(|cnum| match formats.get(&CrateNum::new(cnum)) {
|
||||
Some(&RequireDynamic) => Linkage::Dynamic,
|
||||
|
|
@ -197,7 +197,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
//
|
||||
// If the crate hasn't been included yet and it's not actually required
|
||||
// (e.g., it's an allocator) then we skip it here as well.
|
||||
for &cnum in tcx.used_crates(()).iter() {
|
||||
for &cnum in tcx.crates(()).iter() {
|
||||
let src = tcx.used_crate_source(cnum);
|
||||
if src.dylib.is_none()
|
||||
&& !formats.contains_key(&cnum)
|
||||
|
|
@ -285,7 +285,7 @@ fn add_library(
|
|||
|
||||
fn attempt_static(tcx: TyCtxt<'_>, unavailable: &mut Vec<CrateNum>) -> Option<DependencyList> {
|
||||
let all_crates_available_as_rlib = tcx
|
||||
.used_crates(())
|
||||
.crates(())
|
||||
.iter()
|
||||
.copied()
|
||||
.filter_map(|cnum| {
|
||||
|
|
@ -306,7 +306,7 @@ fn attempt_static(tcx: TyCtxt<'_>, unavailable: &mut Vec<CrateNum>) -> Option<De
|
|||
// All crates are available in an rlib format, so we're just going to link
|
||||
// everything in explicitly so long as it's actually required.
|
||||
let mut ret = tcx
|
||||
.used_crates(())
|
||||
.crates(())
|
||||
.iter()
|
||||
.map(|&cnum| match tcx.dep_kind(cnum) {
|
||||
CrateDepKind::Explicit => Linkage::Static,
|
||||
|
|
|
|||
|
|
@ -439,7 +439,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
|
|||
// traversal, but not globally minimal across all crates.
|
||||
let bfs_queue = &mut VecDeque::new();
|
||||
|
||||
for &cnum in tcx.crates_including_speculative(()) {
|
||||
for &cnum in tcx.crates(()) {
|
||||
// Ignore crates without a corresponding local `extern crate` item.
|
||||
if tcx.missing_extern_crate_item(cnum) {
|
||||
continue;
|
||||
|
|
@ -509,7 +509,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
|
|||
tcx.arena
|
||||
.alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE))
|
||||
},
|
||||
crates_including_speculative: |tcx, ()| {
|
||||
crates: |tcx, ()| {
|
||||
// The list of loaded crates is now frozen in query cache,
|
||||
// so make sure cstore is not mutably accessed from here on.
|
||||
tcx.untracked().cstore.freeze();
|
||||
|
|
|
|||
|
|
@ -1899,7 +1899,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
|
||||
let deps = self
|
||||
.tcx
|
||||
.crates_including_speculative(())
|
||||
.crates(())
|
||||
.iter()
|
||||
.map(|&cnum| {
|
||||
let dep = CrateDep {
|
||||
|
|
|
|||
|
|
@ -156,10 +156,14 @@ fixed_size_enum! {
|
|||
( Impl { of_trait: false } )
|
||||
( Impl { of_trait: true } )
|
||||
( Closure )
|
||||
( Static { mutability: ast::Mutability::Not, nested: false } )
|
||||
( Static { mutability: ast::Mutability::Mut, nested: false } )
|
||||
( Static { mutability: ast::Mutability::Not, nested: true } )
|
||||
( Static { mutability: ast::Mutability::Mut, nested: true } )
|
||||
( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: false } )
|
||||
( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: false } )
|
||||
( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: false } )
|
||||
( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: false } )
|
||||
( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: true } )
|
||||
( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: true } )
|
||||
( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: true } )
|
||||
( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: true } )
|
||||
( Ctor(CtorOf::Struct, CtorKind::Fn) )
|
||||
( Ctor(CtorOf::Struct, CtorKind::Const) )
|
||||
( Ctor(CtorOf::Variant, CtorKind::Fn) )
|
||||
|
|
|
|||
|
|
@ -305,7 +305,9 @@ impl<'hir> Map<'hir> {
|
|||
DefKind::InlineConst => BodyOwnerKind::Const { inline: true },
|
||||
DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn,
|
||||
DefKind::Closure => BodyOwnerKind::Closure,
|
||||
DefKind::Static { mutability, nested: false } => BodyOwnerKind::Static(mutability),
|
||||
DefKind::Static { safety: _, mutability, nested: false } => {
|
||||
BodyOwnerKind::Static(mutability)
|
||||
}
|
||||
dk => bug!("{:?} is not a body node: {:?}", def_id, dk),
|
||||
}
|
||||
}
|
||||
|
|
@ -886,7 +888,7 @@ impl<'hir> Map<'hir> {
|
|||
Node::Variant(variant) => named_span(variant.span, variant.ident, None),
|
||||
Node::ImplItem(item) => named_span(item.span, item.ident, Some(item.generics)),
|
||||
Node::ForeignItem(item) => match item.kind {
|
||||
ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()),
|
||||
ForeignItemKind::Fn(decl, _, _, _) => until_within(item.span, decl.output.span()),
|
||||
_ => named_span(item.span, item.ident, None),
|
||||
},
|
||||
Node::Ctor(_) => return self.span(self.tcx.parent_hir_id(hir_id)),
|
||||
|
|
@ -1040,7 +1042,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
|
|||
let krate = tcx.hir_crate(());
|
||||
let hir_body_hash = krate.opt_hir_hash.expect("HIR hash missing while computing crate hash");
|
||||
|
||||
let upstream_crates = upstream_crates_for_hashing(tcx);
|
||||
let upstream_crates = upstream_crates(tcx);
|
||||
|
||||
let resolutions = tcx.resolutions(());
|
||||
|
||||
|
|
@ -1109,9 +1111,9 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
|
|||
Svh::new(crate_hash)
|
||||
}
|
||||
|
||||
fn upstream_crates_for_hashing(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> {
|
||||
fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> {
|
||||
let mut upstream_crates: Vec<_> = tcx
|
||||
.crates_including_speculative(())
|
||||
.crates(())
|
||||
.iter()
|
||||
.map(|&cnum| {
|
||||
let stable_crate_id = tcx.stable_crate_id(cnum);
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
..
|
||||
})
|
||||
| Node::ForeignItem(&ForeignItem {
|
||||
kind: ForeignItemKind::Fn(_, idents, _),
|
||||
kind: ForeignItemKind::Fn(_, idents, _, _),
|
||||
..
|
||||
}) = tcx.hir_node(tcx.local_def_id_to_hir_id(def_id))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,15 +4,16 @@
|
|||
//! has their own README with further details).
|
||||
//!
|
||||
//! - **HIR.** The "high-level (H) intermediate representation (IR)" is
|
||||
//! defined in the `hir` module.
|
||||
//! defined in the [`hir`] module.
|
||||
//! - **MIR.** The "mid-level (M) intermediate representation (IR)" is
|
||||
//! defined in the `mir` module. This module contains only the
|
||||
//! defined in the [`mir`] module. This module contains only the
|
||||
//! *definition* of the MIR; the passes that transform and operate
|
||||
//! on MIR are found in `rustc_const_eval` crate.
|
||||
//! - **Types.** The internal representation of types used in rustc is
|
||||
//! defined in the `ty` module. This includes the **type context**
|
||||
//! (or `tcx`), which is the central context during most of
|
||||
//! compilation, containing the interners and other things.
|
||||
//! defined in the [`ty`] module. This includes the
|
||||
//! [**type context**][ty::TyCtxt] (or `tcx`), which is the central
|
||||
//! context during most of compilation, containing the interners and
|
||||
//! other things.
|
||||
//!
|
||||
//! For more information about how rustc works, see the [rustc dev guide].
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -204,7 +204,9 @@ pub enum Const<'tcx> {
|
|||
/// Any way of turning `ty::Const` into `ConstValue` should go through `valtree_to_const_val`;
|
||||
/// this ensures that we consistently produce "clean" values without data in the padding or
|
||||
/// anything like that.
|
||||
Ty(ty::Const<'tcx>),
|
||||
///
|
||||
/// FIXME(BoxyUwU): We should remove this `Ty` and look up the type for params via `ParamEnv`
|
||||
Ty(Ty<'tcx>, ty::Const<'tcx>),
|
||||
|
||||
/// An unevaluated mir constant which is not part of the type system.
|
||||
///
|
||||
|
|
@ -237,7 +239,15 @@ impl<'tcx> Const<'tcx> {
|
|||
#[inline(always)]
|
||||
pub fn ty(&self) -> Ty<'tcx> {
|
||||
match self {
|
||||
Const::Ty(c) => c.ty(),
|
||||
Const::Ty(ty, ct) => {
|
||||
match ct.kind() {
|
||||
// Dont use the outter ty as on invalid code we can wind up with them not being the same.
|
||||
// this then results in allowing const eval to add `1_i64 + 1_usize` in cases where the mir
|
||||
// was originally `({N: usize} + 1_usize)` under `generic_const_exprs`.
|
||||
ty::ConstKind::Value(ty, _) => ty,
|
||||
_ => *ty,
|
||||
}
|
||||
}
|
||||
Const::Val(_, ty) | Const::Unevaluated(_, ty) => *ty,
|
||||
}
|
||||
}
|
||||
|
|
@ -247,8 +257,8 @@ impl<'tcx> Const<'tcx> {
|
|||
#[inline]
|
||||
pub fn is_required_const(&self) -> bool {
|
||||
match self {
|
||||
Const::Ty(c) => match c.kind() {
|
||||
ty::ConstKind::Value(_) => false, // already a value, cannot error
|
||||
Const::Ty(_, c) => match c.kind() {
|
||||
ty::ConstKind::Value(_, _) => false, // already a value, cannot error
|
||||
_ => true,
|
||||
},
|
||||
Const::Val(..) => false, // already a value, cannot error
|
||||
|
|
@ -259,8 +269,8 @@ impl<'tcx> Const<'tcx> {
|
|||
#[inline]
|
||||
pub fn try_to_scalar(self) -> Option<Scalar> {
|
||||
match self {
|
||||
Const::Ty(c) => match c.kind() {
|
||||
ty::ConstKind::Value(valtree) if c.ty().is_primitive() => {
|
||||
Const::Ty(_, c) => match c.kind() {
|
||||
ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => {
|
||||
// A valtree of a type where leaves directly represent the scalar const value.
|
||||
// Just checking whether it is a leaf is insufficient as e.g. references are leafs
|
||||
// but the leaf value is the value they point to, not the reference itself!
|
||||
|
|
@ -278,8 +288,8 @@ impl<'tcx> Const<'tcx> {
|
|||
// This is equivalent to `self.try_to_scalar()?.try_to_int().ok()`, but measurably faster.
|
||||
match self {
|
||||
Const::Val(ConstValue::Scalar(Scalar::Int(x)), _) => Some(x),
|
||||
Const::Ty(c) => match c.kind() {
|
||||
ty::ConstKind::Value(valtree) if c.ty().is_primitive() => {
|
||||
Const::Ty(_, c) => match c.kind() {
|
||||
ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => {
|
||||
Some(valtree.unwrap_leaf())
|
||||
}
|
||||
_ => None,
|
||||
|
|
@ -306,11 +316,11 @@ impl<'tcx> Const<'tcx> {
|
|||
span: Span,
|
||||
) -> Result<ConstValue<'tcx>, ErrorHandled> {
|
||||
match self {
|
||||
Const::Ty(c) => {
|
||||
Const::Ty(_, c) => {
|
||||
// We want to consistently have a "clean" value for type system constants (i.e., no
|
||||
// data hidden in the padding), so we always go through a valtree here.
|
||||
let val = c.eval(tcx, param_env, span)?;
|
||||
Ok(tcx.valtree_to_const_val((self.ty(), val)))
|
||||
let (ty, val) = c.eval(tcx, param_env, span)?;
|
||||
Ok(tcx.valtree_to_const_val((ty, val)))
|
||||
}
|
||||
Const::Unevaluated(uneval, _) => {
|
||||
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
|
||||
|
|
@ -326,7 +336,7 @@ impl<'tcx> Const<'tcx> {
|
|||
match self.eval(tcx, param_env, DUMMY_SP) {
|
||||
Ok(val) => Self::Val(val, self.ty()),
|
||||
Err(ErrorHandled::Reported(guar, _span)) => {
|
||||
Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty()))
|
||||
Self::Ty(Ty::new_error(tcx, guar.into()), ty::Const::new_error(tcx, guar.into()))
|
||||
}
|
||||
Err(ErrorHandled::TooGeneric(_span)) => self,
|
||||
}
|
||||
|
|
@ -338,15 +348,16 @@ impl<'tcx> Const<'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Option<Scalar> {
|
||||
match self {
|
||||
Const::Ty(c) if c.ty().is_primitive() => {
|
||||
// Avoid the `valtree_to_const_val` query. Can only be done on primitive types that
|
||||
// are valtree leaves, and *not* on references. (References should return the
|
||||
// pointer here, which valtrees don't represent.)
|
||||
let val = c.eval(tcx, param_env, DUMMY_SP).ok()?;
|
||||
Some(val.unwrap_leaf().into())
|
||||
}
|
||||
_ => self.eval(tcx, param_env, DUMMY_SP).ok()?.try_to_scalar(),
|
||||
if let Const::Ty(_, c) = self
|
||||
&& let ty::ConstKind::Value(ty, val) = c.kind()
|
||||
&& ty.is_primitive()
|
||||
{
|
||||
// Avoid the `valtree_to_const_val` query. Can only be done on primitive types that
|
||||
// are valtree leaves, and *not* on references. (References should return the
|
||||
// pointer here, which valtrees don't represent.)
|
||||
Some(val.unwrap_leaf().into())
|
||||
} else {
|
||||
self.eval(tcx, param_env, DUMMY_SP).ok()?.try_to_scalar()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -439,14 +450,14 @@ impl<'tcx> Const<'tcx> {
|
|||
Self::Val(val, ty)
|
||||
}
|
||||
|
||||
pub fn from_ty_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
pub fn from_ty_const(c: ty::Const<'tcx>, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
match c.kind() {
|
||||
ty::ConstKind::Value(valtree) => {
|
||||
ty::ConstKind::Value(ty, valtree) => {
|
||||
// Make sure that if `c` is normalized, then the return value is normalized.
|
||||
let const_val = tcx.valtree_to_const_val((c.ty(), valtree));
|
||||
Self::Val(const_val, c.ty())
|
||||
let const_val = tcx.valtree_to_const_val((ty, valtree));
|
||||
Self::Val(const_val, ty)
|
||||
}
|
||||
_ => Self::Ty(c),
|
||||
_ => Self::Ty(ty, c),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -458,12 +469,12 @@ impl<'tcx> Const<'tcx> {
|
|||
// - valtrees purposefully generate new allocations
|
||||
// - ConstValue::Slice also generate new allocations
|
||||
match self {
|
||||
Const::Ty(c) => match c.kind() {
|
||||
Const::Ty(_, c) => match c.kind() {
|
||||
ty::ConstKind::Param(..) => true,
|
||||
// A valtree may be a reference. Valtree references correspond to a
|
||||
// different allocation each time they are evaluated. Valtrees for primitive
|
||||
// types are fine though.
|
||||
ty::ConstKind::Value(_) => c.ty().is_primitive(),
|
||||
ty::ConstKind::Value(ty, _) => ty.is_primitive(),
|
||||
ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) => false,
|
||||
// This can happen if evaluation of a constant failed. The result does not matter
|
||||
// much since compilation is doomed.
|
||||
|
|
@ -517,7 +528,7 @@ impl<'tcx> UnevaluatedConst<'tcx> {
|
|||
impl<'tcx> Display for Const<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Const::Ty(c) => pretty_print_const(c, fmt, true),
|
||||
Const::Ty(_, c) => pretty_print_const(c, fmt, true),
|
||||
Const::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
|
||||
// FIXME(valtrees): Correctly print mir constants.
|
||||
Const::Unevaluated(c, _ty) => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId};
|
||||
use super::{
|
||||
ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId,
|
||||
};
|
||||
|
||||
use crate::mir;
|
||||
use crate::query::TyCtxtEnsure;
|
||||
|
|
@ -13,7 +15,7 @@ use tracing::{debug, instrument};
|
|||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
|
||||
/// that can't take any generic arguments like statics, const items or enum discriminants. If a
|
||||
/// that can't take any generic arguments like const items or enum discriminants. If a
|
||||
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> {
|
||||
|
|
@ -27,6 +29,24 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
let param_env = self.param_env(def_id).with_reveal_all_normalized(self);
|
||||
self.const_eval_global_id(param_env, cid, DUMMY_SP)
|
||||
}
|
||||
|
||||
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
|
||||
/// that can't take any generic arguments like const items or enum discriminants. If a
|
||||
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn const_eval_poly_to_alloc(self, def_id: DefId) -> EvalToAllocationRawResult<'tcx> {
|
||||
// In some situations def_id will have generic parameters within scope, but they aren't allowed
|
||||
// to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters
|
||||
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are
|
||||
// encountered.
|
||||
let args = GenericArgs::identity_for_item(self, def_id);
|
||||
let instance = ty::Instance::new(def_id, args);
|
||||
let cid = GlobalId { instance, promoted: None };
|
||||
let param_env = self.param_env(def_id).with_reveal_all_normalized(self);
|
||||
let inputs = self.erase_regions(param_env.and(cid));
|
||||
self.eval_to_allocation_raw(inputs)
|
||||
}
|
||||
|
||||
/// Resolves and evaluates a constant.
|
||||
///
|
||||
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
|
||||
|
|
@ -177,7 +197,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
impl<'tcx> TyCtxtEnsure<'tcx> {
|
||||
/// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts
|
||||
/// that can't take any generic arguments like statics, const items or enum discriminants. If a
|
||||
/// that can't take any generic arguments like const items or enum discriminants. If a
|
||||
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn const_eval_poly(self, def_id: DefId) {
|
||||
|
|
|
|||
|
|
@ -559,10 +559,10 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io:
|
|||
match (kind, body.source.promoted) {
|
||||
(_, Some(_)) => write!(w, "const ")?, // promoteds are the closest to consts
|
||||
(DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?,
|
||||
(DefKind::Static { mutability: hir::Mutability::Not, nested: false }, _) => {
|
||||
(DefKind::Static { safety: _, mutability: hir::Mutability::Not, nested: false }, _) => {
|
||||
write!(w, "static ")?
|
||||
}
|
||||
(DefKind::Static { mutability: hir::Mutability::Mut, nested: false }, _) => {
|
||||
(DefKind::Static { safety: _, mutability: hir::Mutability::Mut, nested: false }, _) => {
|
||||
write!(w, "static mut ")?
|
||||
}
|
||||
(_, _) if is_function => write!(w, "fn ")?,
|
||||
|
|
@ -1313,12 +1313,12 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
|||
};
|
||||
|
||||
let val = match const_ {
|
||||
Const::Ty(ct) => match ct.kind() {
|
||||
Const::Ty(_, ct) => match ct.kind() {
|
||||
ty::ConstKind::Param(p) => format!("ty::Param({p})"),
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
|
||||
}
|
||||
ty::ConstKind::Value(val) => format!("ty::Valtree({})", fmt_valtree(&val)),
|
||||
ty::ConstKind::Value(_, val) => format!("ty::Valtree({})", fmt_valtree(&val)),
|
||||
// No `ty::` prefix since we also use this to represent errors from `mir::Unevaluated`.
|
||||
ty::ConstKind::Error(_) => "Error".to_string(),
|
||||
// These variants shouldn't exist in the MIR.
|
||||
|
|
@ -1417,7 +1417,7 @@ pub fn write_allocations<'tcx>(
|
|||
impl<'tcx> Visitor<'tcx> for CollectAllocIds {
|
||||
fn visit_constant(&mut self, c: &ConstOperand<'tcx>, _: Location) {
|
||||
match c.const_ {
|
||||
Const::Ty(_) | Const::Unevaluated(..) => {}
|
||||
Const::Ty(_, _) | Const::Unevaluated(..) => {}
|
||||
Const::Val(val, _) => {
|
||||
self.0.extend(alloc_ids_from_const_val(val));
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue