Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2025-04-17 17:59:31 +00:00
commit 2602dd93a6
1041 changed files with 11309 additions and 7174 deletions

View file

@ -31,3 +31,5 @@ ec2cc761bc7067712ecc7734502f703fe3b024c8
c682aa162b0d41e21cc6748f4fecfe01efb69d1f
# reformat with updated edition 2024
1fcae03369abb4c2cc180cd5a49e1f4440a81300
# Breaking up of compiletest runtest.rs
60600a6fa403216bfd66e04f948b1822f6450af7

View file

@ -53,6 +53,13 @@ jobs:
steps:
- name: Checkout the source code
uses: actions/checkout@v4
# Cache citool to make its build faster, as it's in the critical path.
# The rust-cache doesn't bleed into the main `job`, so it should not affect any other
# Rust compilation.
- name: Cache citool
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
with:
workspaces: src/ci/citool
- name: Calculate the CI job matrix
env:
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}

View file

@ -292,6 +292,7 @@ James Hinshelwood <jameshinshelwood1@gmail.com> <james.hinshelwood@bigpayme.com>
James Miller <bladeon@gmail.com> <james@aatch.net>
James Perry <james.austin.perry@gmail.com>
James Sanderson <zofrex@gmail.com>
Jamie Hill-Daniel <jamie@hill-daniel.co.uk> <clubby789@gmail.com>
Jana Dönszelmann <jana@donsz.nl>
Jana Dönszelmann <jana@donsz.nl> <jonathan@donsz.nl>
Jana Dönszelmann <jana@donsz.nl> <jonabent@gmail.com>

View file

@ -719,6 +719,7 @@ version = "0.0.0"
dependencies = [
"anstyle-svg",
"build_helper",
"camino",
"colored",
"diff",
"getopts",
@ -931,15 +932,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "deranged"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
dependencies = [
"powerfmt",
]
[[package]]
name = "derive-where"
version = "1.2.7"
@ -1221,7 +1213,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
dependencies = [
"crc32fast",
"miniz_oxide 0.8.7",
"miniz_oxide 0.8.8",
]
[[package]]
@ -2291,9 +2283,9 @@ dependencies = [
[[package]]
name = "miniz_oxide"
version = "0.8.7"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [
"adler2",
]
@ -2425,12 +2417,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-integer"
version = "0.1.46"
@ -2808,12 +2794,6 @@ dependencies = [
"portable-atomic",
]
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
@ -3616,6 +3596,7 @@ name = "rustc_driver_impl"
version = "0.0.0"
dependencies = [
"ctrlc",
"jiff",
"libc",
"rustc_abi",
"rustc_ast",
@ -3662,7 +3643,6 @@ dependencies = [
"rustc_ty_utils",
"serde_json",
"shlex",
"time",
"tracing",
"windows 0.59.0",
]
@ -4692,6 +4672,7 @@ name = "rustdoc-gui-test"
version = "0.1.0"
dependencies = [
"build_helper",
"camino",
"compiletest",
"getopts",
"walkdir",
@ -5356,37 +5337,6 @@ dependencies = [
"libc",
]
[[package]]
name = "time"
version = "0.3.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
[[package]]
name = "time-macros"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "tinystr"
version = "0.7.6"
@ -6111,11 +6061,13 @@ dependencies = [
[[package]]
name = "windows-bindgen"
version = "0.59.0"
version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7fb600834d7e868f6e5bb748a86101427330fafbf9485c331b9d5f562d54a5"
checksum = "ac1c59c20569610dd9ed784d5f003fb493ec57b4cf39d974eb03a84bb7156c90"
dependencies = [
"rayon",
"serde",
"serde_json",
]
[[package]]

View file

@ -315,7 +315,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
repr: &ReprOptions,
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
is_enum: bool,
is_unsafe_cell: bool,
is_special_no_niche: bool,
scalar_valid_range: (Bound<u128>, Bound<u128>),
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
@ -348,7 +348,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
repr,
variants,
is_enum,
is_unsafe_cell,
is_special_no_niche,
scalar_valid_range,
always_sized,
present_first,
@ -505,7 +505,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
repr: &ReprOptions,
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
is_enum: bool,
is_unsafe_cell: bool,
is_special_no_niche: bool,
scalar_valid_range: (Bound<u128>, Bound<u128>),
always_sized: bool,
present_first: VariantIdx,
@ -524,7 +524,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
let mut st = self.univariant(&variants[v], repr, kind)?;
st.variants = Variants::Single { index: v };
if is_unsafe_cell {
if is_special_no_niche {
let hide_niches = |scalar: &mut _| match scalar {
Scalar::Initialized { value, valid_range } => {
*valid_range = WrappingRange::full(value.size(dl))

View file

@ -120,6 +120,17 @@ impl Path {
Path { segments: thin_vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None }
}
pub fn is_ident(&self, name: Symbol) -> bool {
if let [segment] = self.segments.as_ref()
&& segment.args.is_none()
&& segment.ident.name == name
{
true
} else {
false
}
}
pub fn is_global(&self) -> bool {
self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot)
}

View file

@ -6,7 +6,6 @@ use std::fmt;
use std::marker::PhantomData;
use crate::ptr::P;
use crate::token::Nonterminal;
use crate::tokenstream::LazyAttrTokenStream;
use crate::{
Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField,
@ -206,19 +205,6 @@ impl HasTokens for Attribute {
}
}
impl HasTokens for Nonterminal {
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
match self {
Nonterminal::NtBlock(block) => block.tokens(),
}
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
match self {
Nonterminal::NtBlock(block) => block.tokens_mut(),
}
}
}
/// A trait for AST nodes having (or not having) attributes.
pub trait HasAttrs {
/// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner

View file

@ -627,7 +627,7 @@ pub fn mk_doc_comment(
Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
}
pub fn mk_attr(
fn mk_attr(
g: &AttrIdGenerator,
style: AttrStyle,
unsafety: Safety,

View file

@ -6,7 +6,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
test(attr(deny(warnings)))

View file

@ -844,9 +844,9 @@ fn visit_lazy_tts<T: MutVisitor>(vis: &mut T, lazy_tts: &mut Option<LazyAttrToke
visit_lazy_tts_opt_mut(vis, lazy_tts.as_mut());
}
/// Applies ident visitor if it's an ident; applies other visits to interpolated nodes.
/// In practice the ident part is not actually used by specific visitors right now,
/// but there's a test below checking that it works.
/// Applies ident visitor if it's an ident. In practice this is not actually
/// used by specific visitors right now, but there's a test below checking that
/// it works.
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) {
let Token { kind, span } = t;
@ -864,45 +864,11 @@ pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) {
token::NtLifetime(ident, _is_raw) => {
vis.visit_ident(ident);
}
token::Interpolated(nt) => {
let nt = Arc::make_mut(nt);
visit_nonterminal(vis, nt);
}
_ => {}
}
vis.visit_span(span);
}
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
/// Applies the visitor to elements of interpolated nodes.
//
// N.B., this can occur only when applying a visitor to partially expanded
// code, where parsed pieces have gotten implanted ito *other* macro
// invocations. This is relevant for macro hygiene, but possibly not elsewhere.
//
// One problem here occurs because the types for flat_map_item, flat_map_stmt,
// etc., allow the visitor to return *multiple* items; this is a problem for the
// nodes here, because they insist on having exactly one piece. One solution
// would be to mangle the MutVisitor trait to include one-to-many and
// one-to-one versions of these entry points, but that would probably confuse a
// lot of people and help very few. Instead, I'm just going to put in dynamic
// checks. I think the performance impact of this will be pretty much
// nonexistent. The danger is that someone will apply a `MutVisitor` to a
// partially expanded node, and will be confused by the fact that their
// `flat_map_item` or `flat_map_stmt` isn't getting called on `NtItem` or `NtStmt`
// nodes. Hopefully they'll wind up reading this comment, and doing something
// appropriate.
//
// BTW, design choice: I considered just changing the type of, e.g., `NtItem` to
// contain multiple items, but decided against it when I looked at
// `parse_item_or_view_item` and tried to figure out what I would do with
// multiple items there....
fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
match nt {
token::NtBlock(block) => vis.visit_block(block),
}
}
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
fn visit_defaultness<T: MutVisitor>(vis: &mut T, defaultness: &mut Defaultness) {
match defaultness {

View file

@ -1,13 +1,10 @@
use std::borrow::Cow;
use std::fmt;
use std::sync::Arc;
pub use LitKind::*;
pub use Nonterminal::*;
pub use NtExprKind::*;
pub use NtPatKind::*;
pub use TokenKind::*;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::edition::Edition;
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym};
@ -16,7 +13,6 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym};
use rustc_span::{Ident, Symbol};
use crate::ast;
use crate::ptr::P;
use crate::util::case::Case;
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
@ -34,10 +30,6 @@ pub enum InvisibleOrigin {
// Converted from `proc_macro::Delimiter` in
// `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro.
ProcMacro,
// Converted from `TokenKind::Interpolated` in
// `TokenStream::flatten_token`. Treated similarly to `ProcMacro`.
FlattenToken,
}
impl PartialEq for InvisibleOrigin {
@ -134,9 +126,7 @@ impl Delimiter {
match self {
Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false,
Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false,
Delimiter::Invisible(InvisibleOrigin::FlattenToken | InvisibleOrigin::ProcMacro) => {
true
}
Delimiter::Invisible(InvisibleOrigin::ProcMacro) => true,
}
}
@ -337,9 +327,7 @@ impl From<IdentIsRaw> for bool {
}
}
// SAFETY: due to the `Clone` impl below, all fields of all variants other than
// `Interpolated` must impl `Copy`.
#[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum TokenKind {
/* Expression-operator symbols. */
/// `=`
@ -468,21 +456,6 @@ pub enum TokenKind {
/// the `lifetime` metavariable in the macro's RHS.
NtLifetime(Ident, IdentIsRaw),
/// An embedded AST node, as produced by a macro. This only exists for
/// historical reasons. We'd like to get rid of it, for multiple reasons.
/// - It's conceptually very strange. Saying a token can contain an AST
/// node is like saying, in natural language, that a word can contain a
/// sentence.
/// - It requires special handling in a bunch of places in the parser.
/// - It prevents `Token` from implementing `Copy`.
/// It adds complexity and likely slows things down. Please don't add new
/// occurrences of this token kind!
///
/// The span in the surrounding `Token` is that of the metavariable in the
/// macro's RHS. The span within the Nonterminal is that of the fragment
/// passed to the macro at the call site.
Interpolated(Arc<Nonterminal>),
/// A doc comment token.
/// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
/// similarly to symbols in string literal tokens.
@ -492,20 +465,7 @@ pub enum TokenKind {
Eof,
}
impl Clone for TokenKind {
fn clone(&self) -> Self {
// `TokenKind` would impl `Copy` if it weren't for `Interpolated`. So
// for all other variants, this implementation of `clone` is just like
// a copy. This is faster than the `derive(Clone)` version which has a
// separate path for every variant.
match self {
Interpolated(nt) => Interpolated(Arc::clone(nt)),
_ => unsafe { std::ptr::read(self) },
}
}
}
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct Token {
pub kind: TokenKind,
pub span: Span,
@ -600,7 +560,7 @@ impl Token {
| FatArrow | Pound | Dollar | Question | SingleQuote => true,
OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
| NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false,
| NtIdent(..) | Lifetime(..) | NtLifetime(..) | Eof => false,
}
}
@ -631,7 +591,6 @@ impl Token {
PathSep | // global path
Lifetime(..) | // labeled loop
Pound => true, // expression attributes
Interpolated(ref nt) => matches!(&**nt, NtBlock(..)),
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
MetaVarKind::Block |
MetaVarKind::Expr { .. } |
@ -703,7 +662,6 @@ impl Token {
match self.kind {
OpenDelim(Delimiter::Brace) | Literal(..) | Minus => true,
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
Interpolated(ref nt) => matches!(&**nt, NtBlock(..)),
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal,
))) => true,
@ -831,31 +789,20 @@ impl Token {
/// Is this a pre-parsed expression dropped into the token stream
/// (which happens while parsing the result of macro expansion)?
pub fn is_metavar_expr(&self) -> bool {
#[allow(irrefutable_let_patterns)] // FIXME: temporary
if let Interpolated(nt) = &self.kind
&& let NtBlock(_) = &**nt
{
true
} else if matches!(
matches!(
self.is_metavar_seq(),
Some(MetaVarKind::Expr { .. } | MetaVarKind::Literal | MetaVarKind::Path)
) {
true
} else {
matches!(self.is_metavar_seq(), Some(MetaVarKind::Path))
}
Some(
MetaVarKind::Expr { .. }
| MetaVarKind::Literal
| MetaVarKind::Path
| MetaVarKind::Block
)
)
}
/// Is the token an interpolated block (`$b:block`)?
pub fn is_whole_block(&self) -> bool {
#[allow(irrefutable_let_patterns)] // FIXME: temporary
if let Interpolated(nt) = &self.kind
&& let NtBlock(..) = &**nt
{
return true;
}
false
/// Are we at a block from a metavar (`$b:block`)?
pub fn is_metavar_block(&self) -> bool {
matches!(self.is_metavar_seq(), Some(MetaVarKind::Block))
}
/// Returns `true` if the token is either the `mut` or `const` keyword.
@ -1024,7 +971,7 @@ impl Token {
| PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | DotDotDot | DotDotEq
| Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question
| OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..)
| Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof,
| Lifetime(..) | NtLifetime(..) | DocComment(..) | Eof,
_,
) => {
return None;
@ -1063,12 +1010,6 @@ pub enum NtExprKind {
Expr2021 { inferred: bool },
}
#[derive(Clone, Encodable, Decodable)]
/// For interpolation during macro expansion.
pub enum Nonterminal {
NtBlock(P<ast::Block>),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
pub enum NonterminalKind {
Item,
@ -1152,47 +1093,6 @@ impl fmt::Display for NonterminalKind {
}
}
impl Nonterminal {
pub fn use_span(&self) -> Span {
match self {
NtBlock(block) => block.span,
}
}
pub fn descr(&self) -> &'static str {
match self {
NtBlock(..) => "block",
}
}
}
impl PartialEq for Nonterminal {
fn eq(&self, _rhs: &Self) -> bool {
// FIXME: Assume that all nonterminals are not equal, we can't compare them
// correctly based on data from AST. This will prevent them from matching each other
// in macros. The comparison will become possible only when each nonterminal has an
// attached token stream from which it was parsed.
false
}
}
impl fmt::Debug for Nonterminal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
NtBlock(..) => f.pad("NtBlock(..)"),
}
}
}
impl<CTX> HashStable<CTX> for Nonterminal
where
CTX: crate::HashStableContext,
{
fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
panic!("interpolated tokens should not be present in the HIR")
}
}
// Some types are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(target_pointer_width = "64")]
mod size_asserts {
@ -1202,7 +1102,6 @@ mod size_asserts {
// tidy-alphabetical-start
static_assert_size!(Lit, 12);
static_assert_size!(LitKind, 2);
static_assert_size!(Nonterminal, 8);
static_assert_size!(Token, 24);
static_assert_size!(TokenKind, 16);
// tidy-alphabetical-end

View file

@ -25,7 +25,7 @@ use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym};
use crate::ast::AttrStyle;
use crate::ast_traits::{HasAttrs, HasTokens};
use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind};
use crate::token::{self, Delimiter, Token, TokenKind};
use crate::{AttrVec, Attribute};
/// Part of a `TokenStream`.
@ -305,11 +305,6 @@ pub struct AttrsTarget {
}
/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
///
/// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s
/// instead of a representation of the abstract syntax tree.
/// Today's `TokenTree`s can still contain AST via `token::Interpolated` for
/// backwards compatibility.
#[derive(Clone, Debug, Default, Encodable, Decodable)]
pub struct TokenStream(pub(crate) Arc<Vec<TokenTree>>);
@ -476,61 +471,6 @@ impl TokenStream {
TokenStream::new(tts)
}
pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
match nt {
Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
}
}
fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
match token.kind {
token::NtIdent(ident, is_raw) => {
TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
}
token::NtLifetime(ident, is_raw) => TokenTree::Delimited(
DelimSpan::from_single(token.span),
DelimSpacing::new(Spacing::JointHidden, spacing),
Delimiter::Invisible(InvisibleOrigin::FlattenToken),
TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span),
),
token::Interpolated(ref nt) => TokenTree::Delimited(
DelimSpan::from_single(token.span),
DelimSpacing::new(Spacing::JointHidden, spacing),
Delimiter::Invisible(InvisibleOrigin::FlattenToken),
TokenStream::from_nonterminal_ast(&nt).flattened(),
),
_ => TokenTree::Token(token.clone(), spacing),
}
}
fn flatten_token_tree(tree: &TokenTree) -> TokenTree {
match tree {
TokenTree::Token(token, spacing) => TokenStream::flatten_token(token, *spacing),
TokenTree::Delimited(span, spacing, delim, tts) => {
TokenTree::Delimited(*span, *spacing, *delim, tts.flattened())
}
}
}
#[must_use]
pub fn flattened(&self) -> TokenStream {
fn can_skip(stream: &TokenStream) -> bool {
stream.iter().all(|tree| match tree {
TokenTree::Token(token, _) => !matches!(
token.kind,
token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..)
),
TokenTree::Delimited(.., inner) => can_skip(inner),
})
}
if can_skip(self) {
return self.clone();
}
self.iter().map(|tree| TokenStream::flatten_token_tree(tree)).collect()
}
// If `vec` is not empty, try to glue `tt` onto its last token. The return
// value indicates if gluing took place.
fn try_glue_to_last(vec: &mut Vec<TokenTree>, tt: &TokenTree) -> bool {

View file

@ -85,7 +85,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
.delegation_fn_sigs
.get(&local_def_id)
.is_some_and(|sig| sig.has_self),
None => self.tcx.associated_item(def_id).fn_has_self_parameter,
None => self.tcx.associated_item(def_id).is_method(),
},
_ => span_bug!(span, "unexpected DefKind for delegation item"),
}

View file

@ -399,12 +399,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
expr: &'hir hir::Expr<'hir>,
span: Span,
check_ident: Ident,
check_hir_id: HirId,
cond_ident: Ident,
cond_hir_id: HirId,
) -> &'hir hir::Expr<'hir> {
let checker_fn = self.expr_ident(span, check_ident, check_hir_id);
let span = self.mark_span_with_reason(DesugaringKind::Contract, span, None);
self.expr_call(span, checker_fn, std::slice::from_ref(expr))
let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id);
let call_expr = self.expr_call_lang_item_fn_mut(
span,
hir::LangItem::ContractCheckEnsures,
arena_vec![self; *cond_fn, *expr],
);
self.arena.alloc(call_expr)
}
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {

View file

@ -1206,8 +1206,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
let precond = if let Some(req) = &contract.requires {
// Lower the precondition check intrinsic.
let lowered_req = this.lower_expr_mut(&req);
let req_span = this.mark_span_with_reason(
DesugaringKind::Contract,
lowered_req.span,
None,
);
let precond = this.expr_call_lang_item_fn_mut(
req.span,
req_span,
hir::LangItem::ContractCheckRequires,
&*arena_vec![this; lowered_req],
);
@ -1217,6 +1222,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
};
let (postcond, body) = if let Some(ens) = &contract.ensures {
let ens_span = this.lower_span(ens.span);
let ens_span =
this.mark_span_with_reason(DesugaringKind::Contract, ens_span, None);
// Set up the postcondition `let` statement.
let check_ident: Ident =
Ident::from_str_and_span("__ensures_checker", ens_span);

View file

@ -32,7 +32,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(box_patterns)]
@ -917,7 +916,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs {
DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.flattened() }
DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.clone() }
}
/// Lower an associated item constraint.
@ -1766,24 +1765,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ident: Ident,
is_anon_in_path: IsAnonInPath,
) -> &'hir hir::Lifetime {
debug_assert_ne!(ident.name, kw::Empty);
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
let res = match res {
LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param),
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
LifetimeRes::Fresh { param, .. } => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
let param = self.local_def_id(param);
hir::LifetimeName::Param(param)
hir::LifetimeKind::Param(param)
}
LifetimeRes::Infer => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
hir::LifetimeName::Infer
hir::LifetimeKind::Infer
}
LifetimeRes::Static { .. } => {
debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
hir::LifetimeName::Static
hir::LifetimeKind::Static
}
LifetimeRes::Error => hir::LifetimeName::Error,
LifetimeRes::Error => hir::LifetimeKind::Error,
LifetimeRes::ElidedAnchor { .. } => {
panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span);
}
@ -2390,7 +2388,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let r = hir::Lifetime::new(
self.next_id(),
Ident::new(kw::UnderscoreLifetime, self.lower_span(span)),
hir::LifetimeName::ImplicitObjectLifetimeDefault,
hir::LifetimeKind::ImplicitObjectLifetimeDefault,
IsAnonInPath::No,
);
debug!("elided_dyn_bound: r={:?}", r);

View file

@ -448,8 +448,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
generic_args.args.insert_many(
0,
(start.as_u32()..end.as_u32()).map(|i| {
let id = NodeId::from_u32(i);
(start..end).map(|id| {
let l = self.lower_lifetime_anon_in_path(id, elided_lifetime_span);
GenericArg::Lifetime(l)
}),

View file

@ -79,6 +79,10 @@ ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$de
.suggestion = remove the {$remove_descr}
.label = `extern` block begins here
ast_passes_extern_without_abi = `extern` declarations without an explicit ABI are disallowed
.suggestion = specify an ABI
.help = prior to Rust 2024, a default ABI was inferred
ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
.suggestion = remove the attribute
.stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable

View file

@ -684,7 +684,7 @@ impl<'a> AstValidator<'a> {
self.dcx().emit_err(errors::PatternFnPointer { span });
});
if let Extern::Implicit(extern_span) = bfty.ext {
self.maybe_lint_missing_abi(extern_span, ty.id);
self.handle_missing_abi(extern_span, ty.id);
}
}
TyKind::TraitObject(bounds, ..) => {
@ -717,10 +717,12 @@ impl<'a> AstValidator<'a> {
}
}
fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
fn handle_missing_abi(&mut self, span: Span, id: NodeId) {
// FIXME(davidtwco): This is a hack to detect macros which produce spans of the
// call site which do not have a macro backtrace. See #61963.
if self
if span.edition().at_least_edition_future() && self.features.explicit_extern_abis() {
self.dcx().emit_err(errors::MissingAbi { span });
} else if self
.sess
.source_map()
.span_to_snippet(span)
@ -996,7 +998,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
if abi.is_none() {
self.maybe_lint_missing_abi(*extern_span, item.id);
self.handle_missing_abi(*extern_span, item.id);
}
self.with_in_extern_mod(*safety, |this| {
visit::walk_item(this, item);
@ -1370,7 +1372,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
},
) = fk
{
self.maybe_lint_missing_abi(*extern_span, id);
self.handle_missing_abi(*extern_span, id);
}
// Functions without bodies cannot have patterns.

View file

@ -2,7 +2,7 @@
use rustc_ast::ParamKindOrd;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};
@ -394,11 +394,7 @@ pub(crate) struct EmptyLabelManySpans(pub Vec<Span>);
// The derive for `Vec<Span>` does multiple calls to `span_label`, adding commas between each
impl Subdiagnostic for EmptyLabelManySpans {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_labels(self.0, "");
}
}
@ -749,11 +745,7 @@ pub(crate) struct StableFeature {
}
impl Subdiagnostic for StableFeature {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("name", self.name);
diag.arg("since", self.since);
diag.help(fluent::ast_passes_stable_since);
@ -823,3 +815,12 @@ pub(crate) struct DuplicatePreciseCapturing {
#[label]
pub bound2: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_extern_without_abi)]
#[help]
pub(crate) struct MissingAbi {
#[primary_span]
#[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")]
pub span: Span,
}

View file

@ -5,14 +5,10 @@ pub mod state;
use std::borrow::Cow;
use rustc_ast as ast;
use rustc_ast::token::{Nonterminal, Token, TokenKind};
use rustc_ast::token::{Token, TokenKind};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
pub use state::{AnnNode, Comments, PpAnn, PrintState, State, print_crate};
pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
State::new().nonterminal_to_string(nt)
}
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> {
State::new().token_kind_to_string(tok)

View file

@ -11,7 +11,7 @@ use std::sync::Arc;
use rustc_ast::attr::AttrIdGenerator;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
use rustc_ast::util::classify;
use rustc_ast::util::comments::{Comment, CommentStyle};
@ -876,14 +876,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
}
}
fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
// We extract the token stream from the AST fragment and pretty print
// it, rather than using AST pretty printing, because `Nonterminal` is
// slated for removal in #124141. (This method will also then be
// removed.)
self.tts_to_string(&TokenStream::from_nonterminal_ast(nt))
}
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
fn token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str> {
self.token_kind_to_string_ext(tok, None)
@ -976,8 +968,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
doc_comment_to_string(comment_kind, attr_style, data).into()
}
token::Eof => "<eof>".into(),
token::Interpolated(ref nt) => self.nonterminal_to_string(&nt).into(),
}
}

View file

@ -7,7 +7,6 @@ use rustc_session::config::ExpectedValues;
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
use rustc_session::parse::feature_err;
use rustc_span::symbol::kw;
use rustc_span::{Span, Symbol, sym};
use crate::session_diagnostics::{self, UnsupportedLiteralReason};
@ -89,20 +88,6 @@ pub fn eval_condition(
let cfg = match cfg {
MetaItemInner::MetaItem(meta_item) => meta_item,
MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
if let Some(features) = features {
// we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
// and `true`, and we want to keep the former working without feature gate
gate_cfg(
&(
if *b { kw::True } else { kw::False },
sym::cfg_boolean_literals,
|features: &Features| features.cfg_boolean_literals(),
),
cfg.span(),
sess,
features,
);
}
return *b;
}
_ => {

View file

@ -20,7 +20,7 @@ impl SingleAttributeParser for TransparencyParser {
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
match args.name_value().and_then(|nv| nv.value_as_str()) {
Some(sym::transparent) => Some(Transparency::Transparent),
Some(sym::semitransparent) => Some(Transparency::SemiTransparent),
Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
Some(sym::opaque) => Some(Transparency::Opaque),
Some(other) => {
cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`"));

View file

@ -320,7 +320,7 @@ impl<'sess> AttributeParser<'sess> {
ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(DelimArgs {
dspan: args.dspan,
delim: args.delim,
tokens: args.tokens.flattened(),
tokens: args.tokens.clone(),
}),
// This is an inert key-value attribute - it will never be visible to macros
// after it gets lowered to HIR. Therefore, we can extract literals to handle

View file

@ -77,7 +77,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)]
#![feature(let_chains)]
#![feature(rustdoc_internals)]

View file

@ -485,25 +485,7 @@ impl<'a> MetaItemListParserContext<'a> {
}
// or a path.
let path =
if let Some(TokenTree::Token(Token { kind: token::Interpolated(_), span, .. }, _)) =
self.inside_delimiters.peek()
{
self.inside_delimiters.next();
// We go into this path if an expr ended up in an attribute that
// expansion did not turn into a literal. Say, `#[repr(align(macro!()))]`
// where the macro didn't expand to a literal. An error is already given
// for this at this point, and then we do continue. This makes this path
// reachable...
let e = self.dcx.span_delayed_bug(
*span,
"expr in place where literal is expected (builtin attr parsing)",
);
return Some(MetaItemOrLitParser::Err(*span, e));
} else {
self.next_path()?
};
let path = self.next_path()?;
// Paths can be followed by:
// - `(more meta items)` (another list)

View file

@ -77,6 +77,9 @@ pub(crate) fn categorize(context: PlaceContext) -> Option<DefUse> {
// Debug info is neither def nor use.
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None,
// Backwards incompatible drop hint is not a use, just a marker for linting.
PlaceContext::NonUse(NonUseContext::BackwardIncompatibleDropHint) => None,
PlaceContext::MutatingUse(MutatingUseContext::Deinit | MutatingUseContext::SetDiscriminant) => {
bug!("These statements are not allowed in this MIR phase")
}

View file

@ -647,7 +647,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
&& tc.polarity() == ty::PredicatePolarity::Positive
&& supertrait_def_ids(tcx, tc.def_id())
.flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())
.any(|item| item.fn_has_self_parameter)
.any(|item| item.is_method())
})
}) {
return None;
@ -3376,10 +3376,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
Ok(string) => {
let coro_prefix = if string.starts_with("async") {
// `async` is 5 chars long. Not using `.len()` to avoid the cast from `usize`
// to `u32`.
Some(5)
let coro_prefix = if let Some(sub) = string.strip_prefix("async") {
let trimmed_sub = sub.trim_end();
if trimmed_sub.ends_with("gen") {
// `async` is 5 chars long.
Some((trimmed_sub.len() + 5) as _)
} else {
// `async` is 5 chars long.
Some(5)
}
} else if string.starts_with("gen") {
// `gen` is 3 chars long
Some(3)

View file

@ -888,7 +888,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
// Skip `async` desugaring `impl Future`.
}
if let TyKind::TraitObject(_, lt) = alias_ty.kind {
if lt.res == hir::LifetimeName::ImplicitObjectLifetimeDefault {
if lt.kind == hir::LifetimeKind::ImplicitObjectLifetimeDefault {
spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
} else {
spans_suggs.push((lt.ident.span, "'a".to_string()));

View file

@ -2,7 +2,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(box_patterns)]
@ -22,6 +21,7 @@ use std::cell::RefCell;
use std::marker::PhantomData;
use std::ops::{ControlFlow, Deref};
use borrow_set::LocalsStateAtExit;
use root_cx::BorrowCheckRootCtxt;
use rustc_abi::FieldIdx;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@ -304,33 +304,13 @@ fn do_mir_borrowck<'tcx>(
root_cx.set_tainted_by_errors(e);
}
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
for var_debug_info in &input_body.var_debug_info {
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
if let Some(local) = place.as_local() {
if let Some(prev_name) = local_names[local]
&& var_debug_info.name != prev_name
{
span_bug!(
var_debug_info.source_info.span,
"local {:?} has many names (`{}` vs `{}`)",
local,
prev_name,
var_debug_info.name
);
}
local_names[local] = Some(var_debug_info.name);
}
}
}
// Replace all regions with fresh inference variables. This
// requires first making our own copy of the MIR. This copy will
// be modified (in place) to contain non-lexical lifetimes. It
// will have a lifetime tied to the inference context.
let mut body_owned = input_body.clone();
let mut promoted = input_promoted.to_owned();
let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
let body = &body_owned; // no further changes
let location_table = PoloniusLocationTable::new(body);
@ -355,7 +335,7 @@ fn do_mir_borrowck<'tcx>(
} = nll::compute_regions(
root_cx,
&infcx,
free_regions,
universal_regions,
body,
&promoted,
&location_table,
@ -368,24 +348,23 @@ fn do_mir_borrowck<'tcx>(
// Dump MIR results into a file, if that is enabled. This lets us
// write unit-tests, as well as helping with debugging.
nll::dump_nll_mir(&infcx, body, &regioncx, &opt_closure_req, &borrow_set);
polonius::dump_polonius_mir(
&infcx,
body,
&regioncx,
&opt_closure_req,
&borrow_set,
polonius_diagnostics.as_ref(),
);
// We also have a `#[rustc_regions]` annotation that causes us to dump
// information.
nll::dump_annotation(&infcx, body, &regioncx, &opt_closure_req);
let movable_coroutine = body.coroutine.is_some()
&& tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable;
let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
nll::dump_annotation(&infcx, body, &regioncx, &opt_closure_req, diags_buffer);
let movable_coroutine =
// The first argument is the coroutine type passed by value
if let Some(local) = body.local_decls.raw.get(1)
// Get the interior types and args which typeck computed
&& let ty::Coroutine(def_id, _) = *local.ty.kind()
&& tcx.coroutine_movability(def_id) == hir::Movability::Movable
{
true
} else {
false
};
// While promoteds should mostly be correct by construction, we need to check them for
// invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
for promoted_body in &promoted {
@ -403,7 +382,6 @@ fn do_mir_borrowck<'tcx>(
location_table: &location_table,
movable_coroutine,
fn_self_span_reported: Default::default(),
locals_are_invalidated_at_exit,
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
uninitialized_error_reported: Default::default(),
@ -435,6 +413,26 @@ fn do_mir_borrowck<'tcx>(
promoted_mbcx.report_move_errors();
}
let mut local_names = IndexVec::from_elem(None, &body.local_decls);
for var_debug_info in &body.var_debug_info {
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
if let Some(local) = place.as_local() {
if let Some(prev_name) = local_names[local]
&& var_debug_info.name != prev_name
{
span_bug!(
var_debug_info.source_info.span,
"local {:?} has many names (`{}` vs `{}`)",
local,
prev_name,
var_debug_info.name
);
}
local_names[local] = Some(var_debug_info.name);
}
}
}
let mut mbcx = MirBorrowckCtxt {
root_cx,
infcx: &infcx,
@ -442,7 +440,6 @@ fn do_mir_borrowck<'tcx>(
move_data: &move_data,
location_table: &location_table,
movable_coroutine,
locals_are_invalidated_at_exit,
fn_self_span_reported: Default::default(),
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
@ -455,9 +452,9 @@ fn do_mir_borrowck<'tcx>(
local_names,
region_names: RefCell::default(),
next_region_name: RefCell::new(1),
polonius_output,
move_errors: Vec::new(),
diags_buffer,
polonius_output: polonius_output.as_deref(),
polonius_diagnostics: polonius_diagnostics.as_ref(),
};
@ -474,16 +471,6 @@ fn do_mir_borrowck<'tcx>(
mbcx.report_move_errors();
// If requested, dump polonius MIR.
polonius::dump_polonius_mir(
&infcx,
body,
&regioncx,
&borrow_set,
polonius_diagnostics.as_ref(),
&opt_closure_req,
);
// For each non-user used mutable variable, check if it's been assigned from
// a user-declared local. If so, then put that local into the used_mut set.
// Note that this set is expected to be small - only upvars from closures
@ -514,7 +501,6 @@ fn do_mir_borrowck<'tcx>(
};
let body_with_facts = if consumer_options.is_some() {
let output_facts = mbcx.polonius_output;
Some(Box::new(BodyWithBorrowckFacts {
body: body_owned,
promoted,
@ -522,7 +508,7 @@ fn do_mir_borrowck<'tcx>(
region_inference_context: regioncx,
location_table: polonius_input.as_ref().map(|_| location_table),
input_facts: polonius_input,
output_facts,
output_facts: polonius_output,
}))
} else {
None
@ -655,13 +641,6 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
location_table: &'a PoloniusLocationTable,
movable_coroutine: bool,
/// This keeps track of whether local variables are free-ed when the function
/// exits even without a `StorageDead`, which appears to be the case for
/// constants.
///
/// I'm not sure this is the right approach - @eddyb could you try and
/// figure this out?
locals_are_invalidated_at_exit: bool,
/// This field keeps track of when borrow errors are reported in the access_place function
/// so that there is no duplicate reporting. This field cannot also be used for the conflicting
/// borrow errors that is handled by the `reservation_error_reported` field as the inclusion
@ -709,12 +688,11 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
/// The counter for generating new region names.
next_region_name: RefCell<usize>,
/// Results of Polonius analysis.
polonius_output: Option<Box<PoloniusOutput>>,
diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
move_errors: Vec<MoveError<'tcx>>,
/// Results of Polonius analysis.
polonius_output: Option<&'a PoloniusOutput>,
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
}
@ -938,13 +916,20 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
| TerminatorKind::Return
| TerminatorKind::TailCall { .. }
| TerminatorKind::CoroutineDrop => {
// Returning from the function implicitly kills storage for all locals and statics.
// Often, the storage will already have been killed by an explicit
// StorageDead, but we don't always emit those (notably on unwind paths),
// so this "extra check" serves as a kind of backup.
for i in state.borrows.iter() {
let borrow = &self.borrow_set[i];
self.check_for_invalidation_at_exit(loc, borrow, span);
match self.borrow_set.locals_state_at_exit() {
LocalsStateAtExit::AllAreInvalidated => {
// Returning from the function implicitly kills storage for all locals and statics.
// Often, the storage will already have been killed by an explicit
// StorageDead, but we don't always emit those (notably on unwind paths),
// so this "extra check" serves as a kind of backup.
for i in state.borrows.iter() {
let borrow = &self.borrow_set[i];
self.check_for_invalidation_at_exit(loc, borrow, span);
}
}
// If we do not implicitly invalidate all locals on exit,
// we check for conflicts when dropping or moving this local.
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
}
}
@ -1301,7 +1286,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
error_reported
}
/// Through #123739, backward incompatible drops (BIDs) are introduced.
/// Through #123739, `BackwardIncompatibleDropHint`s (BIDs) are introduced.
/// We would like to emit lints whether borrow checking fails at these future drop locations.
#[instrument(level = "debug", skip(self, state))]
fn check_backward_incompatible_drop(
@ -1716,22 +1701,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
// we'll have a memory leak) and assume that all statics have a destructor.
//
// FIXME: allow thread-locals to borrow other thread locals?
let (might_be_alive, will_be_dropped) =
if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
// Thread-locals might be dropped after the function exits
// We have to dereference the outer reference because
// borrows don't conflict behind shared references.
root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
(true, true)
} else {
(false, self.locals_are_invalidated_at_exit)
};
if !will_be_dropped {
debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place);
return;
}
let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
// Thread-locals might be dropped after the function exits
// We have to dereference the outer reference because
// borrows don't conflict behind shared references.
root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
true
} else {
false
};
let sd = if might_be_alive { Deep } else { Shallow(None) };

View file

@ -21,7 +21,7 @@ use tracing::{debug, instrument};
use crate::borrow_set::BorrowSet;
use crate::consumers::ConsumerOptions;
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
use crate::diagnostics::RegionErrors;
use crate::polonius::PoloniusDiagnosticsContext;
use crate::polonius::legacy::{
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
@ -117,11 +117,6 @@ pub(crate) fn compute_regions<'a, 'tcx>(
Rc::clone(&location_map),
);
// Create the region inference context, taking ownership of the
// region inference data that was contained in `infcx`, and the
// base constraints generated by the type-check.
let var_infos = infcx.get_region_var_infos();
// If requested, emit legacy polonius facts.
polonius::legacy::emit_facts(
&mut polonius_facts,
@ -134,13 +129,8 @@ pub(crate) fn compute_regions<'a, 'tcx>(
&constraints,
);
let mut regioncx = RegionInferenceContext::new(
infcx,
var_infos,
constraints,
universal_region_relations,
location_map,
);
let mut regioncx =
RegionInferenceContext::new(infcx, constraints, universal_region_relations, location_map);
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
// and use them to compute loan liveness.
@ -297,7 +287,6 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
diagnostics_buffer: &mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
) {
let tcx = infcx.tcx;
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
@ -335,13 +324,11 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
} else {
let mut err = infcx.dcx().struct_span_note(def_span, "no external requirements");
regioncx.annotate(tcx, &mut err);
err
};
// FIXME(@lcnr): We currently don't dump the inferred hidden types here.
diagnostics_buffer.buffer_non_error(err);
err.emit();
}
fn for_each_region_constraint<'tcx>(

View file

@ -24,9 +24,9 @@ pub(crate) fn dump_polonius_mir<'tcx>(
infcx: &BorrowckInferCtxt<'tcx>,
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
borrow_set: &BorrowSet<'tcx>,
polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
) {
let tcx = infcx.tcx;
if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {

View file

@ -9,7 +9,7 @@ use rustc_errors::Diag;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_index::IndexVec;
use rustc_infer::infer::outlives::test_type_match;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound, VerifyIfEq};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
use rustc_middle::bug;
use rustc_middle::mir::{
@ -145,7 +145,7 @@ pub struct RegionInferenceContext<'tcx> {
/// variables are identified by their index (`RegionVid`). The
/// definition contains information about where the region came
/// from as well as its final inferred value.
pub(crate) definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
pub(crate) definitions: Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>,
/// The liveness constraints added to each region. For most
/// regions, these start out empty and steadily grow, though for
@ -338,8 +338,7 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
let num_components = sccs.num_sccs();
let mut components = vec![FxIndexSet::default(); num_components];
for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() {
let reg_var = ty::RegionVid::from_usize(reg_var_idx);
for (reg_var, scc_idx) in sccs.scc_indices().iter_enumerated() {
let origin = var_to_origin.get(&reg_var).unwrap_or(&RegionCtxt::Unknown);
components[scc_idx.as_usize()].insert((reg_var, *origin));
}
@ -385,6 +384,26 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
debug!("SCC edges {:#?}", scc_node_to_edges);
}
fn create_definitions<'tcx>(
infcx: &BorrowckInferCtxt<'tcx>,
universal_regions: &UniversalRegions<'tcx>,
) -> Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>> {
// Create a RegionDefinition for each inference variable.
let mut definitions: IndexVec<_, _> = infcx
.get_region_var_infos()
.iter()
.map(|info| RegionDefinition::new(info.universe, info.origin))
.collect();
// Add the external name for all universal regions.
for (external_name, variable) in universal_regions.named_universal_regions_iter() {
debug!("region {variable:?} has external name {external_name:?}");
definitions[variable].external_name = Some(external_name);
}
Frozen::freeze(definitions)
}
impl<'tcx> RegionInferenceContext<'tcx> {
/// Creates a new region inference context with a total of
/// `num_region_variables` valid inference variables; the first N
@ -395,7 +414,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// of constraints produced by the MIR type check.
pub(crate) fn new(
infcx: &BorrowckInferCtxt<'tcx>,
var_infos: VarInfos,
constraints: MirTypeckRegionConstraints<'tcx>,
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
location_map: Rc<DenseLocationMap>,
@ -426,11 +444,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
infcx.set_tainted_by_errors(guar);
}
// Create a RegionDefinition for each inference variable.
let definitions: IndexVec<_, _> = var_infos
.iter()
.map(|info| RegionDefinition::new(info.universe, info.origin))
.collect();
let definitions = create_definitions(infcx, &universal_regions);
let constraint_sccs =
outlives_constraints.add_outlives_static(&universal_regions, &definitions);
@ -526,18 +540,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// means that the `R1: !1` constraint here will cause
/// `R1` to become `'static`.
fn init_free_and_bound_regions(&mut self) {
// Update the names (if any)
// This iterator has unstable order but we collect it all into an IndexVec
for (external_name, variable) in
self.universal_region_relations.universal_regions.named_universal_regions_iter()
{
debug!(
"init_free_and_bound_regions: region {:?} has external name {:?}",
variable, external_name
);
self.definitions[variable].external_name = Some(external_name);
}
for variable in self.definitions.indices() {
let scc = self.constraint_sccs.scc(variable);

View file

@ -21,7 +21,6 @@ use crate::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategor
pub(crate) struct ConstraintConversion<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
tcx: TyCtxt<'tcx>,
universal_regions: &'a UniversalRegions<'tcx>,
/// Each RBP `GK: 'a` is assumed to be true. These encode
/// relationships like `T: 'a` that are added via implicit bounds
@ -34,7 +33,6 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
/// logic expecting to see (e.g.) `ReStatic`, and if we supplied
/// our special inference variable there, we would mess that up.
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
param_env: ty::ParamEnv<'tcx>,
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
locations: Locations,
@ -49,7 +47,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
universal_regions: &'a UniversalRegions<'tcx>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
param_env: ty::ParamEnv<'tcx>,
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
locations: Locations,
@ -59,10 +56,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
) -> Self {
Self {
infcx,
tcx: infcx.tcx,
universal_regions,
region_bound_pairs,
implicit_region_bound,
param_env,
known_type_outlives_obligations,
locations,
@ -96,7 +91,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
// into a vector. These are the regions that we will be
// relating to one another.
let closure_mapping = &UniversalRegions::closure_mapping(
self.tcx,
self.infcx.tcx,
closure_args,
closure_requirements.num_external_vids,
closure_def_id,
@ -111,7 +106,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
let subject = match outlives_requirement.subject {
ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
ClosureOutlivesSubject::Ty(subject_ty) => {
subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into()
subject_ty.instantiate(self.infcx.tcx, |vid| closure_mapping[vid]).into()
}
};
@ -127,14 +122,14 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
constraint_category: ConstraintCategory<'tcx>,
) {
let tcx = self.infcx.tcx;
debug!("generate: constraints at: {:#?}", self.locations);
// Extract out various useful fields we'll need below.
let ConstraintConversion {
tcx,
infcx,
universal_regions,
region_bound_pairs,
implicit_region_bound,
known_type_outlives_obligations,
..
} = *self;
@ -145,7 +140,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
break;
}
if !self.tcx.recursion_limit().value_within_limit(iteration) {
if !tcx.recursion_limit().value_within_limit(iteration) {
bug!(
"FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
);
@ -170,10 +165,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
);
}
let implicit_region_bound =
ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = infer::RelateParamBound(self.span, t1, None);
TypeOutlives::new(
&mut *self,
tcx,
@ -205,7 +201,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
/// are dealt with during trait solving.
fn replace_placeholders_with_nll<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
if value.has_placeholders() {
fold_regions(self.tcx, value, |r, _| match r.kind() {
fold_regions(self.infcx.tcx, value, |r, _| match r.kind() {
ty::RePlaceholder(placeholder) => {
self.constraints.placeholder_region(self.infcx, placeholder)
}

View file

@ -49,14 +49,12 @@ pub(crate) struct CreateResult<'tcx> {
pub(crate) fn create<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
universal_regions: UniversalRegions<'tcx>,
constraints: &mut MirTypeckRegionConstraints<'tcx>,
) -> CreateResult<'tcx> {
UniversalRegionRelationsBuilder {
infcx,
param_env,
implicit_region_bound,
constraints,
universal_regions,
region_bound_pairs: Default::default(),
@ -181,7 +179,6 @@ struct UniversalRegionRelationsBuilder<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
universal_regions: UniversalRegions<'tcx>,
implicit_region_bound: ty::Region<'tcx>,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
// outputs:
@ -320,7 +317,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
self.infcx,
&self.universal_regions,
&self.region_bound_pairs,
self.implicit_region_bound,
param_env,
&known_type_outlives_obligations,
Locations::All(span),

View file

@ -113,7 +113,6 @@ pub(crate) fn type_check<'a, 'tcx>(
move_data: &MoveData<'tcx>,
location_map: Rc<DenseLocationMap>,
) -> MirTypeckResults<'tcx> {
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
let mut constraints = MirTypeckRegionConstraints {
placeholder_indices: PlaceholderIndices::default(),
placeholder_index_to_region: IndexVec::default(),
@ -129,13 +128,7 @@ pub(crate) fn type_check<'a, 'tcx>(
region_bound_pairs,
normalized_inputs_and_output,
known_type_outlives_obligations,
} = free_region_relations::create(
infcx,
infcx.param_env,
implicit_region_bound,
universal_regions,
&mut constraints,
);
} = free_region_relations::create(infcx, infcx.param_env, universal_regions, &mut constraints);
let pre_obligations = infcx.take_registered_region_obligations();
assert!(
@ -160,7 +153,6 @@ pub(crate) fn type_check<'a, 'tcx>(
user_type_annotations: &body.user_type_annotations,
region_bound_pairs,
known_type_outlives_obligations,
implicit_region_bound,
reported_errors: Default::default(),
universal_regions: &universal_region_relations.universal_regions,
location_table,
@ -226,7 +218,6 @@ struct TypeChecker<'a, 'tcx> {
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
region_bound_pairs: RegionBoundPairs<'tcx>,
known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
implicit_region_bound: ty::Region<'tcx>,
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
universal_regions: &'a UniversalRegions<'tcx>,
location_table: &'a PoloniusLocationTable,
@ -422,7 +413,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.infcx,
self.universal_regions,
&self.region_bound_pairs,
self.implicit_region_bound,
self.infcx.param_env,
&self.known_type_outlives_obligations,
locations,
@ -1567,11 +1557,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
CastKind::Transmute => {
span_mirbug!(
self,
rvalue,
"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
);
let ty_from = op.ty(self.body, tcx);
match ty_from.kind() {
ty::Pat(base, _) if base == ty => {}
_ => span_mirbug!(
self,
rvalue,
"Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR",
),
}
}
}
}
@ -2507,7 +2501,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.infcx,
self.universal_regions,
&self.region_bound_pairs,
self.implicit_region_bound,
self.infcx.param_env,
&self.known_type_outlives_obligations,
locations,

View file

@ -438,6 +438,10 @@ impl<'tcx> UniversalRegions<'tcx> {
}
}
pub(crate) fn implicit_region_bound(&self) -> RegionVid {
self.fr_fn_body
}
pub(crate) fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
self.indices.tainted_by_errors.get()
}

View file

@ -231,8 +231,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
builtin_macros_format_use_positional = consider using a positional formatting argument instead
builtin_macros_invalid_crate_attribute = invalid crate attribute
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
.note = only one `#[default]` attribute is needed
.label = `#[default]` used here

View file

@ -92,11 +92,7 @@ impl CfgEval<'_> {
// the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
// process is lossless, so this process is invisible to proc-macros.
// 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
// to `None`-delimited groups containing the corresponding tokens. This
// is normally delayed until the proc-macro server actually needs to
// provide a `TokenKind::Interpolated` to a proc-macro. We do this earlier,
// so that we can handle cases like:
// Interesting cases:
//
// ```rust
// #[cfg_eval] #[cfg] $item
@ -104,8 +100,8 @@ impl CfgEval<'_> {
//
// where `$item` is `#[cfg_attr] struct Foo {}`. We want to make
// sure to evaluate *all* `#[cfg]` and `#[cfg_attr]` attributes - the simplest
// way to do this is to do a single parse of a stream without any nonterminals.
let orig_tokens = annotatable.to_tokens().flattened();
// way to do this is to do a single parse of the token stream.
let orig_tokens = annotatable.to_tokens();
// Re-parse the tokens, setting the `capture_cfg` flag to save extra information
// to the captured `AttrTokenStream` (specifically, we capture

View file

@ -1,44 +1,37 @@
//! Attributes injected into the crate root from command line using `-Z crate-attr`.
use rustc_ast::attr::mk_attr;
use rustc_ast::{self as ast, AttrItem, AttrStyle, token};
use rustc_parse::parser::ForceCollect;
use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
use rustc_ast::{self as ast};
use rustc_errors::Diag;
use rustc_parse::parser::attr::InnerAttrPolicy;
use rustc_parse::{parse_in, source_str_to_stream};
use rustc_session::parse::ParseSess;
use rustc_span::FileName;
use crate::errors;
pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
for raw_attr in attrs {
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 { unsafety, path, args, tokens: _ } =
match parser.parse_attr_item(ForceCollect::No) {
Ok(ai) => ai,
Err(err) => {
let source = format!("#![{raw_attr}]");
let parse = || -> Result<ast::Attribute, Vec<Diag<'_>>> {
let tokens = source_str_to_stream(
psess,
FileName::cli_crate_attr_source_code(raw_attr),
source,
None,
)?;
parse_in(psess, tokens, "<crate attribute>", |p| {
p.parse_attribute(InnerAttrPolicy::Permitted)
})
.map_err(|e| vec![e])
};
let meta = match parse() {
Ok(meta) => meta,
Err(errs) => {
for err in errs {
err.emit();
continue;
}
};
let end_span = parser.token.span;
if parser.token != token::Eof {
psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
continue;
}
continue;
}
};
krate.attrs.push(mk_attr(
&psess.attr_id_generator,
AttrStyle::Inner,
unsafety,
path,
args,
start_span.to(end_span),
));
krate.attrs.push(meta);
}
}

View file

@ -1,7 +1,7 @@
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans,
SubdiagMessageOp, Subdiagnostic,
Subdiagnostic,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};
@ -109,13 +109,6 @@ pub(crate) struct ProcMacro {
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_invalid_crate_attribute)]
pub(crate) struct InvalidCrateAttr {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_non_abi)]
pub(crate) struct NonABI {
@ -691,13 +684,9 @@ pub(crate) struct FormatUnusedArg {
// Allow the singular form to be a subdiagnostic of the multiple-unused
// form of diagnostic.
impl Subdiagnostic for FormatUnusedArg {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("named", self.named);
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
let msg = diag.eagerly_translate(crate::fluent_generated::builtin_macros_format_unused_arg);
diag.span_label(self.span, msg);
}
}

View file

@ -5,7 +5,6 @@
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(assert_matches)]

View file

@ -1,6 +1,6 @@
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use rustc_hir::LangItem;
use rustc_middle::ty::{AssocKind, GenericArg};
use rustc_middle::ty::{AssocTag, GenericArg};
use rustc_session::config::EntryFnType;
use rustc_span::{DUMMY_SP, Ident};
@ -107,7 +107,7 @@ pub(crate) fn maybe_create_entry_wrapper(
.find_by_ident_and_kind(
tcx,
Ident::from_str("report"),
AssocKind::Fn,
AssocTag::Fn,
termination_trait,
)
.unwrap();

View file

@ -3,7 +3,6 @@ use std::collections::hash_map::Entry;
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_index::Idx;
use rustc_index::bit_set::DenseBitSet;
use rustc_middle::mir::{Body, SourceScope};
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
@ -43,8 +42,7 @@ pub(crate) fn compute_mir_scopes<'ll, 'tcx>(
let mut instantiated = DenseBitSet::new_empty(mir.source_scopes.len());
let mut discriminators = FxHashMap::default();
// Instantiate all scopes.
for idx in 0..mir.source_scopes.len() {
let scope = SourceScope::new(idx);
for scope in mir.source_scopes.indices() {
make_mir_scope(
cx,
instance,

View file

@ -1315,31 +1315,21 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>(
ty: Ty<'tcx>,
) -> SmallVec<Option<&'ll DIType>> {
if let ty::Adt(def, args) = *ty.kind() {
let generics = cx.tcx.generics_of(def.did());
return get_template_parameters(cx, generics, args);
}
return smallvec![];
}
pub(super) fn get_template_parameters<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
generics: &ty::Generics,
args: ty::GenericArgsRef<'tcx>,
) -> SmallVec<Option<&'ll DIType>> {
if args.types().next().is_some() {
let names = get_parameter_names(cx, generics);
let template_params: SmallVec<_> = iter::zip(args, names)
.filter_map(|(kind, name)| {
kind.as_type().map(|ty| {
let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
let actual_type_di_node = type_di_node(cx, actual_type);
Some(cx.create_template_type_parameter(name.as_str(), actual_type_di_node))
if args.types().next().is_some() {
let generics = cx.tcx.generics_of(def.did());
let names = get_parameter_names(cx, generics);
let template_params: SmallVec<_> = iter::zip(args, names)
.filter_map(|(kind, name)| {
kind.as_type().map(|ty| {
let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
let actual_type_di_node = type_di_node(cx, actual_type);
Some(cx.create_template_type_parameter(name.as_str(), actual_type_di_node))
})
})
})
.collect();
.collect();
return template_params;
return template_params;
}
}
return smallvec![];

View file

@ -363,7 +363,6 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
state_specific_fields.into_iter().chain(common_fields).collect()
},
// FIXME: this is a no-op. `build_generic_type_param_di_nodes` only works for Adts.
|cx| build_generic_type_param_di_nodes(cx, coroutine_type_and_layout.ty),
)
.di_node

View file

@ -2,8 +2,8 @@
use std::cell::{OnceCell, RefCell};
use std::ops::Range;
use std::ptr;
use std::sync::Arc;
use std::{iter, ptr};
use libc::c_uint;
use metadata::create_subroutine_type;
@ -486,10 +486,40 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
generics: &ty::Generics,
args: GenericArgsRef<'tcx>,
) -> &'ll DIArray {
let template_params = metadata::get_template_parameters(cx, generics, args);
if args.types().next().is_none() {
return create_DIArray(DIB(cx), &[]);
}
// Again, only create type information if full debuginfo is enabled
let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
let names = get_parameter_names(cx, generics);
iter::zip(args, names)
.filter_map(|(kind, name)| {
kind.as_type().map(|ty| {
let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
let actual_type_metadata = type_di_node(cx, actual_type);
Some(cx.create_template_type_parameter(
name.as_str(),
actual_type_metadata,
))
})
})
.collect()
} else {
vec![]
};
create_DIArray(DIB(cx), &template_params)
}
fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
get_parameter_names(cx, cx.tcx.generics_of(def_id))
});
names.extend(generics.own_params.iter().map(|param| param.name));
names
}
/// Returns a scope, plus `true` if that's a type scope for "class" methods,
/// otherwise `false` for plain namespace scopes.
fn get_containing_scope<'ll, 'tcx>(

View file

@ -114,7 +114,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
AttributeKind::Repr(reprs) => {
codegen_fn_attrs.alignment = reprs
.iter()
.find_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None });
.filter_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None })
.max();
}
_ => {}

View file

@ -2,7 +2,6 @@
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(assert_matches)]

View file

@ -6,7 +6,7 @@ use rustc_abi::WrappingRange;
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level,
MultiSpan, SubdiagMessageOp, Subdiagnostic,
MultiSpan, Subdiagnostic,
};
use rustc_hir::ConstContext;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@ -290,11 +290,7 @@ pub struct FrameNote {
}
impl Subdiagnostic for FrameNote {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("times", self.times);
diag.arg("where_", self.where_);
diag.arg("instance", self.instance);
@ -302,7 +298,7 @@ impl Subdiagnostic for FrameNote {
if self.has_label && !self.span.is_dummy() {
span.push_span_label(self.span, fluent::const_eval_frame_note_last);
}
let msg = f(diag, fluent::const_eval_frame_note.into());
let msg = diag.eagerly_translate(fluent::const_eval_frame_note);
diag.span_note(span, msg);
}
}

View file

@ -1,7 +1,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(box_patterns)]

View file

@ -1,13 +1,13 @@
use std::alloc::Allocator;
#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \
#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \
Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")]
// This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()`
// is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a
// `Send` type in `IntoDynSyncSend` will create a `DynSend` type.
pub unsafe auto trait DynSend {}
#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \
#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \
Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`")]
// This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()`
// is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a

View file

@ -3,7 +3,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)]
#![feature(rustdoc_internals)]
// tidy-alphabetical-end

View file

@ -4,6 +4,7 @@ version = "0.0.0"
edition = "2024"
[dependencies]
jiff = { version = "0.2.5", default-features = false, features = ["std"] }
# tidy-alphabetical-start
rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
@ -50,7 +51,6 @@ rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }
serde_json = "1.0.59"
shlex = "1.0"
time = { version = "0.3.36", default-features = false, features = ["alloc", "formatting", "macros"] }
tracing = { version = "0.1.35" }
# tidy-alphabetical-end

View file

@ -7,7 +7,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(decl_macro)]
@ -30,7 +29,7 @@ use std::path::{Path, PathBuf};
use std::process::{self, Command, Stdio};
use std::sync::OnceLock;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Instant, SystemTime};
use std::time::Instant;
use std::{env, str};
use rustc_ast as ast;
@ -66,8 +65,6 @@ use rustc_span::FileName;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_target::json::ToJson;
use rustc_target::spec::{Target, TargetTuple};
use time::OffsetDateTime;
use time::macros::format_description;
use tracing::trace;
#[allow(unused_macros)]
@ -1301,13 +1298,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat
.or_else(|| std::env::current_dir().ok())
.unwrap_or_default(),
};
let now: OffsetDateTime = SystemTime::now().into();
let file_now = now
.format(
// Don't use a standard datetime format because Windows doesn't support `:` in paths
&format_description!("[year]-[month]-[day]T[hour]_[minute]_[second]"),
)
.unwrap_or_default();
// Don't use a standard datetime format because Windows doesn't support `:` in paths
let file_now = jiff::Zoned::now().strftime("%Y-%m-%dT%H_%M_%S");
let pid = std::process::id();
path.push(format!("rustc-ice-{file_now}-{pid}.txt"));
Some(path)

View file

@ -5,7 +5,7 @@ Erroneous code example:
```compile_fail,E0755
#![feature(ffi_pure)]
#[ffi_pure] // error!
#[unsafe(ffi_pure)] // error!
pub fn foo() {}
# fn main() {}
```
@ -17,7 +17,7 @@ side effects or infinite loops:
#![feature(ffi_pure)]
extern "C" {
#[ffi_pure] // ok!
#[unsafe(ffi_pure)] // ok!
pub fn strlen(s: *const i8) -> isize;
}
# fn main() {}

View file

@ -6,7 +6,7 @@ Erroneous code example:
```compile_fail,E0756
#![feature(ffi_const)]
#[ffi_const] // error!
#[unsafe(ffi_const)] // error!
pub fn foo() {}
# fn main() {}
```
@ -18,7 +18,7 @@ which have no side effects except for their return value:
#![feature(ffi_const)]
extern "C" {
#[ffi_const] // ok!
#[unsafe(ffi_const)] // ok!
pub fn strlen(s: *const i8) -> i32;
}
# fn main() {}

View file

@ -6,8 +6,9 @@ Erroneous code example:
#![feature(ffi_const, ffi_pure)]
extern "C" {
#[ffi_const]
#[ffi_pure] // error: `#[ffi_const]` function cannot be `#[ffi_pure]`
#[unsafe(ffi_const)]
#[unsafe(ffi_pure)]
//~^ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]`
pub fn square(num: i32) -> i32;
}
```
@ -19,7 +20,7 @@ As `ffi_const` provides stronger guarantees than `ffi_pure`, remove the
#![feature(ffi_const)]
extern "C" {
#[ffi_const]
#[unsafe(ffi_const)]
pub fn square(num: i32) -> i32;
}
```

View file

@ -181,22 +181,9 @@ where
Self: Sized,
{
/// Add a subdiagnostic to an existing diagnostic.
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
self.add_to_diag_with(diag, &|_, m| m);
}
/// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
/// (to optionally perform eager translation).
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
);
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>);
}
pub trait SubdiagMessageOp<G: EmissionGuarantee> =
Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage;
/// Trait implemented by lint types. This should not be implemented manually. Instead, use
/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic].
#[rustc_diagnostic_item = "LintDiagnostic"]
@ -1227,15 +1214,21 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// interpolated variables).
#[rustc_lint_diagnostics]
pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
let dcx = self.dcx;
subdiagnostic.add_to_diag_with(self, &|diag, msg| {
let args = diag.args.iter();
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
dcx.eagerly_translate(msg, args)
});
subdiagnostic.add_to_diag(self);
self
}
/// Fluent variables are not namespaced from each other, so when
/// `Diagnostic`s and `Subdiagnostic`s use the same variable name,
/// one value will clobber the other. Eagerly translating the
/// diagnostic uses the variables defined right then, before the
/// clobbering occurs.
pub fn eagerly_translate(&self, msg: impl Into<SubdiagMessage>) -> SubdiagMessage {
let args = self.args.iter();
let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into());
self.dcx.eagerly_translate(msg, args)
}
with_fn! { with_span,
/// Add a span.
#[rustc_lint_diagnostics]

View file

@ -19,7 +19,7 @@ use {rustc_ast as ast, rustc_hir as hir};
use crate::diagnostic::DiagLocation;
use crate::{
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level,
SubdiagMessageOp, Subdiagnostic, fluent_generated as fluent,
Subdiagnostic, fluent_generated as fluent,
};
pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display);
@ -384,11 +384,7 @@ pub struct SingleLabelManySpans {
pub label: &'static str,
}
impl Subdiagnostic for SingleLabelManySpans {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_labels(self.spans, self.label);
}
}

View file

@ -47,7 +47,7 @@ pub use codes::*;
pub use diagnostic::{
BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString,
Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag,
SubdiagMessageOp, Subdiagnostic,
Subdiagnostic,
};
pub use diagnostic_impls::{
DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,

View file

@ -237,18 +237,6 @@ impl<'a> StripUnconfigured<'a> {
inner = self.configure_tokens(&inner);
Some(AttrTokenTree::Delimited(sp, spacing, delim, inner))
}
AttrTokenTree::Token(
Token {
kind:
TokenKind::NtIdent(..)
| TokenKind::NtLifetime(..)
| TokenKind::Interpolated(..),
..
},
_,
) => {
panic!("Nonterminal should have been flattened: {:?}", tree);
}
AttrTokenTree::Token(
Token { kind: TokenKind::OpenDelim(_) | TokenKind::CloseDelim(_), .. },
_,

View file

@ -66,9 +66,7 @@ pub(super) fn failed_to_match_macro(
}
if let MatcherLoc::Token { token: expected_token } = &remaining_matcher
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|| matches!(token.kind, TokenKind::Interpolated(_))
|| matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))
&& (matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))
|| matches!(token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))))
{
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
@ -162,7 +160,7 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match
.is_none_or(|failure| failure.is_better_position(*approx_position))
{
self.best_failure = Some(BestFailure {
token: token.clone(),
token: *token,
position_in_tokenstream: *approx_position,
msg,
remaining_matcher: self

View file

@ -179,7 +179,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> {
for tt in tts {
match tt {
TokenTree::Token(token) => {
locs.push(MatcherLoc::Token { token: token.clone() });
locs.push(MatcherLoc::Token { token: *token });
}
TokenTree::Delimited(span, _, delimited) => {
let open_token = Token::new(token::OpenDelim(delimited.delim), span.open);
@ -648,7 +648,7 @@ impl TtParser {
// There are no possible next positions AND we aren't waiting for the black-box
// parser: syntax error.
return Failure(T::build_failure(
parser.token.clone(),
parser.token,
parser.approx_token_stream_pos(),
"no rules expected this token in macro call",
));

View file

@ -12,7 +12,7 @@ use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::{AttributeKind, find_attr};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::{Applicability, ErrorGuaranteed};
use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
use rustc_feature::Features;
use rustc_hir as hir;
use rustc_lint_defs::BuiltinLintDiag;
@ -27,19 +27,18 @@ use rustc_span::hygiene::Transparency;
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, kw, sym};
use tracing::{debug, instrument, trace, trace_span};
use super::diagnostics;
use super::macro_parser::{NamedMatches, NamedParseResult};
use super::{SequenceRepetition, diagnostics};
use crate::base::{
DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension,
SyntaxExtensionKind, TTMacroExpander,
};
use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment};
use crate::mbe;
use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
use crate::mbe::macro_check;
use crate::mbe::macro_parser::NamedMatch::*;
use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser};
use crate::mbe::transcribe::transcribe;
use crate::mbe::{self, KleeneOp, macro_check};
pub(crate) struct ParserAnyMacro<'a> {
parser: Parser<'a>,
@ -640,6 +639,37 @@ fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool {
}
}
/// Checks if a `vis` nonterminal fragment is unnecessarily wrapped in an optional repetition.
///
/// When a `vis` fragment (which can already be empty) is wrapped in `$(...)?`,
/// this suggests removing the redundant repetition syntax since it provides no additional benefit.
fn check_redundant_vis_repetition(
err: &mut Diag<'_>,
sess: &Session,
seq: &SequenceRepetition,
span: &DelimSpan,
) {
let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne;
let is_vis = seq.tts.first().map_or(false, |tt| {
matches!(tt, mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)))
});
if is_vis && is_zero_or_one {
err.note("a `vis` fragment can already be empty");
err.multipart_suggestion(
"remove the `$(` and `)?`",
vec![
(
sess.source_map().span_extend_to_prev_char_before(span.open, '$', true),
"".to_string(),
),
(span.close.with_hi(seq.kleene.span.hi()), "".to_string()),
],
Applicability::MaybeIncorrect,
);
}
}
/// Checks that the lhs contains no repetition which could match an empty token
/// tree, because then the matcher would hang indefinitely.
fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(), ErrorGuaranteed> {
@ -654,8 +684,10 @@ fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(),
TokenTree::Sequence(span, seq) => {
if is_empty_token_tree(sess, seq) {
let sp = span.entire();
let guar = sess.dcx().span_err(sp, "repetition matches empty token tree");
return Err(guar);
let mut err =
sess.dcx().struct_span_err(sp, "repetition matches empty token tree");
check_redundant_vis_repetition(&mut err, sess, seq, span);
return Err(err.emit());
}
check_lhs_no_empty_seq(sess, &seq.tts)?
}
@ -778,7 +810,7 @@ impl<'tt> FirstSets<'tt> {
// token could be the separator token itself.
if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) {
first.add_one_maybe(TtHandle::from_token(sep.clone()));
first.add_one_maybe(TtHandle::from_token(*sep));
}
// Reverse scan: Sequence comes before `first`.
@ -841,7 +873,7 @@ impl<'tt> FirstSets<'tt> {
// If the sequence contents can be empty, then the first
// token could be the separator token itself.
if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) {
first.add_one_maybe(TtHandle::from_token(sep.clone()));
first.add_one_maybe(TtHandle::from_token(*sep));
}
assert!(first.maybe_empty);
@ -917,7 +949,7 @@ impl<'tt> Clone for TtHandle<'tt> {
// This variant *must* contain a `mbe::TokenTree::Token`, and not
// any other variant of `mbe::TokenTree`.
TtHandle::Token(mbe::TokenTree::Token(tok)) => {
TtHandle::Token(mbe::TokenTree::Token(tok.clone()))
TtHandle::Token(mbe::TokenTree::Token(*tok))
}
_ => unreachable!(),
@ -1093,7 +1125,7 @@ fn check_matcher_core<'tt>(
let mut new;
let my_suffix = if let Some(sep) = &seq_rep.separator {
new = suffix_first.clone();
new.add_one_maybe(TtHandle::from_token(sep.clone()));
new.add_one_maybe(TtHandle::from_token(*sep));
&new
} else {
&suffix_first

View file

@ -283,7 +283,7 @@ fn parse_tree<'a>(
}
// `tree` is an arbitrary token. Keep it.
tokenstream::TokenTree::Token(token, _) => TokenTree::Token(token.clone()),
tokenstream::TokenTree::Token(token, _) => TokenTree::Token(*token),
// `tree` is the beginning of a delimited set of tokens (e.g., `(` or `{`). We need to
// descend into the delimited set and further parse it.
@ -321,7 +321,7 @@ fn parse_kleene_op(
match iter.next() {
Some(tokenstream::TokenTree::Token(token, _)) => match kleene_op(token) {
Some(op) => Ok(Ok((op, token.span))),
None => Ok(Err(token.clone())),
None => Ok(Err(*token)),
},
tree => Err(tree.map_or(span, tokenstream::TokenTree::span)),
}

View file

@ -1,5 +1,4 @@
use std::mem;
use std::sync::Arc;
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::token::{
@ -165,7 +164,7 @@ pub(super) fn transcribe<'a>(
if repeat_idx < repeat_len {
frame.idx = 0;
if let Some(sep) = sep {
result.push(TokenTree::Token(sep.clone(), Spacing::Alone));
result.push(TokenTree::Token(*sep, Spacing::Alone));
}
continue;
}
@ -307,7 +306,9 @@ pub(super) fn transcribe<'a>(
let tt = match cur_matched {
MatchedSingle(ParseNtResult::Tt(tt)) => {
// `tt`s are emitted into the output stream directly as "raw tokens",
// without wrapping them into groups.
// without wrapping them into groups. Other variables are emitted into
// the output stream as groups with `Delimiter::Invisible` to maintain
// parsing priorities.
maybe_use_metavar_location(psess, &stack, sp, tt, &mut marker)
}
MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
@ -325,6 +326,11 @@ pub(super) fn transcribe<'a>(
MatchedSingle(ParseNtResult::Item(item)) => {
mk_delimited(item.span, MetaVarKind::Item, TokenStream::from_ast(item))
}
MatchedSingle(ParseNtResult::Block(block)) => mk_delimited(
block.span,
MetaVarKind::Block,
TokenStream::from_ast(block),
),
MatchedSingle(ParseNtResult::Stmt(stmt)) => {
let stream = if let StmtKind::Empty = stmt.kind {
// FIXME: Properly collect tokens for empty statements.
@ -385,15 +391,6 @@ pub(super) fn transcribe<'a>(
MatchedSingle(ParseNtResult::Vis(vis)) => {
mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis))
}
MatchedSingle(ParseNtResult::Nt(nt)) => {
// Other variables are emitted into the output stream as groups with
// `Delimiter::Invisible` to maintain parsing priorities.
// `Interpolated` is currently used for such groups in rustc parser.
marker.visit_span(&mut sp);
let use_span = nt.use_span();
with_metavar_spans(|mspans| mspans.insert(use_span, sp));
TokenTree::token_alone(token::Interpolated(Arc::clone(nt)), sp)
}
MatchedSeq(..) => {
// We were unable to descend far enough. This is an error.
return Err(dcx.create_err(VarStillRepeating { span: sp, ident }));
@ -441,7 +438,7 @@ pub(super) fn transcribe<'a>(
// Nothing much to do here. Just push the token to the result, being careful to
// preserve syntax context.
mbe::TokenTree::Token(token) => {
let mut token = token.clone();
let mut token = *token;
mut_visit::visit_token(&mut marker, &mut token);
let tt = TokenTree::Token(token, Spacing::Alone);
result.push(tt);

View file

@ -1,5 +1,4 @@
use std::ops::{Bound, Range};
use std::sync::Arc;
use ast::token::IdentIsRaw;
use pm::bridge::{
@ -18,7 +17,7 @@ use rustc_parse::parser::Parser;
use rustc_parse::{exp, 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::{BytePos, FileName, Pos, SourceFile, Span, Symbol, sym};
use rustc_span::{BytePos, FileName, Pos, Span, Symbol, sym};
use smallvec::{SmallVec, smallvec};
use crate::base::ExtCtxt;
@ -309,15 +308,6 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
}));
}
Interpolated(nt) => {
let stream = TokenStream::from_nonterminal_ast(&nt);
trees.push(TokenTree::Group(Group {
delimiter: pm::Delimiter::None,
stream: Some(stream),
span: DelimSpan::from_single(span),
}))
}
OpenDelim(..) | CloseDelim(..) => unreachable!(),
Eof => unreachable!(),
}
@ -467,7 +457,6 @@ impl<'a, 'b> Rustc<'a, 'b> {
impl server::Types for Rustc<'_, '_> {
type FreeFunctions = FreeFunctions;
type TokenStream = TokenStream;
type SourceFile = Arc<SourceFile>;
type Span = Span;
type Symbol = Symbol;
}
@ -673,28 +662,6 @@ impl server::TokenStream for Rustc<'_, '_> {
}
}
impl server::SourceFile for Rustc<'_, '_> {
fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
Arc::ptr_eq(file1, file2)
}
fn path(&mut self, file: &Self::SourceFile) -> String {
match &file.name {
FileName::Real(name) => name
.local_path()
.expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`")
.to_str()
.expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
.to_string(),
_ => file.name.prefer_local().to_string(),
}
}
fn is_real(&mut self, file: &Self::SourceFile) -> bool {
file.is_real_file()
}
}
impl server::Span for Rustc<'_, '_> {
fn debug(&mut self, span: Self::Span) -> String {
if self.ecx.ecfg.span_debug {
@ -704,8 +671,29 @@ impl server::Span for Rustc<'_, '_> {
}
}
fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
self.psess().source_map().lookup_char_pos(span.lo()).file
fn file(&mut self, span: Self::Span) -> String {
self.psess()
.source_map()
.lookup_char_pos(span.lo())
.file
.name
.prefer_remapped_unconditionaly()
.to_string()
}
fn local_file(&mut self, span: Self::Span) -> Option<String> {
self.psess()
.source_map()
.lookup_char_pos(span.lo())
.file
.name
.clone()
.into_local_path()
.map(|p| {
p.to_str()
.expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
.to_string()
})
}
fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {

View file

@ -95,6 +95,8 @@ declare_features! (
(accepted, c_unwind, "1.81.0", Some(74990)),
/// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`.
(accepted, cfg_attr_multi, "1.33.0", Some(54881)),
/// Allows the use of `#[cfg(<true/false>)]`.
(accepted, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)),
/// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests.
(accepted, cfg_doctest, "1.40.0", Some(62210)),
/// Enables `#[cfg(panic = "...")]` config key.

View file

@ -6,6 +6,7 @@ use AttributeDuplicates::*;
use AttributeGate::*;
use AttributeType::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_span::edition::Edition;
use rustc_span::{Symbol, sym};
use crate::{Features, Stability};
@ -65,9 +66,12 @@ pub enum AttributeSafety {
/// Normal attribute that does not need `#[unsafe(...)]`
Normal,
/// Unsafe attribute that requires safety obligations
/// to be discharged
Unsafe,
/// Unsafe attribute that requires safety obligations to be discharged.
///
/// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
/// is less than the one stored in `unsafe_since`. This handles attributes that were safe in
/// earlier editions, but become unsafe in later ones.
Unsafe { unsafe_since: Option<Edition> },
}
#[derive(Clone, Copy)]
@ -187,12 +191,23 @@ macro_rules! template {
}
macro_rules! ungated {
(unsafe($edition:ident) $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Unsafe { unsafe_since: Some(Edition::$edition) },
template: $tpl,
gate: Ungated,
duplicates: $duplicates,
}
};
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Unsafe,
safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
gate: Ungated,
duplicates: $duplicates,
@ -217,7 +232,7 @@ macro_rules! gated {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Unsafe,
safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
@ -228,7 +243,7 @@ macro_rules! gated {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Unsafe,
safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
@ -423,9 +438,9 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
@ -752,7 +767,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
rustc_attr!(
rustc_macro_transparency, Normal,
template!(NameValueStr: "transparent|semitransparent|opaque"), ErrorFollowing,
template!(NameValueStr: "transparent|semiopaque|opaque"), ErrorFollowing,
EncodeCrossCrate::Yes, "used internally for testing macro hygiene",
),
rustc_attr!(

View file

@ -391,8 +391,6 @@ declare_features! (
(unstable, async_trait_bounds, "1.85.0", Some(62290)),
/// Allows using C-variadics.
(unstable, c_variadic, "1.34.0", Some(44930)),
/// Allows the use of `#[cfg(<true/false>)]`.
(unstable, cfg_boolean_literals, "1.83.0", Some(131204)),
/// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled.
(unstable, cfg_contract_checks, "1.86.0", Some(128044)),
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
@ -477,6 +475,8 @@ declare_features! (
(incomplete, ergonomic_clones, "1.87.0", Some(132290)),
/// Allows exhaustive pattern matching on types that contain uninhabited types.
(unstable, exhaustive_patterns, "1.13.0", Some(51085)),
/// Disallows `extern` without an explicit ABI.
(unstable, explicit_extern_abis, "CURRENT_RUSTC_VERSION", Some(134986)),
/// Allows explicit tail calls via `become` expression.
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
/// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions
@ -565,6 +565,8 @@ declare_features! (
(incomplete, mut_ref, "1.79.0", Some(123076)),
/// Allows using `#[naked]` on functions.
(unstable, naked_functions, "1.9.0", Some(90957)),
/// Allows using `#[naked]` on `extern "Rust"` functions.
(unstable, naked_functions_rustic_abi, "CURRENT_RUSTC_VERSION", Some(138997)),
/// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions.
(unstable, naked_functions_target_feature, "1.86.0", Some(138568)),
/// Allows specifying the as-needed link modifier

View file

@ -25,7 +25,10 @@ fn invocation_relative_path_to_absolute(span: Span, path: &str) -> PathBuf {
path.to_path_buf()
} else {
// `/a/b/c/foo/bar.rs` contains the current macro invocation
#[cfg(bootstrap)]
let mut source_file_path = span.source_file().path();
#[cfg(not(bootstrap))]
let mut source_file_path = span.local_file().unwrap();
// `/a/b/c/foo/`
source_file_path.pop();
// `/a/b/c/foo/../locales/en-US/example.ftl`

View file

@ -47,12 +47,9 @@ impl DefPathTable {
debug_assert_eq!(self.stable_crate_id, def_path_hash.stable_crate_id());
let local_hash = def_path_hash.local_hash();
let index = {
let index = DefIndex::from(self.index_to_key.len());
debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
self.index_to_key.push(key);
index
};
let index = self.index_to_key.push(key);
debug!("DefPathTable::insert() - {key:?} <-> {index:?}");
self.def_path_hashes.push(local_hash);
debug_assert!(self.def_path_hashes.len() == self.index_to_key.len());

View file

@ -42,7 +42,7 @@ pub enum IsAnonInPath {
}
/// A lifetime. The valid field combinations are non-obvious. The following
/// example shows some of them. See also the comments on `LifetimeName`.
/// example shows some of them. See also the comments on `LifetimeKind`.
/// ```
/// #[repr(C)]
/// struct S<'a>(&'a u32); // res=Param, name='a, IsAnonInPath::No
@ -84,7 +84,7 @@ pub struct Lifetime {
pub ident: Ident,
/// Semantics of this lifetime.
pub res: LifetimeName,
pub kind: LifetimeKind,
/// Is the lifetime anonymous and in a path? Used only for error
/// suggestions. See `Lifetime::suggestion` for example use.
@ -130,7 +130,7 @@ impl ParamName {
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
pub enum LifetimeName {
pub enum LifetimeKind {
/// User-given names or fresh (synthetic) names.
Param(LocalDefId),
@ -160,16 +160,16 @@ pub enum LifetimeName {
Static,
}
impl LifetimeName {
impl LifetimeKind {
fn is_elided(&self) -> bool {
match self {
LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true,
LifetimeKind::ImplicitObjectLifetimeDefault | LifetimeKind::Infer => true,
// It might seem surprising that `Fresh` counts as not *elided*
// -- but this is because, as far as the code in the compiler is
// concerned -- `Fresh` variants act equivalently to "some fresh name".
// They correspond to early-bound regions on an impl, in other words.
LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false,
LifetimeKind::Error | LifetimeKind::Param(..) | LifetimeKind::Static => false,
}
}
}
@ -184,10 +184,10 @@ impl Lifetime {
pub fn new(
hir_id: HirId,
ident: Ident,
res: LifetimeName,
kind: LifetimeKind,
is_anon_in_path: IsAnonInPath,
) -> Lifetime {
let lifetime = Lifetime { hir_id, ident, res, is_anon_in_path };
let lifetime = Lifetime { hir_id, ident, kind, is_anon_in_path };
// Sanity check: elided lifetimes form a strict subset of anonymous lifetimes.
#[cfg(debug_assertions)]
@ -202,7 +202,7 @@ impl Lifetime {
}
pub fn is_elided(&self) -> bool {
self.res.is_elided()
self.kind.is_elided()
}
pub fn is_anonymous(&self) -> bool {
@ -1014,7 +1014,7 @@ pub struct WhereRegionPredicate<'hir> {
impl<'hir> WhereRegionPredicate<'hir> {
/// Returns `true` if `param_def_id` matches the `lifetime` of this predicate.
fn is_param_bound(&self, param_def_id: LocalDefId) -> bool {
self.lifetime.res == LifetimeName::Param(param_def_id)
self.lifetime.kind == LifetimeKind::Param(param_def_id)
}
}
@ -1756,7 +1756,7 @@ pub enum PatKind<'hir> {
Never,
/// A tuple pattern (e.g., `(a, b)`).
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
/// If the `..` pattern fragment is present, then `DotDotPos` denotes its position.
/// `0 <= position <= subpats.len()`
Tuple(&'hir [Pat<'hir>], DotDotPos),

View file

@ -57,7 +57,7 @@ fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) {
Lifetime {
hir_id: HirId::INVALID,
ident: Ident::new(sym::name, DUMMY_SP),
res: LifetimeName::Static,
kind: LifetimeKind::Static,
is_anon_in_path: IsAnonInPath::No,
}
},

View file

@ -6,7 +6,7 @@
//! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
//! - Example: find all items with a `#[foo]` attribute on them.
//! - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids
//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir().item*(id)` to filter and
//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir_item*(id)` to filter and
//! access actual item-like thing, respectively.
//! - Pro: Efficient; just walks the lists of item ids and gives users control whether to access
//! the hir_owners themselves or not.

View file

@ -182,6 +182,7 @@ language_item_table! {
DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None;
Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0);
UnsafeUnpin, sym::unsafe_unpin, unsafe_unpin_trait, Target::Trait, GenericRequirement::Exact(0);
FnPtrTrait, sym::fn_ptr_trait, fn_ptr_trait, Target::Trait, GenericRequirement::Exact(0);
FnPtrAddr, sym::fn_ptr_addr, fn_ptr_addr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
@ -235,6 +236,8 @@ language_item_table! {
IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
UnsafePinned, sym::unsafe_pinned, unsafe_pinned_type, Target::Struct, GenericRequirement::None;
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
@ -439,6 +442,8 @@ language_item_table! {
DefaultTrait3, sym::default_trait3, default_trait3_trait, Target::Trait, GenericRequirement::None;
DefaultTrait2, sym::default_trait2, default_trait2_trait, Target::Trait, GenericRequirement::None;
DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None;
ContractCheckEnsures, sym::contract_check_ensures, contract_check_ensures_fn, Target::Fn, GenericRequirement::None;
}
/// The requirement imposed on the generics of a lang item

View file

@ -4,7 +4,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(associated_type_defaults)]
#![feature(box_patterns)]
#![feature(closure_track_caller)]

View file

@ -443,13 +443,13 @@ fn best_definition_site_of_opaque<'tcx>(
let impl_def_id = tcx.local_parent(parent);
for assoc in tcx.associated_items(impl_def_id).in_definition_order() {
match assoc.kind {
ty::AssocKind::Const | ty::AssocKind::Fn => {
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {
if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local())
{
return Some(span);
}
}
ty::AssocKind::Type => {}
ty::AssocKind::Type { .. } => {}
}
}
@ -740,7 +740,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
for &assoc_item in assoc_items.in_definition_order() {
match assoc_item.kind {
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
ty::AssocKind::Type { .. } if assoc_item.defaultness(tcx).has_value() => {
let trait_args = GenericArgs::identity_for_item(tcx, def_id);
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
tcx,
@ -942,7 +942,7 @@ fn check_impl_items_against_trait<'tcx>(
if res.is_ok() {
match ty_impl_item.kind {
ty::AssocKind::Fn => {
ty::AssocKind::Fn { .. } => {
compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait(
tcx,
ty_impl_item,
@ -952,8 +952,8 @@ fn check_impl_items_against_trait<'tcx>(
.instantiate_identity(),
);
}
ty::AssocKind::Const => {}
ty::AssocKind::Type => {}
ty::AssocKind::Const { .. } => {}
ty::AssocKind::Type { .. } => {}
}
}

View file

@ -43,9 +43,11 @@ pub(super) fn compare_impl_item(
debug!(?impl_trait_ref);
match impl_item.kind {
ty::AssocKind::Fn => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Type => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Const => compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Fn { .. } => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Type { .. } => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Const { .. } => {
compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref)
}
}
}
@ -606,7 +608,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// with placeholders, which imply nothing about outlives bounds, and then
// prove below that the hidden types are well formed.
let universe = infcx.create_next_universe();
let mut idx = 0;
let mut idx = ty::BoundVar::ZERO;
let mapping: FxIndexMap<_, _> = collector
.types
.iter()
@ -623,10 +625,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
tcx,
ty::Placeholder {
universe,
bound: ty::BoundTy {
var: ty::BoundVar::from_usize(idx),
kind: ty::BoundTyKind::Anon,
},
bound: ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon },
},
),
)
@ -654,7 +653,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
cause.span,
E0053,
"method `{}` has an incompatible return type for trait",
trait_m.name
trait_m.name()
);
infcx.err_ctxt().note_type_err(
&mut diag,
@ -1032,11 +1031,11 @@ fn report_trait_method_mismatch<'tcx>(
impl_err_span,
E0053,
"method `{}` has an incompatible type for trait",
trait_m.name
trait_m.name()
);
match &terr {
TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
if trait_m.fn_has_self_parameter =>
if trait_m.is_method() =>
{
let ty = trait_sig.inputs()[0];
let sugg = get_self_string(ty, |ty| ty == impl_trait_ref.self_ty());
@ -1255,7 +1254,7 @@ fn compare_self_type<'tcx>(
get_self_string(self_arg_ty, can_eq_self)
};
match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
match (trait_m.is_method(), impl_m.is_method()) {
(false, false) | (true, true) => {}
(false, true) => {
@ -1266,14 +1265,14 @@ fn compare_self_type<'tcx>(
impl_m_span,
E0185,
"method `{}` has a `{}` declaration in the impl, but not in the trait",
trait_m.name,
trait_m.name(),
self_descr
);
err.span_label(impl_m_span, format!("`{self_descr}` used in impl"));
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
err.span_label(span, format!("trait method declared without `{self_descr}`"));
} else {
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
}
return Err(err.emit_unless(delay));
}
@ -1286,14 +1285,14 @@ fn compare_self_type<'tcx>(
impl_m_span,
E0186,
"method `{}` has a `{}` declaration in the trait, but not in the impl",
trait_m.name,
trait_m.name(),
self_descr
);
err.span_label(impl_m_span, format!("expected `{self_descr}` in impl"));
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
err.span_label(span, format!("`{self_descr}` used in trait"));
} else {
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
}
return Err(err.emit_unless(delay));
@ -1363,7 +1362,7 @@ fn compare_number_of_generics<'tcx>(
let mut err_occurred = None;
for (kind, trait_count, impl_count) in matchings {
if impl_count != trait_count {
let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| {
let arg_spans = |item: &ty::AssocItem, generics: &hir::Generics<'_>| {
let mut spans = generics
.params
.iter()
@ -1373,7 +1372,7 @@ fn compare_number_of_generics<'tcx>(
} => {
// A fn can have an arbitrary number of extra elided lifetimes for the
// same signature.
!matches!(kind, ty::AssocKind::Fn)
!item.is_fn()
}
_ => true,
})
@ -1386,7 +1385,7 @@ fn compare_number_of_generics<'tcx>(
};
let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
let trait_item = tcx.hir_expect_trait_item(def_id);
let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics);
let arg_spans: Vec<Span> = arg_spans(&trait_, trait_item.generics);
let impl_trait_spans: Vec<Span> = trait_item
.generics
.params
@ -1412,7 +1411,7 @@ fn compare_number_of_generics<'tcx>(
_ => None,
})
.collect();
let spans = arg_spans(impl_.kind, impl_item.generics);
let spans = arg_spans(&impl_, impl_item.generics);
let span = spans.first().copied();
let mut err = tcx.dcx().struct_span_err(
@ -1421,7 +1420,7 @@ fn compare_number_of_generics<'tcx>(
"{} `{}` has {} {kind} parameter{} but its trait \
declaration has {} {kind} parameter{}",
item_kind,
trait_.name,
trait_.name(),
impl_count,
pluralize!(impl_count),
trait_count,
@ -1512,7 +1511,7 @@ fn compare_number_of_method_arguments<'tcx>(
impl_span,
E0050,
"method `{}` has {} but the declaration in trait `{}` has {}",
trait_m.name,
trait_m.name(),
potentially_plural_count(impl_number_args, "parameter"),
tcx.def_path_str(trait_m.def_id),
trait_number_args
@ -1527,7 +1526,7 @@ fn compare_number_of_method_arguments<'tcx>(
),
);
} else {
err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
}
err.span_label(
@ -1581,7 +1580,7 @@ fn compare_synthetic_generics<'tcx>(
impl_span,
E0643,
"method `{}` has incompatible signature for trait",
trait_m.name
trait_m.name()
);
err.span_label(trait_span, "declaration in trait here");
if impl_synthetic {
@ -1703,7 +1702,7 @@ fn compare_generic_param_kinds<'tcx>(
trait_item: ty::AssocItem,
delay: bool,
) -> Result<(), ErrorGuaranteed> {
assert_eq!(impl_item.kind, trait_item.kind);
assert_eq!(impl_item.as_tag(), trait_item.as_tag());
let ty_const_params_of = |def_id| {
tcx.generics_of(def_id).own_params.iter().filter(|param| {
@ -1741,7 +1740,7 @@ fn compare_generic_param_kinds<'tcx>(
E0053,
"{} `{}` has an incompatible generic parameter for trait `{}`",
impl_item.descr(),
trait_item.name,
trait_item.name(),
&tcx.def_path_str(tcx.parent(trait_item.def_id))
);
@ -1877,7 +1876,7 @@ fn compare_const_predicate_entailment<'tcx>(
cause.span,
E0326,
"implemented const `{}` has an incompatible type for trait",
trait_ct.name
trait_ct.name()
);
let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| {
@ -2235,16 +2234,19 @@ fn param_env_with_gat_bounds<'tcx>(
// of the RPITITs associated with the same body. This is because checking
// the item bounds of RPITITs often involves nested RPITITs having to prove
// bounds about themselves.
let impl_tys_to_install = match impl_ty.opt_rpitit_info {
None => vec![impl_ty],
Some(
ty::ImplTraitInTraitData::Impl { fn_def_id }
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
) => tcx
let impl_tys_to_install = match impl_ty.kind {
ty::AssocKind::Type {
data:
ty::AssocTypeData::Rpitit(
ty::ImplTraitInTraitData::Impl { fn_def_id }
| ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
),
} => tcx
.associated_types_for_impl_traits_in_associated_fn(fn_def_id)
.iter()
.map(|def_id| tcx.associated_item(*def_id))
.collect(),
_ => vec![impl_ty],
};
for impl_ty in impl_tys_to_install {

View file

@ -217,15 +217,11 @@ pub(crate) fn check_intrinsic_type(
};
(n_tps, 0, 0, inputs, output, hir::Safety::Unsafe)
} else if intrinsic_name == sym::contract_check_ensures {
// contract_check_ensures::<'a, Ret, C>(&'a Ret, C)
// where C: impl Fn(&'a Ret) -> bool,
// contract_check_ensures::<Ret, C>(Ret, C) -> Ret
// where C: for<'a> Fn(&'a Ret) -> bool,
//
// so: two type params, one lifetime param, 0 const params, two inputs, no return
let p = generics.param_at(0, tcx);
let r = ty::Region::new_early_param(tcx, p.to_early_bound_region_data());
let ref_ret = Ty::new_imm_ref(tcx, r, param(1));
(2, 1, 0, vec![ref_ret, param(2)], tcx.types.unit, hir::Safety::Safe)
// so: two type params, 0 lifetime param, 0 const params, two inputs, no return
(2, 0, 0, vec![param(0), param(1)], param(1), hir::Safety::Safe)
} else {
let safety = intrinsic_operation_unsafety(tcx, intrinsic_id);
let (n_tps, n_cts, inputs, output) = match intrinsic_name {

View file

@ -205,7 +205,7 @@ fn missing_items_err(
let missing_items_msg = missing_items
.clone()
.map(|trait_item| trait_item.name.to_string())
.map(|trait_item| trait_item.name().to_string())
.collect::<Vec<_>>()
.join("`, `");
@ -236,7 +236,7 @@ fn missing_items_err(
let code = format!("{padding}{snippet}\n{padding}");
if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
missing_trait_item_label
.push(errors::MissingTraitItemLabel { span, item: trait_item.name });
.push(errors::MissingTraitItemLabel { span, item: trait_item.name() });
missing_trait_item.push(errors::MissingTraitItemSuggestion {
span: sugg_sp,
code,
@ -407,14 +407,14 @@ fn fn_sig_suggestion<'tcx>(
.enumerate()
.map(|(i, ty)| {
Some(match ty.kind() {
ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
ty::Ref(reg, ref_ty, mutability) if i == 0 => {
let reg = format!("{reg} ");
let reg = match &reg[..] {
"'_ " | " " => "",
reg => reg,
};
if assoc.fn_has_self_parameter {
if assoc.is_method() {
match ref_ty.kind() {
ty::Param(param) if param.name == kw::SelfUpper => {
format!("&{}{}self", reg, mutability.prefix_str())
@ -427,7 +427,7 @@ fn fn_sig_suggestion<'tcx>(
}
}
_ => {
if assoc.fn_has_self_parameter && i == 0 {
if assoc.is_method() && i == 0 {
format!("self: {ty}")
} else {
format!("_: {ty}")
@ -489,7 +489,7 @@ fn suggestion_signature<'tcx>(
);
match assoc.kind {
ty::AssocKind::Fn => fn_sig_suggestion(
ty::AssocKind::Fn { .. } => fn_sig_suggestion(
tcx,
tcx.liberate_late_bound_regions(
assoc.def_id,
@ -499,14 +499,14 @@ fn suggestion_signature<'tcx>(
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
assoc,
),
ty::AssocKind::Type => {
ty::AssocKind::Type { .. } => {
let (generics, where_clauses) = bounds_from_generic_predicates(
tcx,
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
);
format!("type {}{generics} = /* Type */{where_clauses};", assoc.name)
format!("type {}{generics} = /* Type */{where_clauses};", assoc.name())
}
ty::AssocKind::Const => {
ty::AssocKind::Const { name } => {
let ty = tcx.type_of(assoc.def_id).instantiate_identity();
let val = tcx
.infer_ctxt()
@ -514,7 +514,7 @@ fn suggestion_signature<'tcx>(
.err_ctxt()
.ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
.unwrap_or_else(|| "value".to_string());
format!("const {}: {} = {};", assoc.name, ty, val)
format!("const {}: {} = {};", name, ty, val)
}
}
}

View file

@ -408,7 +408,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
let gat_def_id = gat_item.def_id.expect_local();
let gat_item = tcx.associated_item(gat_def_id);
// If this item is not an assoc ty, or has no args, then it's not a GAT
if gat_item.kind != ty::AssocKind::Type {
if !gat_item.is_type() {
continue;
}
let gat_generics = tcx.generics_of(gat_def_id);
@ -432,7 +432,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
let item_required_bounds = match tcx.associated_item(item_def_id).kind {
// In our example, this corresponds to `into_iter` method
ty::AssocKind::Fn => {
ty::AssocKind::Fn { .. } => {
// For methods, we check the function signature's return type for any GATs
// to constrain. In the `into_iter` case, we see that the return type
// `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
@ -453,7 +453,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
)
}
// In our example, this corresponds to the `Iter` and `Item` associated types
ty::AssocKind::Type => {
ty::AssocKind::Type { .. } => {
// If our associated item is a GAT with missing bounds, add them to
// the param-env here. This allows this GAT to propagate missing bounds
// to other GATs.
@ -474,7 +474,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
gat_generics,
)
}
ty::AssocKind::Const => None,
ty::AssocKind::Const { .. } => None,
};
if let Some(item_required_bounds) = item_required_bounds {
@ -1076,7 +1076,7 @@ fn check_associated_item(
};
match item.kind {
ty::AssocKind::Const => {
ty::AssocKind::Const { .. } => {
let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
@ -1089,7 +1089,7 @@ fn check_associated_item(
);
Ok(())
}
ty::AssocKind::Fn => {
ty::AssocKind::Fn { .. } => {
let sig = tcx.fn_sig(item.def_id).instantiate_identity();
let hir_sig = sig_if_method.expect("bad signature for method");
check_fn_or_method(
@ -1101,7 +1101,7 @@ fn check_associated_item(
);
check_method_receiver(wfcx, hir_sig, item, self_ty)
}
ty::AssocKind::Type => {
ty::AssocKind::Type { .. } => {
if let ty::AssocItemContainer::Trait = item.container {
check_associated_type_bounds(wfcx, item, span)
}
@ -1716,7 +1716,7 @@ fn check_method_receiver<'tcx>(
) -> Result<(), ErrorGuaranteed> {
let tcx = wfcx.tcx();
if !method.fn_has_self_parameter {
if !method.is_method() {
return Ok(());
}

View file

@ -51,7 +51,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
for &item1 in impl_items1.in_definition_order() {
let collision = impl_items2
.filter_by_name_unhygienic(item1.name)
.filter_by_name_unhygienic(item1.name())
.any(|&item2| self.compare_hygienically(item1, item2));
if collision {
@ -64,7 +64,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
fn compare_hygienically(&self, item1: ty::AssocItem, item2: ty::AssocItem) -> bool {
// Symbols and namespace match, compare hygienically.
item1.kind.namespace() == item2.kind.namespace()
item1.namespace() == item2.namespace()
&& item1.ident(self.tcx).normalize_to_macros_2_0()
== item2.ident(self.tcx).normalize_to_macros_2_0()
}
@ -113,7 +113,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
let mut res = Ok(());
for &item1 in impl_items1.in_definition_order() {
let collision = impl_items2
.filter_by_name_unhygienic(item1.name)
.filter_by_name_unhygienic(item1.name())
.find(|&&item2| self.compare_hygienically(item1, item2));
if let Some(item2) = collision {
@ -230,11 +230,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
let mut ids = impl_items
.in_definition_order()
.filter_map(|item| {
let entry = connected_region_ids.entry(item.name);
let entry = connected_region_ids.entry(item.name());
if let IndexEntry::Occupied(e) = &entry {
Some(*e.get())
} else {
idents_to_add.push(item.name);
idents_to_add.push(item.name());
None
}
})

View file

@ -44,7 +44,7 @@ use rustc_trait_selection::traits::ObligationCtxt;
use tracing::{debug, instrument};
use crate::errors;
use crate::hir_ty_lowering::errors::assoc_kind_str;
use crate::hir_ty_lowering::errors::assoc_tag_str;
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
pub(crate) mod dump;
@ -450,7 +450,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
item_def_id: DefId,
item_segment: &rustc_hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
@ -525,7 +525,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
inferred_sugg,
bound,
mpart_sugg,
what: assoc_kind_str(kind),
what: assoc_tag_str(assoc_tag),
}))
}
}

View file

@ -16,7 +16,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
use rustc_hir::{
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeName, Node,
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeKind, Node,
};
use rustc_macros::extension;
use rustc_middle::hir::nested_filter;
@ -646,14 +646,14 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
arg: &'tcx hir::PreciseCapturingArg<'tcx>,
) -> Self::Result {
match *arg {
hir::PreciseCapturingArg::Lifetime(lt) => match lt.res {
LifetimeName::Param(def_id) => {
hir::PreciseCapturingArg::Lifetime(lt) => match lt.kind {
LifetimeKind::Param(def_id) => {
self.resolve_lifetime_ref(def_id, lt);
}
LifetimeName::Error => {}
LifetimeName::ImplicitObjectLifetimeDefault
| LifetimeName::Infer
| LifetimeName::Static => {
LifetimeKind::Error => {}
LifetimeKind::ImplicitObjectLifetimeDefault
| LifetimeKind::Infer
| LifetimeKind::Static => {
self.tcx.dcx().emit_err(errors::BadPreciseCapture {
span: lt.ident.span,
kind: "lifetime",
@ -774,26 +774,26 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
);
}
});
match lifetime.res {
LifetimeName::ImplicitObjectLifetimeDefault => {
match lifetime.kind {
LifetimeKind::ImplicitObjectLifetimeDefault => {
// If the user does not write *anything*, we
// use the object lifetime defaulting
// rules. So e.g., `Box<dyn Debug>` becomes
// `Box<dyn Debug + 'static>`.
self.resolve_object_lifetime_default(&*lifetime)
}
LifetimeName::Infer => {
LifetimeKind::Infer => {
// If the user writes `'_`, we use the *ordinary* elision
// rules. So the `'_` in e.g., `Box<dyn Debug + '_>` will be
// resolved the same as the `'_` in `&'_ Foo`.
//
// cc #48468
}
LifetimeName::Param(..) | LifetimeName::Static => {
LifetimeKind::Param(..) | LifetimeKind::Static => {
// If the user wrote an explicit name, use that.
self.visit_lifetime(&*lifetime);
}
LifetimeName::Error => {}
LifetimeKind::Error => {}
}
}
hir::TyKind::Ref(lifetime_ref, ref mt) => {
@ -873,17 +873,17 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
#[instrument(level = "debug", skip(self))]
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
match lifetime_ref.res {
hir::LifetimeName::Static => {
match lifetime_ref.kind {
hir::LifetimeKind::Static => {
self.insert_lifetime(lifetime_ref, ResolvedArg::StaticLifetime)
}
hir::LifetimeName::Param(param_def_id) => {
hir::LifetimeKind::Param(param_def_id) => {
self.resolve_lifetime_ref(param_def_id, lifetime_ref)
}
// If we've already reported an error, just ignore `lifetime_ref`.
hir::LifetimeName::Error => {}
hir::LifetimeKind::Error => {}
// Those will be resolved by typechecking.
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Infer => {}
hir::LifetimeKind::ImplicitObjectLifetimeDefault | hir::LifetimeKind::Infer => {}
}
}
@ -1063,15 +1063,15 @@ fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectL
for bound in bound.bounds {
if let hir::GenericBound::Outlives(lifetime) = bound {
set.insert(lifetime.res);
set.insert(lifetime.kind);
}
}
}
match set {
Set1::Empty => ObjectLifetimeDefault::Empty,
Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
Set1::One(hir::LifetimeName::Param(param_def_id)) => {
Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static,
Set1::One(hir::LifetimeKind::Param(param_def_id)) => {
ObjectLifetimeDefault::Param(param_def_id.to_def_id())
}
_ => ObjectLifetimeDefault::Ambiguous,
@ -1241,7 +1241,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
// Fresh lifetimes in APIT used to be allowed in async fns and forbidden in
// regular fns.
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
&& let hir::LifetimeName::Param(param_id) = lifetime_ref.res
&& let hir::LifetimeKind::Param(param_id) = lifetime_ref.kind
&& let Some(generics) =
self.tcx.hir_get_generics(self.tcx.local_parent(param_id))
&& let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
@ -1811,7 +1811,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx,
type_def_id,
constraint.ident,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
) {
bound_vars.extend(
self.tcx
@ -1843,7 +1843,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx,
type_def_id,
constraint.ident,
ty::AssocKind::Type,
ty::AssocTag::Type,
)
.map(|(bound_vars, _)| bound_vars);
self.with(scope, |this| {
@ -1875,13 +1875,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
def_id: DefId,
assoc_ident: Ident,
assoc_kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Option<(Vec<ty::BoundVariableKind>, &'tcx ty::AssocItem)> {
let trait_defines_associated_item_named = |trait_def_id: DefId| {
tcx.associated_items(trait_def_id).find_by_ident_and_kind(
tcx,
assoc_ident,
assoc_kind,
assoc_tag,
trait_def_id,
)
};
@ -1894,8 +1894,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
let Some((def_id, bound_vars)) = stack.pop() else {
break None;
};
// See issue #83753. If someone writes an associated type on a non-trait, just treat it as
// there being no supertrait HRTBs.
// See issue #83753. If someone writes an associated type on a non-trait, just treat it
// as there being no supertrait HRTBs.
match tcx.def_kind(def_id) {
DefKind::Trait | DefKind::TraitAlias | DefKind::Impl { .. } => {}
_ => break None,
@ -2067,7 +2067,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx,
trait_def_id,
item_segment.ident,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
)
});
@ -2112,7 +2112,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx,
trait_def_id,
item_segment.ident,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
) else {
return;
};
@ -2440,7 +2440,7 @@ fn is_late_bound_map(
}
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
if let hir::LifetimeKind::Param(def_id) = lifetime_ref.kind {
self.regions.insert(def_id);
}
}
@ -2453,7 +2453,7 @@ fn is_late_bound_map(
impl<'tcx> Visitor<'tcx> for AllCollector {
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
if let hir::LifetimeKind::Param(def_id) = lifetime_ref.kind {
self.regions.insert(def_id);
}
}

View file

@ -32,9 +32,11 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
let assoc = tcx.associated_item(assoc_id);
match assoc.kind {
ty::AssocKind::Const | ty::AssocKind::Fn => locator.check(assoc_id.expect_local()),
ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {
locator.check(assoc_id.expect_local())
}
// Associated types don't have bodies, so they can't constrain hidden types
ty::AssocKind::Type => {}
ty::AssocKind::Type { .. } => {}
}
}

View file

@ -4,7 +4,7 @@ use GenericArgsInfo::*;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize};
use rustc_hir as hir;
use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
use rustc_middle::ty::{self as ty, AssocItems, TyCtxt};
use rustc_span::def_id::DefId;
use tracing::debug;
@ -486,13 +486,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
let items: &AssocItems = self.tcx.associated_items(self.def_id);
items
.in_definition_order()
.filter(|item| item.kind == AssocKind::Type)
.filter(|item| item.is_type())
.filter(|item| {
!self
.gen_args
.constraints
.iter()
.any(|constraint| constraint.ident.name == item.name)
.any(|constraint| constraint.ident.name == item.name())
})
.filter(|item| !item.is_impl_trait_in_trait())
.map(|item| self.tcx.item_ident(item.def_id).to_string())

View file

@ -431,16 +431,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) -> Result<(), ErrorGuaranteed> {
let tcx = self.tcx();
let assoc_kind = if constraint.gen_args.parenthesized
let assoc_tag = if constraint.gen_args.parenthesized
== hir::GenericArgsParentheses::ReturnTypeNotation
{
ty::AssocKind::Fn
ty::AssocTag::Fn
} else if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(_) } =
constraint.kind
{
ty::AssocKind::Const
ty::AssocTag::Const
} else {
ty::AssocKind::Type
ty::AssocTag::Type
};
// Given something like `U: Trait<T = X>`, we want to produce a predicate like
@ -453,7 +453,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// trait SuperTrait<A> { type T; }
let candidate = if self.probe_trait_that_defines_assoc_item(
trait_ref.def_id(),
assoc_kind,
assoc_tag,
constraint.ident,
) {
// Simple case: The assoc item is defined in the current trait.
@ -464,7 +464,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.probe_single_bound_for_assoc_item(
|| traits::supertraits(tcx, trait_ref),
AssocItemQSelf::Trait(trait_ref.def_id()),
assoc_kind,
assoc_tag,
constraint.ident,
path_span,
Some(constraint),
@ -474,7 +474,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let assoc_item = self
.probe_assoc_item(
constraint.ident,
assoc_kind,
assoc_tag,
hir_ref_id,
constraint.span,
candidate.def_id(),
@ -493,7 +493,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
})
.or_insert(constraint.span);
let projection_term = if let ty::AssocKind::Fn = assoc_kind {
let projection_term = if let ty::AssocTag::Fn = assoc_tag {
let bound_vars = tcx.late_bound_vars(constraint.hir_id);
ty::Binder::bind_with_vars(
self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(),
@ -542,7 +542,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};
match constraint.kind {
hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => {
hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocTag::Fn = assoc_tag => {
return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
span: constraint.span,
}));
@ -679,7 +679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_def_id,
hir_ty.span,
item_segment,
ty::AssocKind::Type,
ty::AssocTag::Type,
);
return Ty::new_error(tcx, guar);
};
@ -771,7 +771,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
},
AssocItemQSelf::SelfTyAlias,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
assoc_ident,
span,
None,
@ -783,7 +783,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) => self.probe_single_ty_param_bound_for_assoc_item(
param_did.expect_local(),
qself.span,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
assoc_ident,
span,
)?,
@ -823,7 +823,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let trait_def_id = bound.def_id();
let assoc_ty = self
.probe_assoc_item(assoc_ident, ty::AssocKind::Fn, qpath_hir_id, span, trait_def_id)
.probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id)
.expect("failed to find associated type");
Ok((bound, assoc_ty.def_id))

View file

@ -201,7 +201,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
tcx.associated_items(pred.trait_ref.def_id)
.in_definition_order()
// We only care about associated types.
.filter(|item| item.kind == ty::AssocKind::Type)
.filter(|item| item.is_type())
// No RPITITs -- they're not dyn-compatible for now.
.filter(|item| !item.is_impl_trait_in_trait())
// If the associated type has a `where Self: Sized` bound,
@ -415,7 +415,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime)
} else {
let reason =
if let hir::LifetimeName::ImplicitObjectLifetimeDefault = lifetime.res {
if let hir::LifetimeKind::ImplicitObjectLifetimeDefault = lifetime.kind {
if let hir::Node::Ty(hir::Ty {
kind: hir::TyKind::Ref(parent_lifetime, _),
..

View file

@ -116,7 +116,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
all_candidates: impl Fn() -> I,
qself: AssocItemQSelf,
assoc_kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
assoc_ident: Ident,
span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@ -134,14 +134,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}) {
return self.complain_about_assoc_kind_mismatch(
assoc_item,
assoc_kind,
assoc_tag,
assoc_ident,
span,
constraint,
);
}
let assoc_kind_str = assoc_kind_str(assoc_kind);
let assoc_kind_str = assoc_tag_str(assoc_tag);
let qself_str = qself.to_string(tcx);
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
@ -168,7 +168,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let all_candidate_names: Vec<_> = all_candidates()
.flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
.filter_map(|item| {
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
if !item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag {
item.opt_name()
} else {
None
}
})
.collect();
@ -200,7 +204,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.iter()
.flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
.filter_map(|item| {
(!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
(!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag).then(|| item.name())
})
.collect();
@ -213,7 +217,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.filter(|trait_def_id| {
tcx.associated_items(trait_def_id)
.filter_by_name_unhygienic(suggested_name)
.any(|item| item.kind == assoc_kind)
.any(|item| item.as_tag() == assoc_tag)
})
.collect::<Vec<_>>()[..]
{
@ -330,14 +334,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn complain_about_assoc_kind_mismatch(
&self,
assoc_item: &ty::AssocItem,
assoc_kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
ident: Ident,
span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
) -> ErrorGuaranteed {
let tcx = self.tcx();
let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
let bound_on_assoc_const_label = if let ty::AssocKind::Const { .. } = assoc_item.kind
&& let Some(constraint) = constraint
&& let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind
{
@ -375,17 +379,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir::Term::Ty(ty) => ty.span,
hir::Term::Const(ct) => ct.span(),
};
(span, Some(ident.span), assoc_item.kind, assoc_kind)
(span, Some(ident.span), assoc_item.as_tag(), assoc_tag)
} else {
(ident.span, None, assoc_kind, assoc_item.kind)
(ident.span, None, assoc_tag, assoc_item.as_tag())
};
self.dcx().emit_err(errors::AssocKindMismatch {
span,
expected: assoc_kind_str(expected),
got: assoc_kind_str(got),
expected: assoc_tag_str(expected),
got: assoc_tag_str(got),
expected_because_label,
assoc_kind: assoc_kind_str(assoc_item.kind),
assoc_kind: assoc_tag_str(assoc_item.as_tag()),
def_span: tcx.def_span(assoc_item.def_id),
bound_on_assoc_const_label,
wrap_in_braces_sugg,
@ -398,9 +402,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
types: &[String],
traits: &[String],
name: Symbol,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed {
let kind_str = assoc_kind_str(kind);
let kind_str = assoc_tag_str(assoc_tag);
let mut err =
struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}");
if self
@ -569,7 +573,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
candidates: Vec<(DefId, (DefId, DefId))>,
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
span: Span,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed {
// FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`.
// Either
@ -579,14 +583,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let tcx = self.tcx();
let kind_str = assoc_kind_str(kind);
let assoc_tag_str = assoc_tag_str(assoc_tag);
let adt_did = self_ty.ty_adt_def().map(|def| def.did());
let add_def_label = |err: &mut Diag<'_>| {
if let Some(did) = adt_did {
err.span_label(
tcx.def_span(did),
format!(
"associated {kind_str} `{name}` not found for this {}",
"associated {assoc_tag_str} `{name}` not found for this {}",
tcx.def_descr(did)
),
);
@ -615,11 +619,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.dcx(),
name.span,
E0220,
"associated {kind_str} `{name}` not found for `{self_ty}` in the current scope"
"associated {assoc_tag_str} `{name}` not found for `{self_ty}` in the current scope"
);
err.span_label(name.span, format!("associated item not found in `{self_ty}`"));
err.note(format!(
"the associated {kind_str} was found for\n{type_candidates}{additional_types}",
"the associated {assoc_tag_str} was found for\n{type_candidates}{additional_types}",
));
add_def_label(&mut err);
return err.emit();
@ -700,7 +704,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut err = self.dcx().struct_span_err(
name.span,
format!("the associated {kind_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
format!("the associated {assoc_tag_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
);
if !bounds.is_empty() {
err.note(format!(
@ -710,7 +714,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
err.span_label(
name.span,
format!("associated {kind_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
format!("associated {assoc_tag_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
);
for (span, mut bounds) in bound_spans {
@ -761,7 +765,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// `issue-22560.rs`.
let mut dyn_compatibility_violations = Ok(());
for (assoc_item, trait_ref) in &missing_assoc_types {
names.entry(trait_ref).or_default().push(assoc_item.name);
names.entry(trait_ref).or_default().push(assoc_item.name());
names_len += 1;
let violations =
@ -812,7 +816,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind(
tcx,
ident,
ty::AssocKind::Type,
ty::AssocTag::Type,
trait_def,
);
@ -852,16 +856,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut names: UnordMap<_, usize> = Default::default();
for (item, _) in &missing_assoc_types {
types_count += 1;
*names.entry(item.name).or_insert(0) += 1;
*names.entry(item.name()).or_insert(0) += 1;
}
let mut dupes = false;
let mut shadows = false;
for (item, trait_ref) in &missing_assoc_types {
let prefix = if names[&item.name] > 1 {
let name = item.name();
let prefix = if names[&name] > 1 {
let trait_def_id = trait_ref.def_id();
dupes = true;
format!("{}::", tcx.def_path_str(trait_def_id))
} else if bound_names.get(&item.name).is_some_and(|x| *x != item) {
} else if bound_names.get(&name).is_some_and(|x| *x != item) {
let trait_def_id = trait_ref.def_id();
shadows = true;
format!("{}::", tcx.def_path_str(trait_def_id))
@ -871,7 +876,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut is_shadowed = false;
if let Some(assoc_item) = bound_names.get(&item.name)
if let Some(assoc_item) = bound_names.get(&name)
&& *assoc_item != item
{
is_shadowed = true;
@ -880,17 +885,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
err.span_label(
tcx.def_span(assoc_item.def_id),
format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
format!("`{}{}` shadowed here{}", prefix, name, rename_message),
);
}
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
if let Some(sp) = tcx.hir_span_if_local(item.def_id) {
err.span_label(
sp,
format!("`{}{}` defined here{}", prefix, item.name, rename_message),
);
err.span_label(sp, format!("`{}{}` defined here{}", prefix, name, rename_message));
}
}
if potential_assoc_types.len() == missing_assoc_types.len() {
@ -903,7 +905,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
{
let types: Vec<_> = missing_assoc_types
.iter()
.map(|(item, _)| format!("{} = Type", item.name))
.map(|(item, _)| format!("{} = Type", item.name()))
.collect();
let code = if let Some(snippet) = snippet.strip_suffix('>') {
// The user wrote `Trait<'a>` or similar and we don't have a type we can
@ -938,16 +940,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
for (item, _) in &missing_assoc_types {
types_count += 1;
*names.entry(item.name).or_insert(0) += 1;
*names.entry(item.name()).or_insert(0) += 1;
}
let mut label = vec![];
for (item, trait_ref) in &missing_assoc_types {
let postfix = if names[&item.name] > 1 {
let name = item.name();
let postfix = if names[&name] > 1 {
format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
} else {
String::new()
};
label.push(format!("`{}`{}", item.name, postfix));
label.push(format!("`{}`{}", name, postfix));
}
if !label.is_empty() {
err.span_label(
@ -1022,12 +1025,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.map(|simple_ty| tcx.incoherent_impls(simple_ty))
})
&& let name = Symbol::intern(&format!("{ident2}_{ident3}"))
&& let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = inherent_impls
&& let Some(item) = inherent_impls
.iter()
.flat_map(|inherent_impl| {
tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name)
})
.next()
&& item.is_fn()
{
Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
.with_span_suggestion_verbose(
@ -1629,10 +1633,10 @@ fn generics_args_err_extend<'a>(
}
}
pub(crate) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
match kind {
ty::AssocKind::Fn => "function",
ty::AssocKind::Const => "constant",
ty::AssocKind::Type => "type",
pub(crate) fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str {
match assoc_tag {
ty::AssocTag::Fn => "function",
ty::AssocTag::Const => "constant",
ty::AssocTag::Type => "type",
}
}

View file

@ -501,8 +501,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let names: Vec<_> = tcx
.associated_items(trait_def_id)
.in_definition_order()
.filter(|assoc| assoc.kind.namespace() == Namespace::ValueNS)
.map(|cand| cand.name)
.filter(|assoc| assoc.namespace() == Namespace::ValueNS)
.map(|cand| cand.name())
.collect();
if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
diag.span_suggestion_verbose(

View file

@ -38,8 +38,8 @@ use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::mir::interpret::LitToConstInput;
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
use rustc_middle::ty::{
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
TypeVisitableExt, TypingMode, Upcast, fold_regions,
self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty,
TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions,
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@ -51,7 +51,7 @@ use rustc_trait_selection::traits::wf::object_region_bounds;
use rustc_trait_selection::traits::{self, ObligationCtxt};
use tracing::{debug, instrument};
use self::errors::assoc_kind_str;
use self::errors::assoc_tag_str;
use crate::check::check_abi_fn_ptr;
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed};
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
@ -168,7 +168,7 @@ pub trait HirTyLowerer<'tcx> {
item_def_id: DefId,
item_segment: &hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>;
fn lower_fn_sig(
@ -251,10 +251,10 @@ enum LowerAssocMode {
}
impl LowerAssocMode {
fn kind(self) -> ty::AssocKind {
fn assoc_tag(self) -> ty::AssocTag {
match self {
LowerAssocMode::Type { .. } => ty::AssocKind::Type,
LowerAssocMode::Const => ty::AssocKind::Const,
LowerAssocMode::Type { .. } => ty::AssocTag::Type,
LowerAssocMode::Const => ty::AssocTag::Const,
}
}
@ -268,7 +268,8 @@ impl LowerAssocMode {
fn permit_variants(self) -> bool {
match self {
LowerAssocMode::Type { permit_variants } => permit_variants,
// FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which resolve to const ctors/fn items respectively
// FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which
// resolve to const ctors/fn items respectively.
LowerAssocMode::Const => false,
}
}
@ -932,12 +933,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn probe_trait_that_defines_assoc_item(
&self,
trait_def_id: DefId,
assoc_kind: ty::AssocKind,
assoc_tag: AssocTag,
assoc_ident: Ident,
) -> bool {
self.tcx()
.associated_items(trait_def_id)
.find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_kind, trait_def_id)
.find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_tag, trait_def_id)
.is_some()
}
@ -975,7 +976,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
ty_param_def_id: LocalDefId,
ty_param_span: Span,
kind: ty::AssocKind,
assoc_tag: AssocTag,
assoc_ident: Ident,
span: Span,
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
@ -993,7 +994,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_ident)
},
AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span),
kind,
assoc_tag,
assoc_ident,
span,
None,
@ -1010,7 +1011,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
all_candidates: impl Fn() -> I,
qself: AssocItemQSelf,
assoc_kind: ty::AssocKind,
assoc_tag: AssocTag,
assoc_ident: Ident,
span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@ -1021,14 +1022,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let tcx = self.tcx();
let mut matching_candidates = all_candidates().filter(|r| {
self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_kind, assoc_ident)
self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_tag, assoc_ident)
});
let Some(bound) = matching_candidates.next() else {
let reported = self.complain_about_assoc_item_not_found(
all_candidates,
qself,
assoc_kind,
assoc_tag,
assoc_ident,
span,
constraint,
@ -1040,7 +1041,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if let Some(bound2) = matching_candidates.next() {
debug!(?bound2);
let assoc_kind_str = errors::assoc_kind_str(assoc_kind);
let assoc_kind_str = errors::assoc_tag_str(assoc_tag);
let qself_str = qself.to_string(tcx);
let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
span,
@ -1059,14 +1060,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
},
);
// FIXME(#97583): Print associated item bindings properly (i.e., not as equality predicates!).
// FIXME(#97583): Print associated item bindings properly (i.e., not as equality
// predicates!).
// FIXME: Turn this into a structured, translateable & more actionable suggestion.
let mut where_bounds = vec![];
for bound in [bound, bound2].into_iter().chain(matching_candidates) {
let bound_id = bound.def_id();
let bound_span = tcx
.associated_items(bound_id)
.find_by_ident_and_kind(tcx, assoc_ident, assoc_kind, bound_id)
.find_by_ident_and_kind(tcx, assoc_ident, assoc_tag, bound_id)
.and_then(|item| tcx.hir_span_if_local(item.def_id));
if let Some(bound_span) = bound_span {
@ -1265,7 +1267,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
qself_ty,
hir_ref_id,
span,
mode.kind(),
mode.assoc_tag(),
)? {
return Ok(LoweredAssoc::Term(did, args));
}
@ -1296,7 +1298,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
},
AssocItemQSelf::SelfTyAlias,
mode.kind(),
mode.assoc_tag(),
assoc_ident,
span,
None,
@ -1308,12 +1310,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) => self.probe_single_ty_param_bound_for_assoc_item(
param_did.expect_local(),
qself.span,
mode.kind(),
mode.assoc_tag(),
assoc_ident,
span,
)?,
_ => {
let kind_str = assoc_kind_str(mode.kind());
let kind_str = assoc_tag_str(mode.assoc_tag());
let reported = if variant_resolution.is_some() {
// Variant in type position
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
@ -1420,7 +1422,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&[qself_ty.to_string()],
&traits,
assoc_ident.name,
mode.kind(),
mode.assoc_tag(),
)
};
return Err(reported);
@ -1429,10 +1431,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let trait_did = bound.def_id();
let assoc_item = self
.probe_assoc_item(assoc_ident, mode.kind(), hir_ref_id, span, trait_did)
.probe_assoc_item(assoc_ident, mode.assoc_tag(), hir_ref_id, span, trait_did)
.expect("failed to find associated item");
let (def_id, args) =
self.lower_assoc_shared(span, assoc_item.def_id, assoc_segment, bound, mode.kind())?;
let (def_id, args) = self.lower_assoc_shared(
span,
assoc_item.def_id,
assoc_segment,
bound,
mode.assoc_tag(),
)?;
let result = LoweredAssoc::Term(def_id, args);
if let Some(variant_def_id) = variant_resolution {
@ -1469,20 +1476,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty: Ty<'tcx>,
block: HirId,
span: Span,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<Option<(DefId, GenericArgsRef<'tcx>)>, ErrorGuaranteed> {
let tcx = self.tcx();
if !tcx.features().inherent_associated_types() {
match kind {
// Don't attempt to look up inherent associated types when the feature is not enabled.
// Theoretically it'd be fine to do so since we feature-gate their definition site.
// However, due to current limitations of the implementation (caused by us performing
// selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle
// errors (#108491) which mask the feature-gate error, needlessly confusing users
// who use IATs by accident (#113265).
ty::AssocKind::Type => return Ok(None),
ty::AssocKind::Const => {
match assoc_tag {
// Don't attempt to look up inherent associated types when the feature is not
// enabled. Theoretically it'd be fine to do so since we feature-gate their
// definition site. However, due to current limitations of the implementation
// (caused by us performing selection during HIR ty lowering instead of in the
// trait solver), IATs can lead to cycle errors (#108491) which mask the
// feature-gate error, needlessly confusing users who use IATs by accident
// (#113265).
ty::AssocTag::Type => return Ok(None),
ty::AssocTag::Const => {
// We also gate the mgca codepath for type-level uses of inherent consts
// with the inherent_associated_types feature gate since it relies on the
// same machinery and has similar rough edges.
@ -1494,7 +1502,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
.emit());
}
ty::AssocKind::Fn => unreachable!(),
ty::AssocTag::Fn => unreachable!(),
}
}
@ -1503,7 +1511,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.inherent_impls(adt_did)
.iter()
.filter_map(|&impl_| {
let (item, scope) = self.probe_assoc_item_unchecked(name, kind, block, impl_)?;
let (item, scope) =
self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?;
Some((impl_, (item.def_id, scope)))
})
.collect();
@ -1542,7 +1551,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty,
|self_ty| {
self.select_inherent_assoc_candidates(
infcx, name, span, self_ty, param_env, candidates, kind,
infcx, name, span, self_ty, param_env, candidates, assoc_tag,
)
},
)?;
@ -1570,7 +1579,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self_ty: Ty<'tcx>,
param_env: ParamEnv<'tcx>,
candidates: Vec<(DefId, (DefId, DefId))>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
let tcx = self.tcx();
let mut fulfillment_errors = Vec::new();
@ -1621,7 +1630,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
candidates,
fulfillment_errors,
span,
kind,
assoc_tag,
)),
&[applicable_candidate] => Ok(applicable_candidate),
@ -1640,12 +1649,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn probe_assoc_item(
&self,
ident: Ident,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
block: HirId,
span: Span,
scope: DefId,
) -> Option<ty::AssocItem> {
let (item, scope) = self.probe_assoc_item_unchecked(ident, kind, block, scope)?;
let (item, scope) = self.probe_assoc_item_unchecked(ident, assoc_tag, block, scope)?;
self.check_assoc_item(item.def_id, ident, scope, block, span);
Some(item)
}
@ -1657,7 +1666,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
fn probe_assoc_item_unchecked(
&self,
ident: Ident,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
block: HirId,
scope: DefId,
) -> Option<(ty::AssocItem, /*scope*/ DefId)> {
@ -1670,7 +1679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let item = tcx
.associated_items(scope)
.filter_by_name_unhygienic(ident.name)
.find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
.find(|i| i.as_tag() == assoc_tag && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
Some((*item, def_scope))
}
@ -1722,9 +1731,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
tcx.associated_items(*trait_def_id)
.in_definition_order()
.any(|i| {
i.kind.namespace() == Namespace::TypeNS
i.namespace() == Namespace::TypeNS
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
&& matches!(i.kind, ty::AssocKind::Type)
&& i.is_type()
})
// Consider only accessible traits
&& tcx.visibility(*trait_def_id)
@ -1770,7 +1779,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_def_id,
trait_segment,
item_segment,
ty::AssocKind::Type,
ty::AssocTag::Type,
) {
Ok((item_def_id, item_args)) => {
Ty::new_projection_from_args(self.tcx(), item_def_id, item_args)
@ -1795,7 +1804,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_def_id,
trait_segment,
item_segment,
ty::AssocKind::Const,
ty::AssocTag::Const,
) {
Ok((item_def_id, item_args)) => {
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
@ -1813,7 +1822,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>,
item_segment: &hir::PathSegment<'tcx>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> {
let tcx = self.tcx();
@ -1821,7 +1830,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
debug!(?trait_def_id);
let Some(self_ty) = opt_self_ty else {
return Err(self.error_missing_qpath_self_ty(trait_def_id, span, item_segment, kind));
return Err(self.error_missing_qpath_self_ty(
trait_def_id,
span,
item_segment,
assoc_tag,
));
};
debug!(?self_ty);
@ -1840,7 +1854,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_def_id: DefId,
span: Span,
item_segment: &hir::PathSegment<'tcx>,
kind: ty::AssocKind,
assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed {
let tcx = self.tcx();
let path_str = tcx.def_path_str(trait_def_id);
@ -1877,7 +1891,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
// references the trait. Relevant for the first case in
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
self.report_ambiguous_assoc(span, &type_names, &[path_str], item_segment.ident.name, kind)
self.report_ambiguous_assoc(
span,
&type_names,
&[path_str],
item_segment.ident.name,
assoc_tag,
)
}
pub fn prohibit_generic_args<'a>(
@ -2862,7 +2882,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind(
tcx,
*ident,
ty::AssocKind::Fn,
ty::AssocTag::Fn,
trait_ref.def_id,
)?;

View file

@ -112,14 +112,14 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
.flat_map(|def_id| {
let item = tcx.associated_item(def_id);
match item.kind {
ty::AssocKind::Type => {
ty::AssocKind::Type { .. } => {
if item.defaultness(tcx).has_value() {
cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true)
} else {
vec![]
}
}
ty::AssocKind::Fn | ty::AssocKind::Const => vec![],
ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => vec![],
}
})
.collect();

View file

@ -59,7 +59,6 @@ This API is completely unstable and subject to change.
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(assert_matches)]

View file

@ -1871,10 +1871,11 @@ impl<'a> State<'a> {
fn print_pat(&mut self, pat: &hir::Pat<'_>) {
self.maybe_print_comment(pat.span.lo());
self.ann.pre(self, AnnNode::Pat(pat));
// Pat isn't normalized, but the beauty of it
// is that it doesn't matter
// Pat isn't normalized, but the beauty of it is that it doesn't matter.
match pat.kind {
PatKind::Missing => unreachable!(),
// Printing `_` isn't ideal for a missing pattern, but it's easy and good enough.
// E.g. `fn(u32)` gets printed as `fn(_: u32)`.
PatKind::Missing => self.word("_"),
PatKind::Wild => self.word("_"),
PatKind::Never => self.word("!"),
PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => {
@ -2164,7 +2165,9 @@ impl<'a> State<'a> {
s.end();
});
if decl.c_variadic {
self.word(", ");
if !decl.inputs.is_empty() {
self.word(", ");
}
print_arg(self, None);
self.word("...");
}

View file

@ -1042,30 +1042,31 @@ impl<'a, 'tcx> CastCheck<'tcx> {
m_cast: ty::TypeAndMut<'tcx>,
) -> Result<CastKind, CastError<'tcx>> {
// array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
if m_expr.mutbl >= m_cast.mutbl {
if let ty::Array(ety, _) = m_expr.ty.kind() {
// Due to the limitations of LLVM global constants,
// region pointers end up pointing at copies of
// vector elements instead of the original values.
// To allow raw pointers to work correctly, we
// need to special-case obtaining a raw pointer
// from a region pointer to a vector.
if m_expr.mutbl >= m_cast.mutbl
&& let ty::Array(ety, _) = m_expr.ty.kind()
&& fcx.can_eq(fcx.param_env, *ety, m_cast.ty)
{
// Due to the limitations of LLVM global constants,
// region pointers end up pointing at copies of
// vector elements instead of the original values.
// To allow raw pointers to work correctly, we
// need to special-case obtaining a raw pointer
// from a region pointer to a vector.
// Coerce to a raw pointer so that we generate RawPtr in MIR.
let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl);
fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
.unwrap_or_else(|_| {
bug!(
// Coerce to a raw pointer so that we generate RawPtr in MIR.
let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl);
fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
.unwrap_or_else(|_| {
bug!(
"could not cast from reference to array to pointer to array ({:?} to {:?})",
self.expr_ty,
array_ptr_type,
)
});
});
// this will report a type mismatch if needed
fcx.demand_eqtype(self.span, *ety, m_cast.ty);
return Ok(CastKind::ArrayPtrCast);
}
// this will report a type mismatch if needed
fcx.demand_eqtype(self.span, *ety, m_cast.ty);
return Ok(CastKind::ArrayPtrCast);
}
Err(CastError::IllegalCast)

View file

@ -103,15 +103,6 @@ fn coerce_mutbls<'tcx>(
if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) }
}
/// Do not require any adjustments, i.e. coerce `x -> x`.
fn identity(_: Ty<'_>) -> Vec<Adjustment<'_>> {
vec![]
}
fn simple<'tcx>(kind: Adjust) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> {
move |target| vec![Adjustment { kind, target }]
}
/// This always returns `Ok(...)`.
fn success<'tcx>(
adj: Vec<Adjustment<'tcx>>,
@ -131,7 +122,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
Coerce { fcx, cause, allow_two_phase, use_lub: false, coerce_never }
}
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
fn unify_raw(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
self.commit_if_ok(|_| {
let at = self.at(&self.cause, self.fcx.param_env);
@ -161,13 +152,30 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
})
}
/// Unify two types (using sub or lub).
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
self.unify_raw(a, b)
.and_then(|InferOk { value: ty, obligations }| success(vec![], ty, obligations))
}
/// Unify two types (using sub or lub) and produce a specific coercion.
fn unify_and<F>(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) -> CoerceResult<'tcx>
where
F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
{
self.unify(a, b)
.and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations))
fn unify_and(
&self,
a: Ty<'tcx>,
b: Ty<'tcx>,
adjustments: impl IntoIterator<Item = Adjustment<'tcx>>,
final_adjustment: Adjust,
) -> CoerceResult<'tcx> {
self.unify_raw(a, b).and_then(|InferOk { value: ty, obligations }| {
success(
adjustments
.into_iter()
.chain(std::iter::once(Adjustment { target: ty, kind: final_adjustment }))
.collect(),
ty,
obligations,
)
})
}
#[instrument(skip(self))]
@ -180,10 +188,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// Coercing from `!` to any type is allowed:
if a.is_never() {
if self.coerce_never {
return success(simple(Adjust::NeverToAny)(b), b, PredicateObligations::new());
return success(
vec![Adjustment { kind: Adjust::NeverToAny, target: b }],
b,
PredicateObligations::new(),
);
} else {
// Otherwise the only coercion we can do is unification.
return self.unify_and(a, b, identity);
return self.unify(a, b);
}
}
@ -191,7 +203,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// we have no information about the source type. This will always
// ultimately fall back to some form of subtyping.
if a.is_ty_var() {
return self.coerce_from_inference_variable(a, b, identity);
return self.coerce_from_inference_variable(a, b);
}
// Consider coercing the subtype to a DST
@ -247,7 +259,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
ty::FnPtr(a_sig_tys, a_hdr) => {
// We permit coercion of fn pointers to drop the
// unsafe qualifier.
self.coerce_from_fn_pointer(a, a_sig_tys.with(a_hdr), b)
self.coerce_from_fn_pointer(a_sig_tys.with(a_hdr), b)
}
ty::Closure(closure_def_id_a, args_a) => {
// Non-capturing closures are coercible to
@ -257,7 +269,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
}
_ => {
// Otherwise, just use unification rules.
self.unify_and(a, b, identity)
self.unify(a, b)
}
}
}
@ -265,12 +277,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
/// Coercing *from* an inference variable. In this case, we have no information
/// about the source type, so we can't really do a true coercion and we always
/// fall back to subtyping (`unify_and`).
fn coerce_from_inference_variable(
&self,
a: Ty<'tcx>,
b: Ty<'tcx>,
make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
) -> CoerceResult<'tcx> {
fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
assert!(self.shallow_resolve(b) == b);
@ -298,12 +305,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
"coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}",
target_ty, obligations
);
let adjustments = make_adjustments(target_ty);
InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations })
success(vec![], target_ty, obligations)
} else {
// One unresolved type variable: just apply subtyping, we may be able
// to do something useful.
self.unify_and(a, b, make_adjustments)
self.unify(a, b)
}
}
@ -331,7 +337,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
(r_a, mt_a)
}
_ => return self.unify_and(a, b, identity),
_ => return self.unify(a, b),
};
let span = self.cause.span;
@ -437,7 +443,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
referent_ty,
mutbl_b, // [1] above
);
match self.unify(derefd_ty_a, b) {
match self.unify_raw(derefd_ty_a, b) {
Ok(ok) => {
found = Some(ok);
break;
@ -579,13 +585,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// We only have the latter, so we use an inference variable
// for the former and let type inference do the rest.
let coerce_target = self.next_ty_var(self.cause.span);
let mut coercion = self.unify_and(coerce_target, target, |target| {
let unsize = Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), target };
match reborrow {
None => vec![unsize],
Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone(), unsize],
}
})?;
let mut coercion = self.unify_and(
coerce_target,
target,
reborrow.into_iter().flat_map(|(deref, autoref)| [deref, autoref]),
Adjust::Pointer(PointerCoercion::Unsize),
)?;
let mut selcx = traits::SelectionContext::new(self);
@ -708,7 +714,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
&& let ty::Dynamic(b_data, _, ty::DynStar) = b.kind()
&& a_data.principal_def_id() == b_data.principal_def_id()
{
return self.unify_and(a, b, |_| vec![]);
return self.unify(a, b);
}
// Check the obligations of the cast -- for example, when casting
@ -808,23 +814,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// To complete the reborrow, we need to make sure we can unify the inner types, and if so we
// add the adjustments.
self.unify_and(a, b, |_inner_ty| {
vec![Adjustment { kind: Adjust::ReborrowPin(mut_b), target: b }]
})
self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b))
}
fn coerce_from_safe_fn<F, G>(
fn coerce_from_safe_fn(
&self,
a: Ty<'tcx>,
fn_ty_a: ty::PolyFnSig<'tcx>,
b: Ty<'tcx>,
to_unsafe: F,
normal: G,
) -> CoerceResult<'tcx>
where
F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
{
adjustment: Option<Adjust>,
) -> CoerceResult<'tcx> {
self.commit_if_ok(|snapshot| {
let outer_universe = self.infcx.universe();
@ -833,9 +831,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
&& hdr_b.safety.is_unsafe()
{
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
self.unify_and(unsafe_a, b, to_unsafe)
self.unify_and(
unsafe_a,
b,
adjustment
.map(|kind| Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }),
Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
)
} else {
self.unify_and(a, b, normal)
let a = Ty::new_fn_ptr(self.tcx, fn_ty_a);
match adjustment {
Some(adjust) => self.unify_and(a, b, [], adjust),
None => self.unify(a, b),
}
};
// FIXME(#73154): This is a hack. Currently LUB can generate
@ -852,7 +860,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
fn coerce_from_fn_pointer(
&self,
a: Ty<'tcx>,
fn_ty_a: ty::PolyFnSig<'tcx>,
b: Ty<'tcx>,
) -> CoerceResult<'tcx> {
@ -861,15 +868,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
//!
let b = self.shallow_resolve(b);
debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer");
self.coerce_from_safe_fn(
a,
fn_ty_a,
b,
simple(Adjust::Pointer(PointerCoercion::UnsafeFnPointer)),
identity,
)
self.coerce_from_safe_fn(fn_ty_a, b, None)
}
fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
@ -916,30 +917,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
self.at(&self.cause, self.param_env).normalize(a_sig);
obligations.extend(o1);
let a_fn_pointer = Ty::new_fn_ptr(self.tcx, a_sig);
let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn(
a_fn_pointer,
a_sig,
b,
|unsafe_ty| {
vec![
Adjustment {
kind: Adjust::Pointer(PointerCoercion::ReifyFnPointer),
target: a_fn_pointer,
},
Adjustment {
kind: Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
target: unsafe_ty,
},
]
},
simple(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
Some(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
)?;
obligations.extend(o2);
Ok(InferOk { value, obligations })
}
_ => self.unify_and(a, b, identity),
_ => self.unify(a, b),
}
}
@ -983,10 +970,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
self.unify_and(
pointer_ty,
b,
simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety))),
[],
Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)),
)
}
_ => self.unify_and(a, b, identity),
_ => self.unify(a, b),
}
}
@ -1001,7 +989,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let (is_ref, mt_a) = match *a.kind() {
ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }),
ty::RawPtr(ty, mutbl) => (false, ty::TypeAndMut { ty, mutbl }),
_ => return self.unify_and(a, b, identity),
_ => return self.unify(a, b),
};
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
@ -1011,16 +999,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// representation, we still register an Adjust::DerefRef so that
// regionck knows that the region for `a` must be valid here.
if is_ref {
self.unify_and(a_raw, b, |target| {
vec![
Adjustment { kind: Adjust::Deref(None), target: mt_a.ty },
Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), target },
]
})
self.unify_and(
a_raw,
b,
[Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }],
Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)),
)
} else if mt_a.mutbl != mutbl_b {
self.unify_and(a_raw, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer)))
self.unify_and(a_raw, b, [], Adjust::Pointer(PointerCoercion::MutToConstPointer))
} else {
self.unify_and(a_raw, b, identity)
self.unify(a_raw, b)
}
}
}
@ -1118,9 +1106,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
// We don't ever need two-phase here since we throw out the result of the coercion.
let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
coerce
.autoderef(DUMMY_SP, expr_ty)
.find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps))
coerce.autoderef(DUMMY_SP, expr_ty).find_map(|(ty, steps)| {
self.probe(|_| coerce.unify_raw(ty, target)).ok().map(|_| steps)
})
}
/// Given a type, this function will calculate and return the type given

View file

@ -1089,14 +1089,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// This function checks whether the method is not static and does not accept other parameters than `self`.
fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
match method.kind {
ty::AssocKind::Fn => {
method.fn_has_self_parameter
&& self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len()
== 1
}
_ => false,
}
method.is_method()
&& self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() == 1
}
/// If the given `HirId` corresponds to a block with a trailing expression, return that expression

Some files were not shown because too many files have changed in this diff Show more