Auto merge of #119156 - matthiaskrgr:rollup-482ow65, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #118691 (Add check for possible CStr literals in pre-2021) - #118973 (rustc_codegen_ssa: Don't drop `IncorrectCguReuseType` , make `rustc_expected_cgu_reuse` attr work) - #119071 (-Znext-solver: adapt overflow rules to avoid breakage) - #119089 (effects: fix a comment) - #119094 (Add function ABI and type layout to StableMIR) - #119102 (Add arm-none-eabi and armv7r-none-eabi platform-support documentation.) - #119107 (subtype_predicate: remove unnecessary probe) Failed merges: - #119135 (Fix crash due to `CrateItem::kind()` not handling constructors) - #119141 (Add method to get instance instantiation arguments) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
3e4a15ea06
47 changed files with 1419 additions and 267 deletions
|
@ -278,13 +278,13 @@ impl CguReuseTracker {
|
|||
|
||||
if error {
|
||||
let at_least = if at_least { 1 } else { 0 };
|
||||
errors::IncorrectCguReuseType {
|
||||
sess.emit_err(errors::IncorrectCguReuseType {
|
||||
span: *error_span,
|
||||
cgu_user_name,
|
||||
actual_reuse,
|
||||
expected_reuse,
|
||||
at_least,
|
||||
};
|
||||
});
|
||||
}
|
||||
} else {
|
||||
sess.emit_fatal(errors::CguNotRecorded { cgu_user_name, cgu_name });
|
||||
|
|
|
@ -262,7 +262,7 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>(
|
|||
// impl const PartialEq for () {}
|
||||
// ```
|
||||
//
|
||||
// Since this is a const impl, we need to insert `<false>` at the end of
|
||||
// Since this is a const impl, we need to insert a host arg at the end of
|
||||
// `PartialEq`'s generics, but this errors since `Rhs` isn't specified.
|
||||
// To work around this, we infer all arguments until we reach the host param.
|
||||
args.push(ctx.inferred_kind(Some(&args), param, infer_args));
|
||||
|
|
|
@ -713,10 +713,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx, T> InferOk<'tcx, T> {
|
||||
pub fn unit(self) -> InferOk<'tcx, ()> {
|
||||
InferOk { value: (), obligations: self.obligations }
|
||||
}
|
||||
|
||||
/// Extracts `value`, registering any obligations into `fulfill_cx`.
|
||||
pub fn into_value_registering_obligations(
|
||||
self,
|
||||
|
@ -1025,15 +1021,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
Ok(self.commit_if_ok(|_snapshot| {
|
||||
let ty::SubtypePredicate { a_is_expected, a, b } =
|
||||
self.instantiate_binder_with_placeholders(predicate);
|
||||
|
||||
let ok =
|
||||
self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b)?;
|
||||
|
||||
Ok(ok.unit())
|
||||
}))
|
||||
Ok(self.at(cause, param_env).sub_exp(DefineOpaqueTypes::No, a_is_expected, a, b))
|
||||
}
|
||||
|
||||
pub fn region_outlives_predicate(
|
||||
|
|
|
@ -233,6 +233,27 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Why a specific goal has to be proven.
|
||||
///
|
||||
/// This is necessary as we treat nested goals different depending on
|
||||
/// their source.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum GoalSource {
|
||||
Misc,
|
||||
/// We're proving a where-bound of an impl.
|
||||
///
|
||||
/// FIXME(-Znext-solver=coinductive): Explain how and why this
|
||||
/// changes whether cycles are coinductive.
|
||||
///
|
||||
/// This also impacts whether we erase constraints on overflow.
|
||||
/// Erasing constraints is generally very useful for perf and also
|
||||
/// results in better error messages by avoiding spurious errors.
|
||||
/// We do not erase overflow constraints in `normalizes-to` goals unless
|
||||
/// they are from an impl where-clause. This is necessary due to
|
||||
/// backwards compatability, cc trait-system-refactor-initiatitive#70.
|
||||
ImplWhereBound,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
|
||||
pub enum IsNormalizesToHack {
|
||||
Yes,
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
//! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
|
||||
|
||||
use super::{
|
||||
CandidateSource, Canonical, CanonicalInput, Certainty, Goal, IsNormalizesToHack, NoSolution,
|
||||
QueryInput, QueryResult,
|
||||
CandidateSource, Canonical, CanonicalInput, Certainty, Goal, GoalSource, IsNormalizesToHack,
|
||||
NoSolution, QueryInput, QueryResult,
|
||||
};
|
||||
use crate::{infer::canonical::CanonicalVarValues, ty};
|
||||
use format::ProofTreeFormatter;
|
||||
|
@ -115,7 +115,7 @@ impl Debug for Probe<'_> {
|
|||
pub enum ProbeStep<'tcx> {
|
||||
/// We added a goal to the `EvalCtxt` which will get proven
|
||||
/// the next time `EvalCtxt::try_evaluate_added_goals` is called.
|
||||
AddGoal(CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
|
||||
AddGoal(GoalSource, CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
|
||||
/// The inside of a `EvalCtxt::try_evaluate_added_goals` call.
|
||||
EvaluateGoals(AddedGoalsEvaluation<'tcx>),
|
||||
/// A call to `probe` while proving the current goal. This is
|
||||
|
|
|
@ -123,7 +123,13 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
|
|||
self.nested(|this| {
|
||||
for step in &probe.steps {
|
||||
match step {
|
||||
ProbeStep::AddGoal(goal) => writeln!(this.f, "ADDED GOAL: {goal:?}")?,
|
||||
ProbeStep::AddGoal(source, goal) => {
|
||||
let source = match source {
|
||||
GoalSource::Misc => "misc",
|
||||
GoalSource::ImplWhereBound => "impl where-bound",
|
||||
};
|
||||
writeln!(this.f, "ADDED GOAL ({source}): {goal:?}")?
|
||||
}
|
||||
ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?,
|
||||
ProbeStep::NestedProbe(probe) => this.format_probe(probe)?,
|
||||
ProbeStep::CommitIfOkStart => writeln!(this.f, "COMMIT_IF_OK START")?,
|
||||
|
|
|
@ -10,13 +10,13 @@ use crate::errors::{
|
|||
ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType,
|
||||
DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
|
||||
GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg,
|
||||
HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon,
|
||||
IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg,
|
||||
SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg,
|
||||
StructLiteralNeedingParens, StructLiteralNeedingParensSugg, SuggAddMissingLetStmt,
|
||||
SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, UnexpectedConstInGenericParam,
|
||||
UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets,
|
||||
UseEqInstead, WrapType,
|
||||
HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait,
|
||||
IncorrectSemicolon, IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType,
|
||||
QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
|
||||
StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
|
||||
SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator,
|
||||
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
|
||||
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
|
||||
};
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::parser;
|
||||
|
@ -640,6 +640,28 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// Try to detect an intended c-string literal while using a pre-2021 edition. The heuristic
|
||||
// here is to identify a cooked, uninterpolated `c` id immediately followed by a string, or
|
||||
// a cooked, uninterpolated `cr` id immediately followed by a string or a `#`, in an edition
|
||||
// where c-string literals are not allowed. There is the very slight possibility of a false
|
||||
// positive for a `cr#` that wasn't intended to start a c-string literal, but identifying
|
||||
// that in the parser requires unbounded lookahead, so we only add a hint to the existing
|
||||
// error rather than replacing it entirely.
|
||||
if ((self.prev_token.kind == TokenKind::Ident(sym::c, false)
|
||||
&& matches!(&self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. })))
|
||||
|| (self.prev_token.kind == TokenKind::Ident(sym::cr, false)
|
||||
&& matches!(
|
||||
&self.token.kind,
|
||||
TokenKind::Literal(token::Lit { kind: token::Str, .. }) | token::Pound
|
||||
)))
|
||||
&& self.prev_token.span.hi() == self.token.span.lo()
|
||||
&& !self.token.span.at_least_rust_2021()
|
||||
{
|
||||
err.note("you may be trying to write a c-string literal");
|
||||
err.note("c-string literals require Rust 2021 or later");
|
||||
HelpUseLatestEdition::new().add_to_diagnostic(&mut err);
|
||||
}
|
||||
|
||||
// `pub` may be used for an item or `pub(crate)`
|
||||
if self.prev_token.is_ident_named(sym::public)
|
||||
&& (self.token.can_begin_item()
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
use crate::rustc_smir::Tables;
|
||||
use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
|
||||
use rustc_span::Symbol;
|
||||
use stable_mir::abi::Layout;
|
||||
use stable_mir::mir::alloc::AllocId;
|
||||
use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
|
||||
use stable_mir::mir::{Mutability, Safety};
|
||||
|
@ -460,6 +461,14 @@ impl<'tcx> RustcInternal<'tcx> for Span {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RustcInternal<'tcx> for Layout {
|
||||
type T = rustc_target::abi::Layout<'tcx>;
|
||||
|
||||
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
tables.layouts[*self]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> RustcInternal<'tcx> for &T
|
||||
where
|
||||
T: RustcInternal<'tcx>,
|
||||
|
|
|
@ -12,6 +12,7 @@ use rustc_middle::ty::TyCtxt;
|
|||
use rustc_span::def_id::{CrateNum, DefId};
|
||||
use rustc_span::Span;
|
||||
use scoped_tls::scoped_thread_local;
|
||||
use stable_mir::abi::Layout;
|
||||
use stable_mir::ty::IndexedVal;
|
||||
use stable_mir::Error;
|
||||
use std::cell::Cell;
|
||||
|
@ -136,6 +137,10 @@ impl<'tcx> Tables<'tcx> {
|
|||
pub(crate) fn static_def(&mut self, did: DefId) -> stable_mir::mir::mono::StaticDef {
|
||||
stable_mir::mir::mono::StaticDef(self.create_def_id(did))
|
||||
}
|
||||
|
||||
pub(crate) fn layout_id(&mut self, layout: rustc_target::abi::Layout<'tcx>) -> Layout {
|
||||
self.layouts.create_or_fetch(layout)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
|
||||
|
@ -180,6 +185,7 @@ where
|
|||
types: IndexMap::default(),
|
||||
instances: IndexMap::default(),
|
||||
constants: IndexMap::default(),
|
||||
layouts: IndexMap::default(),
|
||||
}));
|
||||
stable_mir::compiler_interface::run(&tables, || init(&tables, f))
|
||||
}
|
||||
|
|
|
@ -3,12 +3,19 @@
|
|||
//! This trait is currently the main interface between the Rust compiler,
|
||||
//! and the `stable_mir` crate.
|
||||
|
||||
#![allow(rustc::usage_of_qualified_ty)]
|
||||
|
||||
use rustc_abi::HasDataLayout;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::{
|
||||
FnAbiOf, FnAbiOfHelpers, HasParamEnv, HasTyCtxt, LayoutOf, LayoutOfHelpers,
|
||||
};
|
||||
use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
|
||||
use rustc_middle::ty::{
|
||||
GenericPredicates, Instance, ParamEnv, ScalarInt, TypeVisitableExt, ValTree,
|
||||
GenericPredicates, Instance, List, ParamEnv, ScalarInt, TyCtxt, TypeVisitableExt, ValTree,
|
||||
};
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use stable_mir::abi::{FnAbi, Layout, LayoutShape};
|
||||
use stable_mir::compiler_interface::Context;
|
||||
use stable_mir::mir::alloc::GlobalAlloc;
|
||||
use stable_mir::mir::mono::{InstanceDef, StaticDef};
|
||||
|
@ -280,7 +287,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
|
||||
}
|
||||
|
||||
#[allow(rustc::usage_of_qualified_ty)]
|
||||
fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let inner = ty.internal(&mut *tables);
|
||||
|
@ -335,6 +341,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
instance.ty(tables.tcx, ParamEnv::reveal_all()).stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let instance = tables.instances[def];
|
||||
Ok(tables.fn_abi_of_instance(instance, List::empty())?.stable(&mut *tables))
|
||||
}
|
||||
|
||||
fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let def_id = tables.instances[def].def_id();
|
||||
|
@ -473,6 +485,65 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let ty = ty.internal(&mut *tables);
|
||||
let layout = tables.layout_of(ty)?.layout;
|
||||
Ok(layout.stable(&mut *tables))
|
||||
}
|
||||
|
||||
fn layout_shape(&self, id: Layout) -> LayoutShape {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
id.internal(&mut *tables).0.stable(&mut *tables)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
|
||||
|
||||
/// Implement error handling for extracting function ABI information.
|
||||
impl<'tcx> FnAbiOfHelpers<'tcx> for Tables<'tcx> {
|
||||
type FnAbiOfResult = Result<&'tcx rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>>, Error>;
|
||||
|
||||
#[inline]
|
||||
fn handle_fn_abi_err(
|
||||
&self,
|
||||
err: ty::layout::FnAbiError<'tcx>,
|
||||
_span: rustc_span::Span,
|
||||
fn_abi_request: ty::layout::FnAbiRequest<'tcx>,
|
||||
) -> Error {
|
||||
Error::new(format!("Failed to get ABI for `{fn_abi_request:?}`: {err:?}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LayoutOfHelpers<'tcx> for Tables<'tcx> {
|
||||
type LayoutOfResult = Result<ty::layout::TyAndLayout<'tcx>, Error>;
|
||||
|
||||
#[inline]
|
||||
fn handle_layout_err(
|
||||
&self,
|
||||
err: ty::layout::LayoutError<'tcx>,
|
||||
_span: rustc_span::Span,
|
||||
ty: ty::Ty<'tcx>,
|
||||
) -> Error {
|
||||
Error::new(format!("Failed to get layout for `{ty}`: {err}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasParamEnv<'tcx> for Tables<'tcx> {
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
ty::ParamEnv::reveal_all()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasTyCtxt<'tcx> for Tables<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasDataLayout for Tables<'tcx> {
|
||||
fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
|
||||
self.tcx.data_layout()
|
||||
}
|
||||
}
|
||||
|
|
242
compiler/rustc_smir/src/rustc_smir/convert/abi.rs
Normal file
242
compiler/rustc_smir/src/rustc_smir/convert/abi.rs
Normal file
|
@ -0,0 +1,242 @@
|
|||
//! Conversion of internal Rust compiler `rustc_target::abi` and `rustc_abi` items to stable ones.
|
||||
|
||||
#![allow(rustc::usage_of_qualified_ty)]
|
||||
|
||||
use crate::rustc_smir::{Stable, Tables};
|
||||
use rustc_middle::ty;
|
||||
use rustc_target::abi::call::Conv;
|
||||
use stable_mir::abi::{
|
||||
ArgAbi, CallConvention, FieldsShape, FnAbi, Layout, LayoutShape, PassMode, TagEncoding,
|
||||
TyAndLayout, ValueAbi, VariantsShape,
|
||||
};
|
||||
use stable_mir::ty::{Align, IndexedVal, Size, VariantIdx};
|
||||
use stable_mir::{opaque, Opaque};
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
|
||||
type T = VariantIdx;
|
||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
||||
VariantIdx::to_val(self.as_usize())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
|
||||
type T = stable_mir::target::Endian;
|
||||
|
||||
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||
match self {
|
||||
rustc_abi::Endian::Little => stable_mir::target::Endian::Little,
|
||||
rustc_abi::Endian::Big => stable_mir::target::Endian::Big,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> {
|
||||
type T = TyAndLayout;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
TyAndLayout { ty: self.ty.stable(tables), layout: self.layout.stable(tables) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> {
|
||||
type T = Layout;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
tables.layout_id(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx>
|
||||
for rustc_abi::LayoutS<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
|
||||
{
|
||||
type T = LayoutShape;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
LayoutShape {
|
||||
fields: self.fields.stable(tables),
|
||||
variants: self.variants.stable(tables),
|
||||
abi: self.abi.stable(tables),
|
||||
abi_align: self.align.abi.stable(tables),
|
||||
size: self.size.stable(tables),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> {
|
||||
type T = FnAbi;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
assert!(self.args.len() >= self.fixed_count as usize);
|
||||
assert!(!self.c_variadic || matches!(self.conv, Conv::C));
|
||||
FnAbi {
|
||||
args: self.args.as_ref().stable(tables),
|
||||
ret: self.ret.stable(tables),
|
||||
fixed_count: self.fixed_count,
|
||||
conv: self.conv.stable(tables),
|
||||
c_variadic: self.c_variadic,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> {
|
||||
type T = ArgAbi;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
ArgAbi {
|
||||
ty: self.layout.ty.stable(tables),
|
||||
layout: self.layout.layout.stable(tables),
|
||||
mode: self.mode.stable(tables),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv {
|
||||
type T = CallConvention;
|
||||
|
||||
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||
match self {
|
||||
Conv::C => CallConvention::C,
|
||||
Conv::Rust => CallConvention::Rust,
|
||||
Conv::Cold => CallConvention::Cold,
|
||||
Conv::PreserveMost => CallConvention::PreserveMost,
|
||||
Conv::PreserveAll => CallConvention::PreserveAll,
|
||||
Conv::ArmAapcs => CallConvention::ArmAapcs,
|
||||
Conv::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall,
|
||||
Conv::Msp430Intr => CallConvention::Msp430Intr,
|
||||
Conv::PtxKernel => CallConvention::PtxKernel,
|
||||
Conv::X86Fastcall => CallConvention::X86Fastcall,
|
||||
Conv::X86Intr => CallConvention::X86Intr,
|
||||
Conv::X86Stdcall => CallConvention::X86Stdcall,
|
||||
Conv::X86ThisCall => CallConvention::X86ThisCall,
|
||||
Conv::X86VectorCall => CallConvention::X86VectorCall,
|
||||
Conv::X86_64SysV => CallConvention::X86_64SysV,
|
||||
Conv::X86_64Win64 => CallConvention::X86_64Win64,
|
||||
Conv::AmdGpuKernel => CallConvention::AmdGpuKernel,
|
||||
Conv::AvrInterrupt => CallConvention::AvrInterrupt,
|
||||
Conv::AvrNonBlockingInterrupt => CallConvention::AvrNonBlockingInterrupt,
|
||||
Conv::RiscvInterrupt { .. } => CallConvention::RiscvInterrupt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode {
|
||||
type T = PassMode;
|
||||
|
||||
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||
match self {
|
||||
rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore,
|
||||
rustc_target::abi::call::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)),
|
||||
rustc_target::abi::call::PassMode::Pair(first, second) => {
|
||||
PassMode::Pair(opaque(first), opaque(second))
|
||||
}
|
||||
rustc_target::abi::call::PassMode::Cast { pad_i32, cast } => {
|
||||
PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) }
|
||||
}
|
||||
rustc_target::abi::call::PassMode::Indirect { attrs, meta_attrs, on_stack } => {
|
||||
PassMode::Indirect {
|
||||
attrs: opaque(attrs),
|
||||
meta_attrs: opaque(meta_attrs),
|
||||
on_stack: *on_stack,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_target::abi::FieldIdx> {
|
||||
type T = FieldsShape;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
match self {
|
||||
rustc_abi::FieldsShape::Primitive => FieldsShape::Primitive,
|
||||
rustc_abi::FieldsShape::Union(count) => FieldsShape::Union(*count),
|
||||
rustc_abi::FieldsShape::Array { stride, count } => {
|
||||
FieldsShape::Array { stride: stride.stable(tables), count: *count }
|
||||
}
|
||||
rustc_abi::FieldsShape::Arbitrary { offsets, .. } => {
|
||||
FieldsShape::Arbitrary { offsets: offsets.iter().as_slice().stable(tables) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx>
|
||||
for rustc_abi::Variants<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
|
||||
{
|
||||
type T = VariantsShape;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
match self {
|
||||
rustc_abi::Variants::Single { index } => {
|
||||
VariantsShape::Single { index: index.stable(tables) }
|
||||
}
|
||||
rustc_abi::Variants::Multiple { tag, tag_encoding, tag_field, variants } => {
|
||||
VariantsShape::Multiple {
|
||||
tag: tag.stable(tables),
|
||||
tag_encoding: tag_encoding.stable(tables),
|
||||
tag_field: *tag_field,
|
||||
variants: variants.iter().as_slice().stable(tables),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_target::abi::VariantIdx> {
|
||||
type T = TagEncoding;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
match self {
|
||||
rustc_abi::TagEncoding::Direct => TagEncoding::Direct,
|
||||
rustc_abi::TagEncoding::Niche { untagged_variant, niche_variants, niche_start } => {
|
||||
TagEncoding::Niche {
|
||||
untagged_variant: untagged_variant.stable(tables),
|
||||
niche_variants: niche_variants.stable(tables),
|
||||
niche_start: *niche_start,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_abi::Abi {
|
||||
type T = ValueAbi;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
match *self {
|
||||
rustc_abi::Abi::Uninhabited => ValueAbi::Uninhabited,
|
||||
rustc_abi::Abi::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables)),
|
||||
rustc_abi::Abi::ScalarPair(first, second) => {
|
||||
ValueAbi::ScalarPair(first.stable(tables), second.stable(tables))
|
||||
}
|
||||
rustc_abi::Abi::Vector { element, count } => {
|
||||
ValueAbi::Vector { element: element.stable(tables), count }
|
||||
}
|
||||
rustc_abi::Abi::Aggregate { sized } => ValueAbi::Aggregate { sized },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_abi::Size {
|
||||
type T = Size;
|
||||
|
||||
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||
self.bytes_usize()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_abi::Align {
|
||||
type T = Align;
|
||||
|
||||
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||
self.bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_abi::Scalar {
|
||||
type T = Opaque;
|
||||
|
||||
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||
opaque(self)
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
//! Conversion of internal Rust compiler items to stable ones.
|
||||
|
||||
use rustc_target::abi::FieldIdx;
|
||||
use stable_mir::ty::{IndexedVal, VariantIdx};
|
||||
|
||||
use crate::rustc_smir::{Stable, Tables};
|
||||
|
||||
mod abi;
|
||||
mod error;
|
||||
mod mir;
|
||||
mod ty;
|
||||
|
@ -26,13 +26,6 @@ impl<'tcx> Stable<'tcx> for FieldIdx {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
|
||||
type T = VariantIdx;
|
||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
||||
VariantIdx::to_val(self.as_usize())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource {
|
||||
type T = stable_mir::mir::CoroutineSource;
|
||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
||||
|
@ -79,14 +72,3 @@ impl<'tcx> Stable<'tcx> for rustc_span::Span {
|
|||
tables.create_span(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
|
||||
type T = stable_mir::target::Endian;
|
||||
|
||||
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
|
||||
match self {
|
||||
rustc_abi::Endian::Little => stable_mir::target::Endian::Little,
|
||||
rustc_abi::Endian::Big => stable_mir::target::Endian::Big,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,9 +12,11 @@ use rustc_middle::mir;
|
|||
use rustc_middle::mir::interpret::AllocId;
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use stable_mir::abi::Layout;
|
||||
use stable_mir::mir::mono::InstanceDef;
|
||||
use stable_mir::ty::{ConstId, Span};
|
||||
use stable_mir::ItemKind;
|
||||
use std::ops::RangeInclusive;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::rustc_internal::IndexMap;
|
||||
|
@ -32,6 +34,7 @@ pub struct Tables<'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>,
|
||||
pub(crate) layouts: IndexMap<rustc_target::abi::Layout<'tcx>, Layout>,
|
||||
}
|
||||
|
||||
impl<'tcx> Tables<'tcx> {
|
||||
|
@ -162,3 +165,13 @@ where
|
|||
(self.0.stable(tables), self.1.stable(tables))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> Stable<'tcx> for RangeInclusive<T>
|
||||
where
|
||||
T: Stable<'tcx>,
|
||||
{
|
||||
type T = RangeInclusive<T::T>;
|
||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
RangeInclusive::new(self.start().stable(tables), self.end().stable(tables))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
//! * bidirectional-normalizes-to: If `A` and `B` are both projections, and both
|
||||
//! may apply, then we can compute the "intersection" of both normalizes-to by
|
||||
//! performing them together. This is used specifically to resolve ambiguities.
|
||||
use super::EvalCtxt;
|
||||
use super::{EvalCtxt, GoalSource};
|
||||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
||||
|
@ -89,11 +89,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
ty::TermKind::Const(_) => {
|
||||
if let Some(alias) = term.to_alias_ty(self.tcx()) {
|
||||
let term = self.next_term_infer_of_kind(term);
|
||||
self.add_goal(Goal::new(
|
||||
self.tcx(),
|
||||
param_env,
|
||||
ty::NormalizesTo { alias, term },
|
||||
));
|
||||
self.add_goal(
|
||||
GoalSource::Misc,
|
||||
Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias, term }),
|
||||
);
|
||||
self.try_evaluate_added_goals()?;
|
||||
Ok(Some(self.resolve_vars_if_possible(term)))
|
||||
} else {
|
||||
|
@ -109,7 +108,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
opaque: ty::AliasTy<'tcx>,
|
||||
term: ty::Term<'tcx>,
|
||||
) -> QueryResult<'tcx> {
|
||||
self.add_goal(Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias: opaque, term }));
|
||||
self.add_goal(
|
||||
GoalSource::Misc,
|
||||
Goal::new(self.tcx(), param_env, ty::NormalizesTo { alias: opaque, term }),
|
||||
);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Code shared by trait and projection goals for candidate assembly.
|
||||
|
||||
use super::{EvalCtxt, SolverMode};
|
||||
use crate::solve::GoalSource;
|
||||
use crate::traits::coherence;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
|
@ -62,7 +63,9 @@ pub(super) trait GoalKind<'tcx>:
|
|||
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
|
||||
ecx.add_goals(requirements);
|
||||
// FIXME(-Znext-solver=coinductive): check whether this should be
|
||||
// `GoalSource::ImplWhereBound` for any caller.
|
||||
ecx.add_goals(GoalSource::Misc, requirements);
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
}
|
||||
|
@ -94,12 +97,16 @@ pub(super) trait GoalKind<'tcx>:
|
|||
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
|
||||
bug!("expected object type in `consider_object_bound_candidate`");
|
||||
};
|
||||
ecx.add_goals(structural_traits::predicates_for_object_candidate(
|
||||
// FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
|
||||
ecx.add_goals(
|
||||
GoalSource::Misc,
|
||||
structural_traits::predicates_for_object_candidate(
|
||||
ecx,
|
||||
goal.param_env,
|
||||
goal.predicate.trait_ref(tcx),
|
||||
bounds,
|
||||
));
|
||||
),
|
||||
);
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
}
|
||||
|
@ -364,7 +371,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
let normalized_ty = ecx.next_ty_infer();
|
||||
let normalizes_to_goal =
|
||||
goal.with(tcx, ty::NormalizesTo { alias, term: normalized_ty.into() });
|
||||
ecx.add_goal(normalizes_to_goal);
|
||||
ecx.add_goal(GoalSource::Misc, normalizes_to_goal);
|
||||
if let Err(NoSolution) = ecx.try_evaluate_added_goals() {
|
||||
debug!("self type normalization failed");
|
||||
return vec![];
|
||||
|
|
|
@ -94,20 +94,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
);
|
||||
|
||||
let certainty = certainty.unify_with(goals_certainty);
|
||||
if let Certainty::OVERFLOW = certainty {
|
||||
// If we have overflow, it's probable that we're substituting a type
|
||||
// into itself infinitely and any partial substitutions in the query
|
||||
// response are probably not useful anyways, so just return an empty
|
||||
// query response.
|
||||
//
|
||||
// This may prevent us from potentially useful inference, e.g.
|
||||
// 2 candidates, one ambiguous and one overflow, which both
|
||||
// have the same inference constraints.
|
||||
//
|
||||
// Changing this to retain some constraints in the future
|
||||
// won't be a breaking change, so this is good enough for now.
|
||||
return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow));
|
||||
}
|
||||
|
||||
let var_values = self.var_values;
|
||||
let external_constraints = self.compute_external_query_constraints()?;
|
||||
|
|
|
@ -23,14 +23,15 @@ use rustc_middle::ty::{
|
|||
use rustc_session::config::DumpSolverProofTree;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use std::io::Write;
|
||||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
|
||||
|
||||
use super::inspect::ProofTreeBuilder;
|
||||
use super::SolverMode;
|
||||
use super::{search_graph, GoalEvaluationKind};
|
||||
use super::{search_graph::SearchGraph, Goal};
|
||||
use super::{GoalSource, SolverMode};
|
||||
pub use select::InferCtxtSelectExt;
|
||||
|
||||
mod canonical;
|
||||
|
@ -105,7 +106,7 @@ pub(super) struct NestedGoals<'tcx> {
|
|||
/// can be unsound with more powerful coinduction in the future.
|
||||
pub(super) normalizes_to_hack_goal: Option<Goal<'tcx, ty::NormalizesTo<'tcx>>>,
|
||||
/// The rest of the goals which have not yet processed or remain ambiguous.
|
||||
pub(super) goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
pub(super) goals: Vec<(GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>,
|
||||
}
|
||||
|
||||
impl<'tcx> NestedGoals<'tcx> {
|
||||
|
@ -156,7 +157,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
|
|||
Option<inspect::GoalEvaluation<'tcx>>,
|
||||
) {
|
||||
EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
|
||||
ecx.evaluate_goal(GoalEvaluationKind::Root, goal)
|
||||
ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -334,6 +335,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
fn evaluate_goal(
|
||||
&mut self,
|
||||
goal_evaluation_kind: GoalEvaluationKind,
|
||||
source: GoalSource,
|
||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
) -> Result<(bool, Certainty, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
|
||||
let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
|
||||
|
@ -353,10 +355,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
Ok(response) => response,
|
||||
};
|
||||
|
||||
let has_changed = !canonical_response.value.var_values.is_identity_modulo_regions()
|
||||
|| !canonical_response.value.external_constraints.opaque_types.is_empty();
|
||||
let (certainty, nested_goals) = match self.instantiate_and_apply_query_response(
|
||||
let (certainty, has_changed, nested_goals) = match self
|
||||
.instantiate_response_discarding_overflow(
|
||||
goal.param_env,
|
||||
source,
|
||||
orig_values,
|
||||
canonical_response,
|
||||
) {
|
||||
|
@ -386,6 +388,44 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
Ok((has_changed, certainty, nested_goals))
|
||||
}
|
||||
|
||||
fn instantiate_response_discarding_overflow(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
source: GoalSource,
|
||||
original_values: Vec<ty::GenericArg<'tcx>>,
|
||||
response: CanonicalResponse<'tcx>,
|
||||
) -> Result<(Certainty, bool, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), NoSolution> {
|
||||
// The old solver did not evaluate nested goals when normalizing.
|
||||
// It returned the selection constraints allowing a `Projection`
|
||||
// obligation to not hold in coherence while avoiding the fatal error
|
||||
// from overflow.
|
||||
//
|
||||
// We match this behavior here by considering all constraints
|
||||
// from nested goals which are not from where-bounds. We will already
|
||||
// need to track which nested goals are required by impl where-bounds
|
||||
// for coinductive cycles, so we simply reuse that here.
|
||||
//
|
||||
// While we could consider overflow constraints in more cases, this should
|
||||
// not be necessary for backcompat and results in better perf. It also
|
||||
// avoids a potential inconsistency which would otherwise require some
|
||||
// tracking for root goals as well. See #119071 for an example.
|
||||
let keep_overflow_constraints = || {
|
||||
self.search_graph.current_goal_is_normalizes_to()
|
||||
&& source != GoalSource::ImplWhereBound
|
||||
};
|
||||
|
||||
if response.value.certainty == Certainty::OVERFLOW && !keep_overflow_constraints() {
|
||||
Ok((Certainty::OVERFLOW, false, Vec::new()))
|
||||
} else {
|
||||
let has_changed = !response.value.var_values.is_identity_modulo_regions()
|
||||
|| !response.value.external_constraints.opaque_types.is_empty();
|
||||
|
||||
let (certainty, nested_goals) =
|
||||
self.instantiate_and_apply_query_response(param_env, original_values, response)?;
|
||||
Ok((certainty, has_changed, nested_goals))
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
|
||||
let Goal { param_env, predicate } = goal;
|
||||
let kind = predicate.kind();
|
||||
|
@ -439,7 +479,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
let kind = self.infcx.instantiate_binder_with_placeholders(kind);
|
||||
let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
|
||||
self.add_goal(goal);
|
||||
self.add_goal(GoalSource::Misc, goal);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
}
|
||||
|
@ -488,6 +528,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new());
|
||||
|
||||
self.inspect.evaluate_added_goals_loop_start();
|
||||
|
||||
fn with_misc_source<'tcx>(
|
||||
it: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
) -> impl Iterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)> {
|
||||
iter::zip(iter::repeat(GoalSource::Misc), it)
|
||||
}
|
||||
|
||||
// If this loop did not result in any progress, what's our final certainty.
|
||||
let mut unchanged_certainty = Some(Certainty::Yes);
|
||||
if let Some(goal) = goals.normalizes_to_hack_goal.take() {
|
||||
|
@ -501,9 +548,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
|
||||
let (_, certainty, instantiate_goals) = self.evaluate_goal(
|
||||
GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes },
|
||||
GoalSource::Misc,
|
||||
unconstrained_goal,
|
||||
)?;
|
||||
self.nested_goals.goals.extend(instantiate_goals);
|
||||
self.nested_goals.goals.extend(with_misc_source(instantiate_goals));
|
||||
|
||||
// Finally, equate the goal's RHS with the unconstrained var.
|
||||
// We put the nested goals from this into goals instead of
|
||||
|
@ -512,7 +560,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
// matters in practice, though.
|
||||
let eq_goals =
|
||||
self.eq_and_get_goals(goal.param_env, goal.predicate.term, unconstrained_rhs)?;
|
||||
goals.goals.extend(eq_goals);
|
||||
goals.goals.extend(with_misc_source(eq_goals));
|
||||
|
||||
// We only look at the `projection_ty` part here rather than
|
||||
// looking at the "has changed" return from evaluate_goal,
|
||||
|
@ -533,12 +581,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
for goal in goals.goals.drain(..) {
|
||||
for (source, goal) in goals.goals.drain(..) {
|
||||
let (has_changed, certainty, instantiate_goals) = self.evaluate_goal(
|
||||
GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::No },
|
||||
source,
|
||||
goal,
|
||||
)?;
|
||||
self.nested_goals.goals.extend(instantiate_goals);
|
||||
self.nested_goals.goals.extend(with_misc_source(instantiate_goals));
|
||||
if has_changed {
|
||||
unchanged_certainty = None;
|
||||
}
|
||||
|
@ -546,7 +595,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
match certainty {
|
||||
Certainty::Yes => {}
|
||||
Certainty::Maybe(_) => {
|
||||
self.nested_goals.goals.push(goal);
|
||||
self.nested_goals.goals.push((source, goal));
|
||||
unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty));
|
||||
}
|
||||
}
|
||||
|
@ -670,7 +719,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(DefineOpaqueTypes::No, lhs, rhs)
|
||||
.map(|InferOk { value: (), obligations }| {
|
||||
self.add_goals(obligations.into_iter().map(|o| o.into()));
|
||||
self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
|
||||
})
|
||||
.map_err(|e| {
|
||||
debug!(?e, "failed to equate");
|
||||
|
@ -689,7 +738,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
.at(&ObligationCause::dummy(), param_env)
|
||||
.sub(DefineOpaqueTypes::No, sub, sup)
|
||||
.map(|InferOk { value: (), obligations }| {
|
||||
self.add_goals(obligations.into_iter().map(|o| o.into()));
|
||||
self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
|
||||
})
|
||||
.map_err(|e| {
|
||||
debug!(?e, "failed to subtype");
|
||||
|
@ -709,7 +758,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
.at(&ObligationCause::dummy(), param_env)
|
||||
.relate(DefineOpaqueTypes::No, lhs, variance, rhs)
|
||||
.map(|InferOk { value: (), obligations }| {
|
||||
self.add_goals(obligations.into_iter().map(|o| o.into()));
|
||||
self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
|
||||
})
|
||||
.map_err(|e| {
|
||||
debug!(?e, "failed to relate");
|
||||
|
@ -842,7 +891,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
true,
|
||||
&mut obligations,
|
||||
)?;
|
||||
self.add_goals(obligations.into_iter().map(|o| o.into()));
|
||||
self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -862,7 +911,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
hidden_ty,
|
||||
&mut obligations,
|
||||
);
|
||||
self.add_goals(obligations.into_iter().map(|o| o.into()));
|
||||
self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
|
||||
}
|
||||
|
||||
// Do something for each opaque/hidden pair defined with `def_id` in the
|
||||
|
|
|
@ -119,7 +119,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
|||
) {
|
||||
for step in &probe.steps {
|
||||
match step {
|
||||
&inspect::ProbeStep::AddGoal(goal) => nested_goals.push(goal),
|
||||
&inspect::ProbeStep::AddGoal(_source, goal) => nested_goals.push(goal),
|
||||
inspect::ProbeStep::NestedProbe(ref probe) => {
|
||||
// Nested probes have to prove goals added in their parent
|
||||
// but do not leak them, so we truncate the added goals
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::mem;
|
|||
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{
|
||||
CanonicalInput, Certainty, Goal, IsNormalizesToHack, QueryInput, QueryResult,
|
||||
CanonicalInput, Certainty, Goal, GoalSource, IsNormalizesToHack, QueryInput, QueryResult,
|
||||
};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::config::DumpSolverProofTree;
|
||||
|
@ -216,7 +216,7 @@ impl<'tcx> WipProbe<'tcx> {
|
|||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
enum WipProbeStep<'tcx> {
|
||||
AddGoal(inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
|
||||
AddGoal(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
|
||||
EvaluateGoals(WipAddedGoalsEvaluation<'tcx>),
|
||||
NestedProbe(WipProbe<'tcx>),
|
||||
CommitIfOkStart,
|
||||
|
@ -226,7 +226,7 @@ enum WipProbeStep<'tcx> {
|
|||
impl<'tcx> WipProbeStep<'tcx> {
|
||||
fn finalize(self) -> inspect::ProbeStep<'tcx> {
|
||||
match self {
|
||||
WipProbeStep::AddGoal(goal) => inspect::ProbeStep::AddGoal(goal),
|
||||
WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal),
|
||||
WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()),
|
||||
WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()),
|
||||
WipProbeStep::CommitIfOkStart => inspect::ProbeStep::CommitIfOkStart,
|
||||
|
@ -428,7 +428,11 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_goal(ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
|
||||
pub fn add_goal(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
source: GoalSource,
|
||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
) {
|
||||
// Can't use `if let Some(this) = ecx.inspect.as_mut()` here because
|
||||
// we have to immutably use the `EvalCtxt` for `make_canonical_state`.
|
||||
if ecx.inspect.is_noop() {
|
||||
|
@ -442,7 +446,9 @@ impl<'tcx> ProofTreeBuilder<'tcx> {
|
|||
evaluation: WipProbe { steps, .. },
|
||||
..
|
||||
})
|
||||
| DebugSolver::Probe(WipProbe { steps, .. }) => steps.push(WipProbeStep::AddGoal(goal)),
|
||||
| DebugSolver::Probe(WipProbe { steps, .. }) => {
|
||||
steps.push(WipProbeStep::AddGoal(source, goal))
|
||||
}
|
||||
s => unreachable!("tried to add {goal:?} to {s:?}"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ use rustc_infer::infer::DefineOpaqueTypes;
|
|||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::infer::canonical::CanonicalVarInfos;
|
||||
use rustc_middle::traits::solve::{
|
||||
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, IsNormalizesToHack, QueryResult,
|
||||
Response,
|
||||
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
|
||||
QueryResult, Response,
|
||||
};
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
|
||||
use rustc_middle::ty::{
|
||||
|
@ -157,7 +157,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
) -> QueryResult<'tcx> {
|
||||
match self.well_formed_goals(goal.param_env, goal.predicate) {
|
||||
Some(goals) => {
|
||||
self.add_goals(goals);
|
||||
self.add_goals(GoalSource::Misc, goals);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
None => self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS),
|
||||
|
@ -223,15 +223,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn add_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
|
||||
inspect::ProofTreeBuilder::add_goal(self, goal);
|
||||
self.nested_goals.goals.push(goal);
|
||||
fn add_goal(&mut self, source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
|
||||
inspect::ProofTreeBuilder::add_goal(self, source, goal);
|
||||
self.nested_goals.goals.push((source, goal));
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, goals))]
|
||||
fn add_goals(&mut self, goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>) {
|
||||
fn add_goals(
|
||||
&mut self,
|
||||
source: GoalSource,
|
||||
goals: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
) {
|
||||
for goal in goals {
|
||||
self.add_goal(goal);
|
||||
self.add_goal(source, goal);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,7 +339,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
param_env,
|
||||
ty::NormalizesTo { alias, term: normalized_ty.into() },
|
||||
);
|
||||
this.add_goal(normalizes_to_goal);
|
||||
this.add_goal(GoalSource::Misc, normalizes_to_goal);
|
||||
this.try_evaluate_added_goals()?;
|
||||
let ty = this.resolve_vars_if_possible(normalized_ty);
|
||||
Ok(this.try_normalize_ty_recur(param_env, define_opaque_types, depth + 1, ty))
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
//! 1. instantiate substs,
|
||||
//! 2. equate the self type, and
|
||||
//! 3. instantiate and register where clauses.
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
|
||||
use rustc_middle::ty;
|
||||
|
||||
use super::EvalCtxt;
|
||||
use crate::solve::EvalCtxt;
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
pub(super) fn normalize_inherent_associated_type(
|
||||
|
@ -38,7 +38,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
.expect("expected goal term to be fully unconstrained");
|
||||
|
||||
// Check both where clauses on the impl and IAT
|
||||
//
|
||||
// FIXME(-Znext-solver=coinductive): I think this should be split
|
||||
// and we tag the impl bounds with `GoalSource::ImplWhereBound`?
|
||||
// Right not this includes both the impl and the assoc item where bounds,
|
||||
// and I don't think the assoc item where-bounds are allowed to be coinductive.
|
||||
self.add_goals(
|
||||
GoalSource::Misc,
|
||||
tcx.predicates_of(inherent.def_id)
|
||||
.instantiate(tcx, inherent_substs)
|
||||
.into_iter()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::traits::{check_args_compatible, specialization_graph};
|
||||
|
||||
use super::assembly::{self, structural_traits, Candidate};
|
||||
use super::EvalCtxt;
|
||||
use super::{EvalCtxt, GoalSource};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::LangItem;
|
||||
|
@ -128,6 +128,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||
|
||||
// Add GAT where clauses from the trait's definition
|
||||
ecx.add_goals(
|
||||
GoalSource::Misc,
|
||||
tcx.predicates_of(goal.predicate.def_id())
|
||||
.instantiate_own(tcx, goal.predicate.alias.args)
|
||||
.map(|(pred, _)| goal.with(tcx, pred)),
|
||||
|
@ -169,10 +170,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||
.predicates
|
||||
.into_iter()
|
||||
.map(|pred| goal.with(tcx, pred));
|
||||
ecx.add_goals(where_clause_bounds);
|
||||
ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
|
||||
|
||||
// Add GAT where clauses from the trait's definition
|
||||
ecx.add_goals(
|
||||
GoalSource::Misc,
|
||||
tcx.predicates_of(goal.predicate.def_id())
|
||||
.instantiate_own(tcx, goal.predicate.alias.args)
|
||||
.map(|(pred, _)| goal.with(tcx, pred)),
|
||||
|
@ -413,7 +415,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||
DUMMY_SP,
|
||||
[ty::GenericArg::from(goal.predicate.self_ty())],
|
||||
);
|
||||
ecx.add_goal(goal.with(tcx, sized_predicate));
|
||||
// FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
|
||||
ecx.add_goal(GoalSource::Misc, goal.with(tcx, sized_predicate));
|
||||
tcx.types.unit
|
||||
}
|
||||
|
||||
|
@ -421,7 +424,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||
None => tcx.types.unit,
|
||||
Some(field_def) => {
|
||||
let self_ty = field_def.ty(tcx, args);
|
||||
ecx.add_goal(goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)));
|
||||
// FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
|
||||
ecx.add_goal(
|
||||
GoalSource::Misc,
|
||||
goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)),
|
||||
);
|
||||
return ecx
|
||||
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
|
||||
}
|
||||
|
@ -431,7 +438,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||
ty::Tuple(elements) => match elements.last() {
|
||||
None => tcx.types.unit,
|
||||
Some(&self_ty) => {
|
||||
ecx.add_goal(goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)));
|
||||
// FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
|
||||
ecx.add_goal(
|
||||
GoalSource::Misc,
|
||||
goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty)),
|
||||
);
|
||||
return ecx
|
||||
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
//!
|
||||
//! Since a weak alias is not ambiguous, this just computes the `type_of` of
|
||||
//! the alias and registers the where-clauses of the type alias.
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
|
||||
use rustc_middle::ty;
|
||||
|
||||
use super::EvalCtxt;
|
||||
use crate::solve::EvalCtxt;
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
pub(super) fn normalize_weak_type(
|
||||
|
@ -22,6 +22,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
|
||||
// Check where clauses
|
||||
self.add_goals(
|
||||
GoalSource::Misc,
|
||||
tcx.predicates_of(weak_ty.def_id)
|
||||
.instantiate(tcx, weak_ty.args)
|
||||
.predicates
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::solve::GoalSource;
|
||||
|
||||
use super::EvalCtxt;
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
||||
use rustc_middle::ty::{self, ProjectionPredicate};
|
||||
|
@ -22,14 +24,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
)
|
||||
.into(),
|
||||
};
|
||||
self.add_goal(goal.with(
|
||||
let goal = goal.with(
|
||||
tcx,
|
||||
ty::PredicateKind::AliasRelate(
|
||||
projection_term,
|
||||
goal.predicate.term,
|
||||
ty::AliasRelationDirection::Equate,
|
||||
),
|
||||
));
|
||||
);
|
||||
self.add_goal(GoalSource::Misc, goal);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ use rustc_index::IndexVec;
|
|||
use rustc_middle::dep_graph::dep_kinds;
|
||||
use rustc_middle::traits::solve::CacheData;
|
||||
use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Limit;
|
||||
use std::collections::hash_map::Entry;
|
||||
|
@ -111,6 +112,15 @@ impl<'tcx> SearchGraph<'tcx> {
|
|||
self.stack.is_empty()
|
||||
}
|
||||
|
||||
pub(super) fn current_goal_is_normalizes_to(&self) -> bool {
|
||||
self.stack.raw.last().map_or(false, |e| {
|
||||
matches!(
|
||||
e.input.value.goal.predicate.kind().skip_binder(),
|
||||
ty::PredicateKind::NormalizesTo(..)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the remaining depth allowed for nested goals.
|
||||
///
|
||||
/// This is generally simply one less than the current depth.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
|
||||
|
||||
use super::assembly::{self, structural_traits, Candidate};
|
||||
use super::{EvalCtxt, SolverMode};
|
||||
use super::{EvalCtxt, GoalSource, SolverMode};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{LangItem, Movability};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
|
@ -72,7 +72,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||
.predicates
|
||||
.into_iter()
|
||||
.map(|pred| goal.with(tcx, pred));
|
||||
ecx.add_goals(where_clause_bounds);
|
||||
ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
|
||||
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
|
||||
})
|
||||
|
@ -172,7 +172,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||
let nested_obligations = tcx
|
||||
.predicates_of(goal.predicate.def_id())
|
||||
.instantiate(tcx, goal.predicate.trait_ref.args);
|
||||
ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)));
|
||||
// FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
|
||||
ecx.add_goals(
|
||||
GoalSource::Misc,
|
||||
nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)),
|
||||
);
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
}
|
||||
|
@ -512,17 +516,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||
|
||||
// Check that the type implements all of the predicates of the trait object.
|
||||
// (i.e. the principal, all of the associated types match, and any auto traits)
|
||||
ecx.add_goals(b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))));
|
||||
ecx.add_goals(
|
||||
GoalSource::ImplWhereBound,
|
||||
b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
|
||||
);
|
||||
|
||||
// The type must be `Sized` to be unsized.
|
||||
if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
|
||||
ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])));
|
||||
ecx.add_goal(
|
||||
GoalSource::ImplWhereBound,
|
||||
goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])),
|
||||
);
|
||||
} else {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// The type must outlive the lifetime of the `dyn` we're unsizing into.
|
||||
ecx.add_goal(goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region)));
|
||||
ecx.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region)));
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
}
|
||||
|
@ -749,11 +759,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
// Also require that a_ty's lifetime outlives b_ty's lifetime.
|
||||
self.add_goal(Goal::new(
|
||||
self.add_goal(
|
||||
GoalSource::ImplWhereBound,
|
||||
Goal::new(
|
||||
self.tcx(),
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
|
||||
));
|
||||
),
|
||||
);
|
||||
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
|
@ -826,14 +839,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
// Finally, we require that `TailA: Unsize<TailB>` for the tail field
|
||||
// types.
|
||||
self.eq(goal.param_env, unsized_a_ty, b_ty)?;
|
||||
self.add_goal(goal.with(
|
||||
self.add_goal(
|
||||
GoalSource::ImplWhereBound,
|
||||
goal.with(
|
||||
tcx,
|
||||
ty::TraitRef::new(
|
||||
tcx,
|
||||
tcx.lang_items().unsize_trait().unwrap(),
|
||||
[a_tail_ty, b_tail_ty],
|
||||
),
|
||||
));
|
||||
),
|
||||
);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
|
||||
|
@ -865,14 +881,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
self.eq(goal.param_env, unsized_a_ty, b_ty)?;
|
||||
|
||||
// Similar to ADTs, require that we can unsize the tail.
|
||||
self.add_goal(goal.with(
|
||||
self.add_goal(
|
||||
GoalSource::ImplWhereBound,
|
||||
goal.with(
|
||||
tcx,
|
||||
ty::TraitRef::new(
|
||||
tcx,
|
||||
tcx.lang_items().unsize_trait().unwrap(),
|
||||
[a_last_ty, b_last_ty],
|
||||
),
|
||||
));
|
||||
),
|
||||
);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
|
||||
|
@ -981,6 +1000,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
) -> QueryResult<'tcx> {
|
||||
self.probe_misc_candidate("constituent tys").enter(|ecx| {
|
||||
ecx.add_goals(
|
||||
GoalSource::ImplWhereBound,
|
||||
constituent_tys(ecx, goal.predicate.self_ty())?
|
||||
.into_iter()
|
||||
.map(|ty| goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty)))
|
||||
|
|
283
compiler/stable_mir/src/abi.rs
Normal file
283
compiler/stable_mir/src/abi.rs
Normal file
|
@ -0,0 +1,283 @@
|
|||
use crate::compiler_interface::with;
|
||||
use crate::mir::FieldIdx;
|
||||
use crate::ty::{Align, IndexedVal, Size, Ty, VariantIdx};
|
||||
use crate::Opaque;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
/// A function ABI definition.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct FnAbi {
|
||||
/// The types of each argument.
|
||||
pub args: Vec<ArgAbi>,
|
||||
|
||||
/// The expected return type.
|
||||
pub ret: ArgAbi,
|
||||
|
||||
/// The count of non-variadic arguments.
|
||||
///
|
||||
/// Should only be different from `args.len()` when a function is a C variadic function.
|
||||
pub fixed_count: u32,
|
||||
|
||||
/// The ABI convention.
|
||||
pub conv: CallConvention,
|
||||
|
||||
/// Whether this is a variadic C function,
|
||||
pub c_variadic: bool,
|
||||
}
|
||||
|
||||
/// Information about the ABI of a function's argument, or return value.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ArgAbi {
|
||||
pub ty: Ty,
|
||||
pub layout: Layout,
|
||||
pub mode: PassMode,
|
||||
}
|
||||
|
||||
/// How a function argument should be passed in to the target function.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum PassMode {
|
||||
/// Ignore the argument.
|
||||
///
|
||||
/// The argument is either uninhabited or a ZST.
|
||||
Ignore,
|
||||
/// Pass the argument directly.
|
||||
///
|
||||
/// The argument has a layout abi of `Scalar` or `Vector`.
|
||||
Direct(Opaque),
|
||||
/// Pass a pair's elements directly in two arguments.
|
||||
///
|
||||
/// The argument has a layout abi of `ScalarPair`.
|
||||
Pair(Opaque, Opaque),
|
||||
/// Pass the argument after casting it.
|
||||
Cast { pad_i32: bool, cast: Opaque },
|
||||
/// Pass the argument indirectly via a hidden pointer.
|
||||
Indirect { attrs: Opaque, meta_attrs: Opaque, on_stack: bool },
|
||||
}
|
||||
|
||||
/// The layout of a type, alongside the type itself.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct TyAndLayout {
|
||||
pub ty: Ty,
|
||||
pub layout: Layout,
|
||||
}
|
||||
|
||||
/// The layout of a type in memory.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct LayoutShape {
|
||||
/// The fields location withing the layout
|
||||
pub fields: FieldsShape,
|
||||
|
||||
/// Encodes information about multi-variant layouts.
|
||||
/// Even with `Multiple` variants, a layout still has its own fields! Those are then
|
||||
/// shared between all variants.
|
||||
///
|
||||
/// To access all fields of this layout, both `fields` and the fields of the active variant
|
||||
/// must be taken into account.
|
||||
pub variants: VariantsShape,
|
||||
|
||||
/// The `abi` defines how this data is passed between functions.
|
||||
pub abi: ValueAbi,
|
||||
|
||||
/// The ABI mandated alignment in bytes.
|
||||
pub abi_align: Align,
|
||||
|
||||
/// The size of this layout in bytes.
|
||||
pub size: Size,
|
||||
}
|
||||
|
||||
impl LayoutShape {
|
||||
/// Returns `true` if the layout corresponds to an unsized type.
|
||||
#[inline]
|
||||
pub fn is_unsized(&self) -> bool {
|
||||
self.abi.is_unsized()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_sized(&self) -> bool {
|
||||
!self.abi.is_unsized()
|
||||
}
|
||||
|
||||
/// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1).
|
||||
pub fn is_1zst(&self) -> bool {
|
||||
self.is_sized() && self.size == 0 && self.abi_align == 1
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Layout(usize);
|
||||
|
||||
impl Layout {
|
||||
pub fn shape(self) -> LayoutShape {
|
||||
with(|cx| cx.layout_shape(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexedVal for Layout {
|
||||
fn to_val(index: usize) -> Self {
|
||||
Layout(index)
|
||||
}
|
||||
fn to_index(&self) -> usize {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes how the fields of a type are shaped in memory.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum FieldsShape {
|
||||
/// Scalar primitives and `!`, which never have fields.
|
||||
Primitive,
|
||||
|
||||
/// All fields start at no offset. The `usize` is the field count.
|
||||
Union(NonZeroUsize),
|
||||
|
||||
/// Array/vector-like placement, with all fields of identical types.
|
||||
Array { stride: Size, count: u64 },
|
||||
|
||||
/// Struct-like placement, with precomputed offsets.
|
||||
///
|
||||
/// Fields are guaranteed to not overlap, but note that gaps
|
||||
/// before, between and after all the fields are NOT always
|
||||
/// padding, and as such their contents may not be discarded.
|
||||
/// For example, enum variants leave a gap at the start,
|
||||
/// where the discriminant field in the enum layout goes.
|
||||
Arbitrary {
|
||||
/// Offsets for the first byte of each field,
|
||||
/// ordered to match the source definition order.
|
||||
/// I.e.: It follows the same order as [crate::ty::VariantDef::fields()].
|
||||
/// This vector does not go in increasing order.
|
||||
offsets: Vec<Size>,
|
||||
},
|
||||
}
|
||||
|
||||
impl FieldsShape {
|
||||
pub fn fields_by_offset_order(&self) -> Vec<FieldIdx> {
|
||||
match self {
|
||||
FieldsShape::Primitive => vec![],
|
||||
FieldsShape::Union(_) | FieldsShape::Array { .. } => (0..self.count()).collect(),
|
||||
FieldsShape::Arbitrary { offsets, .. } => {
|
||||
let mut indices = (0..offsets.len()).collect::<Vec<_>>();
|
||||
indices.sort_by_key(|idx| offsets[*idx]);
|
||||
indices
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count(&self) -> usize {
|
||||
match self {
|
||||
FieldsShape::Primitive => 0,
|
||||
FieldsShape::Union(count) => count.get(),
|
||||
FieldsShape::Array { count, .. } => *count as usize,
|
||||
FieldsShape::Arbitrary { offsets, .. } => offsets.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum VariantsShape {
|
||||
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
|
||||
Single { index: VariantIdx },
|
||||
|
||||
/// Enum-likes with more than one inhabited variant: each variant comes with
|
||||
/// a *discriminant* (usually the same as the variant index but the user can
|
||||
/// assign explicit discriminant values). That discriminant is encoded
|
||||
/// as a *tag* on the machine. The layout of each variant is
|
||||
/// a struct, and they all have space reserved for the tag.
|
||||
/// For enums, the tag is the sole field of the layout.
|
||||
Multiple {
|
||||
tag: Scalar,
|
||||
tag_encoding: TagEncoding,
|
||||
tag_field: usize,
|
||||
variants: Vec<LayoutShape>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum TagEncoding {
|
||||
/// The tag directly stores the discriminant, but possibly with a smaller layout
|
||||
/// (so converting the tag to the discriminant can require sign extension).
|
||||
Direct,
|
||||
|
||||
/// Niche (values invalid for a type) encoding the discriminant:
|
||||
/// Discriminant and variant index coincide.
|
||||
/// The variant `untagged_variant` contains a niche at an arbitrary
|
||||
/// offset (field `tag_field` of the enum), which for a variant with
|
||||
/// discriminant `d` is set to
|
||||
/// `(d - niche_variants.start).wrapping_add(niche_start)`.
|
||||
///
|
||||
/// For example, `Option<(usize, &T)>` is represented such that
|
||||
/// `None` has a null pointer for the second tuple field, and
|
||||
/// `Some` is the identity function (with a non-null reference).
|
||||
Niche {
|
||||
untagged_variant: VariantIdx,
|
||||
niche_variants: RangeInclusive<VariantIdx>,
|
||||
niche_start: u128,
|
||||
},
|
||||
}
|
||||
|
||||
/// Describes how values of the type are passed by target ABIs,
|
||||
/// in terms of categories of C types there are ABI rules for.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ValueAbi {
|
||||
Uninhabited,
|
||||
Scalar(Scalar),
|
||||
ScalarPair(Scalar, Scalar),
|
||||
Vector {
|
||||
element: Scalar,
|
||||
count: u64,
|
||||
},
|
||||
Aggregate {
|
||||
/// If true, the size is exact, otherwise it's only a lower bound.
|
||||
sized: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl ValueAbi {
|
||||
/// Returns `true` if the layout corresponds to an unsized type.
|
||||
pub fn is_unsized(&self) -> bool {
|
||||
match *self {
|
||||
ValueAbi::Uninhabited
|
||||
| ValueAbi::Scalar(_)
|
||||
| ValueAbi::ScalarPair(..)
|
||||
| ValueAbi::Vector { .. } => false,
|
||||
ValueAbi::Aggregate { sized } => !sized,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// We currently do not support `Scalar`, and use opaque instead.
|
||||
type Scalar = Opaque;
|
||||
|
||||
/// General language calling conventions.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum CallConvention {
|
||||
C,
|
||||
Rust,
|
||||
|
||||
Cold,
|
||||
PreserveMost,
|
||||
PreserveAll,
|
||||
|
||||
// Target-specific calling conventions.
|
||||
ArmAapcs,
|
||||
CCmseNonSecureCall,
|
||||
|
||||
Msp430Intr,
|
||||
|
||||
PtxKernel,
|
||||
|
||||
X86Fastcall,
|
||||
X86Intr,
|
||||
X86Stdcall,
|
||||
X86ThisCall,
|
||||
X86VectorCall,
|
||||
|
||||
X86_64SysV,
|
||||
X86_64Win64,
|
||||
|
||||
AmdGpuKernel,
|
||||
AvrInterrupt,
|
||||
AvrNonBlockingInterrupt,
|
||||
|
||||
RiscvInterrupt,
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
use std::cell::Cell;
|
||||
|
||||
use crate::abi::{FnAbi, Layout, LayoutShape};
|
||||
use crate::mir::alloc::{AllocId, GlobalAlloc};
|
||||
use crate::mir::mono::{Instance, InstanceDef, StaticDef};
|
||||
use crate::mir::Body;
|
||||
|
@ -173,6 +174,15 @@ pub trait Context {
|
|||
|
||||
/// Return information about the target machine.
|
||||
fn target_info(&self) -> MachineInfo;
|
||||
|
||||
/// Get an instance ABI.
|
||||
fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error>;
|
||||
|
||||
/// Get the layout of a type.
|
||||
fn ty_layout(&self, ty: Ty) -> Result<Layout, Error>;
|
||||
|
||||
/// Get the layout shape.
|
||||
fn layout_shape(&self, id: Layout) -> LayoutShape;
|
||||
}
|
||||
|
||||
// A thread local variable that stores a pointer to the tables mapping between TyCtxt
|
||||
|
|
|
@ -33,6 +33,7 @@ use crate::mir::Body;
|
|||
use crate::mir::Mutability;
|
||||
use crate::ty::{ImplDef, ImplTrait, IndexedVal, Span, TraitDecl, TraitDef, Ty};
|
||||
|
||||
pub mod abi;
|
||||
#[macro_use]
|
||||
pub mod crate_def;
|
||||
pub mod compiler_interface;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::abi::FnAbi;
|
||||
use crate::crate_def::CrateDef;
|
||||
use crate::mir::Body;
|
||||
use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
|
||||
|
@ -56,6 +57,11 @@ impl Instance {
|
|||
with(|context| context.instance_ty(self.def))
|
||||
}
|
||||
|
||||
/// Retrieve information about this instance binary interface.
|
||||
pub fn fn_abi(&self) -> Result<FnAbi, Error> {
|
||||
with(|cx| cx.instance_abi(self.def))
|
||||
}
|
||||
|
||||
/// Retrieve the instance's mangled name used for calling the given instance.
|
||||
///
|
||||
/// This will also look up the correct name of instances from upstream crates.
|
||||
|
|
|
@ -3,6 +3,7 @@ use super::{
|
|||
mir::{Body, Mutability},
|
||||
with, DefId, Error, Symbol,
|
||||
};
|
||||
use crate::abi::Layout;
|
||||
use crate::crate_def::CrateDef;
|
||||
use crate::mir::alloc::{read_target_int, read_target_uint, AllocId};
|
||||
use crate::target::MachineInfo;
|
||||
|
@ -85,6 +86,11 @@ impl Ty {
|
|||
pub fn unsigned_ty(inner: UintTy) -> Ty {
|
||||
Ty::from_rigid_kind(RigidTy::Uint(inner))
|
||||
}
|
||||
|
||||
/// Get a type layout.
|
||||
pub fn layout(self) -> Result<Layout, Error> {
|
||||
with(|cx| cx.ty_layout(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ty {
|
||||
|
|
|
@ -22,8 +22,10 @@
|
|||
- [\*-apple-watchos\*](platform-support/apple-watchos.md)
|
||||
- [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
|
||||
- [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md)
|
||||
- [arm-none-eabi](platform-support/arm-none-eabi.md)
|
||||
- [armv4t-none-eabi](platform-support/armv4t-none-eabi.md)
|
||||
- [armv5te-none-eabi](platform-support/armv5te-none-eabi.md)
|
||||
- [armv7r-none-eabi](platform-support/armv7r-none-eabi.md)
|
||||
- [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
|
||||
- [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md)
|
||||
- [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
|
||||
|
|
|
@ -137,17 +137,17 @@ target | std | notes
|
|||
[`arm-linux-androideabi`](platform-support/android.md) | ✓ | ARMv6 Android
|
||||
`arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with MUSL
|
||||
`arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with MUSL, hardfloat
|
||||
`armebv7r-none-eabi` | * | Bare ARMv7-R, Big Endian
|
||||
`armebv7r-none-eabihf` | * | Bare ARMv7-R, Big Endian, hardfloat
|
||||
[`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, Big Endian
|
||||
[`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, Big Endian, hardfloat
|
||||
`armv5te-unknown-linux-gnueabi` | ✓ | ARMv5TE Linux (kernel 4.4, glibc 2.23)
|
||||
`armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL
|
||||
[`armv7-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7-A Android
|
||||
`armv7-unknown-linux-gnueabi` | ✓ | ARMv7-A Linux (kernel 4.15, glibc 2.27)
|
||||
`armv7-unknown-linux-musleabi` | ✓ | ARMv7-A Linux with MUSL
|
||||
`armv7-unknown-linux-musleabihf` | ✓ | ARMv7-A Linux with MUSL, hardfloat
|
||||
`armv7a-none-eabi` | * | Bare ARMv7-A
|
||||
`armv7r-none-eabi` | * | Bare ARMv7-R
|
||||
`armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat
|
||||
[`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7-A
|
||||
[`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R
|
||||
[`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare ARMv7-R, hardfloat
|
||||
`i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE [^x86_32-floats-x87]
|
||||
`i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 3.2, glibc 2.17) [^x86_32-floats-x87]
|
||||
`i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, MUSL [^x86_32-floats-x87]
|
||||
|
@ -166,15 +166,15 @@ target | std | notes
|
|||
`riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA)
|
||||
`sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23)
|
||||
`sparcv9-sun-solaris` | ✓ | SPARC Solaris 11, illumos
|
||||
`thumbv6m-none-eabi` | * | Bare ARMv6-M
|
||||
`thumbv7em-none-eabi` | * | Bare ARMv7E-M
|
||||
`thumbv7em-none-eabihf` | * | Bare ARMV7E-M, hardfloat
|
||||
`thumbv7m-none-eabi` | * | Bare ARMv7-M
|
||||
[`thumbv6m-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv6-M
|
||||
[`thumbv7em-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7E-M
|
||||
[`thumbv7em-none-eabihf`](platform-support/arm-none-eabi.md) | * | Bare ARMV7E-M, hardfloat
|
||||
[`thumbv7m-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv7-M
|
||||
[`thumbv7neon-linux-androideabi`](platform-support/android.md) | ✓ | Thumb2-mode ARMv7-A Android with NEON
|
||||
`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode ARMv7-A Linux with NEON (kernel 4.4, glibc 2.23)
|
||||
`thumbv8m.base-none-eabi` | * | Bare ARMv8-M Baseline
|
||||
`thumbv8m.main-none-eabi` | * | Bare ARMv8-M Mainline
|
||||
`thumbv8m.main-none-eabihf` | * | Bare ARMv8-M Mainline, hardfloat
|
||||
[`thumbv8m.base-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Baseline
|
||||
[`thumbv8m.main-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Mainline
|
||||
[`thumbv8m.main-none-eabihf`](platform-support/arm-none-eabi.md) | * | Bare ARMv8-M Mainline, hardfloat
|
||||
`wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten
|
||||
`wasm32-unknown-unknown` | ✓ | WebAssembly
|
||||
`wasm32-wasi` | ✓ | WebAssembly with WASI
|
||||
|
@ -241,7 +241,7 @@ target | std | host | notes
|
|||
[`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian)
|
||||
[`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS 64-bit with 32-bit pointers
|
||||
[`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | ARM BE8 the default ARM big-endian architecture since [ARMv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en).
|
||||
`armv4t-none-eabi` | * | | Bare ARMv4T
|
||||
[`armv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * | | Bare ARMv4T
|
||||
`armv4t-unknown-linux-gnueabi` | ? | | ARMv4T Linux
|
||||
[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare ARMv5TE
|
||||
`armv5te-unknown-linux-uclibceabi` | ? | | ARMv5TE Linux with uClibc
|
||||
|
@ -257,7 +257,7 @@ target | std | host | notes
|
|||
`armv7-wrs-vxworks-eabihf` | ? | | ARMv7-A for VxWorks
|
||||
[`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3
|
||||
[`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3, hardfloat
|
||||
`armv7a-none-eabihf` | * | | Bare ARMv7-A, hardfloat
|
||||
[`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * | | Bare ARMv7-A, hardfloat
|
||||
[`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARMv7-A Apple WatchOS
|
||||
`armv7s-apple-ios` | ✓ | | ARMv7-A Apple-A6 Apple iOS
|
||||
`avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core`
|
||||
|
@ -333,7 +333,7 @@ target | std | host | notes
|
|||
[`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * | | Bare 32-bit SPARC V7+
|
||||
[`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64
|
||||
[`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64
|
||||
`thumbv4t-none-eabi` | * | | Thumb-mode Bare ARMv4T
|
||||
[`thumbv4t-none-eabi`](platform-support/armv4t-none-eabi.md) | * | | Thumb-mode Bare ARMv4T
|
||||
[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Thumb-mode Bare ARMv5TE
|
||||
`thumbv7a-pc-windows-msvc` | ? | |
|
||||
`thumbv7a-uwp-windows-msvc` | ✓ | |
|
||||
|
|
96
src/doc/rustc/src/platform-support/arm-none-eabi.md
Normal file
96
src/doc/rustc/src/platform-support/arm-none-eabi.md
Normal file
|
@ -0,0 +1,96 @@
|
|||
# `{arm,thumb}*-none-eabi(hf)?`
|
||||
|
||||
**Tier: 2**
|
||||
- [arm(eb)?v7r-none-eabi(hf)?](armv7r-none-eabi.md)
|
||||
- armv7a-none-eabi
|
||||
- thumbv6m-none-eabi
|
||||
- thumbv7m-none-eabi
|
||||
- thumbv7em-none-eabi(hf)?
|
||||
- thumbv8m.base-none-eabi
|
||||
- thumbv8m.main-none-eabi(hf)?
|
||||
|
||||
**Tier: 3**
|
||||
- [{arm,thumb}v4t-none-eabi](armv4t-none-eabi.md)
|
||||
- [{arm,thumb}v5te-none-eabi](armv5te-none-eabi.md)
|
||||
- armv7a-none-eabihf
|
||||
|
||||
Bare-metal target for 32-bit ARM CPUs.
|
||||
|
||||
If a target has a `*hf` variant, that variant uses the hardware floating-point
|
||||
ABI and enables some minimum set of floating-point features based on the FPU(s)
|
||||
available in that processor family.
|
||||
|
||||
## Requirements
|
||||
|
||||
These targets are cross-compiled and use static linking.
|
||||
|
||||
By default, the `lld` linker included with Rust will be used; however, you may
|
||||
want to use the GNU linker instead. This can be obtained for Windows/Mac/Linux
|
||||
from the [Arm Developer Website][arm-gnu-toolchain], or possibly from your OS's
|
||||
package manager. To use it, add the following to your `.cargo/config.toml`:
|
||||
|
||||
```toml
|
||||
[target.<your-target>]
|
||||
linker = "arm-none-eabi-ld"
|
||||
```
|
||||
|
||||
The GNU linker can also be used by specifying `arm-none-eabi-gcc` as the
|
||||
linker. This is needed when using GCC's link time optimization.
|
||||
|
||||
[arm-gnu-toolchain]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
|
||||
|
||||
These targets don't provide a linker script, so you'll need to bring your own
|
||||
according to the specific device you are using. Pass
|
||||
`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
|
||||
`your_script.ld` during linking.
|
||||
|
||||
Targets named `thumb*` instead of `arm*`
|
||||
generate Thumb-mode code by default. M-profile processors (`thumbv*m*-*`
|
||||
targets) only support Thumb-mode code.
|
||||
For the `arm*` targets, Thumb-mode code generation can be enabled by using
|
||||
`-C target-feature=+thumb-mode`. Using the unstable
|
||||
`#![feature(arm_target_feature)]`, the attribute
|
||||
`#[target_feature(enable = "thumb-mode")]` can be applied to individual
|
||||
`unsafe` functions to cause those functions to be compiled to Thumb-mode code.
|
||||
|
||||
## Building Rust Programs
|
||||
|
||||
For the Tier 3 targets in this family, rust does not ship pre-compiled
|
||||
artifacts.
|
||||
|
||||
Just use the `build-std` nightly cargo feature to build the `core` library. You
|
||||
can pass this as a command line argument to cargo, or your `.cargo/config.toml`
|
||||
file might include the following lines:
|
||||
|
||||
```toml
|
||||
[unstable]
|
||||
build-std = ["core"]
|
||||
```
|
||||
|
||||
Most of `core` should work as expected, with the following notes:
|
||||
* If the target is not `*hf`, then floating-point operations are emulated in
|
||||
software.
|
||||
* Integer division is also emulated in software on some targets, depending on
|
||||
the CPU.
|
||||
* Architectures prior to ARMv7 don't have atomic instructions.
|
||||
|
||||
`alloc` is also supported, as long as you provide your own global allocator.
|
||||
|
||||
Rust programs are output as ELF files.
|
||||
|
||||
## Testing
|
||||
|
||||
This is a cross-compiled target that you will need to emulate during testing.
|
||||
|
||||
The exact emulator that you'll need depends on the specific device you want to
|
||||
run your code on.
|
||||
|
||||
## Cross-compilation toolchains and C code
|
||||
|
||||
The target supports C code compiled with the `arm-none-eabi` target triple and
|
||||
a suitable `-march` or `-mcpu` flag.
|
||||
|
||||
`gcc` or `clang` can be used, but note that `gcc` uses `-fshort-enums` by
|
||||
default for `arm-none*` targets, while `clang` does not. `rustc` matches the
|
||||
`gcc` behavior, i.e., the size of a `#[repr(C)] enum` in Rust can be as little
|
||||
as 1 byte, rather than 4, as they are on `arm-linux` targets.
|
|
@ -6,51 +6,16 @@ Bare-metal target for any cpu in the ARMv4T architecture family, supporting
|
|||
ARM/Thumb code interworking (aka `a32`/`t32`), with ARM code as the default code
|
||||
generation.
|
||||
|
||||
In particular this supports the Gameboy Advance (GBA), but there's nothing GBA
|
||||
specific with this target, so any ARMv4T device should work fine.
|
||||
In particular this supports the Game Boy Advance (GBA), but there's nothing
|
||||
GBA-specific with this target, so any ARMv4T device should work fine.
|
||||
|
||||
See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
|
||||
`arm-none-eabi` targets.
|
||||
|
||||
## Target Maintainers
|
||||
|
||||
* [@Lokathor](https://github.com/lokathor)
|
||||
|
||||
## Requirements
|
||||
|
||||
The target is cross-compiled, and uses static linking.
|
||||
|
||||
This target doesn't provide a linker script, you'll need to bring your own
|
||||
according to the specific device you want to target. Pass
|
||||
`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
|
||||
`your_script.ld` during linking.
|
||||
|
||||
## Building Rust Programs
|
||||
|
||||
Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target.
|
||||
|
||||
Just use the `build-std` nightly cargo feature to build the `core` library. You
|
||||
can pass this as a command line argument to cargo, or your `.cargo/config.toml`
|
||||
file might include the following lines:
|
||||
|
||||
```toml
|
||||
[unstable]
|
||||
build-std = ["core"]
|
||||
```
|
||||
|
||||
Most of `core` should work as expected, with the following notes:
|
||||
* the target is "soft float", so `f32` and `f64` operations are emulated in
|
||||
software.
|
||||
* integer division is also emulated in software.
|
||||
* the target is old enough that it doesn't have atomic instructions.
|
||||
|
||||
Rust programs are output as ELF files.
|
||||
|
||||
For running on hardware, you'll generally need to extract the "raw" program code
|
||||
out of the ELF and into a file of its own. The `objcopy` program provided as
|
||||
part of the GNU Binutils can do this:
|
||||
|
||||
```shell
|
||||
arm-none-eabi-objcopy --output-target binary [in_file] [out_file]
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
This is a cross-compiled target that you will need to emulate during testing.
|
||||
|
|
|
@ -8,54 +8,13 @@ generation.
|
|||
|
||||
The `thumbv5te-none-eabi` target is the same as this one, but the instruction set defaults to `t32`.
|
||||
|
||||
See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
|
||||
`arm-none-eabi` targets.
|
||||
|
||||
## Target Maintainers
|
||||
|
||||
* [@QuinnPainter](https://github.com/QuinnPainter)
|
||||
|
||||
## Requirements
|
||||
|
||||
The target is cross-compiled, and uses static linking.
|
||||
|
||||
By default, the `lld` linker included with Rust will be used.
|
||||
|
||||
However, you may want to use the `arm-none-eabi-ld` linker instead. This can be obtained for Windows/Mac/Linux from the [ARM
|
||||
Developer Website][arm-dev], or possibly from your OS's package manager. To use it, add the following to your `.cargo/config.toml`:
|
||||
|
||||
```toml
|
||||
[target.armv5te-none-eabi]
|
||||
linker = "arm-none-eabi-ld"
|
||||
```
|
||||
|
||||
[arm-dev]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
|
||||
|
||||
This target doesn't provide a linker script, you'll need to bring your own
|
||||
according to the specific device you want to target. Pass
|
||||
`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
|
||||
`your_script.ld` during linking.
|
||||
|
||||
## Building Rust Programs
|
||||
|
||||
Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target.
|
||||
|
||||
Just use the `build-std` nightly cargo feature to build the `core` library. You
|
||||
can pass this as a command line argument to cargo, or your `.cargo/config.toml`
|
||||
file might include the following lines:
|
||||
|
||||
```toml
|
||||
[unstable]
|
||||
build-std = ["core"]
|
||||
```
|
||||
|
||||
Most of `core` should work as expected, with the following notes:
|
||||
* the target is "soft float", so `f32` and `f64` operations are emulated in
|
||||
software.
|
||||
* integer division is also emulated in software.
|
||||
* the target is old enough that it doesn't have atomic instructions.
|
||||
|
||||
`alloc` is also supported, as long as you provide your own global allocator.
|
||||
|
||||
Rust programs are output as ELF files.
|
||||
|
||||
## Testing
|
||||
|
||||
This is a cross-compiled target that you will need to emulate during testing.
|
||||
|
@ -63,4 +22,5 @@ This is a cross-compiled target that you will need to emulate during testing.
|
|||
Because this is a device-agnostic target, and the exact emulator that you'll
|
||||
need depends on the specific device you want to run your code on.
|
||||
|
||||
For example, when programming for the DS, you can use one of the several available DS emulators, such as [melonDS](https://melonds.kuribo64.net/).
|
||||
For example, when programming for the DS, you can use one of the several
|
||||
available DS emulators, such as [melonDS](https://melonds.kuribo64.net/).
|
||||
|
|
47
src/doc/rustc/src/platform-support/armv7r-none-eabi.md
Normal file
47
src/doc/rustc/src/platform-support/armv7r-none-eabi.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
# `arm(eb)?v7r-none-eabi(hf)?`
|
||||
|
||||
**Tier: 2**
|
||||
|
||||
Bare-metal target for CPUs in the ARMv7-R architecture family, supporting
|
||||
dual ARM/Thumb mode, with ARM mode as the default.
|
||||
|
||||
Processors in this family include the [Arm Cortex-R4, 5, 7, and 8][cortex-r].
|
||||
|
||||
The `eb` versions of this target generate code for big-endian processors.
|
||||
|
||||
See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
|
||||
`arm-none-eabi` targets.
|
||||
|
||||
[cortex-r]: https://en.wikipedia.org/wiki/ARM_Cortex-R
|
||||
|
||||
## Target maintainers
|
||||
|
||||
- [Chris Copeland](https://github.com/chrisnc), `chris@chrisnc.net`
|
||||
|
||||
## Requirements
|
||||
|
||||
When using the big-endian version of this target, note that some variants of
|
||||
the Cortex-R have both big-endian instructions and data. This configuration is
|
||||
known as BE-32, while data-only big-endianness is known as BE-8. To build
|
||||
programs for BE-32 processors, the GNU linker must be used with the `-mbe32`
|
||||
option. See [ARM Cortex-R Series Programmer's Guide: Endianness][endianness]
|
||||
for more details about different endian modes.
|
||||
|
||||
When using the hardfloat targets, the minimum floating-point features assumed
|
||||
are those of the `vfpv3-d16`, which includes single- and double-precision, with
|
||||
16 double-precision registers. This floating-point unit appears in Cortex-R4F
|
||||
and Cortex-R5F processors. See [VFP in the Cortex-R processors][vfp]
|
||||
for more details on the possible FPU variants.
|
||||
|
||||
If your processor supports a different set of floating-point features than the
|
||||
default expectations of `vfpv3-d16`, then these should also be enabled or
|
||||
disabled as needed with `-C target-feature=(+/-)`.
|
||||
|
||||
[endianness]: https://developer.arm.com/documentation/den0042/a/Coding-for-Cortex-R-Processors/Endianness
|
||||
|
||||
[vfp]: https://developer.arm.com/documentation/den0042/a/Floating-Point/Floating-point-basics-and-the-IEEE-754-standard/VFP-in-the-Cortex-R-processors
|
||||
|
||||
## Cross-compilation toolchains and C code
|
||||
|
||||
This target supports C code compiled with the `arm-none-eabi` target triple and
|
||||
`-march=armv7-r` or a suitable `-mcpu` flag.
|
|
@ -14,14 +14,14 @@
|
|||
kind="no")]
|
||||
#![rustc_expected_cgu_reuse(module="cgu_invalidated_via_import-foo",
|
||||
cfg="cfail3",
|
||||
kind="post-lto")]
|
||||
kind="pre-lto")] // Should be "post-lto", see issue #119076
|
||||
|
||||
#![rustc_expected_cgu_reuse(module="cgu_invalidated_via_import-bar",
|
||||
cfg="cfail2",
|
||||
kind="pre-lto")]
|
||||
#![rustc_expected_cgu_reuse(module="cgu_invalidated_via_import-bar",
|
||||
cfg="cfail3",
|
||||
kind="post-lto")]
|
||||
kind="pre-lto")] // Should be "post-lto", see issue #119076
|
||||
|
||||
mod foo {
|
||||
|
||||
|
|
|
@ -9,21 +9,25 @@
|
|||
|
||||
#![feature(rustc_attrs)]
|
||||
#![crate_type = "rlib"]
|
||||
#![rustc_expected_cgu_reuse(module = "cgu_keeps_identical_fn-foo", cfg = "cfail2", kind = "no")]
|
||||
#![rustc_expected_cgu_reuse(
|
||||
module = "cgu_keeps_identical_fn-foo",
|
||||
cfg = "cfail2",
|
||||
kind = "pre-lto"
|
||||
)]
|
||||
#![rustc_expected_cgu_reuse(
|
||||
module = "cgu_keeps_identical_fn-foo",
|
||||
cfg = "cfail3",
|
||||
kind = "post-lto"
|
||||
kind = "pre-lto" // Should be "post-lto", see issue #119076
|
||||
)]
|
||||
#![rustc_expected_cgu_reuse(
|
||||
module = "cgu_keeps_identical_fn-bar",
|
||||
cfg = "cfail2",
|
||||
kind = "post-lto"
|
||||
kind = "pre-lto" // Should be "post-lto", see issue #119076
|
||||
)]
|
||||
#![rustc_expected_cgu_reuse(
|
||||
module = "cgu_keeps_identical_fn-bar",
|
||||
cfg = "cfail3",
|
||||
kind = "post-lto"
|
||||
kind = "pre-lto" // Should be "post-lto", see issue #119076
|
||||
)]
|
||||
|
||||
mod foo {
|
||||
|
|
|
@ -13,21 +13,21 @@
|
|||
kind="no")]
|
||||
#![rustc_expected_cgu_reuse(module="independent_cgus_dont_affect_each_other-foo",
|
||||
cfg="cfail3",
|
||||
kind="post-lto")]
|
||||
kind="pre-lto")] // Should be "post-lto", see issue #119076
|
||||
|
||||
#![rustc_expected_cgu_reuse(module="independent_cgus_dont_affect_each_other-bar",
|
||||
cfg="cfail2",
|
||||
kind="pre-lto")]
|
||||
#![rustc_expected_cgu_reuse(module="independent_cgus_dont_affect_each_other-bar",
|
||||
cfg="cfail3",
|
||||
kind="post-lto")]
|
||||
kind="pre-lto")] // Should be "post-lto", see issue #119076
|
||||
|
||||
#![rustc_expected_cgu_reuse(module="independent_cgus_dont_affect_each_other-baz",
|
||||
cfg="cfail2",
|
||||
kind="post-lto")]
|
||||
kind="pre-lto")] // Should be "post-lto", see issue #119076
|
||||
#![rustc_expected_cgu_reuse(module="independent_cgus_dont_affect_each_other-baz",
|
||||
cfg="cfail3",
|
||||
kind="post-lto")]
|
||||
kind="pre-lto")] // Should be "post-lto", see issue #119076
|
||||
mod foo {
|
||||
|
||||
#[cfg(cfail1)]
|
||||
|
|
143
tests/ui-fulldeps/stable-mir/check_abi.rs
Normal file
143
tests/ui-fulldeps/stable-mir/check_abi.rs
Normal file
|
@ -0,0 +1,143 @@
|
|||
// run-pass
|
||||
//! Test information regarding type layout.
|
||||
|
||||
// ignore-stage1
|
||||
// ignore-cross-compile
|
||||
// ignore-remote
|
||||
// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
|
||||
|
||||
#![feature(rustc_private)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(ascii_char, ascii_char_variants)]
|
||||
|
||||
extern crate rustc_hir;
|
||||
extern crate rustc_middle;
|
||||
#[macro_use]
|
||||
extern crate rustc_smir;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_interface;
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape};
|
||||
use stable_mir::mir::mono::Instance;
|
||||
use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind};
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::convert::TryFrom;
|
||||
use std::io::Write;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
const CRATE_NAME: &str = "input";
|
||||
|
||||
/// This function uses the Stable MIR APIs to get information about the test crate.
|
||||
fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
|
||||
// Find items in the local crate.
|
||||
let items = stable_mir::all_local_items();
|
||||
|
||||
// Test fn_abi
|
||||
let target_fn = *get_item(&items, (ItemKind::Fn, "fn_abi")).unwrap();
|
||||
let instance = Instance::try_from(target_fn).unwrap();
|
||||
let fn_abi = instance.fn_abi().unwrap();
|
||||
assert_eq!(fn_abi.conv, CallConvention::Rust);
|
||||
assert_eq!(fn_abi.args.len(), 2);
|
||||
|
||||
check_ignore(&fn_abi.args[0]);
|
||||
check_primitive(&fn_abi.args[1]);
|
||||
check_result(fn_abi.ret);
|
||||
|
||||
// Test variadic function.
|
||||
let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap();
|
||||
check_variadic(variadic_fn);
|
||||
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
/// Check the variadic function ABI:
|
||||
/// ```no_run
|
||||
/// pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {
|
||||
/// 0
|
||||
/// }
|
||||
/// ```
|
||||
fn check_variadic(variadic_fn: CrateItem) {
|
||||
let instance = Instance::try_from(variadic_fn).unwrap();
|
||||
let abi = instance.fn_abi().unwrap();
|
||||
assert!(abi.c_variadic);
|
||||
assert_eq!(abi.args.len(), 1);
|
||||
}
|
||||
|
||||
/// Check the argument to be ignored: `ignore: [u8; 0]`.
|
||||
fn check_ignore(abi: &ArgAbi) {
|
||||
assert!(abi.ty.kind().is_array());
|
||||
assert_eq!(abi.mode, PassMode::Ignore);
|
||||
let layout = abi.layout.shape();
|
||||
assert!(layout.is_sized());
|
||||
assert!(layout.is_1zst());
|
||||
}
|
||||
|
||||
/// Check the primitive argument: `primitive: char`.
|
||||
fn check_primitive(abi: &ArgAbi) {
|
||||
assert!(abi.ty.kind().is_char());
|
||||
assert_matches!(abi.mode, PassMode::Direct(_));
|
||||
let layout = abi.layout.shape();
|
||||
assert!(layout.is_sized());
|
||||
assert!(!layout.is_1zst());
|
||||
assert_matches!(layout.fields, FieldsShape::Primitive);
|
||||
}
|
||||
|
||||
/// Check the return value: `Result<usize, &str>`.
|
||||
fn check_result(abi: ArgAbi) {
|
||||
assert!(abi.ty.kind().is_enum());
|
||||
assert_matches!(abi.mode, PassMode::Indirect { .. });
|
||||
let layout = abi.layout.shape();
|
||||
assert!(layout.is_sized());
|
||||
assert_matches!(layout.fields, FieldsShape::Arbitrary { .. });
|
||||
assert_matches!(layout.variants, VariantsShape::Multiple { .. })
|
||||
}
|
||||
|
||||
fn get_item<'a>(
|
||||
items: &'a CrateItems,
|
||||
item: (ItemKind, &str),
|
||||
) -> Option<&'a stable_mir::CrateItem> {
|
||||
items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1)
|
||||
}
|
||||
|
||||
/// This test will generate and analyze a dummy crate using the stable mir.
|
||||
/// For that, it will first write the dummy crate into a file.
|
||||
/// Then it will create a `StableMir` using custom arguments and then
|
||||
/// it will run the compiler.
|
||||
fn main() {
|
||||
let path = "alloc_input.rs";
|
||||
generate_input(&path).unwrap();
|
||||
let args = vec![
|
||||
"rustc".to_string(),
|
||||
"--crate-type=lib".to_string(),
|
||||
"--crate-name".to_string(),
|
||||
CRATE_NAME.to_string(),
|
||||
path.to_string(),
|
||||
];
|
||||
run!(args, tcx, test_stable_mir(tcx)).unwrap();
|
||||
}
|
||||
|
||||
fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
let mut file = std::fs::File::create(path)?;
|
||||
write!(
|
||||
file,
|
||||
r#"
|
||||
#![feature(c_variadic)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result<usize, &'static str> {{
|
||||
// We only care about the signature.
|
||||
todo!()
|
||||
}}
|
||||
|
||||
|
||||
pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{
|
||||
0
|
||||
}}
|
||||
"#
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
|
@ -209,7 +209,6 @@ fn check_len(item: CrateItem) {
|
|||
assert_eq!(alloc.read_uint(), Ok(2));
|
||||
}
|
||||
|
||||
// Use internal API to find a function in a crate.
|
||||
fn get_item<'a>(
|
||||
items: &'a CrateItems,
|
||||
item: (ItemKind, &str),
|
||||
|
|
|
@ -69,9 +69,9 @@ fn extract_elem_ty(ty: Ty) -> Ty {
|
|||
|
||||
/// Check signature and type of `Vec::<u8>::new` and its generic version.
|
||||
fn test_vec_new(instance: mir::mono::Instance) {
|
||||
let sig = instance.ty().kind().fn_sig().unwrap().skip_binder();
|
||||
assert_matches!(sig.inputs(), &[]);
|
||||
let elem_ty = extract_elem_ty(sig.output());
|
||||
let sig = instance.fn_abi().unwrap();
|
||||
assert_eq!(&sig.args, &[]);
|
||||
let elem_ty = extract_elem_ty(sig.ret.ty);
|
||||
assert_matches!(elem_ty.kind(), TyKind::RigidTy(RigidTy::Uint(UintTy::U8)));
|
||||
|
||||
// Get the signature for Vec::<T>::new.
|
||||
|
|
62
tests/ui/editions/edition-cstr-2015-2018.rs
Normal file
62
tests/ui/editions/edition-cstr-2015-2018.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
macro_rules! construct { ($x:ident) => { $x"str" } }
|
||||
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||
//~| NOTE expected one of 8 possible tokens
|
||||
|
||||
macro_rules! contain { () => { c"str" } }
|
||||
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||
//~| NOTE expected one of 8 possible tokens
|
||||
//~| NOTE you may be trying to write a c-string literal
|
||||
//~| NOTE c-string literals require Rust 2021 or later
|
||||
//~| HELP pass `--edition 2021` to `rustc`
|
||||
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||
|
||||
fn check_macro_construct() {
|
||||
construct!(c); //~ NOTE in this expansion of construct!
|
||||
}
|
||||
|
||||
fn check_macro_contain() {
|
||||
contain!();
|
||||
//~^ NOTE in this expansion of contain!
|
||||
//~| NOTE in this expansion of contain!
|
||||
//~| NOTE in this expansion of contain!
|
||||
//~| NOTE in this expansion of contain!
|
||||
//~| NOTE in this expansion of contain!
|
||||
}
|
||||
|
||||
fn check_basic() {
|
||||
c"str";
|
||||
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||
//~| NOTE expected one of 8 possible tokens
|
||||
//~| NOTE you may be trying to write a c-string literal
|
||||
//~| NOTE c-string literals require Rust 2021 or later
|
||||
//~| HELP pass `--edition 2021` to `rustc`
|
||||
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||
}
|
||||
|
||||
fn check_craw() {
|
||||
cr"str";
|
||||
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||
//~| NOTE expected one of 8 possible tokens
|
||||
//~| NOTE you may be trying to write a c-string literal
|
||||
//~| NOTE c-string literals require Rust 2021 or later
|
||||
//~| HELP pass `--edition 2021` to `rustc`
|
||||
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||
}
|
||||
|
||||
fn check_craw_hash() {
|
||||
cr##"str"##;
|
||||
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `#`
|
||||
//~| NOTE expected one of 8 possible tokens
|
||||
//~| NOTE you may be trying to write a c-string literal
|
||||
//~| NOTE c-string literals require Rust 2021 or later
|
||||
//~| HELP pass `--edition 2021` to `rustc`
|
||||
//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||
}
|
||||
|
||||
fn check_cstr_space() {
|
||||
c "str";
|
||||
//~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||
//~| NOTE expected one of 8 possible tokens
|
||||
}
|
||||
|
||||
fn main() {}
|
67
tests/ui/editions/edition-cstr-2015-2018.stderr
Normal file
67
tests/ui/editions/edition-cstr-2015-2018.stderr
Normal file
|
@ -0,0 +1,67 @@
|
|||
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||
--> $DIR/edition-cstr-2015-2018.rs:27:6
|
||||
|
|
||||
LL | c"str";
|
||||
| ^^^^^ expected one of 8 possible tokens
|
||||
|
|
||||
= note: you may be trying to write a c-string literal
|
||||
= note: c-string literals require Rust 2021 or later
|
||||
= help: pass `--edition 2021` to `rustc`
|
||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||
|
||||
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||
--> $DIR/edition-cstr-2015-2018.rs:37:7
|
||||
|
|
||||
LL | cr"str";
|
||||
| ^^^^^ expected one of 8 possible tokens
|
||||
|
|
||||
= note: you may be trying to write a c-string literal
|
||||
= note: c-string literals require Rust 2021 or later
|
||||
= help: pass `--edition 2021` to `rustc`
|
||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||
|
||||
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `#`
|
||||
--> $DIR/edition-cstr-2015-2018.rs:47:7
|
||||
|
|
||||
LL | cr##"str"##;
|
||||
| ^ expected one of 8 possible tokens
|
||||
|
|
||||
= note: you may be trying to write a c-string literal
|
||||
= note: c-string literals require Rust 2021 or later
|
||||
= help: pass `--edition 2021` to `rustc`
|
||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||
|
||||
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||
--> $DIR/edition-cstr-2015-2018.rs:57:7
|
||||
|
|
||||
LL | c "str";
|
||||
| ^^^^^ expected one of 8 possible tokens
|
||||
|
||||
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||
--> $DIR/edition-cstr-2015-2018.rs:1:44
|
||||
|
|
||||
LL | macro_rules! construct { ($x:ident) => { $x"str" } }
|
||||
| ^^^^^ expected one of 8 possible tokens
|
||||
...
|
||||
LL | construct!(c);
|
||||
| ------------- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `construct` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"str"`
|
||||
--> $DIR/edition-cstr-2015-2018.rs:5:33
|
||||
|
|
||||
LL | macro_rules! contain { () => { c"str" } }
|
||||
| ^^^^^ expected one of 8 possible tokens
|
||||
...
|
||||
LL | contain!();
|
||||
| ---------- in this macro invocation
|
||||
|
|
||||
= note: you may be trying to write a c-string literal
|
||||
= note: c-string literals require Rust 2021 or later
|
||||
= help: pass `--edition 2021` to `rustc`
|
||||
= note: for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||
= note: this error originates in the macro `contain` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
|
@ -1,7 +1,15 @@
|
|||
// revisions: old next
|
||||
//[next] compile-flags: -Znext-solver=coherence
|
||||
// check-pass
|
||||
|
||||
// Regression test for issue #90662
|
||||
// Tests that projection caching does not cause a spurious error
|
||||
// Tests that projection caching does not cause a spurious error.
|
||||
// Coherence relies on the following overflowing goal to still constrain
|
||||
// `?0` to `dyn Service`.
|
||||
//
|
||||
// Projection(<ServiceImpl as Provider<TestModule>>::Interface. ?0)
|
||||
//
|
||||
// cc https://github.com/rust-lang/trait-system-refactor-initiative/issues/70.
|
||||
|
||||
trait HasProvider<T: ?Sized> {}
|
||||
trait Provider<M> {
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// compile-flags: -Znext-solver=coherence
|
||||
// check-pass
|
||||
|
||||
// A regression test for trait-system-refactor-initiative#70.
|
||||
|
||||
trait Trait {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
struct W<T: ?Sized>(*mut T);
|
||||
impl<T: ?Sized> Trait for W<W<T>>
|
||||
where
|
||||
W<T>: Trait,
|
||||
{
|
||||
type Assoc = ();
|
||||
}
|
||||
|
||||
trait NoOverlap {}
|
||||
impl<T: Trait<Assoc = u32>> NoOverlap for T {}
|
||||
// `Projection(<W<_> as Trait>::Assoc, u32)` should result in error even
|
||||
// though applying the impl results in overflow. This is necessary to match
|
||||
// the behavior of the old solver.
|
||||
impl<T: ?Sized> NoOverlap for W<T> {}
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Reference in a new issue