Merge from rustc
This commit is contained in:
commit
d7e49c03f6
@ -4557,9 +4557,7 @@ dependencies = [
|
||||
"rustc-demangle",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
@ -4694,6 +4692,7 @@ dependencies = [
|
||||
"arrayvec",
|
||||
"askama",
|
||||
"expect-test",
|
||||
"indexmap 2.0.0",
|
||||
"itertools",
|
||||
"minifier",
|
||||
"once_cell",
|
||||
|
@ -18,7 +18,6 @@
|
||||
#![feature(new_uninit)]
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(pointer_byte_offsets)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
#![feature(strict_provenance)]
|
||||
|
@ -734,6 +734,8 @@ pub enum RangeSyntax {
|
||||
}
|
||||
|
||||
/// All the different flavors of pattern that Rust recognizes.
|
||||
//
|
||||
// Adding a new variant? Please update `test_pat` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum PatKind {
|
||||
/// Represents a wildcard pattern (`_`).
|
||||
@ -967,6 +969,7 @@ impl Stmt {
|
||||
}
|
||||
}
|
||||
|
||||
// Adding a new variant? Please update `test_stmt` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum StmtKind {
|
||||
/// A local (let) binding.
|
||||
@ -1345,6 +1348,7 @@ pub struct StructExpr {
|
||||
pub rest: StructRest,
|
||||
}
|
||||
|
||||
// Adding a new variant? Please update `test_expr` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum ExprKind {
|
||||
/// An array (`[a, b, c, d]`)
|
||||
@ -2015,6 +2019,8 @@ pub struct BareFnTy {
|
||||
}
|
||||
|
||||
/// The various kinds of type recognized by the compiler.
|
||||
//
|
||||
// Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum TyKind {
|
||||
/// A variable-length slice (`[T]`).
|
||||
@ -2880,6 +2886,7 @@ pub struct ConstItem {
|
||||
pub expr: Option<P<Expr>>,
|
||||
}
|
||||
|
||||
// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum ItemKind {
|
||||
/// An `extern crate` item, with the optional *original* crate name if the crate was renamed.
|
||||
|
@ -188,7 +188,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
e.id,
|
||||
None,
|
||||
e.span,
|
||||
hir::AsyncCoroutineKind::Block,
|
||||
hir::CoroutineSource::Block,
|
||||
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
|
||||
),
|
||||
ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
|
||||
@ -598,7 +598,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
closure_node_id: NodeId,
|
||||
ret_ty: Option<hir::FnRetTy<'hir>>,
|
||||
span: Span,
|
||||
async_gen_kind: hir::AsyncCoroutineKind,
|
||||
async_gen_kind: hir::CoroutineSource,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
|
||||
@ -1005,7 +1005,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
inner_closure_id,
|
||||
async_ret_ty,
|
||||
body.span,
|
||||
hir::AsyncCoroutineKind::Closure,
|
||||
hir::CoroutineSource::Closure,
|
||||
|this| this.with_new_scopes(|this| this.lower_expr_mut(body)),
|
||||
);
|
||||
let hir_id = this.lower_node_id(inner_closure_id);
|
||||
|
@ -1206,7 +1206,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
closure_id,
|
||||
None,
|
||||
body.span,
|
||||
hir::AsyncCoroutineKind::Fn,
|
||||
hir::CoroutineSource::Fn,
|
||||
|this| {
|
||||
// Create a block from the user's function body:
|
||||
let user_body = this.lower_block_expr(body);
|
||||
|
@ -1217,7 +1217,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
hir_id: this.lower_node_id(node_id),
|
||||
body: this.lower_const_body(path_expr.span, Some(&path_expr)),
|
||||
});
|
||||
return GenericArg::Const(ConstArg { value: ct, span });
|
||||
return GenericArg::Const(ConstArg {
|
||||
value: ct,
|
||||
span,
|
||||
is_desugared_from_effects: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1228,6 +1232,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg {
|
||||
value: self.lower_anon_const(&ct),
|
||||
span: self.lower_span(ct.value.span),
|
||||
is_desugared_from_effects: false,
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -2525,6 +2530,7 @@ impl<'hir> GenericArgsCtor<'hir> {
|
||||
self.args.push(hir::GenericArg::Const(hir::ConstArg {
|
||||
value: hir::AnonConst { def_id, hir_id, body },
|
||||
span,
|
||||
is_desugared_from_effects: true,
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ use rustc_session::parse::{feature_err, ParseSess};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{symbol::sym, symbol::Symbol, Span};
|
||||
use std::fmt::{self, Display};
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
|
||||
@ -23,10 +24,7 @@ use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
|
||||
/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591).
|
||||
pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
|
||||
|
||||
pub fn rust_version_symbol() -> Symbol {
|
||||
let version = option_env!("CFG_RELEASE").unwrap_or("<current>");
|
||||
Symbol::intern(&version)
|
||||
}
|
||||
pub const CURRENT_RUSTC_VERSION: &str = env!("CFG_RELEASE");
|
||||
|
||||
pub fn is_builtin_attr(attr: &Attribute) -> bool {
|
||||
attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
|
||||
@ -144,13 +142,24 @@ pub enum StabilityLevel {
|
||||
/// `#[stable]`
|
||||
Stable {
|
||||
/// Rust release which stabilized this feature.
|
||||
since: Symbol,
|
||||
since: Since,
|
||||
/// Is this item allowed to be referred to on stable, despite being contained in unstable
|
||||
/// modules?
|
||||
allowed_through_unstable_modules: bool,
|
||||
},
|
||||
}
|
||||
|
||||
/// Rust release in which a feature is stabilized.
|
||||
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum Since {
|
||||
Version(Version),
|
||||
/// Stabilized in the upcoming version, whatever number that is.
|
||||
Current,
|
||||
/// Failed to parse a stabilization version.
|
||||
Err,
|
||||
}
|
||||
|
||||
impl StabilityLevel {
|
||||
pub fn is_unstable(&self) -> bool {
|
||||
matches!(self, StabilityLevel::Unstable { .. })
|
||||
@ -372,22 +381,24 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
|
||||
|
||||
let since = if let Some(since) = since {
|
||||
if since.as_str() == VERSION_PLACEHOLDER {
|
||||
Ok(rust_version_symbol())
|
||||
} else if parse_version(since.as_str(), false).is_some() {
|
||||
Ok(since)
|
||||
Since::Current
|
||||
} else if let Some(version) = parse_version(since.as_str(), false) {
|
||||
Since::Version(version)
|
||||
} else {
|
||||
Err(sess.emit_err(session_diagnostics::InvalidSince { span: attr.span }))
|
||||
sess.emit_err(session_diagnostics::InvalidSince { span: attr.span });
|
||||
Since::Err
|
||||
}
|
||||
} else {
|
||||
Err(sess.emit_err(session_diagnostics::MissingSince { span: attr.span }))
|
||||
sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
|
||||
Since::Err
|
||||
};
|
||||
|
||||
match (feature, since) {
|
||||
(Ok(feature), Ok(since)) => {
|
||||
match feature {
|
||||
Ok(feature) => {
|
||||
let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false };
|
||||
Some((feature, level))
|
||||
}
|
||||
(Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
|
||||
Err(ErrorGuaranteed { .. }) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -556,11 +567,12 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
struct Version {
|
||||
major: u16,
|
||||
minor: u16,
|
||||
patch: u16,
|
||||
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub struct Version {
|
||||
pub major: u16,
|
||||
pub minor: u16,
|
||||
pub patch: u16,
|
||||
}
|
||||
|
||||
fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> {
|
||||
@ -576,6 +588,12 @@ fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> {
|
||||
Some(Version { major, minor, patch })
|
||||
}
|
||||
|
||||
impl Display for Version {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
|
||||
/// evaluate individual items.
|
||||
pub fn eval_condition(
|
||||
@ -609,7 +627,7 @@ pub fn eval_condition(
|
||||
sess.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span });
|
||||
return false;
|
||||
};
|
||||
let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap();
|
||||
let rustc_version = parse_version(CURRENT_RUSTC_VERSION, true).unwrap();
|
||||
|
||||
// See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
|
||||
if sess.assume_incomplete_release {
|
||||
|
@ -8,7 +8,7 @@ use rustc_errors::{
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
|
||||
use rustc_hir::{AsyncCoroutineKind, CoroutineKind, LangItem};
|
||||
use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
@ -2506,8 +2506,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let kind = match use_span.coroutine_kind() {
|
||||
Some(coroutine_kind) => match coroutine_kind {
|
||||
CoroutineKind::Async(async_kind) => match async_kind {
|
||||
AsyncCoroutineKind::Block => "async block",
|
||||
AsyncCoroutineKind::Closure => "async closure",
|
||||
CoroutineSource::Block => "async block",
|
||||
CoroutineSource::Closure => "async closure",
|
||||
_ => bug!("async block/closure expected, but async function found."),
|
||||
},
|
||||
CoroutineKind::Coroutine => "coroutine",
|
||||
|
@ -682,9 +682,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
};
|
||||
let mir_description = match hir.body(body).coroutine_kind {
|
||||
Some(hir::CoroutineKind::Async(gen)) => match gen {
|
||||
hir::AsyncCoroutineKind::Block => " of async block",
|
||||
hir::AsyncCoroutineKind::Closure => " of async closure",
|
||||
hir::AsyncCoroutineKind::Fn => {
|
||||
hir::CoroutineSource::Block => " of async block",
|
||||
hir::CoroutineSource::Closure => " of async closure",
|
||||
hir::CoroutineSource::Fn => {
|
||||
let parent_item =
|
||||
hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id);
|
||||
let output = &parent_item
|
||||
|
@ -8,7 +8,7 @@ use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::traits::query::OutlivesBound;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
||||
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
||||
use std::rc::Rc;
|
||||
use type_op::TypeOpOutput;
|
||||
@ -318,7 +318,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
.param_env
|
||||
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
|
||||
.fully_perform(self.infcx, DUMMY_SP)
|
||||
.unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty));
|
||||
.map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
|
||||
.ok()?;
|
||||
debug!(?bounds, ?constraints);
|
||||
self.add_outlives_bounds(bounds);
|
||||
constraints
|
||||
|
@ -37,8 +37,9 @@
|
||||
//! following snippet
|
||||
//!
|
||||
//! ```rust
|
||||
//! # #![allow(dead_code)]
|
||||
//! struct A { x : i32 }
|
||||
//! struct A {
|
||||
//! x: i32,
|
||||
//! }
|
||||
//!
|
||||
//! struct B(i32);
|
||||
//!
|
||||
@ -74,6 +75,7 @@
|
||||
//! trait PartialEq {
|
||||
//! fn eq(&self, other: &Self) -> bool;
|
||||
//! }
|
||||
//!
|
||||
//! impl PartialEq for i32 {
|
||||
//! fn eq(&self, other: &i32) -> bool {
|
||||
//! *self == *other
|
||||
@ -90,22 +92,22 @@
|
||||
//!
|
||||
//! ```text
|
||||
//! Struct(vec![FieldInfo {
|
||||
//! span: <span of x>
|
||||
//! name: Some(<ident of x>),
|
||||
//! self_: <expr for &self.x>,
|
||||
//! other: vec![<expr for &other.x]
|
||||
//! }])
|
||||
//! span: <span of x>,
|
||||
//! name: Some(<ident of x>),
|
||||
//! self_: <expr for &self.x>,
|
||||
//! other: vec![<expr for &other.x>],
|
||||
//! }])
|
||||
//! ```
|
||||
//!
|
||||
//! For the `B` impl, called with `B(a)` and `B(b)`,
|
||||
//!
|
||||
//! ```text
|
||||
//! Struct(vec![FieldInfo {
|
||||
//! span: <span of `i32`>,
|
||||
//! name: None,
|
||||
//! self_: <expr for &a>
|
||||
//! other: vec![<expr for &b>]
|
||||
//! }])
|
||||
//! span: <span of i32>,
|
||||
//! name: None,
|
||||
//! self_: <expr for &a>,
|
||||
//! other: vec![<expr for &b>],
|
||||
//! }])
|
||||
//! ```
|
||||
//!
|
||||
//! ## Enums
|
||||
@ -114,33 +116,42 @@
|
||||
//! == C0(b)`, the SubstructureFields is
|
||||
//!
|
||||
//! ```text
|
||||
//! EnumMatching(0, <ast::Variant for C0>,
|
||||
//! vec![FieldInfo {
|
||||
//! span: <span of i32>
|
||||
//! name: None,
|
||||
//! self_: <expr for &a>,
|
||||
//! other: vec![<expr for &b>]
|
||||
//! }])
|
||||
//! EnumMatching(
|
||||
//! 0,
|
||||
//! <ast::Variant for C0>,
|
||||
//! vec![FieldInfo {
|
||||
//! span: <span of i32>,
|
||||
//! name: None,
|
||||
//! self_: <expr for &a>,
|
||||
//! other: vec![<expr for &b>],
|
||||
//! }],
|
||||
//! )
|
||||
//! ```
|
||||
//!
|
||||
//! For `C1 {x}` and `C1 {x}`,
|
||||
//!
|
||||
//! ```text
|
||||
//! EnumMatching(1, <ast::Variant for C1>,
|
||||
//! vec![FieldInfo {
|
||||
//! span: <span of x>
|
||||
//! name: Some(<ident of x>),
|
||||
//! self_: <expr for &self.x>,
|
||||
//! other: vec![<expr for &other.x>]
|
||||
//! }])
|
||||
//! EnumMatching(
|
||||
//! 1,
|
||||
//! <ast::Variant for C1>,
|
||||
//! vec![FieldInfo {
|
||||
//! span: <span of x>,
|
||||
//! name: Some(<ident of x>),
|
||||
//! self_: <expr for &self.x>,
|
||||
//! other: vec![<expr for &other.x>],
|
||||
//! }],
|
||||
//! )
|
||||
//! ```
|
||||
//!
|
||||
//! For the tags,
|
||||
//!
|
||||
//! ```text
|
||||
//! EnumTag(
|
||||
//! &[<ident of self tag>, <ident of other tag>], <expr to combine with>)
|
||||
//! &[<ident of self tag>, <ident of other tag>],
|
||||
//! <expr to combine with>,
|
||||
//! )
|
||||
//! ```
|
||||
//!
|
||||
//! Note that this setup doesn't allow for the brute-force "match every variant
|
||||
//! against every other variant" approach, which is bad because it produces a
|
||||
//! quadratic amount of code (see #15375).
|
||||
@ -154,9 +165,13 @@
|
||||
//!
|
||||
//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
|
||||
//!
|
||||
//! StaticEnum(<ast::EnumDef of C>,
|
||||
//! vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
|
||||
//! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))])
|
||||
//! StaticEnum(
|
||||
//! <ast::EnumDef of C>,
|
||||
//! vec![
|
||||
//! (<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
|
||||
//! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)])),
|
||||
//! ],
|
||||
//! )
|
||||
//! ```
|
||||
|
||||
pub use StaticFields::*;
|
||||
@ -522,7 +537,10 @@ impl<'a> TraitDef<'a> {
|
||||
/// Given that we are deriving a trait `DerivedTrait` for a type like:
|
||||
///
|
||||
/// ```ignore (only-for-syntax-highlight)
|
||||
/// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait {
|
||||
/// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z>
|
||||
/// where
|
||||
/// C: WhereTrait,
|
||||
/// {
|
||||
/// a: A,
|
||||
/// b: B::Item,
|
||||
/// b1: <B as DeclaredTrait>::Item,
|
||||
@ -535,12 +553,13 @@ impl<'a> TraitDef<'a> {
|
||||
/// create an impl like:
|
||||
///
|
||||
/// ```ignore (only-for-syntax-highlight)
|
||||
/// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where
|
||||
/// C: WhereTrait,
|
||||
/// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z>
|
||||
/// where
|
||||
/// C: WhereTrait,
|
||||
/// A: DerivedTrait + B1 + ... + BN,
|
||||
/// B: DerivedTrait + B1 + ... + BN,
|
||||
/// C: DerivedTrait + B1 + ... + BN,
|
||||
/// B::Item: DerivedTrait + B1 + ... + BN,
|
||||
/// B::Item: DerivedTrait + B1 + ... + BN,
|
||||
/// <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN,
|
||||
/// ...
|
||||
/// {
|
||||
@ -676,65 +695,59 @@ impl<'a> TraitDef<'a> {
|
||||
}
|
||||
}));
|
||||
|
||||
{
|
||||
// Extra scope required here so ty_params goes out of scope before params is moved
|
||||
let ty_param_names: Vec<Symbol> = params
|
||||
.iter()
|
||||
.filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
|
||||
.map(|ty_param| ty_param.ident.name)
|
||||
.collect();
|
||||
|
||||
let mut ty_params = params
|
||||
.iter()
|
||||
.filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
|
||||
.peekable();
|
||||
if !ty_param_names.is_empty() {
|
||||
for field_ty in field_tys {
|
||||
let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx);
|
||||
|
||||
if ty_params.peek().is_some() {
|
||||
let ty_param_names: Vec<Symbol> =
|
||||
ty_params.map(|ty_param| ty_param.ident.name).collect();
|
||||
|
||||
for field_ty in field_tys {
|
||||
let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx);
|
||||
|
||||
for field_ty_param in field_ty_params {
|
||||
// if we have already handled this type, skip it
|
||||
if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind
|
||||
&& let [sole_segment] = &*p.segments
|
||||
&& ty_param_names.contains(&sole_segment.ident.name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let mut bounds: Vec<_> = self
|
||||
.additional_bounds
|
||||
.iter()
|
||||
.map(|p| {
|
||||
cx.trait_bound(
|
||||
p.to_path(cx, self.span, type_ident, generics),
|
||||
self.is_const,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Require the current trait.
|
||||
if !self.skip_path_as_bound {
|
||||
bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
|
||||
}
|
||||
|
||||
// Add a `Copy` bound if required.
|
||||
if is_packed && self.needs_copy_as_bound_if_packed {
|
||||
let p = deriving::path_std!(marker::Copy);
|
||||
bounds.push(cx.trait_bound(
|
||||
for field_ty_param in field_ty_params {
|
||||
// if we have already handled this type, skip it
|
||||
if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind
|
||||
&& let [sole_segment] = &*p.segments
|
||||
&& ty_param_names.contains(&sole_segment.ident.name)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let mut bounds: Vec<_> = self
|
||||
.additional_bounds
|
||||
.iter()
|
||||
.map(|p| {
|
||||
cx.trait_bound(
|
||||
p.to_path(cx, self.span, type_ident, generics),
|
||||
self.is_const,
|
||||
));
|
||||
}
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if !bounds.is_empty() {
|
||||
let predicate = ast::WhereBoundPredicate {
|
||||
span: self.span,
|
||||
bound_generic_params: field_ty_param.bound_generic_params,
|
||||
bounded_ty: field_ty_param.ty,
|
||||
bounds,
|
||||
};
|
||||
// Require the current trait.
|
||||
if !self.skip_path_as_bound {
|
||||
bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
|
||||
}
|
||||
|
||||
let predicate = ast::WherePredicate::BoundPredicate(predicate);
|
||||
where_clause.predicates.push(predicate);
|
||||
}
|
||||
// Add a `Copy` bound if required.
|
||||
if is_packed && self.needs_copy_as_bound_if_packed {
|
||||
let p = deriving::path_std!(marker::Copy);
|
||||
bounds.push(cx.trait_bound(
|
||||
p.to_path(cx, self.span, type_ident, generics),
|
||||
self.is_const,
|
||||
));
|
||||
}
|
||||
|
||||
if !bounds.is_empty() {
|
||||
let predicate = ast::WhereBoundPredicate {
|
||||
span: self.span,
|
||||
bound_generic_params: field_ty_param.bound_generic_params,
|
||||
bounded_ty: field_ty_param.ty,
|
||||
bounds,
|
||||
};
|
||||
|
||||
let predicate = ast::WherePredicate::BoundPredicate(predicate);
|
||||
where_clause.predicates.push(predicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1026,6 +1039,7 @@ impl<'a> MethodDef<'a> {
|
||||
}
|
||||
|
||||
/// The normal case uses field access.
|
||||
///
|
||||
/// ```
|
||||
/// #[derive(PartialEq)]
|
||||
/// # struct Dummy;
|
||||
@ -1038,10 +1052,12 @@ impl<'a> MethodDef<'a> {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// But if the struct is `repr(packed)`, we can't use something like
|
||||
/// `&self.x` because that might cause an unaligned ref. So for any trait
|
||||
/// method that takes a reference, we use a local block to force a copy.
|
||||
/// This requires that the field impl `Copy`.
|
||||
///
|
||||
/// ```rust,ignore (example)
|
||||
/// # struct A { x: u8, y: u8 }
|
||||
/// impl PartialEq for A {
|
||||
@ -1053,7 +1069,7 @@ impl<'a> MethodDef<'a> {
|
||||
/// impl Hash for A {
|
||||
/// fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
|
||||
/// ::core::hash::Hash::hash(&{ self.x }, state);
|
||||
/// ::core::hash::Hash::hash(&{ self.y }, state)
|
||||
/// ::core::hash::Hash::hash(&{ self.y }, state);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@ -1107,7 +1123,9 @@ impl<'a> MethodDef<'a> {
|
||||
/// A2(i32)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// is equivalent to:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(core_intrinsics)]
|
||||
/// enum A {
|
||||
@ -1119,15 +1137,15 @@ impl<'a> MethodDef<'a> {
|
||||
/// fn eq(&self, other: &A) -> bool {
|
||||
/// let __self_tag = ::core::intrinsics::discriminant_value(self);
|
||||
/// let __arg1_tag = ::core::intrinsics::discriminant_value(other);
|
||||
/// __self_tag == __arg1_tag &&
|
||||
/// match (self, other) {
|
||||
/// (A::A2(__self_0), A::A2(__arg1_0)) =>
|
||||
/// *__self_0 == *__arg1_0,
|
||||
/// __self_tag == __arg1_tag
|
||||
/// && match (self, other) {
|
||||
/// (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0,
|
||||
/// _ => true,
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Creates a tag check combined with a match for a tuple of all
|
||||
/// `selflike_args`, with an arm for each variant with fields, possibly an
|
||||
/// arm for each fieldless variant (if `unify_fieldless_variants` is not
|
||||
@ -1349,7 +1367,7 @@ impl<'a> MethodDef<'a> {
|
||||
// (Variant1, Variant1, ...) => Body1
|
||||
// (Variant2, Variant2, ...) => Body2,
|
||||
// ...
|
||||
// _ => ::core::intrinsics::unreachable()
|
||||
// _ => ::core::intrinsics::unreachable(),
|
||||
// }
|
||||
let get_match_expr = |mut selflike_args: ThinVec<P<Expr>>| {
|
||||
let match_arg = if selflike_args.len() == 1 {
|
||||
|
@ -362,9 +362,14 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
// currently use this mode so we have to allow it -- but we absolutely
|
||||
// shouldn't let any more targets do that.
|
||||
// (Also see <https://github.com/rust-lang/rust/issues/115666>.)
|
||||
//
|
||||
// The unstable abi `PtxKernel` also uses Direct for now.
|
||||
// It needs to switch to something else before stabilization can happen.
|
||||
// (See issue: https://github.com/rust-lang/rust/issues/117271)
|
||||
assert!(
|
||||
matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64"),
|
||||
"`PassMode::Direct` for aggregates only allowed on wasm targets\nProblematic type: {:#?}",
|
||||
matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64")
|
||||
|| self.conv == Conv::PtxKernel,
|
||||
"`PassMode::Direct` for aggregates only allowed on wasm and `extern \"ptx-kernel\"` fns\nProblematic type: {:#?}",
|
||||
arg.layout,
|
||||
);
|
||||
}
|
||||
|
@ -22,7 +22,9 @@ use rustc_session::utils::NativeLibKind;
|
||||
/// need out of the shared crate context before we get rid of it.
|
||||
use rustc_session::{filesearch, Session};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
|
||||
use rustc_target::spec::crt_objects::CrtObjects;
|
||||
use rustc_target::spec::LinkSelfContainedComponents;
|
||||
use rustc_target::spec::LinkSelfContainedDefault;
|
||||
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld, PanicStrategy};
|
||||
use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};
|
||||
|
||||
@ -728,6 +730,7 @@ fn link_natively<'a>(
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
info!("preparing {:?} to {:?}", crate_type, out_filename);
|
||||
let (linker_path, flavor) = linker_and_flavor(sess);
|
||||
let self_contained_components = self_contained_components(sess, crate_type);
|
||||
let mut cmd = linker_with_args(
|
||||
&linker_path,
|
||||
flavor,
|
||||
@ -737,6 +740,7 @@ fn link_natively<'a>(
|
||||
tmpdir,
|
||||
out_filename,
|
||||
codegen_results,
|
||||
self_contained_components,
|
||||
)?;
|
||||
|
||||
linker::disable_localization(&mut cmd);
|
||||
@ -812,14 +816,14 @@ fn link_natively<'a>(
|
||||
"Linker does not support -static-pie command line option. Retrying with -static instead."
|
||||
);
|
||||
// Mirror `add_(pre,post)_link_objects` to replace CRT objects.
|
||||
let self_contained = self_contained(sess, crate_type);
|
||||
let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled();
|
||||
let opts = &sess.target;
|
||||
let pre_objects = if self_contained {
|
||||
let pre_objects = if self_contained_crt_objects {
|
||||
&opts.pre_link_objects_self_contained
|
||||
} else {
|
||||
&opts.pre_link_objects
|
||||
};
|
||||
let post_objects = if self_contained {
|
||||
let post_objects = if self_contained_crt_objects {
|
||||
&opts.post_link_objects_self_contained
|
||||
} else {
|
||||
&opts.post_link_objects
|
||||
@ -830,7 +834,9 @@ fn link_natively<'a>(
|
||||
.iter()
|
||||
.copied()
|
||||
.flatten()
|
||||
.map(|obj| get_object_file_path(sess, obj, self_contained).into_os_string())
|
||||
.map(|obj| {
|
||||
get_object_file_path(sess, obj, self_contained_crt_objects).into_os_string()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
let pre_objects_static_pie = get_objects(pre_objects, LinkOutputKind::StaticPicExe);
|
||||
@ -1710,26 +1716,43 @@ fn detect_self_contained_mingw(sess: &Session) -> bool {
|
||||
/// Various toolchain components used during linking are used from rustc distribution
|
||||
/// instead of being found somewhere on the host system.
|
||||
/// We only provide such support for a very limited number of targets.
|
||||
fn self_contained(sess: &Session, crate_type: CrateType) -> bool {
|
||||
if let Some(self_contained) = sess.opts.cg.link_self_contained.explicitly_set {
|
||||
if sess.target.link_self_contained == LinkSelfContainedDefault::False {
|
||||
sess.emit_err(errors::UnsupportedLinkSelfContained);
|
||||
}
|
||||
return self_contained;
|
||||
}
|
||||
fn self_contained_components(sess: &Session, crate_type: CrateType) -> LinkSelfContainedComponents {
|
||||
// Turn the backwards compatible bool values for `self_contained` into fully inferred
|
||||
// `LinkSelfContainedComponents`.
|
||||
let self_contained =
|
||||
if let Some(self_contained) = sess.opts.cg.link_self_contained.explicitly_set {
|
||||
// Emit an error if the user requested self-contained mode on the CLI but the target
|
||||
// explicitly refuses it.
|
||||
if sess.target.link_self_contained.is_disabled() {
|
||||
sess.emit_err(errors::UnsupportedLinkSelfContained);
|
||||
}
|
||||
self_contained
|
||||
} else {
|
||||
match sess.target.link_self_contained {
|
||||
LinkSelfContainedDefault::False => false,
|
||||
LinkSelfContainedDefault::True => true,
|
||||
|
||||
match sess.target.link_self_contained {
|
||||
LinkSelfContainedDefault::False => false,
|
||||
LinkSelfContainedDefault::True => true,
|
||||
// FIXME: Find a better heuristic for "native musl toolchain is available",
|
||||
// based on host and linker path, for example.
|
||||
// (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237).
|
||||
LinkSelfContainedDefault::Musl => sess.crt_static(Some(crate_type)),
|
||||
LinkSelfContainedDefault::Mingw => {
|
||||
sess.host == sess.target
|
||||
&& sess.target.vendor != "uwp"
|
||||
&& detect_self_contained_mingw(&sess)
|
||||
}
|
||||
LinkSelfContainedDefault::WithComponents(components) => {
|
||||
// For target specs with explicitly enabled components, we can return them
|
||||
// directly.
|
||||
return components;
|
||||
}
|
||||
|
||||
// FIXME: Find a better heuristic for "native musl toolchain is available",
|
||||
// based on host and linker path, for example.
|
||||
// (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237).
|
||||
LinkSelfContainedDefault::InferredForMusl => sess.crt_static(Some(crate_type)),
|
||||
LinkSelfContainedDefault::InferredForMingw => {
|
||||
sess.host == sess.target
|
||||
&& sess.target.vendor != "uwp"
|
||||
&& detect_self_contained_mingw(&sess)
|
||||
}
|
||||
}
|
||||
};
|
||||
if self_contained {
|
||||
LinkSelfContainedComponents::all()
|
||||
} else {
|
||||
LinkSelfContainedComponents::empty()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1889,37 +1912,14 @@ fn add_linked_symbol_object(
|
||||
return;
|
||||
};
|
||||
|
||||
// NOTE(nbdd0121): MSVC will hang if the input object file contains no sections,
|
||||
// so add an empty section.
|
||||
if file.format() == object::BinaryFormat::Coff {
|
||||
// NOTE(nbdd0121): MSVC will hang if the input object file contains no sections,
|
||||
// so add an empty section.
|
||||
file.add_section(Vec::new(), ".text".into(), object::SectionKind::Text);
|
||||
|
||||
// We handle the name decoration of COFF targets in `symbol_export.rs`, so disable the
|
||||
// default mangler in `object` crate.
|
||||
file.set_mangling(object::write::Mangling::None);
|
||||
|
||||
// Add feature flags to the object file. On MSVC this is optional but LLD will complain if
|
||||
// not present.
|
||||
let mut feature = 0;
|
||||
|
||||
if file.architecture() == object::Architecture::I386 {
|
||||
// Indicate that all SEH handlers are registered in .sxdata section.
|
||||
// We don't have generate any code, so we don't need .sxdata section but LLD still
|
||||
// expects us to set this bit (see #96498).
|
||||
// Reference: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
|
||||
feature |= 1;
|
||||
}
|
||||
|
||||
file.add_symbol(object::write::Symbol {
|
||||
name: "@feat.00".into(),
|
||||
value: feature,
|
||||
size: 0,
|
||||
kind: object::SymbolKind::Data,
|
||||
scope: object::SymbolScope::Compilation,
|
||||
weak: false,
|
||||
section: object::write::SymbolSection::Absolute,
|
||||
flags: object::SymbolFlags::None,
|
||||
});
|
||||
}
|
||||
|
||||
for (sym, kind) in symbols.iter() {
|
||||
@ -2053,13 +2053,14 @@ fn linker_with_args<'a>(
|
||||
tmpdir: &Path,
|
||||
out_filename: &Path,
|
||||
codegen_results: &CodegenResults,
|
||||
self_contained_components: LinkSelfContainedComponents,
|
||||
) -> Result<Command, ErrorGuaranteed> {
|
||||
let self_contained = self_contained(sess, crate_type);
|
||||
let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled();
|
||||
let cmd = &mut *super::linker::get_linker(
|
||||
sess,
|
||||
path,
|
||||
flavor,
|
||||
self_contained,
|
||||
self_contained_components.are_any_components_enabled(),
|
||||
&codegen_results.crate_info.target_cpu,
|
||||
);
|
||||
let link_output_kind = link_output_kind(sess, crate_type);
|
||||
@ -2086,7 +2087,7 @@ fn linker_with_args<'a>(
|
||||
// ------------ Object code and libraries, order-dependent ------------
|
||||
|
||||
// Pre-link CRT objects.
|
||||
add_pre_link_objects(cmd, sess, flavor, link_output_kind, self_contained);
|
||||
add_pre_link_objects(cmd, sess, flavor, link_output_kind, self_contained_crt_objects);
|
||||
|
||||
add_linked_symbol_object(
|
||||
cmd,
|
||||
@ -2229,7 +2230,7 @@ fn linker_with_args<'a>(
|
||||
cmd,
|
||||
sess,
|
||||
link_output_kind,
|
||||
self_contained,
|
||||
self_contained_components,
|
||||
flavor,
|
||||
crate_type,
|
||||
codegen_results,
|
||||
@ -2245,7 +2246,7 @@ fn linker_with_args<'a>(
|
||||
// ------------ Object code and libraries, order-dependent ------------
|
||||
|
||||
// Post-link CRT objects.
|
||||
add_post_link_objects(cmd, sess, link_output_kind, self_contained);
|
||||
add_post_link_objects(cmd, sess, link_output_kind, self_contained_crt_objects);
|
||||
|
||||
// ------------ Late order-dependent options ------------
|
||||
|
||||
@ -2262,7 +2263,7 @@ fn add_order_independent_options(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &Session,
|
||||
link_output_kind: LinkOutputKind,
|
||||
self_contained: bool,
|
||||
self_contained_components: LinkSelfContainedComponents,
|
||||
flavor: LinkerFlavor,
|
||||
crate_type: CrateType,
|
||||
codegen_results: &CodegenResults,
|
||||
@ -2270,7 +2271,7 @@ fn add_order_independent_options(
|
||||
tmpdir: &Path,
|
||||
) {
|
||||
// Take care of the flavors and CLI options requesting the `lld` linker.
|
||||
add_lld_args(cmd, sess, flavor);
|
||||
add_lld_args(cmd, sess, flavor, self_contained_components);
|
||||
|
||||
add_apple_sdk(cmd, sess, flavor);
|
||||
|
||||
@ -2295,7 +2296,7 @@ fn add_order_independent_options(
|
||||
// Make the binary compatible with data execution prevention schemes.
|
||||
cmd.add_no_exec();
|
||||
|
||||
if self_contained {
|
||||
if self_contained_components.is_crt_objects_enabled() {
|
||||
cmd.no_crt_objects();
|
||||
}
|
||||
|
||||
@ -2326,7 +2327,7 @@ fn add_order_independent_options(
|
||||
|
||||
cmd.linker_plugin_lto();
|
||||
|
||||
add_library_search_dirs(cmd, sess, self_contained);
|
||||
add_library_search_dirs(cmd, sess, self_contained_components.are_any_components_enabled());
|
||||
|
||||
cmd.output_filename(out_filename);
|
||||
|
||||
@ -2976,8 +2977,16 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, errors::AppleSdkRootErro
|
||||
/// invoke it:
|
||||
/// - when the self-contained linker flag is active: the build of `lld` distributed with rustc,
|
||||
/// - or any `lld` available to `cc`.
|
||||
fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
|
||||
debug!("add_lld_args requested, flavor: '{flavor:?}'");
|
||||
fn add_lld_args(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &Session,
|
||||
flavor: LinkerFlavor,
|
||||
self_contained_components: LinkSelfContainedComponents,
|
||||
) {
|
||||
debug!(
|
||||
"add_lld_args requested, flavor: '{:?}', target self-contained components: {:?}",
|
||||
flavor, self_contained_components,
|
||||
);
|
||||
|
||||
// If the flavor doesn't use a C/C++ compiler to invoke the linker, or doesn't opt in to `lld`,
|
||||
// we don't need to do anything.
|
||||
@ -2986,9 +2995,32 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
|
||||
}
|
||||
|
||||
// 1. Implement the "self-contained" part of this feature by adding rustc distribution
|
||||
// directories to the tool's search path:
|
||||
// - if the self-contained linker is enabled on the CLI.
|
||||
if sess.opts.cg.link_self_contained.is_linker_enabled() {
|
||||
// directories to the tool's search path, depending on a mix between what users can specify on
|
||||
// the CLI, and what the target spec enables (as it can't disable components):
|
||||
// - if the self-contained linker is enabled on the CLI or by the target spec,
|
||||
// - and if the self-contained linker is not disabled on the CLI.
|
||||
let self_contained_cli = sess.opts.cg.link_self_contained.is_linker_enabled();
|
||||
let self_contained_target = self_contained_components.is_linker_enabled();
|
||||
|
||||
// FIXME: in the future, codegen backends may need to have more control over this process: they
|
||||
// don't always support all the features the linker expects here, and vice versa. For example,
|
||||
// at the time of writing this, lld expects a newer style of aarch64 TLS relocations that
|
||||
// cranelift doesn't implement yet. That in turn can impact whether linking would succeed on
|
||||
// such a target when using the `cg_clif` backend and lld.
|
||||
//
|
||||
// Until interactions between backends and linker features are expressible, we limit target
|
||||
// specs to opt-in to lld only when we're on the llvm backend, where it's expected to work and
|
||||
// tested on CI. As usual, the CLI still has precedence over this, so that users and developers
|
||||
// can still override this default when needed (e.g. for tests).
|
||||
let uses_llvm_backend =
|
||||
matches!(sess.opts.unstable_opts.codegen_backend.as_deref(), None | Some("llvm"));
|
||||
if !uses_llvm_backend && !self_contained_cli && sess.opts.cg.linker_flavor.is_none() {
|
||||
// We bail if we're not using llvm and lld was not explicitly requested on the CLI.
|
||||
return;
|
||||
}
|
||||
|
||||
let self_contained_linker = self_contained_cli || self_contained_target;
|
||||
if self_contained_linker && !sess.opts.cg.link_self_contained.is_linker_disabled() {
|
||||
for path in sess.get_tools_search_paths(false) {
|
||||
cmd.arg({
|
||||
let mut arg = OsString::from("-B");
|
||||
|
@ -228,6 +228,35 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
||||
if sess.target.is_like_osx {
|
||||
file.set_macho_build_version(macho_object_build_version_for_target(&sess.target))
|
||||
}
|
||||
if binary_format == BinaryFormat::Coff {
|
||||
// Disable the default mangler to avoid mangling the special "@feat.00" symbol name.
|
||||
let original_mangling = file.mangling();
|
||||
file.set_mangling(object::write::Mangling::None);
|
||||
|
||||
let mut feature = 0;
|
||||
|
||||
if file.architecture() == object::Architecture::I386 {
|
||||
// When linking with /SAFESEH on x86, lld requires that all linker inputs be marked as
|
||||
// safe exception handling compatible. Metadata files masquerade as regular COFF
|
||||
// objects and are treated as linker inputs, despite containing no actual code. Thus,
|
||||
// they still need to be marked as safe exception handling compatible. See #96498.
|
||||
// Reference: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
|
||||
feature |= 1;
|
||||
}
|
||||
|
||||
file.add_symbol(object::write::Symbol {
|
||||
name: "@feat.00".into(),
|
||||
value: feature,
|
||||
size: 0,
|
||||
kind: object::SymbolKind::Data,
|
||||
scope: object::SymbolScope::Compilation,
|
||||
weak: false,
|
||||
section: object::write::SymbolSection::Absolute,
|
||||
flags: object::SymbolFlags::None,
|
||||
});
|
||||
|
||||
file.set_mangling(original_mangling);
|
||||
}
|
||||
let e_flags = match architecture {
|
||||
Architecture::Mips => {
|
||||
let arch = match sess.target.options.cpu.as_ref() {
|
||||
|
@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
|
||||
use rustc_hir::{AsyncCoroutineKind, CoroutineKind, Mutability};
|
||||
use rustc_hir::{CoroutineKind, CoroutineSource, Mutability};
|
||||
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
|
||||
use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
|
||||
@ -560,9 +560,9 @@ pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: &
|
||||
|
||||
fn coroutine_kind_label(coroutine_kind: Option<CoroutineKind>) -> &'static str {
|
||||
match coroutine_kind {
|
||||
Some(CoroutineKind::Async(AsyncCoroutineKind::Block)) => "async_block",
|
||||
Some(CoroutineKind::Async(AsyncCoroutineKind::Closure)) => "async_closure",
|
||||
Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) => "async_fn",
|
||||
Some(CoroutineKind::Async(CoroutineSource::Block)) => "async_block",
|
||||
Some(CoroutineKind::Async(CoroutineSource::Closure)) => "async_closure",
|
||||
Some(CoroutineKind::Async(CoroutineSource::Fn)) => "async_fn",
|
||||
Some(CoroutineKind::Coroutine) => "coroutine",
|
||||
None => "closure",
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
|
||||
pub struct Coroutine(pub hir::CoroutineKind);
|
||||
impl<'tcx> NonConstOp<'tcx> for Coroutine {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
if let hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) = self.0 {
|
||||
if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 {
|
||||
Status::Unstable(sym::const_async_blocks)
|
||||
} else {
|
||||
Status::Forbidden
|
||||
@ -372,8 +372,8 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
|
||||
ccx: &ConstCx<'_, 'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let msg = format!("{}s are not allowed in {}s", self.0.descr(), ccx.const_kind());
|
||||
if let hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) = self.0 {
|
||||
let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind());
|
||||
if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 {
|
||||
ccx.tcx.sess.create_feature_err(
|
||||
errors::UnallowedOpInConstContext { span, msg },
|
||||
sym::const_async_blocks,
|
||||
|
@ -1,5 +1,6 @@
|
||||
driver_impl_ice = the compiler unexpectedly panicked. this is a bug.
|
||||
driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
|
||||
driver_impl_ice_bug_report_internal_feature = using internal features is not supported and expected to cause internal compiler errors when used incorrectly
|
||||
driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
|
||||
|
||||
driver_impl_ice_flags = compiler flags: {$flags}
|
||||
|
@ -60,7 +60,7 @@ use std::path::PathBuf;
|
||||
use std::process::{self, Command, Stdio};
|
||||
use std::str;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::OnceLock;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::time::{Instant, SystemTime};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
@ -136,7 +136,6 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
|
||||
rustc_query_system::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_resolve::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_session::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_symbol_mangling::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_trait_selection::DEFAULT_LOCALE_RESOURCE,
|
||||
rustc_ty_utils::DEFAULT_LOCALE_RESOURCE,
|
||||
// tidy-alphabetical-end
|
||||
@ -223,11 +222,18 @@ pub struct RunCompiler<'a, 'b> {
|
||||
file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
|
||||
make_codegen_backend:
|
||||
Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
|
||||
using_internal_features: Arc<std::sync::atomic::AtomicBool>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> RunCompiler<'a, 'b> {
|
||||
pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self {
|
||||
Self { at_args, callbacks, file_loader: None, make_codegen_backend: None }
|
||||
Self {
|
||||
at_args,
|
||||
callbacks,
|
||||
file_loader: None,
|
||||
make_codegen_backend: None,
|
||||
using_internal_features: Arc::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a custom codegen backend.
|
||||
@ -259,9 +265,23 @@ impl<'a, 'b> RunCompiler<'a, 'b> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the session-global flag that checks whether internal features have been used,
|
||||
/// suppressing the message about submitting an issue in ICEs when enabled.
|
||||
#[must_use]
|
||||
pub fn set_using_internal_features(mut self, using_internal_features: Arc<AtomicBool>) -> Self {
|
||||
self.using_internal_features = using_internal_features;
|
||||
self
|
||||
}
|
||||
|
||||
/// Parse args and run the compiler.
|
||||
pub fn run(self) -> interface::Result<()> {
|
||||
run_compiler(self.at_args, self.callbacks, self.file_loader, self.make_codegen_backend)
|
||||
run_compiler(
|
||||
self.at_args,
|
||||
self.callbacks,
|
||||
self.file_loader,
|
||||
self.make_codegen_backend,
|
||||
self.using_internal_features,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,6 +292,7 @@ fn run_compiler(
|
||||
make_codegen_backend: Option<
|
||||
Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
|
||||
>,
|
||||
using_internal_features: Arc<std::sync::atomic::AtomicBool>,
|
||||
) -> interface::Result<()> {
|
||||
let mut early_error_handler = EarlyErrorHandler::new(ErrorOutputType::default());
|
||||
|
||||
@ -316,6 +337,7 @@ fn run_compiler(
|
||||
override_queries: None,
|
||||
make_codegen_backend,
|
||||
registry: diagnostics_registry(),
|
||||
using_internal_features,
|
||||
expanded_args: args,
|
||||
};
|
||||
|
||||
@ -1333,8 +1355,12 @@ fn ice_path() -> &'static Option<PathBuf> {
|
||||
/// If you have no extra info to report, pass the empty closure `|_| ()` as the argument to
|
||||
/// extra_info.
|
||||
///
|
||||
/// Returns a flag that can be set to disable the note for submitting a bug. This can be passed to
|
||||
/// [`RunCompiler::set_using_internal_features`] to let macro expansion set it when encountering
|
||||
/// internal features.
|
||||
///
|
||||
/// A custom rustc driver can skip calling this to set up a custom ICE hook.
|
||||
pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) {
|
||||
pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) -> Arc<AtomicBool> {
|
||||
// If the user has not explicitly overridden "RUST_BACKTRACE", then produce
|
||||
// full backtraces. When a compiler ICE happens, we want to gather
|
||||
// as much information as possible to present in the issue opened
|
||||
@ -1345,6 +1371,8 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
|
||||
std::env::set_var("RUST_BACKTRACE", "full");
|
||||
}
|
||||
|
||||
let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default());
|
||||
let using_internal_features_hook = using_internal_features.clone();
|
||||
panic::update_hook(Box::new(
|
||||
move |default_hook: &(dyn Fn(&PanicInfo<'_>) + Send + Sync + 'static),
|
||||
info: &PanicInfo<'_>| {
|
||||
@ -1394,9 +1422,11 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
|
||||
}
|
||||
|
||||
// Print the ICE message
|
||||
report_ice(info, bug_report_url, extra_info);
|
||||
report_ice(info, bug_report_url, extra_info, &using_internal_features_hook);
|
||||
},
|
||||
));
|
||||
|
||||
using_internal_features
|
||||
}
|
||||
|
||||
/// Prints the ICE message, including query stack, but without backtrace.
|
||||
@ -1405,7 +1435,12 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
|
||||
///
|
||||
/// When `install_ice_hook` is called, this function will be called as the panic
|
||||
/// hook.
|
||||
fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(&Handler)) {
|
||||
fn report_ice(
|
||||
info: &panic::PanicInfo<'_>,
|
||||
bug_report_url: &str,
|
||||
extra_info: fn(&Handler),
|
||||
using_internal_features: &AtomicBool,
|
||||
) {
|
||||
let fallback_bundle =
|
||||
rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
|
||||
let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
|
||||
@ -1422,7 +1457,11 @@ fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(
|
||||
handler.emit_err(session_diagnostics::Ice);
|
||||
}
|
||||
|
||||
handler.emit_note(session_diagnostics::IceBugReport { bug_report_url });
|
||||
if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
handler.emit_note(session_diagnostics::IceBugReportInternalFeature);
|
||||
} else {
|
||||
handler.emit_note(session_diagnostics::IceBugReport { bug_report_url });
|
||||
}
|
||||
|
||||
let version = util::version_str!().unwrap_or("unknown_version");
|
||||
let triple = config::host_triple();
|
||||
@ -1506,7 +1545,7 @@ pub fn main() -> ! {
|
||||
init_rustc_env_logger(&handler);
|
||||
signal_handler::install();
|
||||
let mut callbacks = TimePassesCallbacks::default();
|
||||
install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
|
||||
let using_internal_features = install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
|
||||
let exit_code = catch_with_exit_code(|| {
|
||||
let args = env::args_os()
|
||||
.enumerate()
|
||||
@ -1516,7 +1555,9 @@ pub fn main() -> ! {
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
RunCompiler::new(&args, &mut callbacks).run()
|
||||
RunCompiler::new(&args, &mut callbacks)
|
||||
.set_using_internal_features(using_internal_features)
|
||||
.run()
|
||||
});
|
||||
|
||||
if let Some(format) = callbacks.time_passes {
|
||||
|
@ -42,6 +42,10 @@ pub(crate) struct IceBugReport<'a> {
|
||||
pub bug_report_url: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(driver_impl_ice_bug_report_internal_feature)]
|
||||
pub(crate) struct IceBugReportInternalFeature;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(driver_impl_ice_version)]
|
||||
pub(crate) struct IceVersion<'a> {
|
||||
|
@ -508,6 +508,8 @@ pub enum StashKey {
|
||||
TraitMissingMethod,
|
||||
OpaqueHiddenTypeMismatch,
|
||||
MaybeForgetReturn,
|
||||
/// Query cycle detected, stashing in favor of a better error.
|
||||
Cycle,
|
||||
}
|
||||
|
||||
fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
|
||||
|
@ -35,7 +35,7 @@ pub struct StripUnconfigured<'a> {
|
||||
pub lint_node_id: NodeId,
|
||||
}
|
||||
|
||||
pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
|
||||
pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -> Features {
|
||||
fn feature_list(attr: &Attribute) -> ThinVec<ast::NestedMetaItem> {
|
||||
if attr.has_name(sym::feature)
|
||||
&& let Some(list) = attr.meta_item_list()
|
||||
@ -167,6 +167,15 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features {
|
||||
// If the declared feature is unstable, record it.
|
||||
if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name) {
|
||||
(f.set_enabled)(&mut features);
|
||||
// When the ICE comes from core, alloc or std (approximation of the standard library), there's a chance
|
||||
// that the person hitting the ICE may be using -Zbuild-std or similar with an untested target.
|
||||
// The bug is probably in the standard library and not the compiler in that case, but that doesn't
|
||||
// really matter - we want a bug report.
|
||||
if features.internal(name)
|
||||
&& ![sym::core, sym::alloc, sym::std].contains(&crate_name)
|
||||
{
|
||||
sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
features.set_declared_lang_feature(name, mi.span(), None);
|
||||
continue;
|
||||
}
|
||||
|
@ -246,6 +246,8 @@ impl<'hir> PathSegment<'hir> {
|
||||
pub struct ConstArg {
|
||||
pub value: AnonConst,
|
||||
pub span: Span,
|
||||
/// Indicates whether this comes from a `~const` desugaring.
|
||||
pub is_desugared_from_effects: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
@ -400,7 +402,14 @@ impl<'hir> GenericArgs<'hir> {
|
||||
/// This function returns the number of type and const generic params.
|
||||
/// It should only be used for diagnostics.
|
||||
pub fn num_generic_params(&self) -> usize {
|
||||
self.args.iter().filter(|arg| !matches!(arg, GenericArg::Lifetime(_))).count()
|
||||
self.args
|
||||
.iter()
|
||||
.filter(|arg| match arg {
|
||||
GenericArg::Lifetime(_)
|
||||
| GenericArg::Const(ConstArg { is_desugared_from_effects: true, .. }) => false,
|
||||
_ => true,
|
||||
})
|
||||
.count()
|
||||
}
|
||||
|
||||
/// The span encompassing the text inside the surrounding brackets.
|
||||
@ -1511,7 +1520,7 @@ impl<'hir> Body<'hir> {
|
||||
#[derive(HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum CoroutineKind {
|
||||
/// An explicit `async` block or the body of an async function.
|
||||
Async(AsyncCoroutineKind),
|
||||
Async(CoroutineSource),
|
||||
|
||||
/// A coroutine literal created via a `yield` inside a closure.
|
||||
Coroutine,
|
||||
@ -1520,56 +1529,45 @@ pub enum CoroutineKind {
|
||||
impl fmt::Display for CoroutineKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
CoroutineKind::Async(k) => fmt::Display::fmt(k, f),
|
||||
CoroutineKind::Async(k) => {
|
||||
if f.alternate() {
|
||||
f.write_str("`async` ")?;
|
||||
} else {
|
||||
f.write_str("async ")?
|
||||
}
|
||||
k.fmt(f)
|
||||
}
|
||||
CoroutineKind::Coroutine => f.write_str("coroutine"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CoroutineKind {
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match self {
|
||||
CoroutineKind::Async(ask) => ask.descr(),
|
||||
CoroutineKind::Coroutine => "coroutine",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// In the case of a coroutine created as part of an async construct,
|
||||
/// which kind of async construct caused it to be created?
|
||||
/// In the case of a coroutine created as part of an async/gen construct,
|
||||
/// which kind of async/gen construct caused it to be created?
|
||||
///
|
||||
/// This helps error messages but is also used to drive coercions in
|
||||
/// type-checking (see #60424).
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
|
||||
#[derive(HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum AsyncCoroutineKind {
|
||||
/// An explicit `async` block written by the user.
|
||||
pub enum CoroutineSource {
|
||||
/// An explicit `async`/`gen` block written by the user.
|
||||
Block,
|
||||
|
||||
/// An explicit `async` closure written by the user.
|
||||
/// An explicit `async`/`gen` closure written by the user.
|
||||
Closure,
|
||||
|
||||
/// The `async` block generated as the body of an async function.
|
||||
/// The `async`/`gen` block generated as the body of an async/gen function.
|
||||
Fn,
|
||||
}
|
||||
|
||||
impl fmt::Display for AsyncCoroutineKind {
|
||||
impl fmt::Display for CoroutineSource {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
AsyncCoroutineKind::Block => "async block",
|
||||
AsyncCoroutineKind::Closure => "async closure body",
|
||||
AsyncCoroutineKind::Fn => "async fn body",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncCoroutineKind {
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match self {
|
||||
AsyncCoroutineKind::Block => "`async` block",
|
||||
AsyncCoroutineKind::Closure => "`async` closure body",
|
||||
AsyncCoroutineKind::Fn => "`async fn` body",
|
||||
CoroutineSource::Block => "block",
|
||||
CoroutineSource::Closure => "closure body",
|
||||
CoroutineSource::Fn => "fn body",
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3781,6 +3779,7 @@ impl<'hir> Node<'hir> {
|
||||
ItemKind::TyAlias(ty, _)
|
||||
| ItemKind::Static(ty, _, _)
|
||||
| ItemKind::Const(ty, _, _) => Some(ty),
|
||||
ItemKind::Impl(impl_item) => Some(&impl_item.self_ty),
|
||||
_ => None,
|
||||
},
|
||||
Node::TraitItem(it) => match it.kind {
|
||||
|
@ -210,6 +210,7 @@ language_item_table! {
|
||||
|
||||
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
|
||||
|
||||
Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
CoroutineState, sym::coroutine_state, gen_state, Target::Enum, GenericRequirement::None;
|
||||
Coroutine, sym::coroutine, gen_trait, Target::Trait, GenericRequirement::Minimum(1);
|
||||
|
@ -429,6 +429,14 @@ pub(crate) fn check_generic_arg_count(
|
||||
.filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. }))
|
||||
.count();
|
||||
let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count;
|
||||
let synth_const_param_count = gen_params
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| {
|
||||
matches!(param.kind, ty::GenericParamDefKind::Const { is_host_effect: true, .. })
|
||||
})
|
||||
.count();
|
||||
let named_const_param_count = param_counts.consts - synth_const_param_count;
|
||||
let infer_lifetimes =
|
||||
(gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
|
||||
|
||||
@ -573,11 +581,13 @@ pub(crate) fn check_generic_arg_count(
|
||||
debug!(?expected_min);
|
||||
debug!(arg_counts.lifetimes=?gen_args.num_lifetime_params());
|
||||
|
||||
let provided = gen_args.num_generic_params();
|
||||
|
||||
check_types_and_consts(
|
||||
expected_min,
|
||||
param_counts.consts + named_type_param_count,
|
||||
param_counts.consts + named_type_param_count + synth_type_param_count,
|
||||
gen_args.num_generic_params(),
|
||||
named_const_param_count + named_type_param_count,
|
||||
named_const_param_count + named_type_param_count + synth_type_param_count,
|
||||
provided,
|
||||
param_counts.lifetimes + has_self as usize,
|
||||
gen_args.num_lifetime_params(),
|
||||
)
|
||||
|
@ -128,7 +128,11 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
|
||||
|
||||
let param_env = tcx.param_env(item_def_id);
|
||||
for field in &def.non_enum_variant().fields {
|
||||
let field_ty = tcx.normalize_erasing_regions(param_env, field.ty(tcx, args));
|
||||
let Ok(field_ty) = tcx.try_normalize_erasing_regions(param_env, field.ty(tcx, args))
|
||||
else {
|
||||
tcx.sess.delay_span_bug(span, "could not normalize field type");
|
||||
continue;
|
||||
};
|
||||
|
||||
if !allowed_union_field(field_ty, tcx, param_env) {
|
||||
let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
|
||||
|
@ -181,14 +181,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
|
||||
})?;
|
||||
}
|
||||
|
||||
tcx.sess.track_errors(|| {
|
||||
tcx.sess.time("impl_wf_inference", || {
|
||||
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module))
|
||||
});
|
||||
})?;
|
||||
|
||||
tcx.sess.track_errors(|| {
|
||||
tcx.sess.time("coherence_checking", || {
|
||||
// Check impls constrain their parameters
|
||||
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module));
|
||||
|
||||
for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
|
||||
tcx.ensure().coherent_trait(trait_def_id);
|
||||
}
|
||||
@ -205,15 +202,19 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
|
||||
})?;
|
||||
}
|
||||
|
||||
tcx.sess.time("wf_checking", || {
|
||||
let errs = tcx.sess.time("wf_checking", || {
|
||||
tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module))
|
||||
})?;
|
||||
});
|
||||
|
||||
// NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.
|
||||
tcx.sess.time("item_types_checking", || {
|
||||
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
|
||||
});
|
||||
|
||||
// HACK: `check_mod_type_wf` may spuriously emit errors due to `delay_span_bug`, even if those errors
|
||||
// only actually get emitted in `check_mod_item_types`.
|
||||
errs?;
|
||||
|
||||
if tcx.features().rustc_attrs {
|
||||
tcx.sess.track_errors(|| collect::test_opaque_hidden_types(tcx))?;
|
||||
}
|
||||
|
@ -129,6 +129,44 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
||||
if self.missing_lifetimes() { "lifetime" } else { "generic" }
|
||||
}
|
||||
|
||||
/// Returns true if the generic type is a trait
|
||||
/// and is being referred to from one of its trait impls
|
||||
fn is_in_trait_impl(&self) -> bool {
|
||||
if self.tcx.is_trait(self.def_id) {
|
||||
// Here we check if the reference to the generic type
|
||||
// is from the 'of_trait' field of the enclosing impl
|
||||
|
||||
let parent = self.tcx.hir().get_parent(self.path_segment.hir_id);
|
||||
let parent_item = self
|
||||
.tcx
|
||||
.hir()
|
||||
.get_by_def_id(self.tcx.hir().get_parent_item(self.path_segment.hir_id).def_id);
|
||||
|
||||
// Get the HIR id of the trait ref
|
||||
let hir::Node::TraitRef(hir::TraitRef { hir_ref_id: trait_ref_id, .. }) = parent else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Get the HIR id of the 'of_trait' field of the impl
|
||||
let hir::Node::Item(hir::Item {
|
||||
kind:
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }),
|
||||
..
|
||||
}),
|
||||
..
|
||||
}) = parent_item
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Check that trait is referred to from the of_trait field of impl
|
||||
trait_ref_id == id_in_of_trait
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn num_provided_args(&self) -> usize {
|
||||
if self.missing_lifetimes() {
|
||||
self.num_provided_lifetime_args()
|
||||
@ -955,20 +993,26 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
||||
// If there is a single unbound associated type and a single excess generic param
|
||||
// suggest replacing the generic param with the associated type bound
|
||||
if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
|
||||
let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
|
||||
let suggestions = iter::zip(unused_generics, &unbound_types)
|
||||
.map(|(potential, name)| (potential.span().shrink_to_lo(), format!("{name} = ")))
|
||||
.collect::<Vec<_>>();
|
||||
// Don't suggest if we're in a trait impl as
|
||||
// that would result in invalid syntax (fixes #116464)
|
||||
if !self.is_in_trait_impl() {
|
||||
let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
|
||||
let suggestions = iter::zip(unused_generics, &unbound_types)
|
||||
.map(|(potential, name)| {
|
||||
(potential.span().shrink_to_lo(), format!("{name} = "))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !suggestions.is_empty() {
|
||||
err.multipart_suggestion_verbose(
|
||||
format!(
|
||||
"replace the generic bound{s} with the associated type{s}",
|
||||
s = pluralize!(unbound_types.len())
|
||||
),
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
if !suggestions.is_empty() {
|
||||
err.multipart_suggestion_verbose(
|
||||
format!(
|
||||
"replace the generic bound{s} with the associated type{s}",
|
||||
s = pluralize!(unbound_types.len())
|
||||
),
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if remove_entire_generics {
|
||||
let span = self
|
||||
|
@ -305,7 +305,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
) = (parent_node, callee_node)
|
||||
{
|
||||
let fn_decl_span = if hir.body(body).coroutine_kind
|
||||
== Some(hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Closure))
|
||||
== Some(hir::CoroutineKind::Async(hir::CoroutineSource::Closure))
|
||||
{
|
||||
// Actually need to unwrap one more layer of HIR to get to
|
||||
// the _real_ closure...
|
||||
|
@ -660,9 +660,21 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||
} else {
|
||||
match self.try_coercion_cast(fcx) {
|
||||
Ok(()) => {
|
||||
self.trivial_cast_lint(fcx);
|
||||
debug!(" -> CoercionCast");
|
||||
fcx.typeck_results.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id);
|
||||
if self.expr_ty.is_unsafe_ptr() && self.cast_ty.is_unsafe_ptr() {
|
||||
// When casting a raw pointer to another raw pointer, we cannot convert the cast into
|
||||
// a coercion because the pointee types might only differ in regions, which HIR typeck
|
||||
// cannot distinguish. This would cause us to erroneously discard a cast which will
|
||||
// lead to a borrowck error like #113257.
|
||||
// We still did a coercion above to unify inference variables for `ptr as _` casts.
|
||||
// This does cause us to miss some trivial casts in the trival cast lint.
|
||||
debug!(" -> PointerCast");
|
||||
} else {
|
||||
self.trivial_cast_lint(fcx);
|
||||
debug!(" -> CoercionCast");
|
||||
fcx.typeck_results
|
||||
.borrow_mut()
|
||||
.set_coercion_cast(self.expr.hir_id.local_id);
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
match self.do_check(fcx) {
|
||||
|
@ -636,7 +636,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// In the case of the async block that we create for a function body,
|
||||
// we expect the return type of the block to match that of the enclosing
|
||||
// function.
|
||||
Some(hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Fn)) => {
|
||||
Some(hir::CoroutineKind::Async(hir::CoroutineSource::Fn)) => {
|
||||
debug!("closure is async fn body");
|
||||
let def_id = self.tcx.hir().body_owner_def_id(body.id());
|
||||
self.deduce_future_output_from_obligations(expr_def_id, def_id).unwrap_or_else(
|
||||
|
@ -962,38 +962,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
expected: Ty<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
) -> bool {
|
||||
let ty::Adt(e, args_e) = expected.kind() else {
|
||||
return false;
|
||||
};
|
||||
let ty::Adt(f, args_f) = found.kind() else {
|
||||
return false;
|
||||
};
|
||||
if e.did() != f.did() {
|
||||
return false;
|
||||
}
|
||||
if Some(e.did()) != self.tcx.get_diagnostic_item(sym::Result) {
|
||||
return false;
|
||||
}
|
||||
let map = self.tcx.hir();
|
||||
if let Some(hir::Node::Expr(expr)) = map.find_parent(expr.hir_id)
|
||||
&& let hir::ExprKind::Ret(_) = expr.kind
|
||||
{
|
||||
// `return foo;`
|
||||
} else if map.get_return_block(expr.hir_id).is_some() {
|
||||
// Function's tail expression.
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
let e = args_e.type_at(1);
|
||||
let f = args_f.type_at(1);
|
||||
if self
|
||||
.infcx
|
||||
.type_implements_trait(
|
||||
self.tcx.get_diagnostic_item(sym::Into).unwrap(),
|
||||
[f, e],
|
||||
self.param_env,
|
||||
)
|
||||
.must_apply_modulo_regions()
|
||||
let returned = matches!(
|
||||
map.find_parent(expr.hir_id),
|
||||
Some(hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. }))
|
||||
) || map.get_return_block(expr.hir_id).is_some();
|
||||
if returned
|
||||
&& let ty::Adt(e, args_e) = expected.kind()
|
||||
&& let ty::Adt(f, args_f) = found.kind()
|
||||
&& e.did() == f.did()
|
||||
&& Some(e.did()) == self.tcx.get_diagnostic_item(sym::Result)
|
||||
&& let e_ok = args_e.type_at(0)
|
||||
&& let f_ok = args_f.type_at(0)
|
||||
&& self.infcx.can_eq(self.param_env, f_ok, e_ok)
|
||||
&& let e_err = args_e.type_at(1)
|
||||
&& let f_err = args_f.type_at(1)
|
||||
&& self
|
||||
.infcx
|
||||
.type_implements_trait(
|
||||
self.tcx.get_diagnostic_item(sym::Into).unwrap(),
|
||||
[f_err, e_err],
|
||||
self.param_env,
|
||||
)
|
||||
.must_apply_modulo_regions()
|
||||
{
|
||||
err.multipart_suggestion(
|
||||
"use `?` to coerce and return an appropriate `Err`, and wrap the resulting value \
|
||||
|
@ -26,7 +26,7 @@ use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtKind, CanonicalUserType, GenericParamDefKind, Ty, TyCtxt, UserType,
|
||||
self, AdtKind, CanonicalUserType, GenericParamDefKind, IsIdentity, Ty, TyCtxt, UserType,
|
||||
};
|
||||
use rustc_middle::ty::{GenericArgKind, GenericArgsRef, UserArgs, UserSelfTy};
|
||||
use rustc_session::lint;
|
||||
@ -207,6 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
) {
|
||||
debug!("fcx {}", self.tag());
|
||||
|
||||
// FIXME: is_identity being on `UserType` and not `Canonical<UserType>` is awkward
|
||||
if !canonical_user_type_annotation.is_identity() {
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
|
@ -10,8 +10,8 @@ use rustc_hir::def::Res;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{
|
||||
AsyncCoroutineKind, CoroutineKind, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath,
|
||||
Stmt, StmtKind, TyKind, WherePredicate,
|
||||
CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath, Stmt,
|
||||
StmtKind, TyKind, WherePredicate,
|
||||
};
|
||||
use rustc_hir_analysis::astconv::AstConv;
|
||||
use rustc_infer::traits::{self, StatementAsExpression};
|
||||
@ -536,7 +536,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty::Coroutine(def_id, ..)
|
||||
if matches!(
|
||||
self.tcx.coroutine_kind(def_id),
|
||||
Some(CoroutineKind::Async(AsyncCoroutineKind::Closure))
|
||||
Some(CoroutineKind::Async(CoroutineSource::Closure))
|
||||
) =>
|
||||
{
|
||||
errors::SuggestBoxing::AsyncBody
|
||||
@ -1747,19 +1747,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
expected: Ty<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
) -> bool {
|
||||
let ty::Adt(adt, args) = found.kind() else { return false };
|
||||
let ty::Adt(adt, args) = found.kind() else {
|
||||
return false;
|
||||
};
|
||||
let ret_ty_matches = |diagnostic_item| {
|
||||
if let Some(ret_ty) = self
|
||||
.ret_coercion
|
||||
.as_ref()
|
||||
.map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
|
||||
&& let ty::Adt(kind, _) = ret_ty.kind()
|
||||
&& self.tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
let Some(sig) = self.body_fn_sig() else {
|
||||
return false;
|
||||
};
|
||||
let ty::Adt(kind, _) = sig.output().kind() else {
|
||||
return false;
|
||||
};
|
||||
self.tcx.is_diagnostic_item(diagnostic_item, kind.did())
|
||||
};
|
||||
|
||||
// don't suggest anything like `Ok(ok_val).unwrap()` , `Some(some_val).unwrap()`,
|
||||
|
@ -5,7 +5,6 @@
|
||||
#![cfg_attr(not(bootstrap), doc(rust_logo))]
|
||||
#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![feature(never_type)]
|
||||
#![recursion_limit = "256"]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
@ -19,15 +18,11 @@ mod assert_dep_graph;
|
||||
mod errors;
|
||||
mod persist;
|
||||
|
||||
use assert_dep_graph::assert_dep_graph;
|
||||
pub use persist::copy_cgu_workproduct_to_incr_comp_cache_dir;
|
||||
pub use persist::delete_workproduct_files;
|
||||
pub use persist::finalize_session_directory;
|
||||
pub use persist::garbage_collect_session_directories;
|
||||
pub use persist::in_incr_comp_dir;
|
||||
pub use persist::in_incr_comp_dir_sess;
|
||||
pub use persist::load_query_result_cache;
|
||||
pub use persist::prepare_session_directory;
|
||||
pub use persist::save_dep_graph;
|
||||
pub use persist::save_work_product_index;
|
||||
pub use persist::setup_dep_graph;
|
||||
|
@ -53,7 +53,7 @@
|
||||
//! ## Synchronization
|
||||
//!
|
||||
//! There is some synchronization needed in order for the compiler to be able to
|
||||
//! determine whether a given private session directory is not in used any more.
|
||||
//! determine whether a given private session directory is not in use any more.
|
||||
//! This is done by creating a lock file for each session directory and
|
||||
//! locking it while the directory is still being used. Since file locks have
|
||||
//! operating system support, we can rely on the lock being released if the
|
||||
@ -136,26 +136,29 @@ const QUERY_CACHE_FILENAME: &str = "query-cache.bin";
|
||||
const INT_ENCODE_BASE: usize = base_n::CASE_INSENSITIVE;
|
||||
|
||||
/// Returns the path to a session's dependency graph.
|
||||
pub fn dep_graph_path(sess: &Session) -> PathBuf {
|
||||
pub(crate) fn dep_graph_path(sess: &Session) -> PathBuf {
|
||||
in_incr_comp_dir_sess(sess, DEP_GRAPH_FILENAME)
|
||||
}
|
||||
|
||||
/// Returns the path to a session's staging dependency graph.
|
||||
///
|
||||
/// On the difference between dep-graph and staging dep-graph,
|
||||
/// see `build_dep_graph`.
|
||||
pub fn staging_dep_graph_path(sess: &Session) -> PathBuf {
|
||||
pub(crate) fn staging_dep_graph_path(sess: &Session) -> PathBuf {
|
||||
in_incr_comp_dir_sess(sess, STAGING_DEP_GRAPH_FILENAME)
|
||||
}
|
||||
pub fn work_products_path(sess: &Session) -> PathBuf {
|
||||
|
||||
pub(crate) fn work_products_path(sess: &Session) -> PathBuf {
|
||||
in_incr_comp_dir_sess(sess, WORK_PRODUCTS_FILENAME)
|
||||
}
|
||||
|
||||
/// Returns the path to a session's query cache.
|
||||
pub fn query_cache_path(sess: &Session) -> PathBuf {
|
||||
in_incr_comp_dir_sess(sess, QUERY_CACHE_FILENAME)
|
||||
}
|
||||
|
||||
/// Locks a given session directory.
|
||||
pub fn lock_file_path(session_dir: &Path) -> PathBuf {
|
||||
fn lock_file_path(session_dir: &Path) -> PathBuf {
|
||||
let crate_dir = session_dir.parent().unwrap();
|
||||
|
||||
let directory_name = session_dir.file_name().unwrap().to_string_lossy();
|
||||
@ -202,7 +205,7 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu
|
||||
/// The garbage collection will take care of it.
|
||||
///
|
||||
/// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph
|
||||
pub fn prepare_session_directory(
|
||||
pub(crate) fn prepare_session_directory(
|
||||
sess: &Session,
|
||||
crate_name: Symbol,
|
||||
stable_crate_id: StableCrateId,
|
||||
@ -373,7 +376,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option<Svh>) {
|
||||
let _ = garbage_collect_session_directories(sess);
|
||||
}
|
||||
|
||||
pub fn delete_all_session_dir_contents(sess: &Session) -> io::Result<()> {
|
||||
pub(crate) fn delete_all_session_dir_contents(sess: &Session) -> io::Result<()> {
|
||||
let sess_dir_iterator = sess.incr_comp_session_dir().read_dir()?;
|
||||
for entry in sess_dir_iterator {
|
||||
let entry = entry?;
|
||||
@ -621,7 +624,7 @@ fn is_old_enough_to_be_collected(timestamp: SystemTime) -> bool {
|
||||
}
|
||||
|
||||
/// Runs garbage collection for the current session.
|
||||
pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
|
||||
pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
|
||||
debug!("garbage_collect_session_directories() - begin");
|
||||
|
||||
let session_directory = sess.incr_comp_session_dir();
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Code to save/load the dep-graph from files.
|
||||
//! Code to load the dep-graph from files.
|
||||
|
||||
use crate::errors;
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
|
@ -11,14 +11,11 @@ mod save;
|
||||
mod work_product;
|
||||
|
||||
pub use fs::finalize_session_directory;
|
||||
pub use fs::garbage_collect_session_directories;
|
||||
pub use fs::in_incr_comp_dir;
|
||||
pub use fs::in_incr_comp_dir_sess;
|
||||
pub use fs::prepare_session_directory;
|
||||
pub use load::load_query_result_cache;
|
||||
pub use load::setup_dep_graph;
|
||||
pub use load::LoadResult;
|
||||
pub use save::save_dep_graph;
|
||||
pub use save::save_work_product_index;
|
||||
pub use work_product::copy_cgu_workproduct_to_incr_comp_cache_dir;
|
||||
pub use work_product::delete_workproduct_files;
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::assert_dep_graph::assert_dep_graph;
|
||||
use crate::errors;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::sync::join;
|
||||
@ -39,7 +40,7 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
|
||||
let dep_graph_path = dep_graph_path(sess);
|
||||
let staging_dep_graph_path = staging_dep_graph_path(sess);
|
||||
|
||||
sess.time("assert_dep_graph", || crate::assert_dep_graph(tcx));
|
||||
sess.time("assert_dep_graph", || assert_dep_graph(tcx));
|
||||
sess.time("check_dirty_clean", || dirty_clean::check_dirty_clean_annotations(tcx));
|
||||
|
||||
if sess.opts.unstable_opts.incremental_info {
|
||||
|
@ -11,7 +11,8 @@ use rustc_session::Session;
|
||||
use std::fs as std_fs;
|
||||
use std::path::Path;
|
||||
|
||||
/// Copies a CGU work product to the incremental compilation directory, so next compilation can find and reuse it.
|
||||
/// Copies a CGU work product to the incremental compilation directory, so next compilation can
|
||||
/// find and reuse it.
|
||||
pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
|
||||
sess: &Session,
|
||||
cgu_name: &str,
|
||||
@ -45,7 +46,7 @@ pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
|
||||
}
|
||||
|
||||
/// Removes files for a given work product.
|
||||
pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
|
||||
pub(crate) fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
|
||||
for (_, path) in work_product.saved_files.items().into_sorted_stable_ord() {
|
||||
let path = in_incr_comp_dir_sess(sess, path);
|
||||
if let Err(err) = std_fs::remove_file(&path) {
|
||||
|
@ -1584,14 +1584,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
target: &str,
|
||||
types: &FxIndexMap<TyCategory, FxIndexSet<Span>>,
|
||||
) {
|
||||
for (key, values) in types.iter() {
|
||||
for (kind, values) in types.iter() {
|
||||
let count = values.len();
|
||||
let kind = key.descr();
|
||||
for &sp in values {
|
||||
err.span_label(
|
||||
sp,
|
||||
format!(
|
||||
"{}{} {}{}",
|
||||
"{}{} {:#}{}",
|
||||
if count == 1 { "the " } else { "one of the " },
|
||||
target,
|
||||
kind,
|
||||
@ -2952,17 +2951,19 @@ pub enum TyCategory {
|
||||
Foreign,
|
||||
}
|
||||
|
||||
impl TyCategory {
|
||||
fn descr(&self) -> &'static str {
|
||||
impl fmt::Display for TyCategory {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Closure => "closure",
|
||||
Self::Opaque => "opaque type",
|
||||
Self::OpaqueFuture => "future",
|
||||
Self::Coroutine(gk) => gk.descr(),
|
||||
Self::Foreign => "foreign type",
|
||||
Self::Closure => "closure".fmt(f),
|
||||
Self::Opaque => "opaque type".fmt(f),
|
||||
Self::OpaqueFuture => "future".fmt(f),
|
||||
Self::Coroutine(gk) => gk.fmt(f),
|
||||
Self::Foreign => "foreign type".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TyCategory {
|
||||
pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
|
||||
match *ty.kind() {
|
||||
ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
|
||||
|
@ -54,13 +54,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
}
|
||||
(ty::Param(expected), ty::Param(found)) => {
|
||||
let generics = tcx.generics_of(body_owner_def_id);
|
||||
let e_span = tcx.def_span(generics.type_param(expected, tcx).def_id);
|
||||
if !sp.contains(e_span) {
|
||||
diag.span_label(e_span, "expected type parameter");
|
||||
if let Some(param) = generics.opt_type_param(expected, tcx) {
|
||||
let e_span = tcx.def_span(param.def_id);
|
||||
if !sp.contains(e_span) {
|
||||
diag.span_label(e_span, "expected type parameter");
|
||||
}
|
||||
}
|
||||
let f_span = tcx.def_span(generics.type_param(found, tcx).def_id);
|
||||
if !sp.contains(f_span) {
|
||||
diag.span_label(f_span, "found type parameter");
|
||||
if let Some(param) = generics.opt_type_param(found, tcx) {
|
||||
let f_span = tcx.def_span(param.def_id);
|
||||
if !sp.contains(f_span) {
|
||||
diag.span_label(f_span, "found type parameter");
|
||||
}
|
||||
}
|
||||
diag.note(
|
||||
"a type parameter was expected, but a different one was found; \
|
||||
@ -83,23 +87,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
| (ty::Alias(ty::Projection, proj), ty::Param(p))
|
||||
if !tcx.is_impl_trait_in_trait(proj.def_id) =>
|
||||
{
|
||||
let p_def_id = tcx.generics_of(body_owner_def_id).type_param(p, tcx).def_id;
|
||||
let p_span = tcx.def_span(p_def_id);
|
||||
let expected = match (values.expected.kind(), values.found.kind()) {
|
||||
(ty::Param(_), _) => "expected ",
|
||||
(_, ty::Param(_)) => "found ",
|
||||
_ => "",
|
||||
};
|
||||
if !sp.contains(p_span) {
|
||||
diag.span_label(p_span, format!("{expected}this type parameter"));
|
||||
}
|
||||
let hir = tcx.hir();
|
||||
let parent = tcx.generics_of(body_owner_def_id)
|
||||
.opt_type_param(p, tcx)
|
||||
.and_then(|param| {
|
||||
let p_def_id = param.def_id;
|
||||
let p_span = tcx.def_span(p_def_id);
|
||||
let expected = match (values.expected.kind(), values.found.kind()) {
|
||||
(ty::Param(_), _) => "expected ",
|
||||
(_, ty::Param(_)) => "found ",
|
||||
_ => "",
|
||||
};
|
||||
if !sp.contains(p_span) {
|
||||
diag.span_label(
|
||||
p_span,
|
||||
format!("{expected}this type parameter"),
|
||||
);
|
||||
}
|
||||
p_def_id.as_local().and_then(|id| {
|
||||
let local_id = tcx.hir().local_def_id_to_hir_id(id);
|
||||
let generics = tcx.hir().find_parent(local_id)?.generics()?;
|
||||
Some((id, generics))
|
||||
})
|
||||
});
|
||||
let mut note = true;
|
||||
let parent = p_def_id.as_local().and_then(|id| {
|
||||
let local_id = hir.local_def_id_to_hir_id(id);
|
||||
let generics = tcx.hir().find_parent(local_id)?.generics()?;
|
||||
Some((id, generics))
|
||||
});
|
||||
if let Some((local_id, generics)) = parent {
|
||||
// Synthesize the associated type restriction `Add<Output = Expected>`.
|
||||
// FIXME: extract this logic for use in other diagnostics.
|
||||
@ -172,14 +182,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
(ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..))
|
||||
| (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => {
|
||||
let generics = tcx.generics_of(body_owner_def_id);
|
||||
let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
|
||||
let expected = match (values.expected.kind(), values.found.kind()) {
|
||||
(ty::Param(_), _) => "expected ",
|
||||
(_, ty::Param(_)) => "found ",
|
||||
_ => "",
|
||||
};
|
||||
if !sp.contains(p_span) {
|
||||
diag.span_label(p_span, format!("{expected}this type parameter"));
|
||||
if let Some(param) = generics.opt_type_param(p, tcx) {
|
||||
let p_span = tcx.def_span(param.def_id);
|
||||
let expected = match (values.expected.kind(), values.found.kind()) {
|
||||
(ty::Param(_), _) => "expected ",
|
||||
(_, ty::Param(_)) => "found ",
|
||||
_ => "",
|
||||
};
|
||||
if !sp.contains(p_span) {
|
||||
diag.span_label(p_span, format!("{expected}this type parameter"));
|
||||
}
|
||||
}
|
||||
diag.help("type parameters must be constrained to match other types");
|
||||
if tcx.sess.teach(&diag.get_code().unwrap()) {
|
||||
@ -217,9 +229,11 @@ impl<T> Trait<T> for X {
|
||||
}
|
||||
(ty::Param(p), ty::Closure(..) | ty::Coroutine(..)) => {
|
||||
let generics = tcx.generics_of(body_owner_def_id);
|
||||
let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
|
||||
if !sp.contains(p_span) {
|
||||
diag.span_label(p_span, "expected this type parameter");
|
||||
if let Some(param) = generics.opt_type_param(p, tcx) {
|
||||
let p_span = tcx.def_span(param.def_id);
|
||||
if !sp.contains(p_span) {
|
||||
diag.span_label(p_span, "expected this type parameter");
|
||||
}
|
||||
}
|
||||
diag.help(format!(
|
||||
"every closure has a distinct type and so could not always match the \
|
||||
@ -228,14 +242,16 @@ impl<T> Trait<T> for X {
|
||||
}
|
||||
(ty::Param(p), _) | (_, ty::Param(p)) => {
|
||||
let generics = tcx.generics_of(body_owner_def_id);
|
||||
let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
|
||||
let expected = match (values.expected.kind(), values.found.kind()) {
|
||||
(ty::Param(_), _) => "expected ",
|
||||
(_, ty::Param(_)) => "found ",
|
||||
_ => "",
|
||||
};
|
||||
if !sp.contains(p_span) {
|
||||
diag.span_label(p_span, format!("{expected}this type parameter"));
|
||||
if let Some(param) = generics.opt_type_param(p, tcx) {
|
||||
let p_span = tcx.def_span(param.def_id);
|
||||
let expected = match (values.expected.kind(), values.found.kind()) {
|
||||
(ty::Param(_), _) => "expected ",
|
||||
(_, ty::Param(_)) => "found ",
|
||||
_ => "",
|
||||
};
|
||||
if !sp.contains(p_span) {
|
||||
diag.span_label(p_span, format!("{expected}this type parameter"));
|
||||
}
|
||||
}
|
||||
}
|
||||
(ty::Alias(ty::Projection | ty::Inherent, proj_ty), _)
|
||||
@ -364,13 +380,14 @@ impl<T> Trait<T> for X {
|
||||
};
|
||||
// Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
|
||||
// This will also work for `impl Trait`.
|
||||
let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() {
|
||||
let generics = tcx.generics_of(body_owner_def_id);
|
||||
generics.type_param(param_ty, tcx).def_id
|
||||
} else {
|
||||
let ty::Param(param_ty) = proj_ty.self_ty().kind() else {
|
||||
return false;
|
||||
};
|
||||
let Some(def_id) = def_id.as_local() else {
|
||||
let generics = tcx.generics_of(body_owner_def_id);
|
||||
let Some(param) = generics.opt_type_param(param_ty, tcx) else {
|
||||
return false;
|
||||
};
|
||||
let Some(def_id) = param.def_id.as_local() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
@ -390,6 +407,10 @@ impl<T> Trait<T> for X {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (param_ty.index as usize) >= generics.parent_count {
|
||||
// The param comes from the current item, do not look at the parent. (#117209)
|
||||
return false;
|
||||
}
|
||||
// If associated item, look to constrain the params of the trait/impl.
|
||||
let hir_id = match item {
|
||||
hir::Node::ImplItem(item) => item.hir_id(),
|
||||
|
@ -24,6 +24,7 @@ use rustc_span::source_map::{FileLoader, FileName};
|
||||
use rustc_span::symbol::sym;
|
||||
use std::path::PathBuf;
|
||||
use std::result;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub type Result<T> = result::Result<T, ErrorGuaranteed>;
|
||||
|
||||
@ -410,6 +411,12 @@ pub struct Config {
|
||||
/// Registry of diagnostics codes.
|
||||
pub registry: Registry,
|
||||
|
||||
/// The inner atomic value is set to true when a feature marked as `internal` is
|
||||
/// enabled. Makes it so that "please report a bug" is hidden, as ICEs with
|
||||
/// internal features are wontfix, and they are usually the cause of the ICEs.
|
||||
/// None signifies that this is not tracked.
|
||||
pub using_internal_features: Arc<std::sync::atomic::AtomicBool>,
|
||||
|
||||
/// All commandline args used to invoke the compiler, with @file args fully expanded.
|
||||
/// This will only be used within debug info, e.g. in the pdb file on windows
|
||||
/// This is mainly useful for other tools that reads that debuginfo to figure out
|
||||
@ -453,6 +460,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
|
||||
config.make_codegen_backend,
|
||||
registry.clone(),
|
||||
config.ice_file,
|
||||
config.using_internal_features,
|
||||
config.expanded_args,
|
||||
);
|
||||
|
||||
|
@ -856,6 +856,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
|
||||
// This check has to be run after all lints are done processing. We don't
|
||||
// define a lint filter, as all lint checks should have finished at this point.
|
||||
sess.time("check_lint_expectations", || tcx.ensure().check_expectations(None));
|
||||
|
||||
// This query is only invoked normally if a diagnostic is emitted that needs any
|
||||
// diagnostic item. If the crate compiles without checking any diagnostic items,
|
||||
// we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally.
|
||||
let _ = tcx.all_diagnostic_items(());
|
||||
});
|
||||
|
||||
if sess.opts.unstable_opts.print_vtable_sizes {
|
||||
|
@ -181,9 +181,11 @@ impl<'tcx> Queries<'tcx> {
|
||||
feed.crate_name(crate_name);
|
||||
|
||||
let feed = tcx.feed_unit_query();
|
||||
feed.features_query(
|
||||
tcx.arena.alloc(rustc_expand::config::features(sess, &pre_configured_attrs)),
|
||||
);
|
||||
feed.features_query(tcx.arena.alloc(rustc_expand::config::features(
|
||||
sess,
|
||||
&pre_configured_attrs,
|
||||
crate_name,
|
||||
)));
|
||||
feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs))));
|
||||
});
|
||||
Ok(qcx)
|
||||
|
@ -35,6 +35,7 @@ use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtecto
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::num::NonZeroUsize;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
type CfgSpecs = FxHashSet<(String, Option<String>)>;
|
||||
|
||||
@ -69,6 +70,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se
|
||||
None,
|
||||
"",
|
||||
None,
|
||||
Arc::default(),
|
||||
Default::default(),
|
||||
);
|
||||
(sess, cfg)
|
||||
@ -612,7 +614,7 @@ fn test_codegen_options_tracking_hash() {
|
||||
tracked!(force_frame_pointers, Some(false));
|
||||
tracked!(force_unwind_tables, Some(true));
|
||||
tracked!(inline_threshold, Some(0xf007ba11));
|
||||
tracked!(instrument_coverage, Some(InstrumentCoverage::All));
|
||||
tracked!(instrument_coverage, InstrumentCoverage::All);
|
||||
tracked!(link_dead_code, Some(true));
|
||||
tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
|
||||
tracked!(llvm_args, vec![String::from("1"), String::from("2")]);
|
||||
@ -789,7 +791,6 @@ fn test_unstable_options_tracking_hash() {
|
||||
tracked!(inline_mir, Some(true));
|
||||
tracked!(inline_mir_hint_threshold, Some(123));
|
||||
tracked!(inline_mir_threshold, Some(123));
|
||||
tracked!(instrument_coverage, Some(InstrumentCoverage::All));
|
||||
tracked!(instrument_mcount, true);
|
||||
tracked!(instrument_xray, Some(InstrumentXRay::default()));
|
||||
tracked!(link_directives, false);
|
||||
|
@ -26,7 +26,7 @@ use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
||||
use std::mem;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::OnceLock;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::thread;
|
||||
|
||||
/// Function pointer type that constructs a new CodegenBackend.
|
||||
@ -71,6 +71,7 @@ pub fn create_session(
|
||||
>,
|
||||
descriptions: Registry,
|
||||
ice_file: Option<PathBuf>,
|
||||
using_internal_features: Arc<AtomicBool>,
|
||||
expanded_args: Vec<String>,
|
||||
) -> (Session, Box<dyn CodegenBackend>) {
|
||||
let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
|
||||
@ -114,6 +115,7 @@ pub fn create_session(
|
||||
target_override,
|
||||
rustc_version_str().unwrap_or("unknown"),
|
||||
ice_file,
|
||||
using_internal_features,
|
||||
expanded_args,
|
||||
);
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(proc_macro_diagnostic)]
|
||||
#![feature(proc_macro_span)]
|
||||
#![feature(proc_macro_tracked_env)]
|
||||
#![allow(rustc::default_hash_types)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
|
@ -97,6 +97,9 @@ struct QueryModifiers {
|
||||
/// A cycle error results in a delay_bug call
|
||||
cycle_delay_bug: Option<Ident>,
|
||||
|
||||
/// A cycle error results in a stashed cycle error that can be unstashed and canceled later
|
||||
cycle_stash: Option<Ident>,
|
||||
|
||||
/// Don't hash the result, instead just mark a query red if it runs
|
||||
no_hash: Option<Ident>,
|
||||
|
||||
@ -127,6 +130,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
|
||||
let mut desc = None;
|
||||
let mut fatal_cycle = None;
|
||||
let mut cycle_delay_bug = None;
|
||||
let mut cycle_stash = None;
|
||||
let mut no_hash = None;
|
||||
let mut anon = None;
|
||||
let mut eval_always = None;
|
||||
@ -181,6 +185,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
|
||||
try_insert!(fatal_cycle = modifier);
|
||||
} else if modifier == "cycle_delay_bug" {
|
||||
try_insert!(cycle_delay_bug = modifier);
|
||||
} else if modifier == "cycle_stash" {
|
||||
try_insert!(cycle_stash = modifier);
|
||||
} else if modifier == "no_hash" {
|
||||
try_insert!(no_hash = modifier);
|
||||
} else if modifier == "anon" {
|
||||
@ -208,6 +214,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
|
||||
desc,
|
||||
fatal_cycle,
|
||||
cycle_delay_bug,
|
||||
cycle_stash,
|
||||
no_hash,
|
||||
anon,
|
||||
eval_always,
|
||||
@ -329,6 +336,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
||||
fatal_cycle,
|
||||
arena_cache,
|
||||
cycle_delay_bug,
|
||||
cycle_stash,
|
||||
no_hash,
|
||||
anon,
|
||||
eval_always,
|
||||
|
@ -26,7 +26,7 @@ use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use std::collections::HashMap;
|
||||
use syn::parse::{Parse, ParseStream, Result};
|
||||
use syn::{braced, punctuated::Punctuated, Ident, LitStr, Token};
|
||||
use syn::{braced, punctuated::Punctuated, Expr, Ident, Lit, LitStr, Macro, Token};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@ -53,21 +53,46 @@ impl Parse for Keyword {
|
||||
|
||||
struct Symbol {
|
||||
name: Ident,
|
||||
value: Option<LitStr>,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
enum Value {
|
||||
SameAsName,
|
||||
String(LitStr),
|
||||
Env(LitStr, Macro),
|
||||
Unsupported(Expr),
|
||||
}
|
||||
|
||||
impl Parse for Symbol {
|
||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||
let name = input.parse()?;
|
||||
let value = match input.parse::<Token![:]>() {
|
||||
Ok(_) => Some(input.parse()?),
|
||||
Err(_) => None,
|
||||
};
|
||||
let colon_token: Option<Token![:]> = input.parse()?;
|
||||
let value = if colon_token.is_some() { input.parse()? } else { Value::SameAsName };
|
||||
|
||||
Ok(Symbol { name, value })
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Value {
|
||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||
let expr: Expr = input.parse()?;
|
||||
match &expr {
|
||||
Expr::Lit(expr) => {
|
||||
if let Lit::Str(lit) = &expr.lit {
|
||||
return Ok(Value::String(lit.clone()));
|
||||
}
|
||||
}
|
||||
Expr::Macro(expr) => {
|
||||
if expr.mac.path.is_ident("env") && let Ok(lit) = expr.mac.parse_body() {
|
||||
return Ok(Value::Env(lit, expr.mac.clone()));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(Value::Unsupported(expr))
|
||||
}
|
||||
}
|
||||
|
||||
struct Input {
|
||||
keywords: Punctuated<Keyword, Token![,]>,
|
||||
symbols: Punctuated<Symbol, Token![,]>,
|
||||
@ -111,6 +136,37 @@ pub fn symbols(input: TokenStream) -> TokenStream {
|
||||
output
|
||||
}
|
||||
|
||||
struct Preinterned {
|
||||
idx: u32,
|
||||
span_of_name: Span,
|
||||
}
|
||||
|
||||
struct Entries {
|
||||
map: HashMap<String, Preinterned>,
|
||||
}
|
||||
|
||||
impl Entries {
|
||||
fn with_capacity(capacity: usize) -> Self {
|
||||
Entries { map: HashMap::with_capacity(capacity) }
|
||||
}
|
||||
|
||||
fn insert(&mut self, span: Span, str: &str, errors: &mut Errors) -> u32 {
|
||||
if let Some(prev) = self.map.get(str) {
|
||||
errors.error(span, format!("Symbol `{str}` is duplicated"));
|
||||
errors.error(prev.span_of_name, "location of previous definition".to_string());
|
||||
prev.idx
|
||||
} else {
|
||||
let idx = self.len();
|
||||
self.map.insert(str.to_string(), Preinterned { idx, span_of_name: span });
|
||||
idx
|
||||
}
|
||||
}
|
||||
|
||||
fn len(&self) -> u32 {
|
||||
u32::try_from(self.map.len()).expect("way too many symbols")
|
||||
}
|
||||
}
|
||||
|
||||
fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
|
||||
let mut errors = Errors::default();
|
||||
|
||||
@ -127,20 +183,9 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
|
||||
let mut keyword_stream = quote! {};
|
||||
let mut symbols_stream = quote! {};
|
||||
let mut prefill_stream = quote! {};
|
||||
let mut counter = 0u32;
|
||||
let mut keys =
|
||||
HashMap::<String, Span>::with_capacity(input.keywords.len() + input.symbols.len() + 10);
|
||||
let mut entries = Entries::with_capacity(input.keywords.len() + input.symbols.len() + 10);
|
||||
let mut prev_key: Option<(Span, String)> = None;
|
||||
|
||||
let mut check_dup = |span: Span, str: &str, errors: &mut Errors| {
|
||||
if let Some(prev_span) = keys.get(str) {
|
||||
errors.error(span, format!("Symbol `{str}` is duplicated"));
|
||||
errors.error(*prev_span, "location of previous definition".to_string());
|
||||
} else {
|
||||
keys.insert(str.to_string(), span);
|
||||
}
|
||||
};
|
||||
|
||||
let mut check_order = |span: Span, str: &str, errors: &mut Errors| {
|
||||
if let Some((prev_span, ref prev_str)) = prev_key {
|
||||
if str < prev_str {
|
||||
@ -156,49 +201,98 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
|
||||
let name = &keyword.name;
|
||||
let value = &keyword.value;
|
||||
let value_string = value.value();
|
||||
check_dup(keyword.name.span(), &value_string, &mut errors);
|
||||
let idx = entries.insert(keyword.name.span(), &value_string, &mut errors);
|
||||
prefill_stream.extend(quote! {
|
||||
#value,
|
||||
});
|
||||
keyword_stream.extend(quote! {
|
||||
pub const #name: Symbol = Symbol::new(#counter);
|
||||
pub const #name: Symbol = Symbol::new(#idx);
|
||||
});
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
// Generate the listed symbols.
|
||||
for symbol in input.symbols.iter() {
|
||||
let name = &symbol.name;
|
||||
let value = match &symbol.value {
|
||||
Some(value) => value.value(),
|
||||
None => name.to_string(),
|
||||
};
|
||||
check_dup(symbol.name.span(), &value, &mut errors);
|
||||
check_order(symbol.name.span(), &name.to_string(), &mut errors);
|
||||
|
||||
let value = match &symbol.value {
|
||||
Value::SameAsName => name.to_string(),
|
||||
Value::String(lit) => lit.value(),
|
||||
Value::Env(..) => continue, // in another loop below
|
||||
Value::Unsupported(expr) => {
|
||||
errors.list.push(syn::Error::new_spanned(
|
||||
expr,
|
||||
concat!(
|
||||
"unsupported expression for symbol value; implement support for this in ",
|
||||
file!(),
|
||||
),
|
||||
));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let idx = entries.insert(symbol.name.span(), &value, &mut errors);
|
||||
|
||||
prefill_stream.extend(quote! {
|
||||
#value,
|
||||
});
|
||||
symbols_stream.extend(quote! {
|
||||
pub const #name: Symbol = Symbol::new(#counter);
|
||||
pub const #name: Symbol = Symbol::new(#idx);
|
||||
});
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
// Generate symbols for the strings "0", "1", ..., "9".
|
||||
let digits_base = counter;
|
||||
counter += 10;
|
||||
for n in 0..10 {
|
||||
let n = n.to_string();
|
||||
check_dup(Span::call_site(), &n, &mut errors);
|
||||
entries.insert(Span::call_site(), &n, &mut errors);
|
||||
prefill_stream.extend(quote! {
|
||||
#n,
|
||||
});
|
||||
}
|
||||
|
||||
// Symbols whose value comes from an environment variable. It's allowed for
|
||||
// these to have the same value as another symbol.
|
||||
for symbol in &input.symbols {
|
||||
let (env_var, expr) = match &symbol.value {
|
||||
Value::Env(lit, expr) => (lit, expr),
|
||||
Value::SameAsName | Value::String(_) | Value::Unsupported(_) => continue,
|
||||
};
|
||||
|
||||
if !proc_macro::is_available() {
|
||||
errors.error(
|
||||
Span::call_site(),
|
||||
"proc_macro::tracked_env is not available in unit test".to_owned(),
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
let value = match proc_macro::tracked_env::var(env_var.value()) {
|
||||
Ok(value) => value,
|
||||
Err(err) => {
|
||||
errors.list.push(syn::Error::new_spanned(expr, err));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let idx = if let Some(prev) = entries.map.get(&value) {
|
||||
prev.idx
|
||||
} else {
|
||||
prefill_stream.extend(quote! {
|
||||
#value,
|
||||
});
|
||||
entries.insert(symbol.name.span(), &value, &mut errors)
|
||||
};
|
||||
|
||||
let name = &symbol.name;
|
||||
symbols_stream.extend(quote! {
|
||||
pub const #name: Symbol = Symbol::new(#idx);
|
||||
});
|
||||
}
|
||||
|
||||
let symbol_digits_base = entries.map["0"].idx;
|
||||
let preinterned_symbols_count = entries.len();
|
||||
let output = quote! {
|
||||
const SYMBOL_DIGITS_BASE: u32 = #digits_base;
|
||||
const PREINTERNED_SYMBOLS_COUNT: u32 = #counter;
|
||||
const SYMBOL_DIGITS_BASE: u32 = #symbol_digits_base;
|
||||
const PREINTERNED_SYMBOLS_COUNT: u32 = #preinterned_symbols_count;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(non_upper_case_globals)]
|
||||
|
@ -27,7 +27,7 @@ fn test_symbols() {
|
||||
|
||||
let body_tokens = m.mac.tokens.clone();
|
||||
|
||||
test_symbols_macro(body_tokens, &[]);
|
||||
test_symbols_macro(body_tokens, &["proc_macro::tracked_env is not available in unit test"]);
|
||||
}
|
||||
|
||||
fn test_symbols_macro(input: TokenStream, expected_errors: &[&str]) {
|
||||
|
@ -21,35 +21,17 @@
|
||||
//!
|
||||
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
|
||||
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_type_ir::Canonical as IrCanonical;
|
||||
use smallvec::SmallVec;
|
||||
use std::ops::Index;
|
||||
|
||||
use crate::infer::MemberConstraint;
|
||||
use crate::mir::ConstraintCategory;
|
||||
use crate::ty::GenericArg;
|
||||
use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
|
||||
use rustc_macros::HashStable;
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt::Display;
|
||||
use std::ops::Index;
|
||||
|
||||
/// A "canonicalized" type `V` is one where all free inference
|
||||
/// variables have been rewritten to "canonical vars". These are
|
||||
/// numbered starting from 0 in order of first appearance.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Canonical<'tcx, V> {
|
||||
pub value: V,
|
||||
pub max_universe: ty::UniverseIndex,
|
||||
pub variables: CanonicalVarInfos<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx, V: Display> std::fmt::Display for Canonical<'tcx, V> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}",
|
||||
self.value, self.max_universe, self.variables
|
||||
)
|
||||
}
|
||||
}
|
||||
pub type Canonical<'tcx, V> = IrCanonical<TyCtxt<'tcx>, V>;
|
||||
|
||||
pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
|
||||
|
||||
@ -379,56 +361,6 @@ impl<'tcx, R> QueryResponse<'tcx, R> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
|
||||
pub fn is_proven(&self) -> bool {
|
||||
self.value.is_proven()
|
||||
}
|
||||
|
||||
pub fn is_ambiguous(&self) -> bool {
|
||||
!self.is_proven()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, V> Canonical<'tcx, V> {
|
||||
/// Allows you to map the `value` of a canonical while keeping the
|
||||
/// same set of bound variables.
|
||||
///
|
||||
/// **WARNING:** This function is very easy to mis-use, hence the
|
||||
/// name! In particular, the new value `W` must use all **the
|
||||
/// same type/region variables** in **precisely the same order**
|
||||
/// as the original! (The ordering is defined by the
|
||||
/// `TypeFoldable` implementation of the type in question.)
|
||||
///
|
||||
/// An example of a **correct** use of this:
|
||||
///
|
||||
/// ```rust,ignore (not real code)
|
||||
/// let a: Canonical<'_, T> = ...;
|
||||
/// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
|
||||
/// ```
|
||||
///
|
||||
/// An example of an **incorrect** use of this:
|
||||
///
|
||||
/// ```rust,ignore (not real code)
|
||||
/// let a: Canonical<'tcx, T> = ...;
|
||||
/// let ty: Ty<'tcx> = ...;
|
||||
/// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
|
||||
/// ```
|
||||
pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> {
|
||||
let Canonical { max_universe, variables, value } = self;
|
||||
Canonical { max_universe, variables, value: map_op(value) }
|
||||
}
|
||||
|
||||
/// Allows you to map the `value` of a canonical while keeping the same set of
|
||||
/// bound variables.
|
||||
///
|
||||
/// **WARNING:** This function is very easy to mis-use, hence the name! See
|
||||
/// the comment of [Canonical::unchecked_map] for more details.
|
||||
pub fn unchecked_rebind<W>(self, value: W) -> Canonical<'tcx, W> {
|
||||
let Canonical { max_universe, variables, value: _ } = self;
|
||||
Canonical { max_universe, variables, value }
|
||||
}
|
||||
}
|
||||
|
||||
pub type QueryOutlivesConstraint<'tcx> =
|
||||
(ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
|
||||
|
||||
|
@ -251,6 +251,7 @@ rustc_queries! {
|
||||
"computing type of opaque `{path}`",
|
||||
path = tcx.def_path_str(key),
|
||||
}
|
||||
cycle_stash
|
||||
}
|
||||
|
||||
query type_alias_is_lazy(key: DefId) -> bool {
|
||||
@ -341,7 +342,7 @@ rustc_queries! {
|
||||
|
||||
query opaque_types_defined_by(
|
||||
key: LocalDefId
|
||||
) -> &'tcx [LocalDefId] {
|
||||
) -> &'tcx ty::List<LocalDefId> {
|
||||
desc {
|
||||
|tcx| "computing the opaque types defined by `{}`",
|
||||
tcx.def_path_str(key.to_def_id())
|
||||
|
@ -230,9 +230,9 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D>
|
||||
assert!(pos >= SHORTHAND_OFFSET);
|
||||
let shorthand = pos - SHORTHAND_OFFSET;
|
||||
|
||||
decoder.with_position(shorthand, ty::PredicateKind::decode)
|
||||
decoder.with_position(shorthand, <ty::PredicateKind<'tcx> as Decodable<D>>::decode)
|
||||
} else {
|
||||
ty::PredicateKind::decode(decoder)
|
||||
<ty::PredicateKind<'tcx> as Decodable<D>>::decode(decoder)
|
||||
},
|
||||
bound_vars,
|
||||
)
|
||||
|
@ -6,7 +6,7 @@ pub mod tls;
|
||||
|
||||
use crate::arena::Arena;
|
||||
use crate::dep_graph::{DepGraph, DepKindStruct};
|
||||
use crate::infer::canonical::CanonicalVarInfo;
|
||||
use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
|
||||
use crate::lint::struct_lint_level;
|
||||
use crate::metadata::ModChild;
|
||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
@ -84,10 +84,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
type AdtDef = ty::AdtDef<'tcx>;
|
||||
type GenericArgs = ty::GenericArgsRef<'tcx>;
|
||||
type GenericArg = ty::GenericArg<'tcx>;
|
||||
type Term = ty::Term<'tcx>;
|
||||
|
||||
type Binder<T> = Binder<'tcx, T>;
|
||||
type Predicate = Predicate<'tcx>;
|
||||
type PredicateKind = ty::PredicateKind<'tcx>;
|
||||
type TypeAndMut = TypeAndMut<'tcx>;
|
||||
type CanonicalVars = CanonicalVarInfos<'tcx>;
|
||||
|
||||
type Ty = Ty<'tcx>;
|
||||
type Tys = &'tcx List<Ty<'tcx>>;
|
||||
type AliasTy = ty::AliasTy<'tcx>;
|
||||
@ -95,10 +97,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
type BoundTy = ty::BoundTy;
|
||||
type PlaceholderTy = ty::PlaceholderType;
|
||||
type InferTy = InferTy;
|
||||
|
||||
type ErrorGuaranteed = ErrorGuaranteed;
|
||||
type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
|
||||
type PolyFnSig = PolyFnSig<'tcx>;
|
||||
type AllocId = crate::mir::interpret::AllocId;
|
||||
|
||||
type Const = ty::Const<'tcx>;
|
||||
type InferConst = ty::InferConst;
|
||||
type AliasConst = ty::UnevaluatedConst<'tcx>;
|
||||
@ -107,6 +111,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
type BoundConst = ty::BoundVar;
|
||||
type ValueConst = ty::ValTree<'tcx>;
|
||||
type ExprConst = ty::Expr<'tcx>;
|
||||
|
||||
type Region = Region<'tcx>;
|
||||
type EarlyBoundRegion = ty::EarlyBoundRegion;
|
||||
type BoundRegion = ty::BoundRegion;
|
||||
@ -114,6 +119,15 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
type InferRegion = ty::RegionVid;
|
||||
type PlaceholderRegion = ty::PlaceholderRegion;
|
||||
|
||||
type Predicate = Predicate<'tcx>;
|
||||
type TraitPredicate = ty::TraitPredicate<'tcx>;
|
||||
type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>;
|
||||
type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>;
|
||||
type ProjectionPredicate = ty::ProjectionPredicate<'tcx>;
|
||||
type SubtypePredicate = ty::SubtypePredicate<'tcx>;
|
||||
type CoercePredicate = ty::CoercePredicate<'tcx>;
|
||||
type ClosureKind = ty::ClosureKind;
|
||||
|
||||
fn ty_and_mut_to_parts(
|
||||
TypeAndMut { ty, mutbl }: TypeAndMut<'tcx>,
|
||||
) -> (Self::Ty, ty::Mutability) {
|
||||
@ -148,6 +162,7 @@ pub struct CtxtInterners<'tcx> {
|
||||
external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>,
|
||||
predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
|
||||
fields: InternedSet<'tcx, List<FieldIdx>>,
|
||||
local_def_ids: InternedSet<'tcx, List<LocalDefId>>,
|
||||
}
|
||||
|
||||
impl<'tcx> CtxtInterners<'tcx> {
|
||||
@ -173,6 +188,7 @@ impl<'tcx> CtxtInterners<'tcx> {
|
||||
external_constraints: Default::default(),
|
||||
predefined_opaques_in_body: Default::default(),
|
||||
fields: Default::default(),
|
||||
local_def_ids: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1559,6 +1575,7 @@ slice_interners!(
|
||||
place_elems: pub mk_place_elems(PlaceElem<'tcx>),
|
||||
bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind),
|
||||
fields: pub mk_fields(FieldIdx),
|
||||
local_def_ids: intern_local_def_ids(LocalDefId),
|
||||
);
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
@ -1788,6 +1805,13 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
self.intern_clauses(clauses)
|
||||
}
|
||||
|
||||
pub fn mk_local_def_ids(self, clauses: &[LocalDefId]) -> &'tcx List<LocalDefId> {
|
||||
// FIXME consider asking the input slice to be sorted to avoid
|
||||
// re-interning permutations, in which case that would be asserted
|
||||
// here.
|
||||
self.intern_local_def_ids(clauses)
|
||||
}
|
||||
|
||||
pub fn mk_const_list_from_iter<I, T>(self, iter: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
|
@ -241,7 +241,9 @@ impl<'tcx> Ty<'tcx> {
|
||||
}
|
||||
ty::Dynamic(..) => "trait object".into(),
|
||||
ty::Closure(..) => "closure".into(),
|
||||
ty::Coroutine(def_id, ..) => tcx.coroutine_kind(def_id).unwrap().descr().into(),
|
||||
ty::Coroutine(def_id, ..) => {
|
||||
format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into()
|
||||
}
|
||||
ty::CoroutineWitness(..) => "coroutine witness".into(),
|
||||
ty::Infer(ty::TyVar(_)) => "inferred type".into(),
|
||||
ty::Infer(ty::IntVar(_)) => "integer".into(),
|
||||
@ -299,7 +301,9 @@ impl<'tcx> Ty<'tcx> {
|
||||
ty::FnPtr(_) => "fn pointer".into(),
|
||||
ty::Dynamic(..) => "trait object".into(),
|
||||
ty::Closure(..) => "closure".into(),
|
||||
ty::Coroutine(def_id, ..) => tcx.coroutine_kind(def_id).unwrap().descr().into(),
|
||||
ty::Coroutine(def_id, ..) => {
|
||||
format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into()
|
||||
}
|
||||
ty::CoroutineWitness(..) => "coroutine witness".into(),
|
||||
ty::Tuple(..) => "tuple".into(),
|
||||
ty::Placeholder(..) => "higher-ranked type".into(),
|
||||
|
@ -134,7 +134,7 @@ impl FlagComputation {
|
||||
if should_remove_further_specializable {
|
||||
self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
|
||||
}
|
||||
self.add_flags(TypeFlags::HAS_TY_GENERATOR);
|
||||
self.add_flags(TypeFlags::HAS_TY_COROUTINE);
|
||||
}
|
||||
|
||||
&ty::Closure(_, args) => {
|
||||
|
@ -237,6 +237,20 @@ impl<'tcx> Generics {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `GenericParamDef` with the given index if available.
|
||||
pub fn opt_param_at(
|
||||
&'tcx self,
|
||||
param_index: usize,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Option<&'tcx GenericParamDef> {
|
||||
if let Some(index) = param_index.checked_sub(self.parent_count) {
|
||||
self.params.get(index)
|
||||
} else {
|
||||
tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
|
||||
.opt_param_at(param_index, tcx)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn params_to(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx [GenericParamDef] {
|
||||
if let Some(index) = param_index.checked_sub(self.parent_count) {
|
||||
&self.params[..index]
|
||||
@ -268,6 +282,20 @@ impl<'tcx> Generics {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `GenericParamDef` associated with this `ParamTy` if it belongs to this
|
||||
/// `Generics`.
|
||||
pub fn opt_type_param(
|
||||
&'tcx self,
|
||||
param: &ParamTy,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Option<&'tcx GenericParamDef> {
|
||||
let param = self.opt_param_at(param.index as usize, tcx)?;
|
||||
match param.kind {
|
||||
GenericParamDefKind::Type { .. } => Some(param),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `GenericParamDef` associated with this `ParamConst`.
|
||||
pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef {
|
||||
let param = self.param_at(param.index as usize, tcx);
|
||||
|
@ -97,17 +97,17 @@ pub use self::rvalue_scopes::RvalueScopes;
|
||||
pub use self::sty::BoundRegionKind::*;
|
||||
pub use self::sty::{
|
||||
AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
|
||||
BoundVariableKind, CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, ConstKind, ConstVid,
|
||||
CoroutineArgs, CoroutineArgsParts, EarlyBoundRegion, EffectVid, ExistentialPredicate,
|
||||
BoundVariableKind, CanonicalPolyFnSig, ClauseKind, ClosureArgs, ClosureArgsParts, ConstKind,
|
||||
ConstVid, CoroutineArgs, CoroutineArgsParts, EarlyBoundRegion, EffectVid, ExistentialPredicate,
|
||||
ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, InlineConstArgs,
|
||||
InlineConstArgsParts, ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection,
|
||||
PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, Region, RegionKind, RegionVid,
|
||||
TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
|
||||
PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, PredicateKind, Region,
|
||||
RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo,
|
||||
};
|
||||
pub use self::trait_def::TraitDef;
|
||||
pub use self::typeck_results::{
|
||||
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, TypeckResults,
|
||||
UserType, UserTypeAnnotationIndex,
|
||||
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity,
|
||||
TypeckResults, UserType, UserTypeAnnotationIndex,
|
||||
};
|
||||
|
||||
pub mod _match;
|
||||
@ -233,6 +233,7 @@ impl MainDefinition {
|
||||
#[derive(Clone, Debug, TypeFoldable, TypeVisitable)]
|
||||
pub struct ImplHeader<'tcx> {
|
||||
pub impl_def_id: DefId,
|
||||
pub impl_args: ty::GenericArgsRef<'tcx>,
|
||||
pub self_ty: Ty<'tcx>,
|
||||
pub trait_ref: Option<TraitRef<'tcx>>,
|
||||
pub predicates: Vec<Predicate<'tcx>>,
|
||||
@ -626,98 +627,6 @@ impl<'tcx> Clause<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
/// A clause is something that can appear in where bounds or be inferred
|
||||
/// by implied bounds.
|
||||
pub enum ClauseKind<'tcx> {
|
||||
/// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
|
||||
/// the `Self` type of the trait reference and `A`, `B`, and `C`
|
||||
/// would be the type parameters.
|
||||
Trait(TraitPredicate<'tcx>),
|
||||
|
||||
/// `where 'a: 'b`
|
||||
RegionOutlives(RegionOutlivesPredicate<'tcx>),
|
||||
|
||||
/// `where T: 'a`
|
||||
TypeOutlives(TypeOutlivesPredicate<'tcx>),
|
||||
|
||||
/// `where <T as TraitRef>::Name == X`, approximately.
|
||||
/// See the `ProjectionPredicate` struct for details.
|
||||
Projection(ProjectionPredicate<'tcx>),
|
||||
|
||||
/// Ensures that a const generic argument to a parameter `const N: u8`
|
||||
/// is of type `u8`.
|
||||
ConstArgHasType(Const<'tcx>, Ty<'tcx>),
|
||||
|
||||
/// No syntax: `T` well-formed.
|
||||
WellFormed(GenericArg<'tcx>),
|
||||
|
||||
/// Constant initializer must evaluate successfully.
|
||||
ConstEvaluatable(ty::Const<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
pub enum PredicateKind<'tcx> {
|
||||
/// Prove a clause
|
||||
Clause(ClauseKind<'tcx>),
|
||||
|
||||
/// Trait must be object-safe.
|
||||
ObjectSafe(DefId),
|
||||
|
||||
/// No direct syntax. May be thought of as `where T: FnFoo<...>`
|
||||
/// for some generic args `...` and `T` being a closure type.
|
||||
/// Satisfied (or refuted) once we know the closure's kind.
|
||||
ClosureKind(DefId, GenericArgsRef<'tcx>, ClosureKind),
|
||||
|
||||
/// `T1 <: T2`
|
||||
///
|
||||
/// This obligation is created most often when we have two
|
||||
/// unresolved type variables and hence don't have enough
|
||||
/// information to process the subtyping obligation yet.
|
||||
Subtype(SubtypePredicate<'tcx>),
|
||||
|
||||
/// `T1` coerced to `T2`
|
||||
///
|
||||
/// Like a subtyping obligation, this is created most often
|
||||
/// when we have two unresolved type variables and hence
|
||||
/// don't have enough information to process the coercion
|
||||
/// obligation yet. At the moment, we actually process coercions
|
||||
/// very much like subtyping and don't handle the full coercion
|
||||
/// logic.
|
||||
Coerce(CoercePredicate<'tcx>),
|
||||
|
||||
/// Constants must be equal. The first component is the const that is expected.
|
||||
ConstEquate(Const<'tcx>, Const<'tcx>),
|
||||
|
||||
/// A marker predicate that is always ambiguous.
|
||||
/// Used for coherence to mark opaque types as possibly equal to each other but ambiguous.
|
||||
Ambiguous,
|
||||
|
||||
/// Separate from `ClauseKind::Projection` which is used for normalization in new solver.
|
||||
/// This predicate requires two terms to be equal to eachother.
|
||||
///
|
||||
/// Only used for new solver
|
||||
AliasRelate(Term<'tcx>, Term<'tcx>, AliasRelationDirection),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, Debug)]
|
||||
pub enum AliasRelationDirection {
|
||||
Equate,
|
||||
Subtype,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for AliasRelationDirection {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
AliasRelationDirection::Equate => write!(f, "=="),
|
||||
AliasRelationDirection::Subtype => write!(f, "<:"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The crate outlives map is computed during typeck and contains the
|
||||
/// outlives of every item in the local crate. You should not use it
|
||||
/// directly, because to do so will make your pass dependent on the
|
||||
|
@ -2649,6 +2649,13 @@ macro_rules! forward_display_to_print {
|
||||
}
|
||||
|
||||
macro_rules! define_print_and_forward_display {
|
||||
(($self:ident, $cx:ident): $($ty:ty $print:block)+) => {
|
||||
define_print!(($self, $cx): $($ty $print)*);
|
||||
forward_display_to_print!($($ty),+);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! define_print {
|
||||
(($self:ident, $cx:ident): $($ty:ty $print:block)+) => {
|
||||
$(impl<'tcx, P: PrettyPrinter<'tcx>> Print<'tcx, P> for $ty {
|
||||
fn print(&$self, $cx: &mut P) -> Result<(), PrintError> {
|
||||
@ -2660,8 +2667,6 @@ macro_rules! define_print_and_forward_display {
|
||||
Ok(())
|
||||
}
|
||||
})+
|
||||
|
||||
forward_display_to_print!($($ty),+);
|
||||
};
|
||||
}
|
||||
|
||||
@ -2759,6 +2764,51 @@ forward_display_to_print! {
|
||||
ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
|
||||
}
|
||||
|
||||
define_print! {
|
||||
(self, cx):
|
||||
|
||||
ty::ClauseKind<'tcx> {
|
||||
match *self {
|
||||
ty::ClauseKind::Trait(ref data) => {
|
||||
p!(print(data))
|
||||
}
|
||||
ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)),
|
||||
ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)),
|
||||
ty::ClauseKind::Projection(predicate) => p!(print(predicate)),
|
||||
ty::ClauseKind::ConstArgHasType(ct, ty) => {
|
||||
p!("the constant `", print(ct), "` has type `", print(ty), "`")
|
||||
},
|
||||
ty::ClauseKind::WellFormed(arg) => p!(print(arg), " well-formed"),
|
||||
ty::ClauseKind::ConstEvaluatable(ct) => {
|
||||
p!("the constant `", print(ct), "` can be evaluated")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::PredicateKind<'tcx> {
|
||||
match *self {
|
||||
ty::PredicateKind::Clause(data) => {
|
||||
p!(print(data))
|
||||
}
|
||||
ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
|
||||
ty::PredicateKind::Coerce(predicate) => p!(print(predicate)),
|
||||
ty::PredicateKind::ObjectSafe(trait_def_id) => {
|
||||
p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
|
||||
}
|
||||
ty::PredicateKind::ClosureKind(closure_def_id, _closure_args, kind) => p!(
|
||||
"the closure `",
|
||||
print_value_path(closure_def_id, &[]),
|
||||
write("` implements the trait `{}`", kind)
|
||||
),
|
||||
ty::PredicateKind::ConstEquate(c1, c2) => {
|
||||
p!("the constant `", print(c1), "` equals `", print(c2), "`")
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => p!("ambiguous"),
|
||||
ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_print_and_forward_display! {
|
||||
(self, cx):
|
||||
|
||||
@ -2887,55 +2937,13 @@ define_print_and_forward_display! {
|
||||
}
|
||||
|
||||
ty::Predicate<'tcx> {
|
||||
let binder = self.kind();
|
||||
p!(print(binder))
|
||||
p!(print(self.kind()))
|
||||
}
|
||||
|
||||
ty::Clause<'tcx> {
|
||||
p!(print(self.kind()))
|
||||
}
|
||||
|
||||
ty::ClauseKind<'tcx> {
|
||||
match *self {
|
||||
ty::ClauseKind::Trait(ref data) => {
|
||||
p!(print(data))
|
||||
}
|
||||
ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)),
|
||||
ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)),
|
||||
ty::ClauseKind::Projection(predicate) => p!(print(predicate)),
|
||||
ty::ClauseKind::ConstArgHasType(ct, ty) => {
|
||||
p!("the constant `", print(ct), "` has type `", print(ty), "`")
|
||||
},
|
||||
ty::ClauseKind::WellFormed(arg) => p!(print(arg), " well-formed"),
|
||||
ty::ClauseKind::ConstEvaluatable(ct) => {
|
||||
p!("the constant `", print(ct), "` can be evaluated")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::PredicateKind<'tcx> {
|
||||
match *self {
|
||||
ty::PredicateKind::Clause(data) => {
|
||||
p!(print(data))
|
||||
}
|
||||
ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
|
||||
ty::PredicateKind::Coerce(predicate) => p!(print(predicate)),
|
||||
ty::PredicateKind::ObjectSafe(trait_def_id) => {
|
||||
p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
|
||||
}
|
||||
ty::PredicateKind::ClosureKind(closure_def_id, _closure_args, kind) => p!(
|
||||
"the closure `",
|
||||
print_value_path(closure_def_id, &[]),
|
||||
write("` implements the trait `{}`", kind)
|
||||
),
|
||||
ty::PredicateKind::ConstEquate(c1, c2) => {
|
||||
p!("the constant `", print(c1), "` equals `", print(c2), "`")
|
||||
}
|
||||
ty::PredicateKind::Ambiguous => p!("ambiguous"),
|
||||
ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
|
||||
}
|
||||
}
|
||||
|
||||
GenericArg<'tcx> {
|
||||
match self.unpack() {
|
||||
GenericArgKind::Lifetime(lt) => p!(print(lt)),
|
||||
|
@ -185,43 +185,6 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::ClauseKind<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
ty::ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"),
|
||||
ty::ClauseKind::Trait(ref a) => a.fmt(f),
|
||||
ty::ClauseKind::RegionOutlives(ref pair) => pair.fmt(f),
|
||||
ty::ClauseKind::TypeOutlives(ref pair) => pair.fmt(f),
|
||||
ty::ClauseKind::Projection(ref pair) => pair.fmt(f),
|
||||
ty::ClauseKind::WellFormed(ref data) => write!(f, "WellFormed({data:?})"),
|
||||
ty::ClauseKind::ConstEvaluatable(ct) => {
|
||||
write!(f, "ConstEvaluatable({ct:?})")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
ty::PredicateKind::Clause(ref a) => a.fmt(f),
|
||||
ty::PredicateKind::Subtype(ref pair) => pair.fmt(f),
|
||||
ty::PredicateKind::Coerce(ref pair) => pair.fmt(f),
|
||||
ty::PredicateKind::ObjectSafe(trait_def_id) => {
|
||||
write!(f, "ObjectSafe({trait_def_id:?})")
|
||||
}
|
||||
ty::PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => {
|
||||
write!(f, "ClosureKind({closure_def_id:?}, {closure_args:?}, {kind:?})")
|
||||
}
|
||||
ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({c1:?}, {c2:?})"),
|
||||
ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"),
|
||||
ty::PredicateKind::AliasRelate(t1, t2, dir) => {
|
||||
write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for AliasTy<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
WithInfcx::with_no_infcx(self).fmt(f)
|
||||
@ -486,7 +449,6 @@ TrivialTypeTraversalImpls! {
|
||||
crate::ty::IntVarValue,
|
||||
crate::ty::adjustment::PointerCoercion,
|
||||
crate::ty::RegionVid,
|
||||
crate::ty::UniverseIndex,
|
||||
crate::ty::Variance,
|
||||
::rustc_span::Span,
|
||||
::rustc_span::symbol::Ident,
|
||||
@ -503,7 +465,6 @@ TrivialTypeTraversalAndLiftImpls! {
|
||||
::rustc_hir::Mutability,
|
||||
::rustc_hir::Unsafety,
|
||||
::rustc_target::spec::abi::Abi,
|
||||
crate::ty::AliasRelationDirection,
|
||||
crate::ty::ClosureKind,
|
||||
crate::ty::ParamConst,
|
||||
crate::ty::ParamTy,
|
||||
|
@ -32,10 +32,12 @@ use std::fmt;
|
||||
use std::ops::{ControlFlow, Deref, Range};
|
||||
use ty::util::IntTypeExt;
|
||||
|
||||
use rustc_type_ir::ClauseKind as IrClauseKind;
|
||||
use rustc_type_ir::CollectAndApply;
|
||||
use rustc_type_ir::ConstKind as IrConstKind;
|
||||
use rustc_type_ir::DebugWithInfcx;
|
||||
use rustc_type_ir::DynKind;
|
||||
use rustc_type_ir::PredicateKind as IrPredicateKind;
|
||||
use rustc_type_ir::RegionKind as IrRegionKind;
|
||||
use rustc_type_ir::TyKind as IrTyKind;
|
||||
use rustc_type_ir::TyKind::*;
|
||||
@ -47,6 +49,8 @@ use super::GenericParamDefKind;
|
||||
pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>;
|
||||
pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>;
|
||||
pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>;
|
||||
pub type PredicateKind<'tcx> = IrPredicateKind<TyCtxt<'tcx>>;
|
||||
pub type ClauseKind<'tcx> = IrClauseKind<TyCtxt<'tcx>>;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
|
@ -594,10 +594,27 @@ pub struct CanonicalUserTypeAnnotation<'tcx> {
|
||||
/// Canonical user type annotation.
|
||||
pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>;
|
||||
|
||||
impl<'tcx> CanonicalUserType<'tcx> {
|
||||
/// A user-given type annotation attached to a constant. These arise
|
||||
/// from constants that are named via paths, like `Foo::<A>::new` and
|
||||
/// so forth.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
|
||||
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub enum UserType<'tcx> {
|
||||
Ty(Ty<'tcx>),
|
||||
|
||||
/// The canonical type is the result of `type_of(def_id)` with the
|
||||
/// given substitutions applied.
|
||||
TypeOf(DefId, UserArgs<'tcx>),
|
||||
}
|
||||
|
||||
pub trait IsIdentity {
|
||||
fn is_identity(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
|
||||
/// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`,
|
||||
/// i.e., each thing is mapped to a canonical variable with the same index.
|
||||
pub fn is_identity(&self) -> bool {
|
||||
fn is_identity(&self) -> bool {
|
||||
match self.value {
|
||||
UserType::Ty(_) => false,
|
||||
UserType::TypeOf(_, user_args) => {
|
||||
@ -640,19 +657,6 @@ impl<'tcx> CanonicalUserType<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A user-given type annotation attached to a constant. These arise
|
||||
/// from constants that are named via paths, like `Foo::<A>::new` and
|
||||
/// so forth.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
|
||||
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub enum UserType<'tcx> {
|
||||
Ty(Ty<'tcx>),
|
||||
|
||||
/// The canonical type is the result of `type_of(def_id)` with the
|
||||
/// given substitutions applied.
|
||||
TypeOf(DefId, UserArgs<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> std::fmt::Display for UserType<'tcx> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
|
@ -48,7 +48,7 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
|
||||
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
|
||||
}
|
||||
fn has_coroutines(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_TY_GENERATOR)
|
||||
self.has_type_flags(TypeFlags::HAS_TY_COROUTINE)
|
||||
}
|
||||
fn references_error(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_ERROR)
|
||||
|
@ -379,6 +379,5 @@ mir_build_unused_unsafe = unnecessary `unsafe` block
|
||||
.label = unnecessary `unsafe` block
|
||||
|
||||
mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
|
||||
mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn
|
||||
|
||||
mir_build_variant_defined_here = not covered
|
||||
|
@ -157,7 +157,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
/// [ 0. Pre-match ]
|
||||
/// |
|
||||
/// [ 1. Evaluate Scrutinee (expression being matched on) ]
|
||||
/// [ (fake read of scrutinee) ]
|
||||
/// [ (PlaceMention of scrutinee) ]
|
||||
/// |
|
||||
/// [ 2. Decision tree -- check discriminants ] <--------+
|
||||
/// | |
|
||||
@ -184,7 +184,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
///
|
||||
/// We generate MIR in the following steps:
|
||||
///
|
||||
/// 1. Evaluate the scrutinee and add the fake read of it ([Builder::lower_scrutinee]).
|
||||
/// 1. Evaluate the scrutinee and add the PlaceMention of it ([Builder::lower_scrutinee]).
|
||||
/// 2. Create the decision tree ([Builder::lower_match_tree]).
|
||||
/// 3. Determine the fake borrows that are needed from the places that were
|
||||
/// matched against and create the required temporaries for them
|
||||
@ -223,6 +223,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let fake_borrow_temps = self.lower_match_tree(
|
||||
block,
|
||||
scrutinee_span,
|
||||
&scrutinee_place,
|
||||
match_start_span,
|
||||
match_has_guard,
|
||||
&mut candidates,
|
||||
@ -238,7 +239,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Evaluate the scrutinee and add the fake read of it.
|
||||
/// Evaluate the scrutinee and add the PlaceMention for it.
|
||||
fn lower_scrutinee(
|
||||
&mut self,
|
||||
mut block: BasicBlock,
|
||||
@ -246,26 +247,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
scrutinee_span: Span,
|
||||
) -> BlockAnd<PlaceBuilder<'tcx>> {
|
||||
let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee));
|
||||
// Matching on a `scrutinee_place` with an uninhabited type doesn't
|
||||
// generate any memory reads by itself, and so if the place "expression"
|
||||
// contains unsafe operations like raw pointer dereferences or union
|
||||
// field projections, we wouldn't know to require an `unsafe` block
|
||||
// around a `match` equivalent to `std::intrinsics::unreachable()`.
|
||||
// See issue #47412 for this hole being discovered in the wild.
|
||||
//
|
||||
// HACK(eddyb) Work around the above issue by adding a dummy inspection
|
||||
// of `scrutinee_place`, specifically by applying `ReadForMatch`.
|
||||
//
|
||||
// NOTE: ReadForMatch also checks that the scrutinee is initialized.
|
||||
// This is currently needed to not allow matching on an uninitialized,
|
||||
// uninhabited value. If we get never patterns, those will check that
|
||||
// the place is initialized, and so this read would only be used to
|
||||
// check safety.
|
||||
let cause_matched_place = FakeReadCause::ForMatchedPlace(None);
|
||||
let source_info = self.source_info(scrutinee_span);
|
||||
|
||||
if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) {
|
||||
self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
|
||||
let source_info = self.source_info(scrutinee_span);
|
||||
self.cfg.push_place_mention(block, source_info, scrutinee_place);
|
||||
}
|
||||
|
||||
block.and(scrutinee_place_builder)
|
||||
@ -304,6 +288,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
scrutinee_span: Span,
|
||||
scrutinee_place_builder: &PlaceBuilder<'tcx>,
|
||||
match_start_span: Span,
|
||||
match_has_guard: bool,
|
||||
candidates: &mut [&mut Candidate<'pat, 'tcx>],
|
||||
@ -331,6 +316,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// otherwise block. Match checking will ensure this is actually
|
||||
// unreachable.
|
||||
let source_info = self.source_info(scrutinee_span);
|
||||
|
||||
// Matching on a `scrutinee_place` with an uninhabited type doesn't
|
||||
// generate any memory reads by itself, and so if the place "expression"
|
||||
// contains unsafe operations like raw pointer dereferences or union
|
||||
// field projections, we wouldn't know to require an `unsafe` block
|
||||
// around a `match` equivalent to `std::intrinsics::unreachable()`.
|
||||
// See issue #47412 for this hole being discovered in the wild.
|
||||
//
|
||||
// HACK(eddyb) Work around the above issue by adding a dummy inspection
|
||||
// of `scrutinee_place`, specifically by applying `ReadForMatch`.
|
||||
//
|
||||
// NOTE: ReadForMatch also checks that the scrutinee is initialized.
|
||||
// This is currently needed to not allow matching on an uninitialized,
|
||||
// uninhabited value. If we get never patterns, those will check that
|
||||
// the place is initialized, and so this read would only be used to
|
||||
// check safety.
|
||||
let cause_matched_place = FakeReadCause::ForMatchedPlace(None);
|
||||
|
||||
if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) {
|
||||
self.cfg.push_fake_read(
|
||||
otherwise_block,
|
||||
source_info,
|
||||
cause_matched_place,
|
||||
scrutinee_place,
|
||||
);
|
||||
}
|
||||
|
||||
self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable);
|
||||
}
|
||||
|
||||
@ -599,13 +611,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
|
||||
_ => {
|
||||
let place_builder = unpack!(block = self.as_place_builder(block, initializer));
|
||||
|
||||
if let Some(place) = place_builder.try_to_place(self) {
|
||||
let source_info = self.source_info(initializer.span);
|
||||
self.cfg.push_place_mention(block, source_info, place);
|
||||
}
|
||||
|
||||
let place_builder =
|
||||
unpack!(block = self.lower_scrutinee(block, initializer, initializer.span));
|
||||
self.place_into_pattern(block, &irrefutable_pat, place_builder, true)
|
||||
}
|
||||
}
|
||||
@ -622,6 +629,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let fake_borrow_temps = self.lower_match_tree(
|
||||
block,
|
||||
irrefutable_pat.span,
|
||||
&initializer,
|
||||
irrefutable_pat.span,
|
||||
false,
|
||||
&mut [&mut candidate],
|
||||
@ -1841,6 +1849,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let fake_borrow_temps = self.lower_match_tree(
|
||||
block,
|
||||
pat.span,
|
||||
&expr_place_builder,
|
||||
pat.span,
|
||||
false,
|
||||
&mut [&mut guard_candidate, &mut otherwise_candidate],
|
||||
@ -2342,6 +2351,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let fake_borrow_temps = this.lower_match_tree(
|
||||
block,
|
||||
initializer_span,
|
||||
&scrutinee,
|
||||
pattern.span,
|
||||
false,
|
||||
&mut [&mut candidate, &mut wildcard],
|
||||
|
@ -13,6 +13,7 @@ use rustc_span::def_id::{DefId, LocalDefId};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
|
||||
use std::mem;
|
||||
use std::ops::Bound;
|
||||
|
||||
struct UnsafetyVisitor<'a, 'tcx> {
|
||||
@ -24,7 +25,6 @@ struct UnsafetyVisitor<'a, 'tcx> {
|
||||
/// The current "safety context". This notably tracks whether we are in an
|
||||
/// `unsafe` block, and whether it has been used.
|
||||
safety_context: SafetyContext,
|
||||
body_unsafety: BodyUnsafety,
|
||||
/// The `#[target_feature]` attributes of the body. Used for checking
|
||||
/// calls to functions with `#[target_feature]` (RFC 2396).
|
||||
body_target_features: &'tcx [Symbol],
|
||||
@ -34,43 +34,50 @@ struct UnsafetyVisitor<'a, 'tcx> {
|
||||
in_union_destructure: bool,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
inside_adt: bool,
|
||||
warnings: &'a mut Vec<UnusedUnsafeWarning>,
|
||||
}
|
||||
|
||||
impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
||||
fn in_safety_context(&mut self, safety_context: SafetyContext, f: impl FnOnce(&mut Self)) {
|
||||
if let (
|
||||
SafetyContext::UnsafeBlock { span: enclosing_span, .. },
|
||||
SafetyContext::UnsafeBlock { span: block_span, hir_id, .. },
|
||||
) = (self.safety_context, safety_context)
|
||||
let prev_context = mem::replace(&mut self.safety_context, safety_context);
|
||||
|
||||
f(self);
|
||||
|
||||
let safety_context = mem::replace(&mut self.safety_context, prev_context);
|
||||
if let SafetyContext::UnsafeBlock { used, span, hir_id, nested_used_blocks } =
|
||||
safety_context
|
||||
{
|
||||
self.warn_unused_unsafe(
|
||||
hir_id,
|
||||
block_span,
|
||||
Some(UnusedUnsafeEnclosing::Block {
|
||||
span: self.tcx.sess.source_map().guess_head_span(enclosing_span),
|
||||
}),
|
||||
);
|
||||
f(self);
|
||||
} else {
|
||||
let prev_context = self.safety_context;
|
||||
self.safety_context = safety_context;
|
||||
if !used {
|
||||
self.warn_unused_unsafe(hir_id, span, None);
|
||||
|
||||
f(self);
|
||||
if let SafetyContext::UnsafeBlock {
|
||||
nested_used_blocks: ref mut prev_nested_used_blocks,
|
||||
..
|
||||
} = self.safety_context
|
||||
{
|
||||
prev_nested_used_blocks.extend(nested_used_blocks);
|
||||
}
|
||||
} else {
|
||||
for block in nested_used_blocks {
|
||||
self.warn_unused_unsafe(
|
||||
block.hir_id,
|
||||
block.span,
|
||||
Some(UnusedUnsafeEnclosing::Block {
|
||||
span: self.tcx.sess.source_map().guess_head_span(span),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if let SafetyContext::UnsafeBlock { used: false, span, hir_id } = self.safety_context {
|
||||
self.warn_unused_unsafe(
|
||||
hir_id,
|
||||
span,
|
||||
if self.unsafe_op_in_unsafe_fn_allowed() {
|
||||
self.body_unsafety
|
||||
.unsafe_fn_sig_span()
|
||||
.map(|span| UnusedUnsafeEnclosing::Function { span })
|
||||
} else {
|
||||
None
|
||||
},
|
||||
);
|
||||
match self.safety_context {
|
||||
SafetyContext::UnsafeBlock {
|
||||
nested_used_blocks: ref mut prev_nested_used_blocks,
|
||||
..
|
||||
} => {
|
||||
prev_nested_used_blocks.push(NestedUsedBlock { hir_id, span });
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
self.safety_context = prev_context;
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,18 +109,12 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
||||
}
|
||||
|
||||
fn warn_unused_unsafe(
|
||||
&self,
|
||||
&mut self,
|
||||
hir_id: hir::HirId,
|
||||
block_span: Span,
|
||||
enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
|
||||
) {
|
||||
let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_UNSAFE,
|
||||
hir_id,
|
||||
block_span,
|
||||
UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe },
|
||||
);
|
||||
self.warnings.push(UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe });
|
||||
}
|
||||
|
||||
/// Whether the `unsafe_op_in_unsafe_fn` lint is `allow`ed at the current HIR node.
|
||||
@ -128,7 +129,14 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
||||
self.tcx.ensure_with_value().mir_built(def);
|
||||
let inner_thir = &inner_thir.steal();
|
||||
let hir_context = self.tcx.hir().local_def_id_to_hir_id(def);
|
||||
let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self };
|
||||
let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe);
|
||||
let mut inner_visitor = UnsafetyVisitor {
|
||||
thir: inner_thir,
|
||||
hir_context,
|
||||
safety_context,
|
||||
warnings: self.warnings,
|
||||
..*self
|
||||
};
|
||||
inner_visitor.visit_expr(&inner_thir[expr]);
|
||||
// Unsafe blocks can be used in the inner body, make sure to take it into account
|
||||
self.safety_context = inner_visitor.safety_context;
|
||||
@ -195,8 +203,15 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||
});
|
||||
}
|
||||
BlockSafety::ExplicitUnsafe(hir_id) => {
|
||||
let used =
|
||||
matches!(self.tcx.lint_level_at_node(UNUSED_UNSAFE, hir_id), (Level::Allow, _));
|
||||
self.in_safety_context(
|
||||
SafetyContext::UnsafeBlock { span: block.span, hir_id, used: false },
|
||||
SafetyContext::UnsafeBlock {
|
||||
span: block.span,
|
||||
hir_id,
|
||||
used,
|
||||
nested_used_blocks: Vec::new(),
|
||||
},
|
||||
|this| visit::walk_block(this, block),
|
||||
);
|
||||
}
|
||||
@ -481,36 +496,29 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone)]
|
||||
enum SafetyContext {
|
||||
Safe,
|
||||
BuiltinUnsafeBlock,
|
||||
UnsafeFn,
|
||||
UnsafeBlock { span: Span, hir_id: hir::HirId, used: bool },
|
||||
UnsafeBlock {
|
||||
span: Span,
|
||||
hir_id: hir::HirId,
|
||||
used: bool,
|
||||
nested_used_blocks: Vec<NestedUsedBlock>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum BodyUnsafety {
|
||||
/// The body is not unsafe.
|
||||
Safe,
|
||||
/// The body is an unsafe function. The span points to
|
||||
/// the signature of the function.
|
||||
Unsafe(Span),
|
||||
struct NestedUsedBlock {
|
||||
hir_id: hir::HirId,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl BodyUnsafety {
|
||||
/// Returns whether the body is unsafe.
|
||||
fn is_unsafe(&self) -> bool {
|
||||
matches!(self, BodyUnsafety::Unsafe(_))
|
||||
}
|
||||
|
||||
/// If the body is unsafe, returns the `Span` of its signature.
|
||||
fn unsafe_fn_sig_span(self) -> Option<Span> {
|
||||
match self {
|
||||
BodyUnsafety::Unsafe(span) => Some(span),
|
||||
BodyUnsafety::Safe => None,
|
||||
}
|
||||
}
|
||||
struct UnusedUnsafeWarning {
|
||||
hir_id: hir::HirId,
|
||||
block_span: Span,
|
||||
enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
@ -803,27 +811,37 @@ pub fn thir_check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
|
||||
}
|
||||
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def);
|
||||
let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| {
|
||||
let safety_context = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
|
||||
if fn_sig.header.unsafety == hir::Unsafety::Unsafe {
|
||||
BodyUnsafety::Unsafe(fn_sig.span)
|
||||
SafetyContext::UnsafeFn
|
||||
} else {
|
||||
BodyUnsafety::Safe
|
||||
SafetyContext::Safe
|
||||
}
|
||||
});
|
||||
let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features;
|
||||
let safety_context =
|
||||
if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
|
||||
let mut warnings = Vec::new();
|
||||
let mut visitor = UnsafetyVisitor {
|
||||
tcx,
|
||||
thir,
|
||||
safety_context,
|
||||
hir_context: hir_id,
|
||||
body_unsafety,
|
||||
body_target_features,
|
||||
assignment_info: None,
|
||||
in_union_destructure: false,
|
||||
param_env: tcx.param_env(def),
|
||||
inside_adt: false,
|
||||
warnings: &mut warnings,
|
||||
};
|
||||
visitor.visit_expr(&thir[expr]);
|
||||
|
||||
warnings.sort_by_key(|w| w.block_span);
|
||||
for UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe } in warnings {
|
||||
let block_span = tcx.sess.source_map().guess_head_span(block_span);
|
||||
tcx.emit_spanned_lint(
|
||||
UNUSED_UNSAFE,
|
||||
hir_id,
|
||||
block_span,
|
||||
UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -392,11 +392,6 @@ pub enum UnusedUnsafeEnclosing {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(mir_build_unused_unsafe_enclosing_fn_label)]
|
||||
Function {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
|
||||
|
@ -20,7 +20,7 @@ mod build;
|
||||
mod check_unsafety;
|
||||
mod errors;
|
||||
pub mod lints;
|
||||
pub mod thir;
|
||||
mod thir;
|
||||
|
||||
use rustc_middle::query::Providers;
|
||||
|
||||
|
@ -191,11 +191,16 @@ impl<'tcx> Cx<'tcx> {
|
||||
source: self.mirror_expr(source),
|
||||
cast: PointerCoercion::ArrayToPointer,
|
||||
}
|
||||
} else {
|
||||
// check whether this is casting an enum variant discriminant
|
||||
// to prevent cycles, we refer to the discriminant initializer
|
||||
} else if let hir::ExprKind::Path(ref qpath) = source.kind
|
||||
&& let res = self.typeck_results().qpath_res(qpath, source.hir_id)
|
||||
&& let ty = self.typeck_results().node_type(source.hir_id)
|
||||
&& let ty::Adt(adt_def, args) = ty.kind()
|
||||
&& let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res
|
||||
{
|
||||
// Check whether this is casting an enum variant discriminant.
|
||||
// To prevent cycles, we refer to the discriminant initializer,
|
||||
// which is always an integer and thus doesn't need to know the
|
||||
// enum's layout (or its tag type) to compute it during const eval
|
||||
// enum's layout (or its tag type) to compute it during const eval.
|
||||
// Example:
|
||||
// enum Foo {
|
||||
// A,
|
||||
@ -204,21 +209,6 @@ impl<'tcx> Cx<'tcx> {
|
||||
// The correct solution would be to add symbolic computations to miri,
|
||||
// so we wouldn't have to compute and store the actual value
|
||||
|
||||
let hir::ExprKind::Path(ref qpath) = source.kind else {
|
||||
return ExprKind::Cast { source: self.mirror_expr(source) };
|
||||
};
|
||||
|
||||
let res = self.typeck_results().qpath_res(qpath, source.hir_id);
|
||||
let ty = self.typeck_results().node_type(source.hir_id);
|
||||
let ty::Adt(adt_def, args) = ty.kind() else {
|
||||
return ExprKind::Cast { source: self.mirror_expr(source) };
|
||||
};
|
||||
|
||||
let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res
|
||||
else {
|
||||
return ExprKind::Cast { source: self.mirror_expr(source) };
|
||||
};
|
||||
|
||||
let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id);
|
||||
let (discr_did, discr_offset) = adt_def.discriminant_def_for_variant(idx);
|
||||
|
||||
@ -255,6 +245,10 @@ impl<'tcx> Cx<'tcx> {
|
||||
};
|
||||
|
||||
ExprKind::Cast { source }
|
||||
} else {
|
||||
// Default to `ExprKind::Cast` for all explicit casts.
|
||||
// MIR building then picks the right MIR casts based on the types.
|
||||
ExprKind::Cast { source: self.mirror_expr(source) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,14 +53,13 @@ use smallvec::{smallvec, SmallVec};
|
||||
use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::{HirId, RangeEnd};
|
||||
use rustc_hir::RangeEnd;
|
||||
use rustc_index::Idx;
|
||||
use rustc_middle::middle::stability::EvalResult;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
|
||||
|
||||
@ -68,7 +67,6 @@ use self::Constructor::*;
|
||||
use self::SliceKind::*;
|
||||
|
||||
use super::usefulness::{MatchCheckCtxt, PatCtxt};
|
||||
use crate::errors::{Overlap, OverlappingRangeEndpoints};
|
||||
|
||||
/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
|
||||
fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
|
||||
@ -111,15 +109,15 @@ pub(crate) struct IntRange {
|
||||
|
||||
impl IntRange {
|
||||
#[inline]
|
||||
fn is_integral(ty: Ty<'_>) -> bool {
|
||||
pub(super) fn is_integral(ty: Ty<'_>) -> bool {
|
||||
matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool)
|
||||
}
|
||||
|
||||
fn is_singleton(&self) -> bool {
|
||||
pub(super) fn is_singleton(&self) -> bool {
|
||||
self.range.start() == self.range.end()
|
||||
}
|
||||
|
||||
fn boundaries(&self) -> (u128, u128) {
|
||||
pub(super) fn boundaries(&self) -> (u128, u128) {
|
||||
(*self.range.start(), *self.range.end())
|
||||
}
|
||||
|
||||
@ -177,23 +175,6 @@ impl IntRange {
|
||||
}
|
||||
}
|
||||
|
||||
fn suspicious_intersection(&self, other: &Self) -> bool {
|
||||
// `false` in the following cases:
|
||||
// 1 ---- // 1 ---------- // 1 ---- // 1 ----
|
||||
// 2 ---------- // 2 ---- // 2 ---- // 2 ----
|
||||
//
|
||||
// The following are currently `false`, but could be `true` in the future (#64007):
|
||||
// 1 --------- // 1 ---------
|
||||
// 2 ---------- // 2 ----------
|
||||
//
|
||||
// `true` in the following cases:
|
||||
// 1 ------- // 1 -------
|
||||
// 2 -------- // 2 -------
|
||||
let (lo, hi) = self.boundaries();
|
||||
let (other_lo, other_hi) = other.boundaries();
|
||||
(lo == other_hi || hi == other_lo) && !self.is_singleton() && !other.is_singleton()
|
||||
}
|
||||
|
||||
/// Partition a range of integers into disjoint subranges. This does constructor splitting for
|
||||
/// integer ranges as explained at the top of the file.
|
||||
///
|
||||
@ -293,7 +274,7 @@ impl IntRange {
|
||||
}
|
||||
|
||||
/// Only used for displaying the range.
|
||||
fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
|
||||
pub(super) fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
|
||||
let (lo, hi) = self.boundaries();
|
||||
|
||||
let bias = IntRange::signed_bias(tcx, ty);
|
||||
@ -315,51 +296,6 @@ impl IntRange {
|
||||
|
||||
Pat { ty, span: DUMMY_SP, kind }
|
||||
}
|
||||
|
||||
/// Lint on likely incorrect range patterns (#63987)
|
||||
pub(super) fn lint_overlapping_range_endpoints<'a, 'p: 'a, 'tcx: 'a>(
|
||||
&self,
|
||||
pcx: &PatCtxt<'_, 'p, 'tcx>,
|
||||
pats: impl Iterator<Item = &'a DeconstructedPat<'p, 'tcx>>,
|
||||
column_count: usize,
|
||||
lint_root: HirId,
|
||||
) {
|
||||
if self.is_singleton() {
|
||||
return;
|
||||
}
|
||||
|
||||
if column_count != 1 {
|
||||
// FIXME: for now, only check for overlapping ranges on simple range
|
||||
// patterns. Otherwise with the current logic the following is detected
|
||||
// as overlapping:
|
||||
// ```
|
||||
// match (0u8, true) {
|
||||
// (0 ..= 125, false) => {}
|
||||
// (125 ..= 255, true) => {}
|
||||
// _ => {}
|
||||
// }
|
||||
// ```
|
||||
return;
|
||||
}
|
||||
|
||||
let overlap: Vec<_> = pats
|
||||
.filter_map(|pat| Some((pat.ctor().as_int_range()?, pat.span())))
|
||||
.filter(|(range, _)| self.suspicious_intersection(range))
|
||||
.map(|(range, span)| Overlap {
|
||||
range: self.intersection(&range).unwrap().to_pat(pcx.cx.tcx, pcx.ty),
|
||||
span,
|
||||
})
|
||||
.collect();
|
||||
|
||||
if !overlap.is_empty() {
|
||||
pcx.cx.tcx.emit_spanned_lint(
|
||||
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
|
||||
lint_root,
|
||||
pcx.span,
|
||||
OverlappingRangeEndpoints { overlap, range: pcx.span },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Note: this is often not what we want: e.g. `false` is converted into the range `0..=0` and
|
||||
@ -644,7 +580,7 @@ impl<'tcx> Constructor<'tcx> {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn as_int_range(&self) -> Option<&IntRange> {
|
||||
pub(super) fn as_int_range(&self) -> Option<&IntRange> {
|
||||
match self {
|
||||
IntRange(range) => Some(range),
|
||||
_ => None,
|
||||
|
@ -307,8 +307,10 @@
|
||||
|
||||
use self::ArmType::*;
|
||||
use self::Usefulness::*;
|
||||
use super::deconstruct_pat::{Constructor, ConstructorSet, DeconstructedPat, WitnessPat};
|
||||
use crate::errors::{NonExhaustiveOmittedPattern, Uncovered};
|
||||
use super::deconstruct_pat::{
|
||||
Constructor, ConstructorSet, DeconstructedPat, IntRange, SplitConstructorSet, WitnessPat,
|
||||
};
|
||||
use crate::errors::{NonExhaustiveOmittedPattern, Overlap, OverlappingRangeEndpoints, Uncovered};
|
||||
|
||||
use rustc_data_structures::captures::Captures;
|
||||
|
||||
@ -317,6 +319,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
@ -473,11 +476,6 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
||||
Matrix { patterns: vec![] }
|
||||
}
|
||||
|
||||
/// Number of columns of this matrix. `None` is the matrix is empty.
|
||||
pub(super) fn column_count(&self) -> Option<usize> {
|
||||
self.patterns.get(0).map(|r| r.len())
|
||||
}
|
||||
|
||||
/// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
|
||||
/// expands it.
|
||||
fn push(&mut self, row: PatStack<'p, 'tcx>) {
|
||||
@ -833,15 +831,6 @@ fn is_useful<'p, 'tcx>(
|
||||
|
||||
let v_ctor = v.head().ctor();
|
||||
debug!(?v_ctor);
|
||||
if let Constructor::IntRange(ctor_range) = &v_ctor {
|
||||
// Lint on likely incorrect range patterns (#63987)
|
||||
ctor_range.lint_overlapping_range_endpoints(
|
||||
pcx,
|
||||
matrix.heads(),
|
||||
matrix.column_count().unwrap_or(0),
|
||||
lint_root,
|
||||
)
|
||||
}
|
||||
// We split the head constructor of `v`.
|
||||
let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
|
||||
// For each constructor, we compute whether there's a value that starts with it that would
|
||||
@ -875,22 +864,102 @@ fn is_useful<'p, 'tcx>(
|
||||
ret
|
||||
}
|
||||
|
||||
/// A column of patterns in the matrix, where a column is the intuitive notion of "subpatterns that
|
||||
/// inspect the same subvalue".
|
||||
/// This is used to traverse patterns column-by-column for lints. Despite similarities with
|
||||
/// `is_useful`, this is a different traversal. Notably this is linear in the depth of patterns,
|
||||
/// whereas `is_useful` is worst-case exponential (exhaustiveness is NP-complete).
|
||||
#[derive(Debug)]
|
||||
struct PatternColumn<'p, 'tcx> {
|
||||
patterns: Vec<&'p DeconstructedPat<'p, 'tcx>>,
|
||||
}
|
||||
|
||||
impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
|
||||
fn new(patterns: Vec<&'p DeconstructedPat<'p, 'tcx>>) -> Self {
|
||||
Self { patterns }
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.patterns.is_empty()
|
||||
}
|
||||
fn head_ty(&self) -> Option<Ty<'tcx>> {
|
||||
if self.patterns.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
// If the type is opaque and it is revealed anywhere in the column, we take the revealed
|
||||
// version. Otherwise we could encounter constructors for the revealed type and crash.
|
||||
let is_opaque = |ty: Ty<'tcx>| matches!(ty.kind(), ty::Alias(ty::Opaque, ..));
|
||||
let first_ty = self.patterns[0].ty();
|
||||
if is_opaque(first_ty) {
|
||||
for pat in &self.patterns {
|
||||
let ty = pat.ty();
|
||||
if !is_opaque(ty) {
|
||||
return Some(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(first_ty)
|
||||
}
|
||||
|
||||
fn analyze_ctors(&self, pcx: &PatCtxt<'_, 'p, 'tcx>) -> SplitConstructorSet<'tcx> {
|
||||
let column_ctors = self.patterns.iter().map(|p| p.ctor());
|
||||
ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, column_ctors)
|
||||
}
|
||||
fn iter<'a>(&'a self) -> impl Iterator<Item = &'p DeconstructedPat<'p, 'tcx>> + Captures<'a> {
|
||||
self.patterns.iter().copied()
|
||||
}
|
||||
|
||||
/// Does specialization: given a constructor, this takes the patterns from the column that match
|
||||
/// the constructor, and outputs their fields.
|
||||
/// This returns one column per field of the constructor. The normally all have the same length
|
||||
/// (the number of patterns in `self` that matched `ctor`), except that we expand or-patterns
|
||||
/// which may change the lengths.
|
||||
fn specialize(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Vec<Self> {
|
||||
let arity = ctor.arity(pcx);
|
||||
if arity == 0 {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
// We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These
|
||||
// columns may have different lengths in the presence of or-patterns (this is why we can't
|
||||
// reuse `Matrix`).
|
||||
let mut specialized_columns: Vec<_> =
|
||||
(0..arity).map(|_| Self { patterns: Vec::new() }).collect();
|
||||
let relevant_patterns =
|
||||
self.patterns.iter().filter(|pat| ctor.is_covered_by(pcx, pat.ctor()));
|
||||
for pat in relevant_patterns {
|
||||
let specialized = pat.specialize(pcx, &ctor);
|
||||
for (subpat, column) in specialized.iter().zip(&mut specialized_columns) {
|
||||
if subpat.is_or_pat() {
|
||||
column.patterns.extend(subpat.iter_fields())
|
||||
} else {
|
||||
column.patterns.push(subpat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert!(
|
||||
!specialized_columns[0].is_empty(),
|
||||
"ctor {ctor:?} was listed as present but isn't;
|
||||
there is an inconsistency between `Constructor::is_covered_by` and `ConstructorSet::split`"
|
||||
);
|
||||
specialized_columns
|
||||
}
|
||||
}
|
||||
|
||||
/// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned
|
||||
/// in a given column. This traverses patterns column-by-column, where a column is the intuitive
|
||||
/// notion of "subpatterns that inspect the same subvalue".
|
||||
/// Despite similarities with `is_useful`, this traversal is different. Notably this is linear in the
|
||||
/// depth of patterns, whereas `is_useful` is worst-case exponential (exhaustiveness is NP-complete).
|
||||
/// in a given column.
|
||||
#[instrument(level = "debug", skip(cx), ret)]
|
||||
fn collect_nonexhaustive_missing_variants<'p, 'tcx>(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
column: &[&DeconstructedPat<'p, 'tcx>],
|
||||
column: &PatternColumn<'p, 'tcx>,
|
||||
) -> Vec<WitnessPat<'tcx>> {
|
||||
if column.is_empty() {
|
||||
let Some(ty) = column.head_ty() else {
|
||||
return Vec::new();
|
||||
}
|
||||
let ty = column[0].ty();
|
||||
};
|
||||
let pcx = &PatCtxt { cx, ty, span: DUMMY_SP, is_top_level: false };
|
||||
|
||||
let set = ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, column.iter().map(|p| p.ctor()));
|
||||
let set = column.analyze_ctors(pcx);
|
||||
if set.present.is_empty() {
|
||||
// We can't consistently handle the case where no constructors are present (since this would
|
||||
// require digging deep through any type in case there's a non_exhaustive enum somewhere),
|
||||
@ -911,35 +980,11 @@ fn collect_nonexhaustive_missing_variants<'p, 'tcx>(
|
||||
|
||||
// Recurse into the fields.
|
||||
for ctor in set.present {
|
||||
let arity = ctor.arity(pcx);
|
||||
if arity == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These
|
||||
// columns may have different lengths in the presence of or-patterns (this is why we can't
|
||||
// reuse `Matrix`).
|
||||
let mut specialized_columns: Vec<Vec<_>> = (0..arity).map(|_| Vec::new()).collect();
|
||||
let relevant_patterns = column.iter().filter(|pat| ctor.is_covered_by(pcx, pat.ctor()));
|
||||
for pat in relevant_patterns {
|
||||
let specialized = pat.specialize(pcx, &ctor);
|
||||
for (subpat, sub_column) in specialized.iter().zip(&mut specialized_columns) {
|
||||
if subpat.is_or_pat() {
|
||||
sub_column.extend(subpat.iter_fields())
|
||||
} else {
|
||||
sub_column.push(subpat)
|
||||
}
|
||||
}
|
||||
}
|
||||
debug_assert!(
|
||||
!specialized_columns[0].is_empty(),
|
||||
"ctor {ctor:?} was listed as present but isn't"
|
||||
);
|
||||
|
||||
let specialized_columns = column.specialize(pcx, &ctor);
|
||||
let wild_pat = WitnessPat::wild_from_ctor(pcx, ctor);
|
||||
for (i, col_i) in specialized_columns.iter().enumerate() {
|
||||
// Compute witnesses for each column.
|
||||
let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i.as_slice());
|
||||
let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i);
|
||||
// For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`,
|
||||
// adding enough wildcards to match `arity`.
|
||||
for wit in wits_for_col_i {
|
||||
@ -952,6 +997,81 @@ fn collect_nonexhaustive_missing_variants<'p, 'tcx>(
|
||||
witnesses
|
||||
}
|
||||
|
||||
/// Traverse the patterns to warn the user about ranges that overlap on their endpoints.
|
||||
#[instrument(level = "debug", skip(cx, lint_root))]
|
||||
fn lint_overlapping_range_endpoints<'p, 'tcx>(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
column: &PatternColumn<'p, 'tcx>,
|
||||
lint_root: HirId,
|
||||
) {
|
||||
let Some(ty) = column.head_ty() else {
|
||||
return;
|
||||
};
|
||||
let pcx = &PatCtxt { cx, ty, span: DUMMY_SP, is_top_level: false };
|
||||
|
||||
let set = column.analyze_ctors(pcx);
|
||||
|
||||
if IntRange::is_integral(ty) {
|
||||
let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| {
|
||||
let overlap_as_pat = overlap.to_pat(cx.tcx, ty);
|
||||
let overlaps: Vec<_> = overlapped_spans
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|span| Overlap { range: overlap_as_pat.clone(), span })
|
||||
.collect();
|
||||
cx.tcx.emit_spanned_lint(
|
||||
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
|
||||
lint_root,
|
||||
this_span,
|
||||
OverlappingRangeEndpoints { overlap: overlaps, range: this_span },
|
||||
);
|
||||
};
|
||||
|
||||
// If two ranges overlapped, the split set will contain their intersection as a singleton.
|
||||
let split_int_ranges = set.present.iter().filter_map(|c| c.as_int_range());
|
||||
for overlap_range in split_int_ranges.clone() {
|
||||
if overlap_range.is_singleton() {
|
||||
let overlap: u128 = overlap_range.boundaries().0;
|
||||
// Spans of ranges that start or end with the overlap.
|
||||
let mut prefixes: SmallVec<[_; 1]> = Default::default();
|
||||
let mut suffixes: SmallVec<[_; 1]> = Default::default();
|
||||
// Iterate on patterns that contained `overlap`.
|
||||
for pat in column.iter() {
|
||||
let this_span = pat.span();
|
||||
let Constructor::IntRange(this_range) = pat.ctor() else { continue };
|
||||
if this_range.is_singleton() {
|
||||
// Don't lint when one of the ranges is a singleton.
|
||||
continue;
|
||||
}
|
||||
let (start, end) = this_range.boundaries();
|
||||
if start == overlap {
|
||||
// `this_range` looks like `overlap..=end`; it overlaps with any ranges that
|
||||
// look like `start..=overlap`.
|
||||
if !prefixes.is_empty() {
|
||||
emit_lint(overlap_range, this_span, &prefixes);
|
||||
}
|
||||
suffixes.push(this_span)
|
||||
} else if end == overlap {
|
||||
// `this_range` looks like `start..=overlap`; it overlaps with any ranges
|
||||
// that look like `overlap..=end`.
|
||||
if !suffixes.is_empty() {
|
||||
emit_lint(overlap_range, this_span, &suffixes);
|
||||
}
|
||||
prefixes.push(this_span)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Recurse into the fields.
|
||||
for ctor in set.present {
|
||||
for col in column.specialize(pcx, &ctor) {
|
||||
lint_overlapping_range_endpoints(cx, &col, lint_root);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The arm of a match expression.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) struct MatchArm<'p, 'tcx> {
|
||||
@ -1022,6 +1142,10 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
|
||||
NoWitnesses { .. } => bug!(),
|
||||
};
|
||||
|
||||
let pat_column = arms.iter().flat_map(|arm| arm.pat.flatten_or_pat()).collect::<Vec<_>>();
|
||||
let pat_column = PatternColumn::new(pat_column);
|
||||
lint_overlapping_range_endpoints(cx, &pat_column, lint_root);
|
||||
|
||||
// Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
|
||||
// `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
|
||||
if cx.refutable
|
||||
@ -1031,9 +1155,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
|
||||
rustc_session::lint::Level::Allow
|
||||
)
|
||||
{
|
||||
let pat_column = arms.iter().flat_map(|arm| arm.pat.flatten_or_pat()).collect::<Vec<_>>();
|
||||
let witnesses = collect_nonexhaustive_missing_variants(cx, &pat_column);
|
||||
|
||||
if !witnesses.is_empty() {
|
||||
// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
|
||||
// is not exhaustive enough.
|
||||
|
@ -438,10 +438,8 @@ impl<'tcx> Inliner<'tcx> {
|
||||
return Err("incompatible instruction set");
|
||||
}
|
||||
|
||||
for feature in &callee_attrs.target_features {
|
||||
if !self.codegen_fn_attrs.target_features.contains(feature) {
|
||||
return Err("incompatible target feature");
|
||||
}
|
||||
if callee_attrs.target_features != self.codegen_fn_attrs.target_features {
|
||||
return Err("incompatible target features");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -20,6 +20,7 @@ extern crate tracing;
|
||||
#[macro_use]
|
||||
extern crate rustc_middle;
|
||||
|
||||
use hir::ConstContext;
|
||||
use required_consts::RequiredConstsVisitor;
|
||||
use rustc_const_eval::util;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
@ -251,8 +252,13 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {
|
||||
let const_kind = tcx.hir().body_const_context(def);
|
||||
|
||||
// No need to const-check a non-const `fn`.
|
||||
if const_kind.is_none() {
|
||||
return Default::default();
|
||||
match const_kind {
|
||||
Some(ConstContext::Const { .. } | ConstContext::Static(_))
|
||||
| Some(ConstContext::ConstFn) => {}
|
||||
None => span_bug!(
|
||||
tcx.def_span(def),
|
||||
"`mir_const_qualif` should only be called on const fns and const items"
|
||||
),
|
||||
}
|
||||
|
||||
// N.B., this `borrow()` is guaranteed to be valid (i.e., the value
|
||||
@ -317,7 +323,21 @@ fn mir_promoted(
|
||||
// Ensure that we compute the `mir_const_qualif` for constants at
|
||||
// this point, before we steal the mir-const result.
|
||||
// Also this means promotion can rely on all const checks having been done.
|
||||
let const_qualifs = tcx.mir_const_qualif(def);
|
||||
|
||||
let const_qualifs = match tcx.def_kind(def) {
|
||||
DefKind::Fn | DefKind::AssocFn | DefKind::Closure
|
||||
if tcx.constness(def) == hir::Constness::Const
|
||||
|| tcx.is_const_default_method(def.to_def_id()) =>
|
||||
{
|
||||
tcx.mir_const_qualif(def)
|
||||
}
|
||||
DefKind::AssocConst
|
||||
| DefKind::Const
|
||||
| DefKind::Static(_)
|
||||
| DefKind::InlineConst
|
||||
| DefKind::AnonConst => tcx.mir_const_qualif(def),
|
||||
_ => ConstQualifs::default(),
|
||||
};
|
||||
let mut body = tcx.mir_const(def).steal();
|
||||
if let Some(error_reported) = const_qualifs.tainted_by_errors {
|
||||
body.tainted_by_errors = Some(error_reported);
|
||||
|
@ -504,8 +504,10 @@ impl<'a> Parser<'a> {
|
||||
|
||||
// Special-case "expected `;`" errors
|
||||
if expected.contains(&TokenType::Token(token::Semi)) {
|
||||
if self.prev_token == token::Question && self.maybe_recover_from_ternary_operator() {
|
||||
return Ok(true);
|
||||
// If the user is trying to write a ternary expression, recover it and
|
||||
// return an Err to prevent a cascade of irrelevant diagnostics
|
||||
if self.prev_token == token::Question && let Err(e) = self.maybe_recover_from_ternary_operator() {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP {
|
||||
@ -1428,10 +1430,10 @@ impl<'a> Parser<'a> {
|
||||
|
||||
/// Rust has no ternary operator (`cond ? then : else`). Parse it and try
|
||||
/// to recover from it if `then` and `else` are valid expressions. Returns
|
||||
/// whether it was a ternary operator.
|
||||
pub(super) fn maybe_recover_from_ternary_operator(&mut self) -> bool {
|
||||
/// an err if this appears to be a ternary expression.
|
||||
pub(super) fn maybe_recover_from_ternary_operator(&mut self) -> PResult<'a, ()> {
|
||||
if self.prev_token != token::Question {
|
||||
return false;
|
||||
return PResult::Ok(());
|
||||
}
|
||||
|
||||
let lo = self.prev_token.span.lo();
|
||||
@ -1449,20 +1451,18 @@ impl<'a> Parser<'a> {
|
||||
if self.eat_noexpect(&token::Colon) {
|
||||
match self.parse_expr() {
|
||||
Ok(_) => {
|
||||
self.sess.emit_err(TernaryOperator { span: self.token.span.with_lo(lo) });
|
||||
return true;
|
||||
return Err(self
|
||||
.sess
|
||||
.create_err(TernaryOperator { span: self.token.span.with_lo(lo) }));
|
||||
}
|
||||
Err(err) => {
|
||||
err.cancel();
|
||||
self.restore_snapshot(snapshot);
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
self.restore_snapshot(snapshot);
|
||||
};
|
||||
|
||||
false
|
||||
}
|
||||
self.restore_snapshot(snapshot);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> {
|
||||
|
@ -159,8 +159,9 @@ pub struct Parser<'a> {
|
||||
/// appropriately.
|
||||
///
|
||||
/// See the comments in the `parse_path_segment` function for more details.
|
||||
unmatched_angle_bracket_count: u32,
|
||||
max_angle_bracket_count: u32,
|
||||
unmatched_angle_bracket_count: u16,
|
||||
max_angle_bracket_count: u16,
|
||||
angle_bracket_nesting: u16,
|
||||
|
||||
last_unexpected_token_span: Option<Span>,
|
||||
/// If present, this `Parser` is not parsing Rust code but rather a macro call.
|
||||
@ -394,6 +395,7 @@ impl<'a> Parser<'a> {
|
||||
break_last_token: false,
|
||||
unmatched_angle_bracket_count: 0,
|
||||
max_angle_bracket_count: 0,
|
||||
angle_bracket_nesting: 0,
|
||||
last_unexpected_token_span: None,
|
||||
subparser_name,
|
||||
capture_state: CaptureState {
|
||||
|
@ -487,10 +487,24 @@ impl<'a> Parser<'a> {
|
||||
// Take a snapshot before attempting to parse - we can restore this later.
|
||||
let snapshot = is_first_invocation.then(|| self.clone());
|
||||
|
||||
self.angle_bracket_nesting += 1;
|
||||
debug!("parse_generic_args_with_leading_angle_bracket_recovery: (snapshotting)");
|
||||
match self.parse_angle_args(ty_generics) {
|
||||
Ok(args) => Ok(args),
|
||||
Ok(args) => {
|
||||
self.angle_bracket_nesting -= 1;
|
||||
Ok(args)
|
||||
}
|
||||
Err(mut e) if self.angle_bracket_nesting > 10 => {
|
||||
self.angle_bracket_nesting -= 1;
|
||||
// When encountering severely malformed code where there are several levels of
|
||||
// nested unclosed angle args (`f::<f::<f::<f::<...`), we avoid severe O(n^2)
|
||||
// behavior by bailing out earlier (#117080).
|
||||
e.emit();
|
||||
rustc_errors::FatalError.raise();
|
||||
}
|
||||
Err(e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
|
||||
self.angle_bracket_nesting -= 1;
|
||||
|
||||
// Swap `self` with our backup of the parser state before attempting to parse
|
||||
// generic arguments.
|
||||
let snapshot = mem::replace(self, snapshot.unwrap());
|
||||
@ -520,8 +534,8 @@ impl<'a> Parser<'a> {
|
||||
// Make a span over ${unmatched angle bracket count} characters.
|
||||
// This is safe because `all_angle_brackets` ensures that there are only `<`s,
|
||||
// i.e. no multibyte characters, in this range.
|
||||
let span =
|
||||
lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
|
||||
let span = lo
|
||||
.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count.into()));
|
||||
self.sess.emit_err(errors::UnmatchedAngle {
|
||||
span,
|
||||
plural: snapshot.unmatched_angle_bracket_count > 1,
|
||||
@ -531,7 +545,10 @@ impl<'a> Parser<'a> {
|
||||
self.parse_angle_args(ty_generics)
|
||||
}
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
Err(e) => {
|
||||
self.angle_bracket_nesting -= 1;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,6 +393,9 @@ passes_invalid_attr_at_crate_level =
|
||||
`{$name}` attribute cannot be used at crate level
|
||||
.suggestion = perhaps you meant to use an outer attribute
|
||||
|
||||
passes_invalid_attr_at_crate_level_item =
|
||||
the inner attribute doesn't annotate this {$kind}
|
||||
|
||||
passes_invalid_deprecation_version =
|
||||
invalid deprecation version found
|
||||
.label = invalid deprecation version
|
||||
@ -402,11 +405,6 @@ passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]
|
||||
|
||||
passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
|
||||
|
||||
passes_invalid_stability =
|
||||
invalid stability version found
|
||||
.label = invalid stability version
|
||||
.item = the stability attribute annotates this item
|
||||
|
||||
passes_lang_item_fn_with_target_feature =
|
||||
`{$name}` language item function is not allowed to have `#[target_feature]`
|
||||
.label = `{$name}` language item function is not allowed to have `#[target_feature]`
|
||||
|
@ -2534,10 +2534,30 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
|
||||
if attr.style == AttrStyle::Inner {
|
||||
for attr_to_check in ATTRS_TO_CHECK {
|
||||
if attr.has_name(*attr_to_check) {
|
||||
let item = tcx
|
||||
.hir()
|
||||
.items()
|
||||
.map(|id| tcx.hir().item(id))
|
||||
.find(|item| !item.span.is_dummy()) // Skip prelude `use`s
|
||||
.map(|item| errors::ItemFollowingInnerAttr {
|
||||
span: item.ident.span,
|
||||
kind: item.kind.descr(),
|
||||
});
|
||||
tcx.sess.emit_err(errors::InvalidAttrAtCrateLevel {
|
||||
span: attr.span,
|
||||
snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(),
|
||||
sugg_span: tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(attr.span)
|
||||
.ok()
|
||||
.filter(|src| src.starts_with("#!["))
|
||||
.map(|_| {
|
||||
attr.span
|
||||
.with_lo(attr.span.lo() + BytePos(1))
|
||||
.with_hi(attr.span.lo() + BytePos(2))
|
||||
}),
|
||||
name: *attr_to_check,
|
||||
item,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -856,8 +856,15 @@ pub struct UnknownLangItem {
|
||||
|
||||
pub struct InvalidAttrAtCrateLevel {
|
||||
pub span: Span,
|
||||
pub snippet: Option<String>,
|
||||
pub sugg_span: Option<Span>,
|
||||
pub name: Symbol,
|
||||
pub item: Option<ItemFollowingInnerAttr>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ItemFollowingInnerAttr {
|
||||
pub span: Span,
|
||||
pub kind: &'static str,
|
||||
}
|
||||
|
||||
impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
|
||||
@ -871,15 +878,18 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
|
||||
diag.set_arg("name", self.name);
|
||||
// Only emit an error with a suggestion if we can create a string out
|
||||
// of the attribute span
|
||||
if let Some(src) = self.snippet {
|
||||
let replacement = src.replace("#!", "#");
|
||||
if let Some(span) = self.sugg_span {
|
||||
diag.span_suggestion_verbose(
|
||||
self.span,
|
||||
span,
|
||||
fluent::passes_suggestion,
|
||||
replacement,
|
||||
String::new(),
|
||||
rustc_errors::Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
if let Some(item) = self.item {
|
||||
diag.set_arg("kind", item.kind);
|
||||
diag.span_label(item.span, fluent::passes_invalid_attr_at_crate_level_item);
|
||||
}
|
||||
diag
|
||||
}
|
||||
}
|
||||
@ -1504,16 +1514,6 @@ pub struct UselessStability {
|
||||
pub item_sp: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_invalid_stability)]
|
||||
pub struct InvalidStability {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[label(passes_item)]
|
||||
pub item_sp: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_cannot_stabilize_deprecated)]
|
||||
pub struct CannotStabilizeDeprecated {
|
||||
|
@ -5,7 +5,7 @@
|
||||
//! collect them instead.
|
||||
|
||||
use rustc_ast::Attribute;
|
||||
use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER};
|
||||
use rustc_attr::VERSION_PLACEHOLDER;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::middle::lib_features::LibFeatures;
|
||||
@ -59,7 +59,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
|
||||
if let Some(s) = since
|
||||
&& s.as_str() == VERSION_PLACEHOLDER
|
||||
{
|
||||
since = Some(rust_version_symbol());
|
||||
since = Some(sym::env_CFG_RELEASE);
|
||||
}
|
||||
|
||||
if let Some(feature) = feature {
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
use crate::errors;
|
||||
use rustc_attr::{
|
||||
self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable,
|
||||
UnstableReason, VERSION_PLACEHOLDER,
|
||||
self as attr, ConstStability, Since, Stability, StabilityLevel, Unstable, UnstableReason,
|
||||
VERSION_PLACEHOLDER,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
use rustc_hir as hir;
|
||||
@ -226,37 +226,43 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||
if let (&Some(dep_since), &attr::Stable { since: stab_since, .. }) =
|
||||
(&depr.as_ref().and_then(|(d, _)| d.since), &stab.level)
|
||||
{
|
||||
// Explicit version of iter::order::lt to handle parse errors properly
|
||||
for (dep_v, stab_v) in
|
||||
iter::zip(dep_since.as_str().split('.'), stab_since.as_str().split('.'))
|
||||
{
|
||||
match stab_v.parse::<u64>() {
|
||||
Err(_) => {
|
||||
self.tcx.sess.emit_err(errors::InvalidStability { span, item_sp });
|
||||
break;
|
||||
}
|
||||
Ok(stab_vp) => match dep_v.parse::<u64>() {
|
||||
Ok(dep_vp) => match dep_vp.cmp(&stab_vp) {
|
||||
Ordering::Less => {
|
||||
self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated {
|
||||
span,
|
||||
item_sp,
|
||||
});
|
||||
match stab_since {
|
||||
Since::Current => {
|
||||
self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
|
||||
}
|
||||
Since::Version(stab_since) => {
|
||||
// Explicit version of iter::order::lt to handle parse errors properly
|
||||
for (dep_v, stab_v) in iter::zip(
|
||||
dep_since.as_str().split('.'),
|
||||
[stab_since.major, stab_since.minor, stab_since.patch],
|
||||
) {
|
||||
match dep_v.parse::<u64>() {
|
||||
Ok(dep_vp) => match dep_vp.cmp(&u64::from(stab_v)) {
|
||||
Ordering::Less => {
|
||||
self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated {
|
||||
span,
|
||||
item_sp,
|
||||
});
|
||||
break;
|
||||
}
|
||||
Ordering::Equal => continue,
|
||||
Ordering::Greater => break,
|
||||
},
|
||||
Err(_) => {
|
||||
if dep_v != "TBD" {
|
||||
self.tcx.sess.emit_err(errors::InvalidDeprecationVersion {
|
||||
span,
|
||||
item_sp,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
Ordering::Equal => continue,
|
||||
Ordering::Greater => break,
|
||||
},
|
||||
Err(_) => {
|
||||
if dep_v != "TBD" {
|
||||
self.tcx.sess.emit_err(errors::InvalidDeprecationVersion {
|
||||
span,
|
||||
item_sp,
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
Since::Err => {
|
||||
// An error already reported. Assume the unparseable stabilization
|
||||
// version is older than the deprecation version.
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1109,7 +1115,7 @@ fn unnecessary_stable_feature_lint(
|
||||
mut since: Symbol,
|
||||
) {
|
||||
if since.as_str() == VERSION_PLACEHOLDER {
|
||||
since = rust_version_symbol();
|
||||
since = sym::env_CFG_RELEASE;
|
||||
}
|
||||
tcx.emit_spanned_lint(
|
||||
lint::builtin::STABLE_FEATURES,
|
||||
|
@ -210,22 +210,7 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::Alias(ty::Weak, alias) => {
|
||||
self.def_id_visitor.visit_def_id(alias.def_id, "type alias", &ty);
|
||||
}
|
||||
ty::Alias(ty::Projection, proj) => {
|
||||
if V::SKIP_ASSOC_TYS {
|
||||
// Visitors searching for minimal visibility/reachability want to
|
||||
// conservatively approximate associated types like `<Type as Trait>::Alias`
|
||||
// as visible/reachable even if both `Type` and `Trait` are private.
|
||||
// Ideally, associated types should be substituted in the same way as
|
||||
// free type aliases, but this isn't done yet.
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
// This will also visit args if necessary, so we don't need to recurse.
|
||||
return self.visit_projection_ty(proj);
|
||||
}
|
||||
ty::Alias(ty::Inherent, data) => {
|
||||
ty::Alias(kind @ (ty::Inherent | ty::Weak | ty::Projection), data) => {
|
||||
if V::SKIP_ASSOC_TYS {
|
||||
// Visitors searching for minimal visibility/reachability want to
|
||||
// conservatively approximate associated types like `Type::Alias`
|
||||
@ -235,9 +220,14 @@ where
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
let kind = match kind {
|
||||
ty::Inherent | ty::Projection => "associated type",
|
||||
ty::Weak => "type alias",
|
||||
ty::Opaque => unreachable!(),
|
||||
};
|
||||
self.def_id_visitor.visit_def_id(
|
||||
data.def_id,
|
||||
"associated type",
|
||||
kind,
|
||||
&LazyDefPathStr { def_id: data.def_id, tcx },
|
||||
)?;
|
||||
|
||||
|
@ -197,6 +197,9 @@ macro_rules! handle_cycle_error {
|
||||
([(fatal_cycle) $($rest:tt)*]) => {{
|
||||
rustc_query_system::HandleCycleError::Fatal
|
||||
}};
|
||||
([(cycle_stash) $($rest:tt)*]) => {{
|
||||
rustc_query_system::HandleCycleError::Stash
|
||||
}};
|
||||
([(cycle_delay_bug) $($rest:tt)*]) => {{
|
||||
rustc_query_system::HandleCycleError::DelayBug
|
||||
}};
|
||||
|
@ -15,6 +15,7 @@ pub enum HandleCycleError {
|
||||
Error,
|
||||
Fatal,
|
||||
DelayBug,
|
||||
Stash,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
@ -19,7 +19,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_data_structures::sync::Lock;
|
||||
#[cfg(parallel_compiler)]
|
||||
use rustc_data_structures::{outline, sync};
|
||||
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, FatalError};
|
||||
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, FatalError, StashKey};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use std::cell::Cell;
|
||||
use std::collections::hash_map::Entry;
|
||||
@ -133,6 +133,17 @@ where
|
||||
let guar = error.delay_as_bug();
|
||||
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar)
|
||||
}
|
||||
Stash => {
|
||||
let guar = if let Some(root) = cycle_error.cycle.first()
|
||||
&& let Some(span) = root.query.span
|
||||
{
|
||||
error.stash(span, StashKey::Cycle);
|
||||
qcx.dep_context().sess().delay_span_bug(span, "delayed cycle error")
|
||||
} else {
|
||||
error.emit()
|
||||
};
|
||||
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,7 +335,7 @@ impl Resolver<'_, '_> {
|
||||
|
||||
for unused in visitor.unused_imports.values() {
|
||||
let mut fixes = Vec::new();
|
||||
let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
|
||||
let spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) {
|
||||
UnusedSpanResult::Used => continue,
|
||||
UnusedSpanResult::FlatUnused(span, remove) => {
|
||||
fixes.push((remove, String::new()));
|
||||
@ -353,20 +353,19 @@ impl Resolver<'_, '_> {
|
||||
}
|
||||
};
|
||||
|
||||
let len = spans.len();
|
||||
spans.sort();
|
||||
let ms = MultiSpan::from_spans(spans.clone());
|
||||
let mut span_snippets = spans
|
||||
let ms = MultiSpan::from_spans(spans);
|
||||
|
||||
let mut span_snippets = ms
|
||||
.primary_spans()
|
||||
.iter()
|
||||
.filter_map(|s| match tcx.sess.source_map().span_to_snippet(*s) {
|
||||
Ok(s) => Some(format!("`{s}`")),
|
||||
_ => None,
|
||||
})
|
||||
.filter_map(|span| tcx.sess.source_map().span_to_snippet(*span).ok())
|
||||
.map(|s| format!("`{s}`"))
|
||||
.collect::<Vec<String>>();
|
||||
span_snippets.sort();
|
||||
|
||||
let msg = format!(
|
||||
"unused import{}{}",
|
||||
pluralize!(len),
|
||||
pluralize!(ms.primary_spans().len()),
|
||||
if !span_snippets.is_empty() {
|
||||
format!(": {}", span_snippets.join(", "))
|
||||
} else {
|
||||
@ -376,7 +375,7 @@ impl Resolver<'_, '_> {
|
||||
|
||||
let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
|
||||
"remove the whole `use` item"
|
||||
} else if spans.len() > 1 {
|
||||
} else if ms.primary_spans().len() > 1 {
|
||||
"remove the unused imports"
|
||||
} else {
|
||||
"remove the unused import"
|
||||
|
@ -25,7 +25,7 @@ use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, Span, SyntaxContext};
|
||||
use thin_vec::ThinVec;
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
||||
use crate::errors::{
|
||||
AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
|
||||
@ -1147,7 +1147,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
namespace: Namespace,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
start_module: Module<'a>,
|
||||
crate_name: Ident,
|
||||
crate_path: ThinVec<ast::PathSegment>,
|
||||
filter_fn: FilterFn,
|
||||
) -> Vec<ImportSuggestion>
|
||||
where
|
||||
@ -1163,8 +1163,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
Some(x) => Some(x),
|
||||
} {
|
||||
let in_module_is_extern = !in_module.def_id().is_local();
|
||||
// We have to visit module children in deterministic order to avoid
|
||||
// instabilities in reported imports (#43552).
|
||||
in_module.for_each_child(self, |this, ident, ns, name_binding| {
|
||||
// avoid non-importable candidates
|
||||
if !name_binding.is_importable() {
|
||||
@ -1214,12 +1212,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
let res = name_binding.res();
|
||||
if filter_fn(res) {
|
||||
// create the path
|
||||
let mut segms = path_segments.clone();
|
||||
if lookup_ident.span.at_least_rust_2018() {
|
||||
let mut segms = if lookup_ident.span.at_least_rust_2018() {
|
||||
// crate-local absolute paths start with `crate::` in edition 2018
|
||||
// FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
|
||||
segms.insert(0, ast::PathSegment::from_ident(crate_name));
|
||||
}
|
||||
crate_path.clone()
|
||||
} else {
|
||||
ThinVec::new()
|
||||
};
|
||||
segms.append(&mut path_segments.clone());
|
||||
|
||||
segms.push(ast::PathSegment::from_ident(ident));
|
||||
let path = Path { span: name_binding.span, segments: segms, tokens: None };
|
||||
@ -1318,18 +1318,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
where
|
||||
FilterFn: Fn(Res) -> bool,
|
||||
{
|
||||
let crate_path = thin_vec![ast::PathSegment::from_ident(Ident::with_dummy_span(kw::Crate))];
|
||||
let mut suggestions = self.lookup_import_candidates_from_module(
|
||||
lookup_ident,
|
||||
namespace,
|
||||
parent_scope,
|
||||
self.graph_root,
|
||||
Ident::with_dummy_span(kw::Crate),
|
||||
crate_path,
|
||||
&filter_fn,
|
||||
);
|
||||
|
||||
if lookup_ident.span.at_least_rust_2018() {
|
||||
let extern_prelude_names = self.extern_prelude.clone();
|
||||
for (ident, _) in extern_prelude_names.into_iter() {
|
||||
for ident in self.extern_prelude.clone().into_keys() {
|
||||
if ident.span.from_expansion() {
|
||||
// Idents are adjusted to the root context before being
|
||||
// resolved in the extern prelude, so reporting this to the
|
||||
@ -1340,13 +1340,43 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
}
|
||||
let crate_id = self.crate_loader(|c| c.maybe_process_path_extern(ident.name));
|
||||
if let Some(crate_id) = crate_id {
|
||||
let crate_root = self.expect_module(crate_id.as_def_id());
|
||||
let crate_def_id = crate_id.as_def_id();
|
||||
let crate_root = self.expect_module(crate_def_id);
|
||||
|
||||
// Check if there's already an item in scope with the same name as the crate.
|
||||
// If so, we have to disambiguate the potential import suggestions by making
|
||||
// the paths *global* (i.e., by prefixing them with `::`).
|
||||
let needs_disambiguation =
|
||||
self.resolutions(parent_scope.module).borrow().iter().any(
|
||||
|(key, name_resolution)| {
|
||||
if key.ns == TypeNS
|
||||
&& key.ident == ident
|
||||
&& let Some(binding) = name_resolution.borrow().binding
|
||||
{
|
||||
match binding.res() {
|
||||
// No disambiguation needed if the identically named item we
|
||||
// found in scope actually refers to the crate in question.
|
||||
Res::Def(_, def_id) => def_id != crate_def_id,
|
||||
Res::PrimTy(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
);
|
||||
let mut crate_path = ThinVec::new();
|
||||
if needs_disambiguation {
|
||||
crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP));
|
||||
}
|
||||
crate_path.push(ast::PathSegment::from_ident(ident));
|
||||
|
||||
suggestions.extend(self.lookup_import_candidates_from_module(
|
||||
lookup_ident,
|
||||
namespace,
|
||||
parent_scope,
|
||||
crate_root,
|
||||
ident,
|
||||
crate_path,
|
||||
&filter_fn,
|
||||
));
|
||||
}
|
||||
@ -2554,7 +2584,7 @@ fn show_candidates(
|
||||
|
||||
candidates.iter().for_each(|c| {
|
||||
(if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings })
|
||||
.push((path_names_to_string(&c.path), c.descr, c.did, &c.note, c.via_import))
|
||||
.push((pprust::path_to_string(&c.path), c.descr, c.did, &c.note, c.via_import))
|
||||
});
|
||||
|
||||
// we want consistent results across executions, but candidates are produced
|
||||
|
@ -1570,7 +1570,26 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||
err.set_primary_message(
|
||||
"cannot initialize a tuple struct which contains private fields",
|
||||
);
|
||||
|
||||
if !def_id.is_local()
|
||||
&& self
|
||||
.r
|
||||
.tcx
|
||||
.inherent_impls(def_id)
|
||||
.iter()
|
||||
.flat_map(|impl_def_id| {
|
||||
self.r.tcx.provided_trait_methods(*impl_def_id)
|
||||
})
|
||||
.any(|assoc| !assoc.fn_has_self_parameter && assoc.name == sym::new)
|
||||
{
|
||||
// FIXME: look for associated functions with Self return type,
|
||||
// instead of relying only on the name and lack of self receiver.
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"you might have meant to use the `new` associated function",
|
||||
"::new".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
// Use spans of the tuple struct definition.
|
||||
self.r.field_def_ids(def_id).map(|field_ids| {
|
||||
field_ids
|
||||
|
@ -2739,32 +2739,25 @@ pub fn build_session_options(
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
|
||||
// precedence.
|
||||
match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
|
||||
(Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
|
||||
handler.early_error(
|
||||
"incompatible values passed for `-C instrument-coverage` \
|
||||
and `-Z instrument-coverage`",
|
||||
);
|
||||
// Check for unstable values of `-C instrument-coverage`.
|
||||
// This is what prevents them from being used on stable compilers.
|
||||
match cg.instrument_coverage {
|
||||
// Stable values:
|
||||
InstrumentCoverage::All | InstrumentCoverage::Off => {}
|
||||
// Unstable values:
|
||||
InstrumentCoverage::Branch
|
||||
| InstrumentCoverage::ExceptUnusedFunctions
|
||||
| InstrumentCoverage::ExceptUnusedGenerics => {
|
||||
if !unstable_opts.unstable_options {
|
||||
handler.early_error(
|
||||
"`-C instrument-coverage=branch` and `-C instrument-coverage=except-*` \
|
||||
require `-Z unstable-options`",
|
||||
);
|
||||
}
|
||||
}
|
||||
(Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
|
||||
(Some(_), _) if !unstable_opts.unstable_options => {
|
||||
handler.early_error(
|
||||
"`-C instrument-coverage=branch` and `-C instrument-coverage=except-*` \
|
||||
require `-Z unstable-options`",
|
||||
);
|
||||
}
|
||||
(None, None) => {}
|
||||
(None, ic) => {
|
||||
handler
|
||||
.early_warn("`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`");
|
||||
cg.instrument_coverage = ic;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
|
||||
if cg.instrument_coverage != InstrumentCoverage::Off {
|
||||
if cg.profile_generate.enabled() || cg.profile_use.is_some() {
|
||||
handler.early_error(
|
||||
"option `-C instrument-coverage` is not compatible with either `-C profile-use` \
|
||||
|
@ -294,7 +294,7 @@ impl CodegenOptions {
|
||||
// JUSTIFICATION: defn of the suggested wrapper fn
|
||||
#[allow(rustc::bad_opt_access)]
|
||||
pub fn instrument_coverage(&self) -> InstrumentCoverage {
|
||||
self.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
|
||||
self.instrument_coverage
|
||||
}
|
||||
}
|
||||
|
||||
@ -913,23 +913,23 @@ mod parse {
|
||||
}
|
||||
|
||||
pub(crate) fn parse_instrument_coverage(
|
||||
slot: &mut Option<InstrumentCoverage>,
|
||||
slot: &mut InstrumentCoverage,
|
||||
v: Option<&str>,
|
||||
) -> bool {
|
||||
if v.is_some() {
|
||||
let mut bool_arg = None;
|
||||
if parse_opt_bool(&mut bool_arg, v) {
|
||||
*slot = bool_arg.unwrap().then_some(InstrumentCoverage::All);
|
||||
let mut bool_arg = false;
|
||||
if parse_bool(&mut bool_arg, v) {
|
||||
*slot = if bool_arg { InstrumentCoverage::All } else { InstrumentCoverage::Off };
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
let Some(v) = v else {
|
||||
*slot = Some(InstrumentCoverage::All);
|
||||
*slot = InstrumentCoverage::All;
|
||||
return true;
|
||||
};
|
||||
|
||||
*slot = Some(match v {
|
||||
*slot = match v {
|
||||
"all" => InstrumentCoverage::All,
|
||||
"branch" => InstrumentCoverage::Branch,
|
||||
"except-unused-generics" | "except_unused_generics" => {
|
||||
@ -940,7 +940,7 @@ mod parse {
|
||||
}
|
||||
"off" | "no" | "n" | "false" | "0" => InstrumentCoverage::Off,
|
||||
_ => return false,
|
||||
});
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
@ -1352,7 +1352,7 @@ options! {
|
||||
inline_threshold: Option<u32> = (None, parse_opt_number, [TRACKED],
|
||||
"set the threshold for inlining a function"),
|
||||
#[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
|
||||
instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED],
|
||||
instrument_coverage: InstrumentCoverage = (InstrumentCoverage::Off, parse_instrument_coverage, [TRACKED],
|
||||
"instrument the generated code to support LLVM source-based code coverage \
|
||||
reports (note, the compiler build config must include `profiler = true`); \
|
||||
implies `-C symbol-mangling-version=v0`. Optional values are:
|
||||
@ -1593,16 +1593,6 @@ options! {
|
||||
"a default MIR inlining threshold (default: 50)"),
|
||||
input_stats: bool = (false, parse_bool, [UNTRACKED],
|
||||
"gather statistics about the input (default: no)"),
|
||||
#[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
|
||||
instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED],
|
||||
"instrument the generated code to support LLVM source-based code coverage \
|
||||
reports (note, the compiler build config must include `profiler = true`); \
|
||||
implies `-C symbol-mangling-version=v0`. Optional values are:
|
||||
`=all` (implicit value)
|
||||
`=branch`
|
||||
`=except-unused-generics`
|
||||
`=except-unused-functions`
|
||||
`=off` (default)"),
|
||||
instrument_mcount: bool = (false, parse_bool, [TRACKED],
|
||||
"insert function instrument code for mcount-based tracing (default: no)"),
|
||||
instrument_xray: Option<InstrumentXRay> = (None, parse_instrument_xray, [TRACKED],
|
||||
|
@ -45,7 +45,7 @@ use std::fmt;
|
||||
use std::ops::{Div, Mul};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{atomic::AtomicBool, Arc};
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct OptimizationFuel {
|
||||
@ -202,6 +202,12 @@ pub struct Session {
|
||||
/// The version of the rustc process, possibly including a commit hash and description.
|
||||
pub cfg_version: &'static str,
|
||||
|
||||
/// The inner atomic value is set to true when a feature marked as `internal` is
|
||||
/// enabled. Makes it so that "please report a bug" is hidden, as ICEs with
|
||||
/// internal features are wontfix, and they are usually the cause of the ICEs.
|
||||
/// None signifies that this is not tracked.
|
||||
pub using_internal_features: Arc<AtomicBool>,
|
||||
|
||||
/// All commandline args used to invoke the compiler, with @file args fully expanded.
|
||||
/// This will only be used within debug info, e.g. in the pdb file on windows
|
||||
/// This is mainly useful for other tools that reads that debuginfo to figure out
|
||||
@ -1389,6 +1395,7 @@ pub fn build_session(
|
||||
target_override: Option<Target>,
|
||||
cfg_version: &'static str,
|
||||
ice_file: Option<PathBuf>,
|
||||
using_internal_features: Arc<AtomicBool>,
|
||||
expanded_args: Vec<String>,
|
||||
) -> Session {
|
||||
// FIXME: This is not general enough to make the warning lint completely override
|
||||
@ -1525,6 +1532,7 @@ pub fn build_session(
|
||||
target_features: Default::default(),
|
||||
unstable_target_features: Default::default(),
|
||||
cfg_version,
|
||||
using_internal_features,
|
||||
expanded_args,
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#![cfg_attr(not(bootstrap), doc(rust_logo))]
|
||||
#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![allow(rustc::usage_of_ty_tykind)]
|
||||
|
||||
pub mod rustc_internal;
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
//! due to incomplete stable coverage.
|
||||
|
||||
// Prefer importing stable_mir over internal rustc constructs to make this file more readable.
|
||||
use crate::rustc_smir::{MaybeStable, Tables};
|
||||
use crate::rustc_smir::Tables;
|
||||
use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
|
||||
use stable_mir::ty::{Const, GenericArgKind, GenericArgs, Region, Ty};
|
||||
use stable_mir::DefId;
|
||||
@ -31,7 +31,7 @@ impl<'tcx> RustcInternal<'tcx> for GenericArgKind {
|
||||
match self {
|
||||
GenericArgKind::Lifetime(reg) => reg.internal(tables).into(),
|
||||
GenericArgKind::Type(ty) => ty.internal(tables).into(),
|
||||
GenericArgKind::Const(cnst) => cnst.internal(tables).into(),
|
||||
GenericArgKind::Const(cnst) => ty_const(cnst, tables).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,16 +46,22 @@ impl<'tcx> RustcInternal<'tcx> for Region {
|
||||
impl<'tcx> RustcInternal<'tcx> for Ty {
|
||||
type T = InternalTy<'tcx>;
|
||||
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
match tables.types[self.0] {
|
||||
MaybeStable::Stable(_) => todo!(),
|
||||
MaybeStable::Rustc(ty) => ty,
|
||||
tables.types[*self]
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_const<'tcx>(constant: &Const, tables: &mut Tables<'tcx>) -> rustc_ty::Const<'tcx> {
|
||||
match constant.internal(tables) {
|
||||
rustc_middle::mir::Const::Ty(c) => c,
|
||||
cnst => {
|
||||
panic!("Trying to covert constant `{constant:?}` to type constant, but found {cnst:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RustcInternal<'tcx> for Const {
|
||||
type T = rustc_ty::Const<'tcx>;
|
||||
fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||
todo!()
|
||||
type T = rustc_middle::mir::Const<'tcx>;
|
||||
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
tables.constants[self.id]
|
||||
}
|
||||
}
|
||||
|
@ -167,8 +167,9 @@ pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
|
||||
def_ids: IndexMap::default(),
|
||||
alloc_ids: IndexMap::default(),
|
||||
spans: IndexMap::default(),
|
||||
types: vec![],
|
||||
types: IndexMap::default(),
|
||||
instances: IndexMap::default(),
|
||||
constants: IndexMap::default(),
|
||||
}));
|
||||
stable_mir::run(&tables, || init(&tables, f));
|
||||
}
|
||||
|
@ -20,7 +20,8 @@ use rustc_target::abi::FieldIdx;
|
||||
use stable_mir::mir::mono::InstanceDef;
|
||||
use stable_mir::mir::{Body, CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx};
|
||||
use stable_mir::ty::{
|
||||
FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span, TyKind, UintTy,
|
||||
Const, ConstId, ConstantKind, FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy,
|
||||
Span, TyKind, UintTy,
|
||||
};
|
||||
use stable_mir::{self, opaque, Context, Filename};
|
||||
use std::cell::RefCell;
|
||||
@ -147,14 +148,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||
|
||||
fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
tables.types[ty.0].clone().stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn mk_ty(&self, kind: TyKind) -> stable_mir::ty::Ty {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let n = tables.types.len();
|
||||
tables.types.push(MaybeStable::Stable(kind));
|
||||
stable_mir::ty::Ty(n)
|
||||
tables.types[ty].kind().stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
|
||||
@ -213,8 +207,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||
fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let instance = tables.instances[def];
|
||||
let ty = instance.ty(tables.tcx, ParamEnv::empty());
|
||||
tables.intern_ty(ty)
|
||||
instance.ty(tables.tcx, ParamEnv::empty()).stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
|
||||
@ -252,33 +245,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum MaybeStable<S, R> {
|
||||
Stable(S),
|
||||
Rustc(R),
|
||||
}
|
||||
|
||||
impl<'tcx, S, R> MaybeStable<S, R> {
|
||||
fn stable(self, tables: &mut Tables<'tcx>) -> S
|
||||
where
|
||||
R: Stable<'tcx, T = S>,
|
||||
{
|
||||
match self {
|
||||
MaybeStable::Stable(s) => s,
|
||||
MaybeStable::Rustc(r) => r.stable(tables),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, R: PartialEq> PartialEq<R> for MaybeStable<S, R> {
|
||||
fn eq(&self, other: &R) -> bool {
|
||||
match self {
|
||||
MaybeStable::Stable(_) => false,
|
||||
MaybeStable::Rustc(r) => r == other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell<Tables<'tcx>>);
|
||||
|
||||
pub struct Tables<'tcx> {
|
||||
@ -286,18 +252,18 @@ pub struct Tables<'tcx> {
|
||||
pub(crate) def_ids: IndexMap<DefId, stable_mir::DefId>,
|
||||
pub(crate) alloc_ids: IndexMap<AllocId, stable_mir::AllocId>,
|
||||
pub(crate) spans: IndexMap<rustc_span::Span, Span>,
|
||||
pub(crate) types: Vec<MaybeStable<TyKind, Ty<'tcx>>>,
|
||||
pub(crate) types: IndexMap<Ty<'tcx>, stable_mir::ty::Ty>,
|
||||
pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
|
||||
pub(crate) constants: IndexMap<mir::Const<'tcx>, ConstId>,
|
||||
}
|
||||
|
||||
impl<'tcx> Tables<'tcx> {
|
||||
fn intern_ty(&mut self, ty: Ty<'tcx>) -> stable_mir::ty::Ty {
|
||||
if let Some(id) = self.types.iter().position(|t| *t == ty) {
|
||||
return stable_mir::ty::Ty(id);
|
||||
}
|
||||
let id = self.types.len();
|
||||
self.types.push(MaybeStable::Rustc(ty));
|
||||
stable_mir::ty::Ty(id)
|
||||
self.types.create_or_fetch(ty)
|
||||
}
|
||||
|
||||
fn intern_const(&mut self, constant: mir::Const<'tcx>) -> ConstId {
|
||||
self.constants.create_or_fetch(constant)
|
||||
}
|
||||
}
|
||||
|
||||
@ -321,9 +287,8 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
|
||||
type T = stable_mir::mir::Body;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
stable_mir::mir::Body {
|
||||
blocks: self
|
||||
.basic_blocks
|
||||
stable_mir::mir::Body::new(
|
||||
self.basic_blocks
|
||||
.iter()
|
||||
.map(|block| stable_mir::mir::BasicBlock {
|
||||
terminator: block.terminator().stable(tables),
|
||||
@ -334,15 +299,15 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
|
||||
.collect(),
|
||||
})
|
||||
.collect(),
|
||||
locals: self
|
||||
.local_decls
|
||||
self.local_decls
|
||||
.iter()
|
||||
.map(|decl| stable_mir::mir::LocalDecl {
|
||||
ty: tables.intern_ty(decl.ty),
|
||||
ty: decl.ty.stable(tables),
|
||||
span: decl.source_info.span.stable(tables),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
self.arg_count,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,7 +401,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
|
||||
Cast(cast_kind, op, ty) => stable_mir::mir::Rvalue::Cast(
|
||||
cast_kind.stable(tables),
|
||||
op.stable(tables),
|
||||
tables.intern_ty(*ty),
|
||||
ty.stable(tables),
|
||||
),
|
||||
BinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::BinaryOp(
|
||||
bin_op.stable(tables),
|
||||
@ -449,7 +414,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
|
||||
ops.1.stable(tables),
|
||||
),
|
||||
NullaryOp(null_op, ty) => {
|
||||
stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), tables.intern_ty(*ty))
|
||||
stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), ty.stable(tables))
|
||||
}
|
||||
UnaryOp(un_op, op) => {
|
||||
stable_mir::mir::Rvalue::UnaryOp(un_op.stable(tables), op.stable(tables))
|
||||
@ -460,7 +425,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
|
||||
stable_mir::mir::Rvalue::Aggregate(agg_kind.stable(tables), operands)
|
||||
}
|
||||
ShallowInitBox(op, ty) => {
|
||||
stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), tables.intern_ty(*ty))
|
||||
stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), ty.stable(tables))
|
||||
}
|
||||
CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)),
|
||||
}
|
||||
@ -604,7 +569,7 @@ impl<'tcx> Stable<'tcx> for ty::TermKind<'tcx> {
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
use stable_mir::ty::TermKind;
|
||||
match self {
|
||||
ty::TermKind::Ty(ty) => TermKind::Type(tables.intern_ty(*ty)),
|
||||
ty::TermKind::Ty(ty) => TermKind::Type(ty.stable(tables)),
|
||||
ty::TermKind::Const(cnst) => {
|
||||
let cnst = cnst.stable(tables);
|
||||
TermKind::Const(cnst)
|
||||
@ -885,7 +850,7 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
match self {
|
||||
mir::AggregateKind::Array(ty) => {
|
||||
stable_mir::mir::AggregateKind::Array(tables.intern_ty(*ty))
|
||||
stable_mir::mir::AggregateKind::Array(ty.stable(tables))
|
||||
}
|
||||
mir::AggregateKind::Tuple => stable_mir::mir::AggregateKind::Tuple,
|
||||
mir::AggregateKind::Adt(def_id, var_idx, generic_arg, user_ty_index, field_idx) => {
|
||||
@ -917,13 +882,13 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
|
||||
impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind {
|
||||
type T = stable_mir::mir::CoroutineKind;
|
||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
||||
use rustc_hir::{AsyncCoroutineKind, CoroutineKind};
|
||||
use rustc_hir::{CoroutineKind, CoroutineSource};
|
||||
match self {
|
||||
CoroutineKind::Async(async_gen) => {
|
||||
let async_gen = match async_gen {
|
||||
AsyncCoroutineKind::Block => stable_mir::mir::AsyncCoroutineKind::Block,
|
||||
AsyncCoroutineKind::Closure => stable_mir::mir::AsyncCoroutineKind::Closure,
|
||||
AsyncCoroutineKind::Fn => stable_mir::mir::AsyncCoroutineKind::Fn,
|
||||
CoroutineSource::Block => stable_mir::mir::CoroutineSource::Block,
|
||||
CoroutineSource::Closure => stable_mir::mir::CoroutineSource::Closure,
|
||||
CoroutineSource::Fn => stable_mir::mir::CoroutineSource::Fn,
|
||||
};
|
||||
stable_mir::mir::CoroutineKind::Async(async_gen)
|
||||
}
|
||||
@ -1053,7 +1018,7 @@ impl<'tcx> Stable<'tcx> for ty::GenericArgKind<'tcx> {
|
||||
use stable_mir::ty::GenericArgKind;
|
||||
match self {
|
||||
ty::GenericArgKind::Lifetime(region) => GenericArgKind::Lifetime(region.stable(tables)),
|
||||
ty::GenericArgKind::Type(ty) => GenericArgKind::Type(tables.intern_ty(*ty)),
|
||||
ty::GenericArgKind::Type(ty) => GenericArgKind::Type(ty.stable(tables)),
|
||||
ty::GenericArgKind::Const(cnst) => GenericArgKind::Const(cnst.stable(tables)),
|
||||
}
|
||||
}
|
||||
@ -1099,11 +1064,7 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> {
|
||||
use stable_mir::ty::{Abi, FnSig};
|
||||
|
||||
FnSig {
|
||||
inputs_and_output: self
|
||||
.inputs_and_output
|
||||
.iter()
|
||||
.map(|ty| tables.intern_ty(ty))
|
||||
.collect(),
|
||||
inputs_and_output: self.inputs_and_output.iter().map(|ty| ty.stable(tables)).collect(),
|
||||
c_variadic: self.c_variadic,
|
||||
unsafety: self.unsafety.stable(tables),
|
||||
abi: match self.abi {
|
||||
@ -1241,9 +1202,16 @@ impl<'tcx> Stable<'tcx> for hir::Movability {
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for Ty<'tcx> {
|
||||
type T = stable_mir::ty::Ty;
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
tables.intern_ty(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
|
||||
type T = stable_mir::ty::TyKind;
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
match self.kind() {
|
||||
match self {
|
||||
ty::Bool => TyKind::RigidTy(RigidTy::Bool),
|
||||
ty::Char => TyKind::RigidTy(RigidTy::Char),
|
||||
ty::Int(int_ty) => TyKind::RigidTy(RigidTy::Int(int_ty.stable(tables))),
|
||||
@ -1256,15 +1224,15 @@ impl<'tcx> Stable<'tcx> for Ty<'tcx> {
|
||||
ty::Foreign(def_id) => TyKind::RigidTy(RigidTy::Foreign(tables.foreign_def(*def_id))),
|
||||
ty::Str => TyKind::RigidTy(RigidTy::Str),
|
||||
ty::Array(ty, constant) => {
|
||||
TyKind::RigidTy(RigidTy::Array(tables.intern_ty(*ty), constant.stable(tables)))
|
||||
TyKind::RigidTy(RigidTy::Array(ty.stable(tables), constant.stable(tables)))
|
||||
}
|
||||
ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(tables.intern_ty(*ty))),
|
||||
ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables))),
|
||||
ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
|
||||
TyKind::RigidTy(RigidTy::RawPtr(tables.intern_ty(*ty), mutbl.stable(tables)))
|
||||
TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables), mutbl.stable(tables)))
|
||||
}
|
||||
ty::Ref(region, ty, mutbl) => TyKind::RigidTy(RigidTy::Ref(
|
||||
region.stable(tables),
|
||||
tables.intern_ty(*ty),
|
||||
ty.stable(tables),
|
||||
mutbl.stable(tables),
|
||||
)),
|
||||
ty::FnDef(def_id, generic_args) => {
|
||||
@ -1291,9 +1259,9 @@ impl<'tcx> Stable<'tcx> for Ty<'tcx> {
|
||||
movability.stable(tables),
|
||||
)),
|
||||
ty::Never => TyKind::RigidTy(RigidTy::Never),
|
||||
ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple(
|
||||
fields.iter().map(|ty| tables.intern_ty(ty)).collect(),
|
||||
)),
|
||||
ty::Tuple(fields) => {
|
||||
TyKind::RigidTy(RigidTy::Tuple(fields.iter().map(|ty| ty.stable(tables)).collect()))
|
||||
}
|
||||
ty::Alias(alias_kind, alias_ty) => {
|
||||
TyKind::Alias(alias_kind.stable(tables), alias_ty.stable(tables))
|
||||
}
|
||||
@ -1312,32 +1280,36 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
|
||||
type T = stable_mir::ty::Const;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
stable_mir::ty::Const {
|
||||
literal: match self.kind() {
|
||||
ty::Value(val) => {
|
||||
let const_val = tables.tcx.valtree_to_const_val((self.ty(), val));
|
||||
let kind = match self.kind() {
|
||||
ty::Value(val) => {
|
||||
let const_val = tables.tcx.valtree_to_const_val((self.ty(), val));
|
||||
if matches!(const_val, mir::ConstValue::ZeroSized) {
|
||||
ConstantKind::ZeroSized
|
||||
} else {
|
||||
stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(
|
||||
self.ty(),
|
||||
const_val,
|
||||
tables,
|
||||
))
|
||||
}
|
||||
ty::ParamCt(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)),
|
||||
ty::ErrorCt(_) => unreachable!(),
|
||||
ty::InferCt(_) => unreachable!(),
|
||||
ty::BoundCt(_, _) => unimplemented!(),
|
||||
ty::PlaceholderCt(_) => unimplemented!(),
|
||||
ty::Unevaluated(uv) => {
|
||||
stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
|
||||
def: tables.const_def(uv.def),
|
||||
args: uv.args.stable(tables),
|
||||
promoted: None,
|
||||
})
|
||||
}
|
||||
ty::ExprCt(_) => unimplemented!(),
|
||||
},
|
||||
ty: tables.intern_ty(self.ty()),
|
||||
}
|
||||
}
|
||||
ty::ParamCt(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)),
|
||||
ty::ErrorCt(_) => unreachable!(),
|
||||
ty::InferCt(_) => unreachable!(),
|
||||
ty::BoundCt(_, _) => unimplemented!(),
|
||||
ty::PlaceholderCt(_) => unimplemented!(),
|
||||
ty::Unevaluated(uv) => {
|
||||
stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
|
||||
def: tables.const_def(uv.def),
|
||||
args: uv.args.stable(tables),
|
||||
promoted: None,
|
||||
})
|
||||
}
|
||||
ty::ExprCt(_) => unimplemented!(),
|
||||
};
|
||||
let ty = self.ty().stable(tables);
|
||||
let id = tables.intern_const(mir::Const::Ty(*self));
|
||||
Const::new(kind, ty, id)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1422,22 +1394,28 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> {
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
match *self {
|
||||
mir::Const::Ty(c) => c.stable(tables),
|
||||
mir::Const::Unevaluated(unev_const, ty) => stable_mir::ty::Const {
|
||||
literal: stable_mir::ty::ConstantKind::Unevaluated(
|
||||
stable_mir::ty::UnevaluatedConst {
|
||||
mir::Const::Unevaluated(unev_const, ty) => {
|
||||
let kind =
|
||||
stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst {
|
||||
def: tables.const_def(unev_const.def),
|
||||
args: unev_const.args.stable(tables),
|
||||
promoted: unev_const.promoted.map(|u| u.as_u32()),
|
||||
},
|
||||
),
|
||||
ty: tables.intern_ty(ty),
|
||||
},
|
||||
mir::Const::Val(val, ty) => stable_mir::ty::Const {
|
||||
literal: stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(
|
||||
ty, val, tables,
|
||||
)),
|
||||
ty: tables.intern_ty(ty),
|
||||
},
|
||||
});
|
||||
let ty = ty.stable(tables);
|
||||
let id = tables.intern_const(*self);
|
||||
Const::new(kind, ty, id)
|
||||
}
|
||||
mir::Const::Val(val, ty) if matches!(val, mir::ConstValue::ZeroSized) => {
|
||||
let ty = ty.stable(tables);
|
||||
let id = tables.intern_const(*self);
|
||||
Const::new(ConstantKind::ZeroSized, ty, id)
|
||||
}
|
||||
mir::Const::Val(val, ty) => {
|
||||
let kind = ConstantKind::Allocated(alloc::new_allocation(ty, val, tables));
|
||||
let ty = ty.stable(tables);
|
||||
let id = tables.intern_const(*self);
|
||||
Const::new(kind, ty, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1551,30 +1529,32 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> {
|
||||
type T = stable_mir::ty::ClauseKind;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
use ty::ClauseKind::*;
|
||||
use ty::ClauseKind;
|
||||
match *self {
|
||||
Trait(trait_object) => stable_mir::ty::ClauseKind::Trait(trait_object.stable(tables)),
|
||||
RegionOutlives(region_outlives) => {
|
||||
ClauseKind::Trait(trait_object) => {
|
||||
stable_mir::ty::ClauseKind::Trait(trait_object.stable(tables))
|
||||
}
|
||||
ClauseKind::RegionOutlives(region_outlives) => {
|
||||
stable_mir::ty::ClauseKind::RegionOutlives(region_outlives.stable(tables))
|
||||
}
|
||||
TypeOutlives(type_outlives) => {
|
||||
ClauseKind::TypeOutlives(type_outlives) => {
|
||||
let ty::OutlivesPredicate::<_, _>(a, b) = type_outlives;
|
||||
stable_mir::ty::ClauseKind::TypeOutlives(stable_mir::ty::OutlivesPredicate(
|
||||
tables.intern_ty(a),
|
||||
a.stable(tables),
|
||||
b.stable(tables),
|
||||
))
|
||||
}
|
||||
Projection(projection_predicate) => {
|
||||
ClauseKind::Projection(projection_predicate) => {
|
||||
stable_mir::ty::ClauseKind::Projection(projection_predicate.stable(tables))
|
||||
}
|
||||
ConstArgHasType(const_, ty) => stable_mir::ty::ClauseKind::ConstArgHasType(
|
||||
ClauseKind::ConstArgHasType(const_, ty) => stable_mir::ty::ClauseKind::ConstArgHasType(
|
||||
const_.stable(tables),
|
||||
tables.intern_ty(ty),
|
||||
ty.stable(tables),
|
||||
),
|
||||
WellFormed(generic_arg) => {
|
||||
ClauseKind::WellFormed(generic_arg) => {
|
||||
stable_mir::ty::ClauseKind::WellFormed(generic_arg.unpack().stable(tables))
|
||||
}
|
||||
ConstEvaluatable(const_) => {
|
||||
ClauseKind::ConstEvaluatable(const_) => {
|
||||
stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables))
|
||||
}
|
||||
}
|
||||
@ -1599,7 +1579,7 @@ impl<'tcx> Stable<'tcx> for ty::SubtypePredicate<'tcx> {
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
let ty::SubtypePredicate { a, b, a_is_expected: _ } = self;
|
||||
stable_mir::ty::SubtypePredicate { a: tables.intern_ty(*a), b: tables.intern_ty(*b) }
|
||||
stable_mir::ty::SubtypePredicate { a: a.stable(tables), b: b.stable(tables) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1608,7 +1588,7 @@ impl<'tcx> Stable<'tcx> for ty::CoercePredicate<'tcx> {
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
let ty::CoercePredicate { a, b } = self;
|
||||
stable_mir::ty::CoercePredicate { a: tables.intern_ty(*a), b: tables.intern_ty(*b) }
|
||||
stable_mir::ty::CoercePredicate { a: a.stable(tables), b: b.stable(tables) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -713,6 +713,7 @@ symbols! {
|
||||
encode,
|
||||
end,
|
||||
env,
|
||||
env_CFG_RELEASE: env!("CFG_RELEASE"),
|
||||
eprint_macro,
|
||||
eprintln_macro,
|
||||
eq,
|
||||
@ -910,6 +911,7 @@ symbols! {
|
||||
iter,
|
||||
iter_mut,
|
||||
iter_repeat,
|
||||
iterator,
|
||||
iterator_collect_fn,
|
||||
kcfi,
|
||||
keyword,
|
||||
|
@ -15,9 +15,7 @@ twox-hash = "1.6.3"
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
|
@ -1 +0,0 @@
|
||||
symbol_mangling_test_output = {$kind}({$content})
|
@ -1,18 +1,32 @@
|
||||
//! Errors emitted by symbol_mangling.
|
||||
|
||||
use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_errors::{ErrorGuaranteed, IntoDiagnostic};
|
||||
use rustc_span::Span;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(symbol_mangling_test_output)]
|
||||
pub struct TestOutput {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub kind: Kind,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
// This diagnostic doesn't need translation because (a) it doesn't contain any
|
||||
// natural language, and (b) it's only used in tests. So we construct it
|
||||
// manually and avoid the fluent machinery.
|
||||
impl IntoDiagnostic<'_> for TestOutput {
|
||||
fn into_diagnostic(
|
||||
self,
|
||||
handler: &'_ rustc_errors::Handler,
|
||||
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
let TestOutput { span, kind, content } = self;
|
||||
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
let mut diag = handler.struct_err(format!("{kind}({content})"));
|
||||
diag.set_span(span);
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Kind {
|
||||
SymbolName,
|
||||
Demangling,
|
||||
@ -20,15 +34,13 @@ pub enum Kind {
|
||||
DefPath,
|
||||
}
|
||||
|
||||
impl IntoDiagnosticArg for Kind {
|
||||
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
|
||||
let kind = match self {
|
||||
Kind::SymbolName => "symbol-name",
|
||||
Kind::Demangling => "demangling",
|
||||
Kind::DemanglingAlt => "demangling-alt",
|
||||
Kind::DefPath => "def-path",
|
||||
impl fmt::Display for Kind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Kind::SymbolName => write!(f, "symbol-name"),
|
||||
Kind::Demangling => write!(f, "demangling"),
|
||||
Kind::DemanglingAlt => write!(f, "demangling-alt"),
|
||||
Kind::DefPath => write!(f, "def-path"),
|
||||
}
|
||||
.into();
|
||||
DiagnosticArgValue::Str(kind)
|
||||
}
|
||||
}
|
||||
|
@ -103,8 +103,6 @@ extern crate rustc_middle;
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
|
||||
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
|
||||
use rustc_fluent_macro::fluent_messages;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
@ -121,8 +119,6 @@ pub mod errors;
|
||||
pub mod test;
|
||||
pub mod typeid;
|
||||
|
||||
fluent_messages! { "../messages.ftl" }
|
||||
|
||||
/// This function computes the symbol name for the given `instance` and the
|
||||
/// given instantiating crate. That is, if you know that instance X is
|
||||
/// instantiated in crate Y, this is the symbol name this instance would have.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user