Merge from rustc
This commit is contained in:
commit
65e76849ac
183 changed files with 2692 additions and 874 deletions
|
|
@ -5,7 +5,7 @@ use rustc_ast::*;
|
|||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
|
||||
use rustc_hir::{self as hir, HirId, IsAnonInPath, PredicateOrigin};
|
||||
use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin};
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
|
|
@ -1868,7 +1868,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
GenericParamKind::Lifetime => {
|
||||
let lt_id = self.next_node_id();
|
||||
let lifetime = self.new_named_lifetime(id, lt_id, ident, IsAnonInPath::No);
|
||||
let lifetime =
|
||||
self.new_named_lifetime(id, lt_id, ident, LifetimeSource::Other, ident.into());
|
||||
hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
|
||||
lifetime,
|
||||
bounds,
|
||||
|
|
@ -1901,7 +1902,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}),
|
||||
WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => {
|
||||
hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
|
||||
lifetime: self.lower_lifetime(lifetime),
|
||||
lifetime: self.lower_lifetime(
|
||||
lifetime,
|
||||
LifetimeSource::Other,
|
||||
lifetime.ident.into(),
|
||||
),
|
||||
bounds: self.lower_param_bounds(
|
||||
bounds,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
|
|||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::{
|
||||
self as hir, ConstArg, GenericArg, HirId, IsAnonInPath, ItemLocalMap, LangItem, ParamName,
|
||||
TraitCandidate,
|
||||
self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, LifetimeSource,
|
||||
LifetimeSyntax, ParamName, TraitCandidate,
|
||||
};
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
use rustc_macros::extension;
|
||||
|
|
@ -1079,7 +1079,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
itctx: ImplTraitContext,
|
||||
) -> hir::GenericArg<'hir> {
|
||||
match arg {
|
||||
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)),
|
||||
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(
|
||||
lt,
|
||||
LifetimeSource::Path { with_angle_brackets: true },
|
||||
lt.ident.into(),
|
||||
)),
|
||||
ast::GenericArg::Type(ty) => {
|
||||
// We cannot just match on `TyKind::Infer` as `(_)` is represented as
|
||||
// `TyKind::Paren(TyKind::Infer)` and should also be lowered to `GenericArg::Infer`
|
||||
|
|
@ -1198,35 +1202,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
|
||||
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
|
||||
TyKind::Ref(region, mt) => {
|
||||
let region = region.unwrap_or_else(|| {
|
||||
let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
|
||||
self.resolver.get_lifetime_res(t.id)
|
||||
{
|
||||
debug_assert_eq!(start.plus(1), end);
|
||||
start
|
||||
} else {
|
||||
self.next_node_id()
|
||||
};
|
||||
let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi();
|
||||
Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
|
||||
});
|
||||
let lifetime = self.lower_lifetime(®ion);
|
||||
let lifetime = self.lower_ty_direct_lifetime(t, *region);
|
||||
hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx))
|
||||
}
|
||||
TyKind::PinnedRef(region, mt) => {
|
||||
let region = region.unwrap_or_else(|| {
|
||||
let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
|
||||
self.resolver.get_lifetime_res(t.id)
|
||||
{
|
||||
debug_assert_eq!(start.plus(1), end);
|
||||
start
|
||||
} else {
|
||||
self.next_node_id()
|
||||
};
|
||||
let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi();
|
||||
Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
|
||||
});
|
||||
let lifetime = self.lower_lifetime(®ion);
|
||||
let lifetime = self.lower_ty_direct_lifetime(t, *region);
|
||||
let kind = hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx));
|
||||
let span = self.lower_span(t.span);
|
||||
let arg = hir::Ty { kind, span, hir_id: self.next_id() };
|
||||
|
|
@ -1302,7 +1282,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
GenericBound::Outlives(lifetime) => {
|
||||
if lifetime_bound.is_none() {
|
||||
lifetime_bound = Some(this.lower_lifetime(lifetime));
|
||||
lifetime_bound = Some(this.lower_lifetime(
|
||||
lifetime,
|
||||
LifetimeSource::Other,
|
||||
lifetime.ident.into(),
|
||||
));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
@ -1393,6 +1377,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }
|
||||
}
|
||||
|
||||
fn lower_ty_direct_lifetime(
|
||||
&mut self,
|
||||
t: &Ty,
|
||||
region: Option<Lifetime>,
|
||||
) -> &'hir hir::Lifetime {
|
||||
let (region, syntax) = match region {
|
||||
Some(region) => (region, region.ident.into()),
|
||||
|
||||
None => {
|
||||
let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
|
||||
self.resolver.get_lifetime_res(t.id)
|
||||
{
|
||||
debug_assert_eq!(start.plus(1), end);
|
||||
start
|
||||
} else {
|
||||
self.next_node_id()
|
||||
};
|
||||
let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi();
|
||||
let region = Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id };
|
||||
(region, LifetimeSyntax::Hidden)
|
||||
}
|
||||
};
|
||||
self.lower_lifetime(®ion, LifetimeSource::Reference, syntax)
|
||||
}
|
||||
|
||||
/// Lowers a `ReturnPositionOpaqueTy` (`-> impl Trait`) or a `TypeAliasesOpaqueTy` (`type F =
|
||||
/// impl Trait`): this creates the associated Opaque Type (TAIT) definition and then returns a
|
||||
/// HIR type that references the TAIT.
|
||||
|
|
@ -1474,9 +1483,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
precise_capturing_args: &[PreciseCapturingArg],
|
||||
) -> &'hir [hir::PreciseCapturingArg<'hir>] {
|
||||
self.arena.alloc_from_iter(precise_capturing_args.iter().map(|arg| match arg {
|
||||
PreciseCapturingArg::Lifetime(lt) => {
|
||||
hir::PreciseCapturingArg::Lifetime(self.lower_lifetime(lt))
|
||||
}
|
||||
PreciseCapturingArg::Lifetime(lt) => hir::PreciseCapturingArg::Lifetime(
|
||||
self.lower_lifetime(lt, LifetimeSource::PreciseCapturing, lt.ident.into()),
|
||||
),
|
||||
PreciseCapturingArg::Arg(path, id) => {
|
||||
let [segment] = path.segments.as_slice() else {
|
||||
panic!();
|
||||
|
|
@ -1739,9 +1748,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
) -> hir::GenericBound<'hir> {
|
||||
match tpb {
|
||||
GenericBound::Trait(p) => hir::GenericBound::Trait(self.lower_poly_trait_ref(p, itctx)),
|
||||
GenericBound::Outlives(lifetime) => {
|
||||
hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
|
||||
}
|
||||
GenericBound::Outlives(lifetime) => hir::GenericBound::Outlives(self.lower_lifetime(
|
||||
lifetime,
|
||||
LifetimeSource::OutlivesBound,
|
||||
lifetime.ident.into(),
|
||||
)),
|
||||
GenericBound::Use(args, span) => hir::GenericBound::Use(
|
||||
self.lower_precise_capturing_args(args),
|
||||
self.lower_span(*span),
|
||||
|
|
@ -1749,12 +1760,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime {
|
||||
self.new_named_lifetime(l.id, l.id, l.ident, IsAnonInPath::No)
|
||||
fn lower_lifetime(
|
||||
&mut self,
|
||||
l: &Lifetime,
|
||||
source: LifetimeSource,
|
||||
syntax: LifetimeSyntax,
|
||||
) -> &'hir hir::Lifetime {
|
||||
self.new_named_lifetime(l.id, l.id, l.ident, source, syntax)
|
||||
}
|
||||
|
||||
fn lower_lifetime_anon_in_path(&mut self, id: NodeId, span: Span) -> &'hir hir::Lifetime {
|
||||
self.new_named_lifetime(id, id, Ident::new(kw::UnderscoreLifetime, span), IsAnonInPath::Yes)
|
||||
fn lower_lifetime_hidden_in_path(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
span: Span,
|
||||
with_angle_brackets: bool,
|
||||
) -> &'hir hir::Lifetime {
|
||||
self.new_named_lifetime(
|
||||
id,
|
||||
id,
|
||||
Ident::new(kw::UnderscoreLifetime, span),
|
||||
LifetimeSource::Path { with_angle_brackets },
|
||||
LifetimeSyntax::Hidden,
|
||||
)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
|
|
@ -1763,7 +1790,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
id: NodeId,
|
||||
new_id: NodeId,
|
||||
ident: Ident,
|
||||
is_anon_in_path: IsAnonInPath,
|
||||
source: LifetimeSource,
|
||||
syntax: LifetimeSyntax,
|
||||
) -> &'hir hir::Lifetime {
|
||||
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
|
||||
let res = match res {
|
||||
|
|
@ -1787,17 +1815,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
};
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
if is_anon_in_path == IsAnonInPath::Yes {
|
||||
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
}
|
||||
|
||||
debug!(?res);
|
||||
self.arena.alloc(hir::Lifetime::new(
|
||||
self.lower_node_id(new_id),
|
||||
self.lower_ident(ident),
|
||||
res,
|
||||
is_anon_in_path,
|
||||
source,
|
||||
syntax,
|
||||
))
|
||||
}
|
||||
|
||||
|
|
@ -2389,7 +2413,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.next_id(),
|
||||
Ident::new(kw::UnderscoreLifetime, self.lower_span(span)),
|
||||
hir::LifetimeKind::ImplicitObjectLifetimeDefault,
|
||||
IsAnonInPath::No,
|
||||
LifetimeSource::Other,
|
||||
LifetimeSyntax::Hidden,
|
||||
);
|
||||
debug!("elided_dyn_bound: r={:?}", r);
|
||||
self.arena.alloc(r)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::GenericArg;
|
||||
use rustc_hir::def::{DefKind, PartialRes, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, GenericArg};
|
||||
use rustc_middle::{span_bug, ty};
|
||||
use rustc_session::parse::add_feature_diagnostics;
|
||||
use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
|
||||
|
|
@ -433,23 +432,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
// Note: these spans are used for diagnostics when they can't be inferred.
|
||||
// See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
|
||||
let elided_lifetime_span = if generic_args.span.is_empty() {
|
||||
let (elided_lifetime_span, with_angle_brackets) = if generic_args.span.is_empty() {
|
||||
// If there are no brackets, use the identifier span.
|
||||
// HACK: we use find_ancestor_inside to properly suggest elided spans in paths
|
||||
// originating from macros, since the segment's span might be from a macro arg.
|
||||
segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span)
|
||||
(segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span), false)
|
||||
} else if generic_args.is_empty() {
|
||||
// If there are brackets, but not generic arguments, then use the opening bracket
|
||||
generic_args.span.with_hi(generic_args.span.lo() + BytePos(1))
|
||||
(generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)), true)
|
||||
} else {
|
||||
// Else use an empty span right after the opening bracket.
|
||||
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
|
||||
(generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(), true)
|
||||
};
|
||||
|
||||
generic_args.args.insert_many(
|
||||
0,
|
||||
(start..end).map(|id| {
|
||||
let l = self.lower_lifetime_anon_in_path(id, elided_lifetime_span);
|
||||
let l = self.lower_lifetime_hidden_in_path(
|
||||
id,
|
||||
elided_lifetime_span,
|
||||
with_angle_brackets,
|
||||
);
|
||||
GenericArg::Lifetime(l)
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -799,7 +799,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
has_bang,
|
||||
Some(*ident),
|
||||
macro_def.body.delim,
|
||||
¯o_def.body.tokens.clone(),
|
||||
¯o_def.body.tokens,
|
||||
true,
|
||||
sp,
|
||||
);
|
||||
|
|
@ -1468,7 +1468,7 @@ impl<'a> State<'a> {
|
|||
true,
|
||||
None,
|
||||
m.args.delim,
|
||||
&m.args.tokens.clone(),
|
||||
&m.args.tokens,
|
||||
true,
|
||||
m.span(),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![feature(no_core, unboxed_closures)]
|
||||
#![no_core]
|
||||
#![allow(dead_code)]
|
||||
#![allow(dead_code, unnecessary_transmutes)]
|
||||
|
||||
extern crate mini_core;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![feature(no_core, unboxed_closures)]
|
||||
#![no_core]
|
||||
#![allow(dead_code)]
|
||||
#![allow(dead_code, unnecessary_transmutes)]
|
||||
|
||||
extern crate mini_core;
|
||||
|
||||
|
|
@ -11,11 +11,7 @@ fn abc(a: u8) -> u8 {
|
|||
}
|
||||
|
||||
fn bcd(b: bool, a: u8) -> u8 {
|
||||
if b {
|
||||
a * 2
|
||||
} else {
|
||||
a * 3
|
||||
}
|
||||
if b { a * 2 } else { a * 3 }
|
||||
}
|
||||
|
||||
fn call() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
//! Set and unset common attributes on LLVM values.
|
||||
|
||||
use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
|
@ -28,6 +27,22 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn has_attr(llfn: &Value, idx: AttributePlace, attr: AttributeKind) -> bool {
|
||||
llvm::HasAttributeAtIndex(llfn, idx, attr)
|
||||
}
|
||||
|
||||
pub(crate) fn has_string_attr(llfn: &Value, name: &str) -> bool {
|
||||
llvm::HasStringAttribute(llfn, name)
|
||||
}
|
||||
|
||||
pub(crate) fn remove_from_llfn(llfn: &Value, place: AttributePlace, kind: AttributeKind) {
|
||||
llvm::RemoveRustEnumAttributeAtIndex(llfn, place, kind);
|
||||
}
|
||||
|
||||
pub(crate) fn remove_string_attr_from_llfn(llfn: &Value, name: &str) {
|
||||
llvm::RemoveStringAttrFromFn(llfn, name);
|
||||
}
|
||||
|
||||
/// Get LLVM attribute for the provided inline heuristic.
|
||||
#[inline]
|
||||
fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll Attribute> {
|
||||
|
|
|
|||
|
|
@ -28,8 +28,9 @@ use crate::back::write::{
|
|||
use crate::errors::{
|
||||
DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, LtoProcMacro,
|
||||
};
|
||||
use crate::llvm::AttributePlace::Function;
|
||||
use crate::llvm::{self, build_string};
|
||||
use crate::{LlvmCodegenBackend, ModuleLlvm};
|
||||
use crate::{LlvmCodegenBackend, ModuleLlvm, SimpleCx, attributes};
|
||||
|
||||
/// We keep track of the computed LTO cache keys from the previous
|
||||
/// session to determine which CGUs we can reuse.
|
||||
|
|
@ -584,12 +585,10 @@ fn thin_lto(
|
|||
}
|
||||
}
|
||||
|
||||
fn enable_autodiff_settings(ad: &[config::AutoDiff], module: &mut ModuleCodegen<ModuleLlvm>) {
|
||||
fn enable_autodiff_settings(ad: &[config::AutoDiff]) {
|
||||
for &val in ad {
|
||||
// We intentionally don't use a wildcard, to not forget handling anything new.
|
||||
match val {
|
||||
config::AutoDiff::PrintModBefore => {
|
||||
unsafe { llvm::LLVMDumpModule(module.module_llvm.llmod()) };
|
||||
}
|
||||
config::AutoDiff::PrintPerf => {
|
||||
llvm::set_print_perf(true);
|
||||
}
|
||||
|
|
@ -603,17 +602,23 @@ fn enable_autodiff_settings(ad: &[config::AutoDiff], module: &mut ModuleCodegen<
|
|||
llvm::set_inline(true);
|
||||
}
|
||||
config::AutoDiff::LooseTypes => {
|
||||
llvm::set_loose_types(false);
|
||||
llvm::set_loose_types(true);
|
||||
}
|
||||
config::AutoDiff::PrintSteps => {
|
||||
llvm::set_print(true);
|
||||
}
|
||||
// We handle this below
|
||||
// We handle this in the PassWrapper.cpp
|
||||
config::AutoDiff::PrintPasses => {}
|
||||
// We handle this in the PassWrapper.cpp
|
||||
config::AutoDiff::PrintModBefore => {}
|
||||
// We handle this in the PassWrapper.cpp
|
||||
config::AutoDiff::PrintModAfter => {}
|
||||
// We handle this below
|
||||
// We handle this in the PassWrapper.cpp
|
||||
config::AutoDiff::PrintModFinal => {}
|
||||
// This is required and already checked
|
||||
config::AutoDiff::Enable => {}
|
||||
// We handle this below
|
||||
config::AutoDiff::NoPostopt => {}
|
||||
}
|
||||
}
|
||||
// This helps with handling enums for now.
|
||||
|
|
@ -647,27 +652,52 @@ pub(crate) fn run_pass_manager(
|
|||
// We then run the llvm_optimize function a second time, to optimize the code which we generated
|
||||
// in the enzyme differentiation pass.
|
||||
let enable_ad = config.autodiff.contains(&config::AutoDiff::Enable);
|
||||
let stage =
|
||||
if enable_ad { write::AutodiffStage::DuringAD } else { write::AutodiffStage::PostAD };
|
||||
let stage = if thin {
|
||||
write::AutodiffStage::PreAD
|
||||
} else {
|
||||
if enable_ad { write::AutodiffStage::DuringAD } else { write::AutodiffStage::PostAD }
|
||||
};
|
||||
|
||||
if enable_ad {
|
||||
enable_autodiff_settings(&config.autodiff, module);
|
||||
enable_autodiff_settings(&config.autodiff);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage)?;
|
||||
}
|
||||
|
||||
if cfg!(llvm_enzyme) && enable_ad {
|
||||
// This is the post-autodiff IR, mainly used for testing and educational purposes.
|
||||
if config.autodiff.contains(&config::AutoDiff::PrintModAfter) {
|
||||
unsafe { llvm::LLVMDumpModule(module.module_llvm.llmod()) };
|
||||
if cfg!(llvm_enzyme) && enable_ad && !thin {
|
||||
let cx =
|
||||
SimpleCx::new(module.module_llvm.llmod(), &module.module_llvm.llcx, cgcx.pointer_size);
|
||||
|
||||
for function in cx.get_functions() {
|
||||
let enzyme_marker = "enzyme_marker";
|
||||
if attributes::has_string_attr(function, enzyme_marker) {
|
||||
// Sanity check: Ensure 'noinline' is present before replacing it.
|
||||
assert!(
|
||||
!attributes::has_attr(function, Function, llvm::AttributeKind::NoInline),
|
||||
"Expected __enzyme function to have 'noinline' before adding 'alwaysinline'"
|
||||
);
|
||||
|
||||
attributes::remove_from_llfn(function, Function, llvm::AttributeKind::NoInline);
|
||||
attributes::remove_string_attr_from_llfn(function, enzyme_marker);
|
||||
|
||||
assert!(
|
||||
!attributes::has_string_attr(function, enzyme_marker),
|
||||
"Expected function to not have 'enzyme_marker'"
|
||||
);
|
||||
|
||||
let always_inline = llvm::AttributeKind::AlwaysInline.create_attr(cx.llcx);
|
||||
attributes::apply_to_llfn(function, Function, &[always_inline]);
|
||||
}
|
||||
}
|
||||
|
||||
let opt_stage = llvm::OptStage::FatLTO;
|
||||
let stage = write::AutodiffStage::PostAD;
|
||||
unsafe {
|
||||
write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage)?;
|
||||
if !config.autodiff.contains(&config::AutoDiff::NoPostopt) {
|
||||
unsafe {
|
||||
write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage)?;
|
||||
}
|
||||
}
|
||||
|
||||
// This is the final IR, so people should be able to inspect the optimized autodiff output,
|
||||
|
|
|
|||
|
|
@ -572,6 +572,10 @@ pub(crate) unsafe fn llvm_optimize(
|
|||
|
||||
let consider_ad = cfg!(llvm_enzyme) && config.autodiff.contains(&config::AutoDiff::Enable);
|
||||
let run_enzyme = autodiff_stage == AutodiffStage::DuringAD;
|
||||
let print_before_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModBefore);
|
||||
let print_after_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModAfter);
|
||||
let print_passes = config.autodiff.contains(&config::AutoDiff::PrintPasses);
|
||||
let merge_functions;
|
||||
let unroll_loops;
|
||||
let vectorize_slp;
|
||||
let vectorize_loop;
|
||||
|
|
@ -579,13 +583,20 @@ pub(crate) unsafe fn llvm_optimize(
|
|||
// When we build rustc with enzyme/autodiff support, we want to postpone size-increasing
|
||||
// optimizations until after differentiation. Our pipeline is thus: (opt + enzyme), (full opt).
|
||||
// We therefore have two calls to llvm_optimize, if autodiff is used.
|
||||
//
|
||||
// We also must disable merge_functions, since autodiff placeholder/dummy bodies tend to be
|
||||
// identical. We run opts before AD, so there is a chance that LLVM will merge our dummies.
|
||||
// In that case, we lack some dummy bodies and can't replace them with the real AD code anymore.
|
||||
// We then would need to abort compilation. This was especially common in test cases.
|
||||
if consider_ad && autodiff_stage != AutodiffStage::PostAD {
|
||||
merge_functions = false;
|
||||
unroll_loops = false;
|
||||
vectorize_slp = false;
|
||||
vectorize_loop = false;
|
||||
} else {
|
||||
unroll_loops =
|
||||
opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin;
|
||||
merge_functions = config.merge_functions;
|
||||
vectorize_slp = config.vectorize_slp;
|
||||
vectorize_loop = config.vectorize_loop;
|
||||
}
|
||||
|
|
@ -663,13 +674,16 @@ pub(crate) unsafe fn llvm_optimize(
|
|||
thin_lto_buffer,
|
||||
config.emit_thin_lto,
|
||||
config.emit_thin_lto_summary,
|
||||
config.merge_functions,
|
||||
merge_functions,
|
||||
unroll_loops,
|
||||
vectorize_slp,
|
||||
vectorize_loop,
|
||||
config.no_builtins,
|
||||
config.emit_lifetime_markers,
|
||||
run_enzyme,
|
||||
print_before_enzyme,
|
||||
print_after_enzyme,
|
||||
print_passes,
|
||||
sanitizer_options.as_ref(),
|
||||
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
|
|
|
|||
|
|
@ -594,6 +594,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
fn load(&mut self, ty: &'ll Type, ptr: &'ll Value, align: Align) -> &'ll Value {
|
||||
unsafe {
|
||||
let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED);
|
||||
let align = align.min(self.cx().tcx.sess.target.max_reliable_alignment());
|
||||
llvm::LLVMSetAlignment(load, align.bytes() as c_uint);
|
||||
load
|
||||
}
|
||||
|
|
@ -807,6 +808,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
assert_eq!(self.cx.type_kind(self.cx.val_ty(ptr)), TypeKind::Pointer);
|
||||
unsafe {
|
||||
let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
|
||||
let align = align.min(self.cx().tcx.sess.target.max_reliable_alignment());
|
||||
let align =
|
||||
if flags.contains(MemFlags::UNALIGNED) { 1 } else { align.bytes() as c_uint };
|
||||
llvm::LLVMSetAlignment(store, align);
|
||||
|
|
|
|||
|
|
@ -361,6 +361,11 @@ fn generate_enzyme_call<'ll>(
|
|||
let attr = llvm::AttributeKind::NoInline.create_attr(cx.llcx);
|
||||
attributes::apply_to_llfn(ad_fn, Function, &[attr]);
|
||||
|
||||
// We add a made-up attribute just such that we can recognize it after AD to update
|
||||
// (no)-inline attributes. We'll then also remove this attribute.
|
||||
let enzyme_marker_attr = llvm::CreateAttrString(cx.llcx, "enzyme_marker");
|
||||
attributes::apply_to_llfn(outer_fn, Function, &[enzyme_marker_attr]);
|
||||
|
||||
// first, remove all calls from fnc
|
||||
let entry = llvm::LLVMGetFirstBasicBlock(outer_fn);
|
||||
let br = llvm::LLVMRustGetTerminator(entry);
|
||||
|
|
@ -473,7 +478,7 @@ pub(crate) fn differentiate<'ll>(
|
|||
return Err(diag_handler.handle().emit_almost_fatal(AutoDiffWithoutEnable));
|
||||
}
|
||||
|
||||
// Before dumping the module, we want all the TypeTrees to become part of the module.
|
||||
// Here we replace the placeholder code with the actual autodiff code, which calls Enzyme.
|
||||
for item in diff_items.iter() {
|
||||
let name = item.source.clone();
|
||||
let fn_def: Option<&llvm::Value> = cx.get_function(&name);
|
||||
|
|
|
|||
|
|
@ -698,6 +698,16 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
|||
llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn get_functions(&self) -> Vec<&'ll Value> {
|
||||
let mut functions = vec![];
|
||||
let mut func = unsafe { llvm::LLVMGetFirstFunction(self.llmod()) };
|
||||
while let Some(f) = func {
|
||||
functions.push(f);
|
||||
func = unsafe { llvm::LLVMGetNextFunction(f) }
|
||||
}
|
||||
functions
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,19 @@ unsafe extern "C" {
|
|||
pub(crate) fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
|
||||
pub(crate) fn LLVMRustHasAttributeAtIndex(V: &Value, i: c_uint, Kind: AttributeKind) -> bool;
|
||||
pub(crate) fn LLVMRustGetArrayNumElements(Ty: &Type) -> u64;
|
||||
pub(crate) fn LLVMRustHasFnAttribute(
|
||||
F: &Value,
|
||||
Name: *const c_char,
|
||||
NameLen: libc::size_t,
|
||||
) -> bool;
|
||||
pub(crate) fn LLVMRustRemoveFnAttribute(F: &Value, Name: *const c_char, NameLen: libc::size_t);
|
||||
pub(crate) fn LLVMGetFirstFunction(M: &Module) -> Option<&Value>;
|
||||
pub(crate) fn LLVMGetNextFunction(Fn: &Value) -> Option<&Value>;
|
||||
pub(crate) fn LLVMRustRemoveEnumAttributeAtIndex(
|
||||
Fn: &Value,
|
||||
index: c_uint,
|
||||
kind: AttributeKind,
|
||||
);
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
|
|
|
|||
|
|
@ -2454,6 +2454,9 @@ unsafe extern "C" {
|
|||
DisableSimplifyLibCalls: bool,
|
||||
EmitLifetimeMarkers: bool,
|
||||
RunEnzyme: bool,
|
||||
PrintBeforeEnzyme: bool,
|
||||
PrintAfterEnzyme: bool,
|
||||
PrintPasses: bool,
|
||||
SanitizerOptions: Option<&SanitizerOptions>,
|
||||
PGOGenPath: *const c_char,
|
||||
PGOUsePath: *const c_char,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,32 @@ pub(crate) fn AddFunctionAttributes<'ll>(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn HasAttributeAtIndex<'ll>(
|
||||
llfn: &'ll Value,
|
||||
idx: AttributePlace,
|
||||
kind: AttributeKind,
|
||||
) -> bool {
|
||||
unsafe { LLVMRustHasAttributeAtIndex(llfn, idx.as_uint(), kind) }
|
||||
}
|
||||
|
||||
pub(crate) fn HasStringAttribute<'ll>(llfn: &'ll Value, name: &str) -> bool {
|
||||
unsafe { LLVMRustHasFnAttribute(llfn, name.as_c_char_ptr(), name.len()) }
|
||||
}
|
||||
|
||||
pub(crate) fn RemoveStringAttrFromFn<'ll>(llfn: &'ll Value, name: &str) {
|
||||
unsafe { LLVMRustRemoveFnAttribute(llfn, name.as_c_char_ptr(), name.len()) }
|
||||
}
|
||||
|
||||
pub(crate) fn RemoveRustEnumAttributeAtIndex(
|
||||
llfn: &Value,
|
||||
place: AttributePlace,
|
||||
kind: AttributeKind,
|
||||
) {
|
||||
unsafe {
|
||||
LLVMRustRemoveEnumAttributeAtIndex(llfn, place.as_uint(), kind);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn AddCallSiteAttributes<'ll>(
|
||||
callsite: &'ll Value,
|
||||
idx: AttributePlace,
|
||||
|
|
|
|||
|
|
@ -128,6 +128,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
|||
(**self).borrow().llcx
|
||||
}
|
||||
|
||||
pub(crate) fn llmod(&self) -> &'ll llvm::Module {
|
||||
(**self).borrow().llmod
|
||||
}
|
||||
|
||||
pub(crate) fn isize_ty(&self) -> &'ll Type {
|
||||
(**self).borrow().isize_ty
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2015,6 +2015,12 @@ fn add_linked_symbol_object(
|
|||
file.set_mangling(object::write::Mangling::None);
|
||||
}
|
||||
|
||||
if file.format() == object::BinaryFormat::MachO {
|
||||
// Divide up the sections into sub-sections via symbols for dead code stripping.
|
||||
// Without this flag, unused `#[no_mangle]` or `#[used]` cannot be discard on MachO targets.
|
||||
file.set_subsections_via_symbols();
|
||||
}
|
||||
|
||||
// ld64 requires a relocation to load undefined symbols, see below.
|
||||
// Not strictly needed if linking with lld, but might as well do it there too.
|
||||
let ld64_section_helper = if file.format() == object::BinaryFormat::MachO {
|
||||
|
|
|
|||
|
|
@ -158,6 +158,31 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
self.copy_op(&val, dest)?;
|
||||
}
|
||||
|
||||
sym::fadd_algebraic
|
||||
| sym::fsub_algebraic
|
||||
| sym::fmul_algebraic
|
||||
| sym::fdiv_algebraic
|
||||
| sym::frem_algebraic => {
|
||||
let a = self.read_immediate(&args[0])?;
|
||||
let b = self.read_immediate(&args[1])?;
|
||||
|
||||
let op = match intrinsic_name {
|
||||
sym::fadd_algebraic => BinOp::Add,
|
||||
sym::fsub_algebraic => BinOp::Sub,
|
||||
sym::fmul_algebraic => BinOp::Mul,
|
||||
sym::fdiv_algebraic => BinOp::Div,
|
||||
sym::frem_algebraic => BinOp::Rem,
|
||||
|
||||
_ => bug!(),
|
||||
};
|
||||
|
||||
let res = self.binary_op(op, &a, &b)?;
|
||||
// `binary_op` already called `generate_nan` if needed.
|
||||
|
||||
// FIXME: Miri should add some non-determinism to the result here to catch any dependences on exact computations. This has previously been done, but the behaviour was removed as part of constification.
|
||||
self.write_immediate(*res, dest)?;
|
||||
}
|
||||
|
||||
sym::ctpop
|
||||
| sym::cttz
|
||||
| sym::cttz_nonzero
|
||||
|
|
|
|||
|
|
@ -36,43 +36,110 @@ pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
|
|||
use crate::intravisit::{FnKind, VisitorExt};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
|
||||
pub enum IsAnonInPath {
|
||||
No,
|
||||
Yes,
|
||||
pub enum LifetimeSource {
|
||||
/// E.g. `&Type`, `&'_ Type`, `&'a Type`, `&mut Type`, `&'_ mut Type`, `&'a mut Type`
|
||||
Reference,
|
||||
|
||||
/// E.g. `ContainsLifetime`, `ContainsLifetime<'_>`, `ContainsLifetime<'a>`
|
||||
Path {
|
||||
/// - true for `ContainsLifetime<'_>`, `ContainsLifetime<'a>`,
|
||||
/// `ContainsLifetime<'_, T>`, `ContainsLifetime<'a, T>`
|
||||
/// - false for `ContainsLifetime`
|
||||
with_angle_brackets: bool,
|
||||
},
|
||||
|
||||
/// E.g. `impl Trait + '_`, `impl Trait + 'a`
|
||||
OutlivesBound,
|
||||
|
||||
/// E.g. `impl Trait + use<'_>`, `impl Trait + use<'a>`
|
||||
PreciseCapturing,
|
||||
|
||||
/// Other usages which have not yet been categorized. Feel free to
|
||||
/// add new sources that you find useful.
|
||||
///
|
||||
/// Some non-exhaustive examples:
|
||||
/// - `where T: 'a`
|
||||
/// - `fn(_: dyn Trait + 'a)`
|
||||
Other,
|
||||
}
|
||||
|
||||
/// A lifetime. The valid field combinations are non-obvious. The following
|
||||
/// example shows some of them. See also the comments on `LifetimeKind`.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
|
||||
pub enum LifetimeSyntax {
|
||||
/// E.g. `&Type`, `ContainsLifetime`
|
||||
Hidden,
|
||||
|
||||
/// E.g. `&'_ Type`, `ContainsLifetime<'_>`, `impl Trait + '_`, `impl Trait + use<'_>`
|
||||
Anonymous,
|
||||
|
||||
/// E.g. `&'a Type`, `ContainsLifetime<'a>`, `impl Trait + 'a`, `impl Trait + use<'a>`
|
||||
Named,
|
||||
}
|
||||
|
||||
impl From<Ident> for LifetimeSyntax {
|
||||
fn from(ident: Ident) -> Self {
|
||||
let name = ident.name;
|
||||
|
||||
if name == kw::Empty {
|
||||
unreachable!("A lifetime name should never be empty");
|
||||
} else if name == kw::UnderscoreLifetime {
|
||||
LifetimeSyntax::Anonymous
|
||||
} else {
|
||||
debug_assert!(name.as_str().starts_with('\''));
|
||||
LifetimeSyntax::Named
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A lifetime. The valid field combinations are non-obvious and not all
|
||||
/// combinations are possible. The following example shows some of
|
||||
/// them. See also the comments on `LifetimeKind` and `LifetimeSource`.
|
||||
///
|
||||
/// ```
|
||||
/// #[repr(C)]
|
||||
/// struct S<'a>(&'a u32); // res=Param, name='a, IsAnonInPath::No
|
||||
/// struct S<'a>(&'a u32); // res=Param, name='a, source=Reference, syntax=Named
|
||||
/// unsafe extern "C" {
|
||||
/// fn f1(s: S); // res=Param, name='_, IsAnonInPath::Yes
|
||||
/// fn f2(s: S<'_>); // res=Param, name='_, IsAnonInPath::No
|
||||
/// fn f3<'a>(s: S<'a>); // res=Param, name='a, IsAnonInPath::No
|
||||
/// fn f1(s: S); // res=Param, name='_, source=Path, syntax=Hidden
|
||||
/// fn f2(s: S<'_>); // res=Param, name='_, source=Path, syntax=Anonymous
|
||||
/// fn f3<'a>(s: S<'a>); // res=Param, name='a, source=Path, syntax=Named
|
||||
/// }
|
||||
///
|
||||
/// struct St<'a> { x: &'a u32 } // res=Param, name='a, IsAnonInPath::No
|
||||
/// struct St<'a> { x: &'a u32 } // res=Param, name='a, source=Reference, syntax=Named
|
||||
/// fn f() {
|
||||
/// _ = St { x: &0 }; // res=Infer, name='_, IsAnonInPath::Yes
|
||||
/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, IsAnonInPath::No
|
||||
/// _ = St { x: &0 }; // res=Infer, name='_, source=Path, syntax=Hidden
|
||||
/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, source=Path, syntax=Anonymous
|
||||
/// }
|
||||
///
|
||||
/// struct Name<'a>(&'a str); // res=Param, name='a, IsAnonInPath::No
|
||||
/// const A: Name = Name("a"); // res=Static, name='_, IsAnonInPath::Yes
|
||||
/// const B: &str = ""; // res=Static, name='_, IsAnonInPath::No
|
||||
/// static C: &'_ str = ""; // res=Static, name='_, IsAnonInPath::No
|
||||
/// static D: &'static str = ""; // res=Static, name='static, IsAnonInPath::No
|
||||
/// struct Name<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named
|
||||
/// const A: Name = Name("a"); // res=Static, name='_, source=Path, syntax=Hidden
|
||||
/// const B: &str = ""; // res=Static, name='_, source=Reference, syntax=Hidden
|
||||
/// static C: &'_ str = ""; // res=Static, name='_, source=Reference, syntax=Anonymous
|
||||
/// static D: &'static str = ""; // res=Static, name='static, source=Reference, syntax=Named
|
||||
///
|
||||
/// trait Tr {}
|
||||
/// fn tr(_: Box<dyn Tr>) {} // res=ImplicitObjectLifetimeDefault, name='_, IsAnonInPath::No
|
||||
/// fn tr(_: Box<dyn Tr>) {} // res=ImplicitObjectLifetimeDefault, name='_, source=Other, syntax=Hidden
|
||||
///
|
||||
/// fn capture_outlives<'a>() ->
|
||||
/// impl FnOnce() + 'a // res=Param, ident='a, source=OutlivesBound, syntax=Named
|
||||
/// {
|
||||
/// || {}
|
||||
/// }
|
||||
///
|
||||
/// fn capture_precise<'a>() ->
|
||||
/// impl FnOnce() + use<'a> // res=Param, ident='a, source=PreciseCapturing, syntax=Named
|
||||
/// {
|
||||
/// || {}
|
||||
/// }
|
||||
///
|
||||
/// // (commented out because these cases trigger errors)
|
||||
/// // struct S1<'a>(&'a str); // res=Param, name='a, IsAnonInPath::No
|
||||
/// // struct S2(S1); // res=Error, name='_, IsAnonInPath::Yes
|
||||
/// // struct S3(S1<'_>); // res=Error, name='_, IsAnonInPath::No
|
||||
/// // struct S4(S1<'a>); // res=Error, name='a, IsAnonInPath::No
|
||||
/// // struct S1<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named
|
||||
/// // struct S2(S1); // res=Error, name='_, source=Path, syntax=Hidden
|
||||
/// // struct S3(S1<'_>); // res=Error, name='_, source=Path, syntax=Anonymous
|
||||
/// // struct S4(S1<'a>); // res=Error, name='a, source=Path, syntax=Named
|
||||
/// ```
|
||||
///
|
||||
/// Some combinations that cannot occur are `LifetimeSyntax::Hidden` with
|
||||
/// `LifetimeSource::OutlivesBound` or `LifetimeSource::PreciseCapturing`
|
||||
/// — there's no way to "elide" these lifetimes.
|
||||
#[derive(Debug, Copy, Clone, HashStable_Generic)]
|
||||
pub struct Lifetime {
|
||||
#[stable_hasher(ignore)]
|
||||
|
|
@ -86,9 +153,13 @@ pub struct Lifetime {
|
|||
/// Semantics of this lifetime.
|
||||
pub kind: LifetimeKind,
|
||||
|
||||
/// Is the lifetime anonymous and in a path? Used only for error
|
||||
/// suggestions. See `Lifetime::suggestion` for example use.
|
||||
pub is_anon_in_path: IsAnonInPath,
|
||||
/// The context in which the lifetime occurred. See `Lifetime::suggestion`
|
||||
/// for example use.
|
||||
pub source: LifetimeSource,
|
||||
|
||||
/// The syntax that the user used to declare this lifetime. See
|
||||
/// `Lifetime::suggestion` for example use.
|
||||
pub syntax: LifetimeSyntax,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, HashStable_Generic)]
|
||||
|
|
@ -185,9 +256,10 @@ impl Lifetime {
|
|||
hir_id: HirId,
|
||||
ident: Ident,
|
||||
kind: LifetimeKind,
|
||||
is_anon_in_path: IsAnonInPath,
|
||||
source: LifetimeSource,
|
||||
syntax: LifetimeSyntax,
|
||||
) -> Lifetime {
|
||||
let lifetime = Lifetime { hir_id, ident, kind, is_anon_in_path };
|
||||
let lifetime = Lifetime { hir_id, ident, kind, source, syntax };
|
||||
|
||||
// Sanity check: elided lifetimes form a strict subset of anonymous lifetimes.
|
||||
#[cfg(debug_assertions)]
|
||||
|
|
@ -209,23 +281,44 @@ impl Lifetime {
|
|||
self.ident.name == kw::UnderscoreLifetime
|
||||
}
|
||||
|
||||
pub fn is_syntactically_hidden(&self) -> bool {
|
||||
matches!(self.syntax, LifetimeSyntax::Hidden)
|
||||
}
|
||||
|
||||
pub fn is_syntactically_anonymous(&self) -> bool {
|
||||
matches!(self.syntax, LifetimeSyntax::Anonymous)
|
||||
}
|
||||
|
||||
pub fn is_static(&self) -> bool {
|
||||
self.kind == LifetimeKind::Static
|
||||
}
|
||||
|
||||
pub fn suggestion(&self, new_lifetime: &str) -> (Span, String) {
|
||||
use LifetimeSource::*;
|
||||
use LifetimeSyntax::*;
|
||||
|
||||
debug_assert!(new_lifetime.starts_with('\''));
|
||||
|
||||
match (self.is_anon_in_path, self.ident.span.is_empty()) {
|
||||
match (self.syntax, self.source) {
|
||||
// The user wrote `'a` or `'_`.
|
||||
(Named | Anonymous, _) => (self.ident.span, format!("{new_lifetime}")),
|
||||
|
||||
// The user wrote `Path<T>`, and omitted the `'_,`.
|
||||
(IsAnonInPath::Yes, true) => (self.ident.span, format!("{new_lifetime}, ")),
|
||||
(Hidden, Path { with_angle_brackets: true }) => {
|
||||
(self.ident.span, format!("{new_lifetime}, "))
|
||||
}
|
||||
|
||||
// The user wrote `Path` and omitted the `<'_>`.
|
||||
(IsAnonInPath::Yes, false) => {
|
||||
(Hidden, Path { with_angle_brackets: false }) => {
|
||||
(self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>"))
|
||||
}
|
||||
|
||||
// The user wrote `&type` or `&mut type`.
|
||||
(IsAnonInPath::No, true) => (self.ident.span, format!("{new_lifetime} ")),
|
||||
(Hidden, Reference) => (self.ident.span, format!("{new_lifetime} ")),
|
||||
|
||||
// The user wrote `'a` or `'_`.
|
||||
(IsAnonInPath::No, false) => (self.ident.span, format!("{new_lifetime}")),
|
||||
(Hidden, source) => {
|
||||
unreachable!("can't suggest for a hidden lifetime of {source:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) {
|
|||
hir_id: HirId::INVALID,
|
||||
ident: Ident::new(sym::name, DUMMY_SP),
|
||||
kind: LifetimeKind::Static,
|
||||
is_anon_in_path: IsAnonInPath::No,
|
||||
source: LifetimeSource::Other,
|
||||
syntax: LifetimeSyntax::Hidden,
|
||||
}
|
||||
},
|
||||
syntax,
|
||||
|
|
|
|||
|
|
@ -759,22 +759,54 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Byte string patterns behave the same way as array patterns
|
||||
// They can denote both statically and dynamically-sized byte arrays.
|
||||
// Additionally, when `deref_patterns` is enabled, byte string literal patterns may have
|
||||
// types `[u8]` or `[u8; N]`, in order to type, e.g., `deref!(b"..."): Vec<u8>`.
|
||||
let mut pat_ty = ty;
|
||||
if let hir::PatExprKind::Lit {
|
||||
lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, ..
|
||||
} = lt.kind
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
let expected = self.structurally_resolve_type(span, expected);
|
||||
if let ty::Ref(_, inner_ty, _) = *expected.kind()
|
||||
&& self.try_structurally_resolve_type(span, inner_ty).is_slice()
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
|
||||
pat_ty =
|
||||
Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_slice(tcx, tcx.types.u8));
|
||||
match *expected.kind() {
|
||||
// Allow `b"...": &[u8]`
|
||||
ty::Ref(_, inner_ty, _)
|
||||
if self.try_structurally_resolve_type(span, inner_ty).is_slice() =>
|
||||
{
|
||||
trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
|
||||
pat_ty = Ty::new_imm_ref(
|
||||
tcx,
|
||||
tcx.lifetimes.re_static,
|
||||
Ty::new_slice(tcx, tcx.types.u8),
|
||||
);
|
||||
}
|
||||
// Allow `b"...": [u8; 3]` for `deref_patterns`
|
||||
ty::Array(..) if tcx.features().deref_patterns() => {
|
||||
pat_ty = match *ty.kind() {
|
||||
ty::Ref(_, inner_ty, _) => inner_ty,
|
||||
_ => span_bug!(span, "found byte string literal with non-ref type {ty:?}"),
|
||||
}
|
||||
}
|
||||
// Allow `b"...": [u8]` for `deref_patterns`
|
||||
ty::Slice(..) if tcx.features().deref_patterns() => {
|
||||
pat_ty = Ty::new_slice(tcx, tcx.types.u8);
|
||||
}
|
||||
// Otherwise, `b"...": &[u8; 3]`
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// When `deref_patterns` is enabled, in order to allow `deref!("..."): String`, we allow
|
||||
// string literal patterns to have type `str`. This is accounted for when lowering to MIR.
|
||||
if self.tcx.features().deref_patterns()
|
||||
&& let hir::PatExprKind::Lit {
|
||||
lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
|
||||
} = lt.kind
|
||||
&& self.try_structurally_resolve_type(span, expected).is_str()
|
||||
{
|
||||
pat_ty = self.tcx.types.str_;
|
||||
}
|
||||
|
||||
if self.tcx.features().string_deref_patterns()
|
||||
&& let hir::PatExprKind::Lit {
|
||||
lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_abi::{BackendRepr, TagEncoding, VariantIdx, Variants, WrappingRange};
|
||||
use rustc_abi::{
|
||||
BackendRepr, Integer, IntegerType, TagEncoding, VariantIdx, Variants, WrappingRange,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::DiagMessage;
|
||||
use rustc_hir::intravisit::VisitorExt;
|
||||
|
|
@ -1243,6 +1245,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
};
|
||||
}
|
||||
|
||||
if let Some(IntegerType::Fixed(Integer::I128, _)) = def.repr().int {
|
||||
return FfiUnsafe {
|
||||
ty,
|
||||
reason: fluent::lint_improper_ctypes_128bit,
|
||||
help: None,
|
||||
};
|
||||
}
|
||||
|
||||
use improper_ctypes::check_non_exhaustive_variant;
|
||||
|
||||
let non_exhaustive = def.variant_list_has_applicable_non_exhaustive();
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ declare_lint_pass! {
|
|||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
UNNAMEABLE_TEST_ITEMS,
|
||||
UNNAMEABLE_TYPES,
|
||||
UNNECESSARY_TRANSMUTES,
|
||||
UNREACHABLE_CODE,
|
||||
UNREACHABLE_PATTERNS,
|
||||
UNSAFE_ATTR_OUTSIDE_UNSAFE,
|
||||
|
|
@ -4909,6 +4910,30 @@ declare_lint! {
|
|||
"detects pointer to integer transmutes in const functions and associated constants",
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unnecessary_transmutes` lint detects transmutations that have safer alternatives.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// fn bytes_at_home(x: [u8; 4]) -> u32 {
|
||||
/// unsafe { std::mem::transmute(x) }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Using an explicit method is preferable over calls to
|
||||
/// [`transmute`](https://doc.rust-lang.org/std/mem/fn.transmute.html) as
|
||||
/// they more clearly communicate the intent, are easier to review, and
|
||||
/// are less likely to accidentally result in unsoundness.
|
||||
pub UNNECESSARY_TRANSMUTES,
|
||||
Warn,
|
||||
"detects transmutes that are shadowed by std methods"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location,
|
||||
/// that runs a custom `Drop` destructor.
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IRPrinter/IRPrintingPasses.h"
|
||||
#include "llvm/LTO/LTO.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/TargetRegistry.h"
|
||||
|
|
@ -703,7 +704,8 @@ extern "C" LLVMRustResult LLVMRustOptimize(
|
|||
bool LintIR, LLVMRustThinLTOBuffer **ThinLTOBufferRef, bool EmitThinLTO,
|
||||
bool EmitThinLTOSummary, bool MergeFunctions, bool UnrollLoops,
|
||||
bool SLPVectorize, bool LoopVectorize, bool DisableSimplifyLibCalls,
|
||||
bool EmitLifetimeMarkers, bool RunEnzyme,
|
||||
bool EmitLifetimeMarkers, bool RunEnzyme, bool PrintBeforeEnzyme,
|
||||
bool PrintAfterEnzyme, bool PrintPasses,
|
||||
LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath,
|
||||
const char *PGOUsePath, bool InstrumentCoverage,
|
||||
const char *InstrProfileOutput, const char *PGOSampleUsePath,
|
||||
|
|
@ -1048,14 +1050,38 @@ extern "C" LLVMRustResult LLVMRustOptimize(
|
|||
// now load "-enzyme" pass:
|
||||
#ifdef ENZYME
|
||||
if (RunEnzyme) {
|
||||
registerEnzymeAndPassPipeline(PB, true);
|
||||
|
||||
if (PrintBeforeEnzyme) {
|
||||
// Handle the Rust flag `-Zautodiff=PrintModBefore`.
|
||||
std::string Banner = "Module before EnzymeNewPM";
|
||||
MPM.addPass(PrintModulePass(outs(), Banner, true, false));
|
||||
}
|
||||
|
||||
registerEnzymeAndPassPipeline(PB, false);
|
||||
if (auto Err = PB.parsePassPipeline(MPM, "enzyme")) {
|
||||
std::string ErrMsg = toString(std::move(Err));
|
||||
LLVMRustSetLastError(ErrMsg.c_str());
|
||||
return LLVMRustResult::Failure;
|
||||
}
|
||||
|
||||
if (PrintAfterEnzyme) {
|
||||
// Handle the Rust flag `-Zautodiff=PrintModAfter`.
|
||||
std::string Banner = "Module after EnzymeNewPM";
|
||||
MPM.addPass(PrintModulePass(outs(), Banner, true, false));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (PrintPasses) {
|
||||
// Print all passes from the PM:
|
||||
std::string Pipeline;
|
||||
raw_string_ostream SOS(Pipeline);
|
||||
MPM.printPipeline(SOS, [&PIC](StringRef ClassName) {
|
||||
auto PassName = PIC.getPassNameForClassName(ClassName);
|
||||
return PassName.empty() ? ClassName : PassName;
|
||||
});
|
||||
outs() << Pipeline;
|
||||
outs() << "\n";
|
||||
}
|
||||
|
||||
// Upgrade all calls to old intrinsics first.
|
||||
for (Module::iterator I = TheModule->begin(), E = TheModule->end(); I != E;)
|
||||
|
|
|
|||
|
|
@ -973,6 +973,27 @@ extern "C" LLVMMetadataRef LLVMRustDIGetInstMetadata(LLVMValueRef x) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
LLVMRustRemoveEnumAttributeAtIndex(LLVMValueRef F, size_t index,
|
||||
LLVMRustAttributeKind RustAttr) {
|
||||
LLVMRemoveEnumAttributeAtIndex(F, index, fromRust(RustAttr));
|
||||
}
|
||||
|
||||
extern "C" bool LLVMRustHasFnAttribute(LLVMValueRef F, const char *Name,
|
||||
size_t NameLen) {
|
||||
if (auto *Fn = dyn_cast<Function>(unwrap<Value>(F))) {
|
||||
return Fn->hasFnAttribute(StringRef(Name, NameLen));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustRemoveFnAttribute(LLVMValueRef Fn, const char *Name,
|
||||
size_t NameLen) {
|
||||
if (auto *F = dyn_cast<Function>(unwrap<Value>(Fn))) {
|
||||
F->removeFnAttr(StringRef(Name, NameLen));
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind,
|
||||
LLVMMetadataRef MD) {
|
||||
unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD));
|
||||
|
|
|
|||
|
|
@ -55,8 +55,7 @@ use synstructure::Structure;
|
|||
///
|
||||
/// See rustc dev guide for more examples on using the `#[derive(Diagnostic)]`:
|
||||
/// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html>
|
||||
pub(super) fn diagnostic_derive(mut s: Structure<'_>) -> TokenStream {
|
||||
s.underscore_const(true);
|
||||
pub(super) fn diagnostic_derive(s: Structure<'_>) -> TokenStream {
|
||||
DiagnosticDerive::new(s).into_tokens()
|
||||
}
|
||||
|
||||
|
|
@ -102,8 +101,7 @@ pub(super) fn diagnostic_derive(mut s: Structure<'_>) -> TokenStream {
|
|||
///
|
||||
/// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`:
|
||||
/// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html#reference>
|
||||
pub(super) fn lint_diagnostic_derive(mut s: Structure<'_>) -> TokenStream {
|
||||
s.underscore_const(true);
|
||||
pub(super) fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
|
||||
LintDiagnosticDerive::new(s).into_tokens()
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +151,6 @@ pub(super) fn lint_diagnostic_derive(mut s: Structure<'_>) -> TokenStream {
|
|||
///
|
||||
/// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
|
||||
/// ```
|
||||
pub(super) fn subdiagnostic_derive(mut s: Structure<'_>) -> TokenStream {
|
||||
s.underscore_const(true);
|
||||
pub(super) fn subdiagnostic_derive(s: Structure<'_>) -> TokenStream {
|
||||
SubdiagnosticDerive::new().into_tokens(s)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,8 +74,6 @@ fn hash_stable_derive_with_mode(
|
|||
HashStableMode::Generic | HashStableMode::NoContext => parse_quote!(__CTX),
|
||||
};
|
||||
|
||||
s.underscore_const(true);
|
||||
|
||||
// no_context impl is able to derive by-field, which is closer to a perfect derive.
|
||||
s.add_bounds(match mode {
|
||||
HashStableMode::Normal | HashStableMode::Generic => synstructure::AddBounds::Generics,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ use syn::parse_quote;
|
|||
pub(super) fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||||
s.add_bounds(synstructure::AddBounds::Generics);
|
||||
s.bind_with(|_| synstructure::BindStyle::Move);
|
||||
s.underscore_const(true);
|
||||
|
||||
let tcx: syn::Lifetime = parse_quote!('tcx);
|
||||
let newtcx: syn::GenericParam = parse_quote!('__lifted);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ pub(super) fn type_decodable_derive(
|
|||
let decoder_ty = quote! { __D };
|
||||
s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_middle::ty::codec::TyDecoder<'tcx> });
|
||||
s.add_bounds(synstructure::AddBounds::Fields);
|
||||
s.underscore_const(true);
|
||||
|
||||
decodable_body(s, decoder_ty)
|
||||
}
|
||||
|
|
@ -26,7 +25,6 @@ pub(super) fn meta_decodable_derive(
|
|||
s.add_impl_generic(parse_quote! { '__a });
|
||||
let decoder_ty = quote! { DecodeContext<'__a, 'tcx> };
|
||||
s.add_bounds(synstructure::AddBounds::Generics);
|
||||
s.underscore_const(true);
|
||||
|
||||
decodable_body(s, decoder_ty)
|
||||
}
|
||||
|
|
@ -35,7 +33,6 @@ pub(super) fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro
|
|||
let decoder_ty = quote! { __D };
|
||||
s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_span::SpanDecoder });
|
||||
s.add_bounds(synstructure::AddBounds::Generics);
|
||||
s.underscore_const(true);
|
||||
|
||||
decodable_body(s, decoder_ty)
|
||||
}
|
||||
|
|
@ -46,13 +43,12 @@ pub(super) fn decodable_nocontext_derive(
|
|||
let decoder_ty = quote! { __D };
|
||||
s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_serialize::Decoder });
|
||||
s.add_bounds(synstructure::AddBounds::Fields);
|
||||
s.underscore_const(true);
|
||||
|
||||
decodable_body(s, decoder_ty)
|
||||
}
|
||||
|
||||
fn decodable_body(
|
||||
mut s: synstructure::Structure<'_>,
|
||||
s: synstructure::Structure<'_>,
|
||||
decoder_ty: TokenStream,
|
||||
) -> proc_macro2::TokenStream {
|
||||
if let syn::Data::Union(_) = s.ast().data {
|
||||
|
|
@ -98,7 +94,6 @@ fn decodable_body(
|
|||
}
|
||||
}
|
||||
};
|
||||
s.underscore_const(true);
|
||||
|
||||
s.bound_impl(
|
||||
quote!(::rustc_serialize::Decodable<#decoder_ty>),
|
||||
|
|
@ -133,7 +128,6 @@ pub(super) fn type_encodable_derive(
|
|||
}
|
||||
s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_middle::ty::codec::TyEncoder<'tcx> });
|
||||
s.add_bounds(synstructure::AddBounds::Fields);
|
||||
s.underscore_const(true);
|
||||
|
||||
encodable_body(s, encoder_ty, false)
|
||||
}
|
||||
|
|
@ -147,7 +141,6 @@ pub(super) fn meta_encodable_derive(
|
|||
s.add_impl_generic(parse_quote! { '__a });
|
||||
let encoder_ty = quote! { EncodeContext<'__a, 'tcx> };
|
||||
s.add_bounds(synstructure::AddBounds::Generics);
|
||||
s.underscore_const(true);
|
||||
|
||||
encodable_body(s, encoder_ty, true)
|
||||
}
|
||||
|
|
@ -156,7 +149,6 @@ pub(super) fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro
|
|||
let encoder_ty = quote! { __E };
|
||||
s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_span::SpanEncoder });
|
||||
s.add_bounds(synstructure::AddBounds::Generics);
|
||||
s.underscore_const(true);
|
||||
|
||||
encodable_body(s, encoder_ty, false)
|
||||
}
|
||||
|
|
@ -167,7 +159,6 @@ pub(super) fn encodable_nocontext_derive(
|
|||
let encoder_ty = quote! { __E };
|
||||
s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder });
|
||||
s.add_bounds(synstructure::AddBounds::Fields);
|
||||
s.underscore_const(true);
|
||||
|
||||
encodable_body(s, encoder_ty, false)
|
||||
}
|
||||
|
|
@ -181,7 +172,6 @@ fn encodable_body(
|
|||
panic!("cannot derive on union")
|
||||
}
|
||||
|
||||
s.underscore_const(true);
|
||||
s.bind_with(|binding| {
|
||||
// Handle the lack of a blanket reference impl.
|
||||
if let syn::Type::Reference(_) = binding.ast().ty {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_m
|
|||
panic!("cannot derive on union")
|
||||
}
|
||||
|
||||
s.underscore_const(true);
|
||||
|
||||
if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
|
||||
s.add_impl_generic(parse_quote! { 'tcx });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ pub(super) fn type_visitable_derive(
|
|||
panic!("cannot derive on union")
|
||||
}
|
||||
|
||||
s.underscore_const(true);
|
||||
|
||||
// ignore fields with #[type_visitable(ignore)]
|
||||
s.filter(|bi| {
|
||||
let mut ignored = false;
|
||||
|
|
|
|||
|
|
@ -146,6 +146,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let mut place = place;
|
||||
let mut block = block;
|
||||
match ty.kind() {
|
||||
ty::Str => {
|
||||
// String literal patterns may have type `str` if `deref_patterns` is
|
||||
// enabled, in order to allow `deref!("..."): String`. In this case, `value`
|
||||
// is of type `&str`, so we compare it to `&place`.
|
||||
if !tcx.features().deref_patterns() {
|
||||
span_bug!(
|
||||
test.span,
|
||||
"matching on `str` went through without enabling deref_patterns"
|
||||
);
|
||||
}
|
||||
let re_erased = tcx.lifetimes.re_erased;
|
||||
let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_);
|
||||
let ref_place = self.temp(ref_str_ty, test.span);
|
||||
// `let ref_place: &str = &place;`
|
||||
self.cfg.push_assign(
|
||||
block,
|
||||
self.source_info(test.span),
|
||||
ref_place,
|
||||
Rvalue::Ref(re_erased, BorrowKind::Shared, place),
|
||||
);
|
||||
place = ref_place;
|
||||
ty = ref_str_ty;
|
||||
}
|
||||
ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => {
|
||||
if !tcx.features().string_deref_patterns() {
|
||||
span_bug!(
|
||||
|
|
|
|||
|
|
@ -37,13 +37,23 @@ pub(crate) fn lit_to_const<'tcx>(
|
|||
let str_bytes = s.as_str().as_bytes();
|
||||
ty::ValTree::from_raw_bytes(tcx, str_bytes)
|
||||
}
|
||||
(ast::LitKind::Str(s, _), ty::Str) if tcx.features().deref_patterns() => {
|
||||
// String literal patterns may have type `str` if `deref_patterns` is enabled, in order
|
||||
// to allow `deref!("..."): String`.
|
||||
let str_bytes = s.as_str().as_bytes();
|
||||
ty::ValTree::from_raw_bytes(tcx, str_bytes)
|
||||
}
|
||||
(ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _))
|
||||
if matches!(inner_ty.kind(), ty::Slice(_)) =>
|
||||
if matches!(inner_ty.kind(), ty::Slice(_) | ty::Array(..)) =>
|
||||
{
|
||||
let bytes = data as &[u8];
|
||||
ty::ValTree::from_raw_bytes(tcx, bytes)
|
||||
}
|
||||
(ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
|
||||
(ast::LitKind::ByteStr(data, _), ty::Slice(_) | ty::Array(..))
|
||||
if tcx.features().deref_patterns() =>
|
||||
{
|
||||
// Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is
|
||||
// enabled, in order to allow, e.g., `deref!(b"..."): Vec<u8>`.
|
||||
let bytes = data as &[u8];
|
||||
ty::ValTree::from_raw_bytes(tcx, bytes)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -280,6 +280,16 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||
slice: None,
|
||||
suffix: Box::new([]),
|
||||
},
|
||||
ty::Str => {
|
||||
// String literal patterns may have type `str` if `deref_patterns` is enabled, in
|
||||
// order to allow `deref!("..."): String`. Since we need a `&str` for the comparison
|
||||
// when lowering to MIR in `Builder::perform_test`, treat the constant as a `&str`.
|
||||
// This works because `str` and `&str` have the same valtree representation.
|
||||
let ref_str_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty);
|
||||
PatKind::Constant {
|
||||
value: mir::Const::Ty(ref_str_ty, ty::Const::new_value(tcx, cv, ref_str_ty)),
|
||||
}
|
||||
}
|
||||
ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
|
||||
// `&str` is represented as a valtree, let's keep using this
|
||||
// optimization for now.
|
||||
|
|
|
|||
|
|
@ -84,3 +84,4 @@ mir_transform_undefined_transmute = pointers cannot be transmuted to integers du
|
|||
.help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
|
||||
|
||||
mir_transform_unknown_pass_name = MIR pass `{$name}` is unknown and will be ignored
|
||||
mir_transform_unnecessary_transmute = unnecessary transmute
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use rustc_abi::Align;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::interpret::Scalar;
|
||||
use rustc_middle::mir::visit::PlaceContext;
|
||||
|
|
@ -11,10 +12,6 @@ pub(super) struct CheckAlignment;
|
|||
|
||||
impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
|
||||
fn is_enabled(&self, sess: &Session) -> bool {
|
||||
// FIXME(#112480) MSVC and rustc disagree on minimum stack alignment on x86 Windows
|
||||
if sess.target.llvm_target == "i686-pc-windows-msvc" {
|
||||
return false;
|
||||
}
|
||||
sess.ub_checks()
|
||||
}
|
||||
|
||||
|
|
@ -87,6 +84,33 @@ fn insert_alignment_check<'tcx>(
|
|||
))),
|
||||
});
|
||||
|
||||
// If this target does not have reliable alignment, further limit the mask by anding it with
|
||||
// the mask for the highest reliable alignment.
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
if let max_align = tcx.sess.target.max_reliable_alignment()
|
||||
&& max_align < Align::MAX
|
||||
{
|
||||
let max_mask = max_align.bytes() - 1;
|
||||
let max_mask = Operand::Constant(Box::new(ConstOperand {
|
||||
span: source_info.span,
|
||||
user_ty: None,
|
||||
const_: Const::Val(
|
||||
ConstValue::Scalar(Scalar::from_target_usize(max_mask, &tcx)),
|
||||
tcx.types.usize,
|
||||
),
|
||||
}));
|
||||
stmts.push(Statement {
|
||||
source_info,
|
||||
kind: StatementKind::Assign(Box::new((
|
||||
alignment_mask,
|
||||
Rvalue::BinaryOp(
|
||||
BinOp::BitAnd,
|
||||
Box::new((Operand::Copy(alignment_mask), max_mask)),
|
||||
),
|
||||
))),
|
||||
});
|
||||
}
|
||||
|
||||
// BitAnd the alignment mask with the pointer
|
||||
let alignment_bits =
|
||||
local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
|
||||
|
|
|
|||
100
compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs
Normal file
100
compiler/rustc_mir_transform/src/check_unnecessary_transmutes.rs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{Body, Location, Operand, Terminator, TerminatorKind};
|
||||
use rustc_middle::ty::*;
|
||||
use rustc_session::lint::builtin::UNNECESSARY_TRANSMUTES;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{Span, sym};
|
||||
|
||||
use crate::errors::UnnecessaryTransmute as Error;
|
||||
|
||||
/// Check for transmutes that overlap with stdlib methods.
|
||||
/// For example, transmuting `[u8; 4]` to `u32`.
|
||||
pub(super) struct CheckUnnecessaryTransmutes;
|
||||
|
||||
impl<'tcx> crate::MirLint<'tcx> for CheckUnnecessaryTransmutes {
|
||||
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
let mut checker = UnnecessaryTransmuteChecker { body, tcx };
|
||||
checker.visit_body(body);
|
||||
}
|
||||
}
|
||||
|
||||
struct UnnecessaryTransmuteChecker<'a, 'tcx> {
|
||||
body: &'a Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> UnnecessaryTransmuteChecker<'a, 'tcx> {
|
||||
fn is_unnecessary_transmute(
|
||||
&self,
|
||||
function: &Operand<'tcx>,
|
||||
arg: String,
|
||||
span: Span,
|
||||
) -> Option<Error> {
|
||||
let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder();
|
||||
let [input] = fn_sig.inputs() else { return None };
|
||||
|
||||
let err = |sugg| Error { span, sugg, help: None };
|
||||
|
||||
Some(match (input.kind(), fn_sig.output().kind()) {
|
||||
// dont check the length; transmute does that for us.
|
||||
// [u8; _] => primitive
|
||||
(Array(t, _), Uint(_) | Float(_) | Int(_)) if *t.kind() == Uint(UintTy::U8) => Error {
|
||||
sugg: format!("{}::from_ne_bytes({arg})", fn_sig.output()),
|
||||
help: Some(
|
||||
"there's also `from_le_bytes` and `from_be_bytes` if you expect a particular byte order",
|
||||
),
|
||||
span,
|
||||
},
|
||||
// primitive => [u8; _]
|
||||
(Uint(_) | Float(_) | Int(_), Array(t, _)) if *t.kind() == Uint(UintTy::U8) => Error {
|
||||
sugg: format!("{input}::to_ne_bytes({arg})"),
|
||||
help: Some(
|
||||
"there's also `to_le_bytes` and `to_be_bytes` if you expect a particular byte order",
|
||||
),
|
||||
span,
|
||||
},
|
||||
// char → u32
|
||||
(Char, Uint(UintTy::U32)) => err(format!("u32::from({arg})")),
|
||||
// u32 → char
|
||||
(Uint(UintTy::U32), Char) => Error {
|
||||
sugg: format!("char::from_u32_unchecked({arg})"),
|
||||
help: Some("consider `char::from_u32(…).unwrap()`"),
|
||||
span,
|
||||
},
|
||||
// uNN → iNN
|
||||
(Uint(ty), Int(_)) => err(format!("{}::cast_signed({arg})", ty.name_str())),
|
||||
// iNN → uNN
|
||||
(Int(ty), Uint(_)) => err(format!("{}::cast_unsigned({arg})", ty.name_str())),
|
||||
// fNN → uNN
|
||||
(Float(ty), Uint(..)) => err(format!("{}::to_bits({arg})", ty.name_str())),
|
||||
// uNN → fNN
|
||||
(Uint(_), Float(ty)) => err(format!("{}::from_bits({arg})", ty.name_str())),
|
||||
// bool → { x8 }
|
||||
(Bool, Int(..) | Uint(..)) => err(format!("({arg}) as {}", fn_sig.output())),
|
||||
// u8 → bool
|
||||
(Uint(_), Bool) => err(format!("({arg} == 1)")),
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for UnnecessaryTransmuteChecker<'_, 'tcx> {
|
||||
// Check each block's terminator for calls to pointer to integer transmutes
|
||||
// in const functions or associated constants and emit a lint.
|
||||
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
|
||||
if let TerminatorKind::Call { func, args, .. } = &terminator.kind
|
||||
&& let [Spanned { span: arg, .. }] = **args
|
||||
&& let Some((func_def_id, _)) = func.const_fn_def()
|
||||
&& self.tcx.is_intrinsic(func_def_id, sym::transmute)
|
||||
&& let span = self.body.source_info(location).span
|
||||
&& let Some(lint) = self.is_unnecessary_transmute(
|
||||
func,
|
||||
self.tcx.sess.source_map().span_to_snippet(arg).expect("ok"),
|
||||
span,
|
||||
)
|
||||
&& let Some(hir_id) = terminator.source_info.scope.lint_root(&self.body.source_scopes)
|
||||
{
|
||||
self.tcx.emit_node_span_lint(UNNECESSARY_TRANSMUTES, hir_id, span, lint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -158,6 +158,26 @@ pub(crate) struct MustNotSuspendReason {
|
|||
pub reason: String,
|
||||
}
|
||||
|
||||
pub(crate) struct UnnecessaryTransmute {
|
||||
pub span: Span,
|
||||
pub sugg: String,
|
||||
pub help: Option<&'static str>,
|
||||
}
|
||||
|
||||
// Needed for def_path_str
|
||||
impl<'a> LintDiagnostic<'a, ()> for UnnecessaryTransmute {
|
||||
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) {
|
||||
diag.primary_message(fluent::mir_transform_unnecessary_transmute);
|
||||
diag.span_suggestion(
|
||||
self.span,
|
||||
"replace this with",
|
||||
self.sugg,
|
||||
lint::Applicability::MachineApplicable,
|
||||
);
|
||||
self.help.map(|help| diag.help(help));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_transform_undefined_transmute)]
|
||||
#[note]
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ declare_passes! {
|
|||
mod check_null : CheckNull;
|
||||
mod check_packed_ref : CheckPackedRef;
|
||||
mod check_undefined_transmutes : CheckUndefinedTransmutes;
|
||||
mod check_unnecessary_transmutes: CheckUnnecessaryTransmutes;
|
||||
// This pass is public to allow external drivers to perform MIR cleanup
|
||||
pub mod cleanup_post_borrowck : CleanupPostBorrowck;
|
||||
|
||||
|
|
@ -391,6 +392,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
|
|||
&Lint(check_const_item_mutation::CheckConstItemMutation),
|
||||
&Lint(function_item_references::FunctionItemReferences),
|
||||
&Lint(check_undefined_transmutes::CheckUndefinedTransmutes),
|
||||
&Lint(check_unnecessary_transmutes::CheckUnnecessaryTransmutes),
|
||||
// What we need to do constant evaluation.
|
||||
&simplify::SimplifyCfg::Initial,
|
||||
&Lint(sanity_check::SanityCheck),
|
||||
|
|
|
|||
|
|
@ -1308,18 +1308,6 @@ where
|
|||
return true;
|
||||
}
|
||||
|
||||
// We don't consider a trait-bound global if it has a projection bound.
|
||||
//
|
||||
// See ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
|
||||
// for an example where this is necessary.
|
||||
for p in goal.param_env.caller_bounds().iter() {
|
||||
if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() {
|
||||
if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
|
|
|
|||
|
|
@ -2058,6 +2058,17 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
self.expect_field_ty_separator()?;
|
||||
let ty = self.parse_ty()?;
|
||||
if self.token == token::Colon && self.look_ahead(1, |&t| t != token::Colon) {
|
||||
self.dcx()
|
||||
.struct_span_err(self.token.span, "found single colon in a struct field type path")
|
||||
.with_span_suggestion_verbose(
|
||||
self.token.span,
|
||||
"write a path separator here",
|
||||
"::",
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
let default = if self.token == token::Eq {
|
||||
self.bump();
|
||||
let const_expr = self.parse_expr_anon_const()?;
|
||||
|
|
|
|||
|
|
@ -248,19 +248,13 @@ impl<'a> Parser<'a> {
|
|||
segments.push(segment);
|
||||
|
||||
if self.is_import_coupler() || !self.eat_path_sep() {
|
||||
let ok_for_recovery = self.may_recover()
|
||||
&& match style {
|
||||
PathStyle::Expr => true,
|
||||
PathStyle::Type if let Some((ident, _)) = self.prev_token.ident() => {
|
||||
self.token == token::Colon
|
||||
&& ident.as_str().chars().all(|c| c.is_lowercase())
|
||||
&& self.token.span.lo() == self.prev_token.span.hi()
|
||||
&& self
|
||||
.look_ahead(1, |token| self.token.span.hi() == token.span.lo())
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
if ok_for_recovery
|
||||
// IMPORTANT: We can *only ever* treat single colons as typo'ed double colons in
|
||||
// expression contexts (!) since only there paths cannot possibly be followed by
|
||||
// a colon and still form a syntactically valid construct. In pattern contexts,
|
||||
// a path may be followed by a type annotation. E.g., `let pat:ty`. In type
|
||||
// contexts, a path may be followed by a list of bounds. E.g., `where ty:bound`.
|
||||
if self.may_recover()
|
||||
&& style == PathStyle::Expr // (!)
|
||||
&& self.token == token::Colon
|
||||
&& self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -246,6 +246,10 @@ pub enum AutoDiff {
|
|||
/// Print the module after running autodiff and optimizations.
|
||||
PrintModFinal,
|
||||
|
||||
/// Print all passes scheduled by LLVM
|
||||
PrintPasses,
|
||||
/// Disable extra opt run after running autodiff
|
||||
NoPostopt,
|
||||
/// Enzyme's loose type debug helper (can cause incorrect gradients!!)
|
||||
/// Usable in cases where Enzyme errors with `can not deduce type of X`.
|
||||
LooseTypes,
|
||||
|
|
|
|||
|
|
@ -711,7 +711,7 @@ mod desc {
|
|||
pub(crate) const parse_list: &str = "a space-separated list of strings";
|
||||
pub(crate) const parse_list_with_polarity: &str =
|
||||
"a comma-separated list of strings, with elements beginning with + or -";
|
||||
pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `LooseTypes`, `Inline`";
|
||||
pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`";
|
||||
pub(crate) const parse_comma_list: &str = "a comma-separated list of strings";
|
||||
pub(crate) const parse_opt_comma_list: &str = parse_comma_list;
|
||||
pub(crate) const parse_number: &str = "a number";
|
||||
|
|
@ -1360,6 +1360,8 @@ pub mod parse {
|
|||
"PrintModBefore" => AutoDiff::PrintModBefore,
|
||||
"PrintModAfter" => AutoDiff::PrintModAfter,
|
||||
"PrintModFinal" => AutoDiff::PrintModFinal,
|
||||
"NoPostopt" => AutoDiff::NoPostopt,
|
||||
"PrintPasses" => AutoDiff::PrintPasses,
|
||||
"LooseTypes" => AutoDiff::LooseTypes,
|
||||
"Inline" => AutoDiff::Inline,
|
||||
_ => {
|
||||
|
|
@ -2098,6 +2100,8 @@ options! {
|
|||
`=PrintModBefore`
|
||||
`=PrintModAfter`
|
||||
`=PrintModFinal`
|
||||
`=PrintPasses`,
|
||||
`=NoPostopt`
|
||||
`=LooseTypes`
|
||||
`=Inline`
|
||||
Multiple options can be combined with commas."),
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
pub mod rustc_internal;
|
||||
|
||||
// Make this module private for now since external users should not call these directly.
|
||||
mod rustc_smir;
|
||||
pub mod rustc_smir;
|
||||
|
||||
pub mod stable_mir;
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@ use rustc_span::def_id::{CrateNum, DefId};
|
|||
use scoped_tls::scoped_thread_local;
|
||||
use stable_mir::Error;
|
||||
use stable_mir::abi::Layout;
|
||||
use stable_mir::compiler_interface::SmirInterface;
|
||||
use stable_mir::ty::IndexedVal;
|
||||
|
||||
use crate::rustc_smir::context::TablesWrapper;
|
||||
use crate::rustc_smir::context::SmirCtxt;
|
||||
use crate::rustc_smir::{Stable, Tables};
|
||||
use crate::stable_mir;
|
||||
|
||||
|
|
@ -196,12 +197,12 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
|
|||
// datastructures and stable MIR datastructures
|
||||
scoped_thread_local! (static TLV: Cell<*const ()>);
|
||||
|
||||
pub(crate) fn init<'tcx, F, T>(tables: &TablesWrapper<'tcx>, f: F) -> T
|
||||
pub(crate) fn init<'tcx, F, T>(cx: &SmirCtxt<'tcx>, f: F) -> T
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
{
|
||||
assert!(!TLV.is_set());
|
||||
let ptr = tables as *const _ as *const ();
|
||||
let ptr = cx as *const _ as *const ();
|
||||
TLV.set(&Cell::new(ptr), || f())
|
||||
}
|
||||
|
||||
|
|
@ -212,8 +213,8 @@ pub(crate) fn with_tables<R>(f: impl for<'tcx> FnOnce(&mut Tables<'tcx>) -> R) -
|
|||
TLV.with(|tlv| {
|
||||
let ptr = tlv.get();
|
||||
assert!(!ptr.is_null());
|
||||
let wrapper = ptr as *const TablesWrapper<'_>;
|
||||
let mut tables = unsafe { (*wrapper).0.borrow_mut() };
|
||||
let context = ptr as *const SmirCtxt<'_>;
|
||||
let mut tables = unsafe { (*context).0.borrow_mut() };
|
||||
f(&mut *tables)
|
||||
})
|
||||
}
|
||||
|
|
@ -222,7 +223,7 @@ pub fn run<F, T>(tcx: TyCtxt<'_>, f: F) -> Result<T, Error>
|
|||
where
|
||||
F: FnOnce() -> T,
|
||||
{
|
||||
let tables = TablesWrapper(RefCell::new(Tables {
|
||||
let tables = SmirCtxt(RefCell::new(Tables {
|
||||
tcx,
|
||||
def_ids: IndexMap::default(),
|
||||
alloc_ids: IndexMap::default(),
|
||||
|
|
@ -233,7 +234,12 @@ where
|
|||
mir_consts: IndexMap::default(),
|
||||
layouts: IndexMap::default(),
|
||||
}));
|
||||
stable_mir::compiler_interface::run(&tables, || init(&tables, f))
|
||||
|
||||
let interface = SmirInterface { cx: tables };
|
||||
|
||||
// Pass the `SmirInterface` to compiler_interface::run
|
||||
// and initialize the rustc-specific TLS with tables.
|
||||
stable_mir::compiler_interface::run(&interface, || init(&interface.cx, f))
|
||||
}
|
||||
|
||||
/// Instantiate and run the compiler with the provided arguments and callback.
|
||||
|
|
@ -256,7 +262,7 @@ where
|
|||
/// // Your code goes in here.
|
||||
/// # ControlFlow::Continue(())
|
||||
/// }
|
||||
/// # let args = vec!["--verbose".to_string()];
|
||||
/// # let args = &["--verbose".to_string()];
|
||||
/// let result = run!(args, analyze_code);
|
||||
/// # assert_eq!(result, Err(CompilerError::Skipped))
|
||||
/// # }
|
||||
|
|
@ -278,7 +284,7 @@ where
|
|||
/// // Your code goes in here.
|
||||
/// # ControlFlow::Continue(())
|
||||
/// }
|
||||
/// # let args = vec!["--verbose".to_string()];
|
||||
/// # let args = &["--verbose".to_string()];
|
||||
/// # let extra_args = vec![];
|
||||
/// let result = run!(args, || analyze_code(extra_args));
|
||||
/// # assert_eq!(result, Err(CompilerError::Skipped))
|
||||
|
|
@ -340,7 +346,6 @@ macro_rules! run_driver {
|
|||
C: Send,
|
||||
F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
|
||||
{
|
||||
args: Vec<String>,
|
||||
callback: Option<F>,
|
||||
result: Option<ControlFlow<B, C>>,
|
||||
}
|
||||
|
|
@ -352,14 +357,14 @@ macro_rules! run_driver {
|
|||
F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
|
||||
{
|
||||
/// Creates a new `StableMir` instance, with given test_function and arguments.
|
||||
pub fn new(args: Vec<String>, callback: F) -> Self {
|
||||
StableMir { args, callback: Some(callback), result: None }
|
||||
pub fn new(callback: F) -> Self {
|
||||
StableMir { callback: Some(callback), result: None }
|
||||
}
|
||||
|
||||
/// Runs the compiler against given target and tests it with `test_function`
|
||||
pub fn run(&mut self) -> Result<C, CompilerError<B>> {
|
||||
pub fn run(&mut self, args: &[String]) -> Result<C, CompilerError<B>> {
|
||||
let compiler_result = rustc_driver::catch_fatal_errors(|| -> interface::Result::<()> {
|
||||
run_compiler(&self.args.clone(), self);
|
||||
run_compiler(&args, self);
|
||||
Ok(())
|
||||
});
|
||||
match (compiler_result, self.result.take()) {
|
||||
|
|
@ -409,7 +414,7 @@ macro_rules! run_driver {
|
|||
}
|
||||
}
|
||||
|
||||
StableMir::new($args, $callback).run()
|
||||
StableMir::new($callback).run($args)
|
||||
}};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
//! Implementation of `[stable_mir::compiler_interface::Context]` trait.
|
||||
//!
|
||||
//! This trait is currently the main interface between the Rust compiler,
|
||||
//! and the `stable_mir` crate.
|
||||
//! Implementation of StableMIR Context.
|
||||
|
||||
#![allow(rustc::usage_of_qualified_ty)]
|
||||
|
||||
|
|
@ -20,7 +17,6 @@ use rustc_middle::ty::{
|
|||
use rustc_middle::{mir, ty};
|
||||
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};
|
||||
use stable_mir::mir::{BinOp, Body, Place, UnOp};
|
||||
|
|
@ -37,8 +33,14 @@ use crate::rustc_smir::builder::BodyBuilder;
|
|||
use crate::rustc_smir::{Stable, Tables, alloc, filter_def_ids, new_item_kind, smir_crate};
|
||||
use crate::stable_mir;
|
||||
|
||||
impl<'tcx> Context for TablesWrapper<'tcx> {
|
||||
fn target_info(&self) -> MachineInfo {
|
||||
/// Provides direct access to rustc's internal queries.
|
||||
///
|
||||
/// The [`crate::stable_mir::compiler_interface::SmirInterface`] must go through
|
||||
/// this context to obtain rustc-level information.
|
||||
pub struct SmirCtxt<'tcx>(pub RefCell<Tables<'tcx>>);
|
||||
|
||||
impl<'tcx> SmirCtxt<'tcx> {
|
||||
pub fn target_info(&self) -> MachineInfo {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
MachineInfo {
|
||||
endian: tables.tcx.data_layout.endian.stable(&mut *tables),
|
||||
|
|
@ -48,31 +50,35 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
|
||||
pub fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
Some(tables.crate_item(tcx.entry_fn(())?.0))
|
||||
}
|
||||
|
||||
fn all_local_items(&self) -> stable_mir::CrateItems {
|
||||
/// Retrieve all items of the local crate that have a MIR associated with them.
|
||||
pub fn all_local_items(&self) -> stable_mir::CrateItems {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
tables.tcx.mir_keys(()).iter().map(|item| tables.crate_item(item.to_def_id())).collect()
|
||||
}
|
||||
|
||||
fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body {
|
||||
/// Retrieve the body of a function.
|
||||
/// This function will panic if the body is not available.
|
||||
pub fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let def_id = tables[item];
|
||||
tables.tcx.instance_mir(rustc_middle::ty::InstanceKind::Item(def_id)).stable(&mut tables)
|
||||
}
|
||||
|
||||
fn has_body(&self, def: DefId) -> bool {
|
||||
/// Check whether the body of a function is available.
|
||||
pub fn has_body(&self, def: DefId) -> bool {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let def_id = def.internal(&mut *tables, tcx);
|
||||
tables.item_has_body(def_id)
|
||||
}
|
||||
|
||||
fn foreign_modules(&self, crate_num: CrateNum) -> Vec<stable_mir::ty::ForeignModuleDef> {
|
||||
pub fn foreign_modules(&self, crate_num: CrateNum) -> Vec<stable_mir::ty::ForeignModuleDef> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
tcx.foreign_modules(crate_num.internal(&mut *tables, tcx))
|
||||
|
|
@ -81,21 +87,23 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> {
|
||||
/// Retrieve all functions defined in this crate.
|
||||
pub fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let krate = crate_num.internal(&mut *tables, tcx);
|
||||
filter_def_ids(tcx, krate, |def_id| tables.to_fn_def(def_id))
|
||||
}
|
||||
|
||||
fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> {
|
||||
/// Retrieve all static items defined in this crate.
|
||||
pub fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let krate = crate_num.internal(&mut *tables, tcx);
|
||||
filter_def_ids(tcx, krate, |def_id| tables.to_static(def_id))
|
||||
}
|
||||
|
||||
fn foreign_module(
|
||||
pub fn foreign_module(
|
||||
&self,
|
||||
mod_def: stable_mir::ty::ForeignModuleDef,
|
||||
) -> stable_mir::ty::ForeignModule {
|
||||
|
|
@ -105,7 +113,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
mod_def.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn foreign_items(&self, mod_def: stable_mir::ty::ForeignModuleDef) -> Vec<ForeignDef> {
|
||||
pub fn foreign_items(&self, mod_def: stable_mir::ty::ForeignModuleDef) -> Vec<ForeignDef> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let def_id = tables[mod_def.def_id()];
|
||||
tables
|
||||
|
|
@ -119,12 +127,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn all_trait_decls(&self) -> stable_mir::TraitDecls {
|
||||
pub fn all_trait_decls(&self) -> stable_mir::TraitDecls {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
tables.tcx.all_traits().map(|trait_def_id| tables.trait_def(trait_def_id)).collect()
|
||||
}
|
||||
|
||||
fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls {
|
||||
pub fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
tcx.traits(crate_num.internal(&mut *tables, tcx))
|
||||
|
|
@ -133,14 +141,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
|
||||
pub fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let def_id = tables[trait_def.0];
|
||||
let trait_def = tables.tcx.trait_def(def_id);
|
||||
trait_def.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
|
||||
pub fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
iter::once(LOCAL_CRATE)
|
||||
|
|
@ -150,7 +158,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls {
|
||||
pub fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
tcx.trait_impls_in_crate(crate_num.internal(&mut *tables, tcx))
|
||||
|
|
@ -159,21 +167,21 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
|
||||
pub fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let def_id = tables[impl_def.0];
|
||||
let impl_trait = tables.tcx.impl_trait_ref(def_id).unwrap();
|
||||
impl_trait.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
|
||||
pub fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let def_id = tables[def_id];
|
||||
let generics = tables.tcx.generics_of(def_id);
|
||||
generics.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
|
||||
pub fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let def_id = tables[def_id];
|
||||
let GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id);
|
||||
|
|
@ -191,7 +199,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn explicit_predicates_of(
|
||||
pub fn explicit_predicates_of(
|
||||
&self,
|
||||
def_id: stable_mir::DefId,
|
||||
) -> stable_mir::ty::GenericPredicates {
|
||||
|
|
@ -212,17 +220,20 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn local_crate(&self) -> stable_mir::Crate {
|
||||
/// Get information about the local crate.
|
||||
pub fn local_crate(&self) -> stable_mir::Crate {
|
||||
let tables = self.0.borrow();
|
||||
smir_crate(tables.tcx, LOCAL_CRATE)
|
||||
}
|
||||
|
||||
fn external_crates(&self) -> Vec<stable_mir::Crate> {
|
||||
/// Retrieve a list of all external crates.
|
||||
pub fn external_crates(&self) -> Vec<stable_mir::Crate> {
|
||||
let tables = self.0.borrow();
|
||||
tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect()
|
||||
}
|
||||
|
||||
fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> {
|
||||
/// Find a crate with the given name.
|
||||
pub fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> {
|
||||
let tables = self.0.borrow();
|
||||
let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE]
|
||||
.iter()
|
||||
|
|
@ -235,7 +246,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
crates
|
||||
}
|
||||
|
||||
fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol {
|
||||
/// Returns the name of given `DefId`.
|
||||
pub fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol {
|
||||
let tables = self.0.borrow();
|
||||
if trimmed {
|
||||
with_forced_trimmed_paths!(tables.tcx.def_path_str(tables[def_id]))
|
||||
|
|
@ -244,7 +256,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn tool_attrs(
|
||||
/// Return registered tool attributes with the given attribute name.
|
||||
///
|
||||
/// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool
|
||||
/// attributes will simply return an empty list.
|
||||
///
|
||||
/// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`.
|
||||
/// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
|
||||
pub fn tool_attrs(
|
||||
&self,
|
||||
def_id: stable_mir::DefId,
|
||||
attr: &[stable_mir::Symbol],
|
||||
|
|
@ -268,7 +287,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn all_tool_attrs(&self, def_id: stable_mir::DefId) -> Vec<stable_mir::crate_def::Attribute> {
|
||||
/// Get all tool attributes of a definition.
|
||||
pub fn all_tool_attrs(
|
||||
&self,
|
||||
def_id: stable_mir::DefId,
|
||||
) -> Vec<stable_mir::crate_def::Attribute> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let did = tables[def_id];
|
||||
|
|
@ -292,12 +315,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
|
||||
/// Returns printable, human readable form of `Span`.
|
||||
pub fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
|
||||
let tables = self.0.borrow();
|
||||
tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span])
|
||||
}
|
||||
|
||||
fn get_filename(&self, span: &Span) -> Filename {
|
||||
/// Return filename from given `Span`, for diagnostic purposes.
|
||||
pub fn get_filename(&self, span: &Span) -> Filename {
|
||||
let tables = self.0.borrow();
|
||||
tables
|
||||
.tcx
|
||||
|
|
@ -308,23 +333,27 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.to_string()
|
||||
}
|
||||
|
||||
fn get_lines(&self, span: &Span) -> LineInfo {
|
||||
/// Return lines corresponding to this `Span`.
|
||||
pub fn get_lines(&self, span: &Span) -> LineInfo {
|
||||
let tables = self.0.borrow();
|
||||
let lines = &tables.tcx.sess.source_map().span_to_location_info(tables[*span]);
|
||||
LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 }
|
||||
}
|
||||
|
||||
fn item_kind(&self, item: CrateItem) -> ItemKind {
|
||||
/// Returns the `kind` of given `DefId`.
|
||||
pub fn item_kind(&self, item: CrateItem) -> ItemKind {
|
||||
let tables = self.0.borrow();
|
||||
new_item_kind(tables.tcx.def_kind(tables[item.0]))
|
||||
}
|
||||
|
||||
fn is_foreign_item(&self, item: DefId) -> bool {
|
||||
/// Returns whether this is a foreign item.
|
||||
pub fn is_foreign_item(&self, item: DefId) -> bool {
|
||||
let tables = self.0.borrow();
|
||||
tables.tcx.is_foreign_item(tables[item])
|
||||
}
|
||||
|
||||
fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind {
|
||||
/// Returns the kind of a given foreign item.
|
||||
pub fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let def_id = tables[def.def_id()];
|
||||
let tcx = tables.tcx;
|
||||
|
|
@ -339,32 +368,37 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn adt_kind(&self, def: AdtDef) -> AdtKind {
|
||||
/// Returns the kind of a given algebraic data type.
|
||||
pub fn adt_kind(&self, def: AdtDef) -> AdtKind {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
def.internal(&mut *tables, tcx).adt_kind().stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn adt_is_box(&self, def: AdtDef) -> bool {
|
||||
/// Returns if the ADT is a box.
|
||||
pub fn adt_is_box(&self, def: AdtDef) -> bool {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
def.internal(&mut *tables, tcx).is_box()
|
||||
}
|
||||
|
||||
fn adt_is_simd(&self, def: AdtDef) -> bool {
|
||||
/// Returns whether this ADT is simd.
|
||||
pub fn adt_is_simd(&self, def: AdtDef) -> bool {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
def.internal(&mut *tables, tcx).repr().simd()
|
||||
}
|
||||
|
||||
fn adt_is_cstr(&self, def: AdtDef) -> bool {
|
||||
/// Returns whether this definition is a C string.
|
||||
pub fn adt_is_cstr(&self, def: AdtDef) -> bool {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let def_id = def.0.internal(&mut *tables, tcx);
|
||||
tables.tcx.is_lang_item(def_id, LangItem::CStr)
|
||||
}
|
||||
|
||||
fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
|
||||
/// Retrieve the function signature for the given generic arguments.
|
||||
pub fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let def_id = def.0.internal(&mut *tables, tcx);
|
||||
|
|
@ -373,7 +407,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
sig.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn intrinsic(&self, def: DefId) -> Option<IntrinsicDef> {
|
||||
/// Retrieve the intrinsic definition if the item corresponds one.
|
||||
pub fn intrinsic(&self, def: DefId) -> Option<IntrinsicDef> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let def_id = def.internal(&mut *tables, tcx);
|
||||
|
|
@ -381,14 +416,16 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
intrinsic.map(|_| IntrinsicDef(def))
|
||||
}
|
||||
|
||||
fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol {
|
||||
/// Retrieve the plain function name of an intrinsic.
|
||||
pub fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let def_id = def.0.internal(&mut *tables, tcx);
|
||||
tcx.intrinsic(def_id).unwrap().name.to_string()
|
||||
}
|
||||
|
||||
fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
|
||||
/// Retrieve the closure signature for the given generic arguments.
|
||||
pub fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let args_ref = args.internal(&mut *tables, tcx);
|
||||
|
|
@ -396,25 +433,28 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
sig.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn adt_variants_len(&self, def: AdtDef) -> usize {
|
||||
/// The number of variants in this ADT.
|
||||
pub fn adt_variants_len(&self, def: AdtDef) -> usize {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
def.internal(&mut *tables, tcx).variants().len()
|
||||
}
|
||||
|
||||
fn variant_name(&self, def: VariantDef) -> Symbol {
|
||||
/// The name of a variant.
|
||||
pub fn variant_name(&self, def: VariantDef) -> Symbol {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
def.internal(&mut *tables, tcx).name.to_string()
|
||||
}
|
||||
|
||||
fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef> {
|
||||
pub fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
def.internal(&mut *tables, tcx).fields.iter().map(|f| f.stable(&mut *tables)).collect()
|
||||
}
|
||||
|
||||
fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error> {
|
||||
/// Evaluate constant as a target usize.
|
||||
pub fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let mir_const = cnst.internal(&mut *tables, tcx);
|
||||
|
|
@ -422,7 +462,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.try_eval_target_usize(tables.tcx, ty::TypingEnv::fully_monomorphized())
|
||||
.ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
|
||||
}
|
||||
fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error> {
|
||||
pub fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let mir_const = cnst.internal(&mut *tables, tcx);
|
||||
|
|
@ -431,7 +471,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64")))
|
||||
}
|
||||
|
||||
fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error> {
|
||||
/// Create a new zero-sized constant.
|
||||
pub fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let ty_internal = ty.internal(&mut *tables, tcx);
|
||||
|
|
@ -456,7 +497,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.stable(&mut *tables))
|
||||
}
|
||||
|
||||
fn new_const_str(&self, value: &str) -> MirConst {
|
||||
/// Create a new constant that represents the given string value.
|
||||
pub fn new_const_str(&self, value: &str) -> MirConst {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let ty = ty::Ty::new_static_str(tcx);
|
||||
|
|
@ -467,12 +509,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
mir::Const::from_value(val, ty).stable(&mut tables)
|
||||
}
|
||||
|
||||
fn new_const_bool(&self, value: bool) -> MirConst {
|
||||
/// Create a new constant that represents the given boolean value.
|
||||
pub fn new_const_bool(&self, value: bool) -> MirConst {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
mir::Const::from_bool(tables.tcx, value).stable(&mut tables)
|
||||
}
|
||||
|
||||
fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error> {
|
||||
/// Create a new constant that represents the given value.
|
||||
pub fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx));
|
||||
|
|
@ -487,7 +531,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
Ok(mir::Const::from_scalar(tcx, mir::interpret::Scalar::Int(scalar), ty)
|
||||
.stable(&mut tables))
|
||||
}
|
||||
fn try_new_ty_const_uint(
|
||||
pub fn try_new_ty_const_uint(
|
||||
&self,
|
||||
value: u128,
|
||||
uint_ty: UintTy,
|
||||
|
|
@ -509,27 +553,35 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.stable(&mut *tables))
|
||||
}
|
||||
|
||||
fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty {
|
||||
/// Create a new type from the given kind.
|
||||
pub fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let internal_kind = kind.internal(&mut *tables, tcx);
|
||||
tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty {
|
||||
/// Create a new box type, `Box<T>`, for the given inner type `T`.
|
||||
pub fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let inner = ty.internal(&mut *tables, tcx);
|
||||
ty::Ty::new_box(tables.tcx, inner).stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty {
|
||||
/// Returns the type of given crate item.
|
||||
pub fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
tcx.type_of(item.internal(&mut *tables, tcx)).instantiate_identity().stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn def_ty_with_args(&self, item: stable_mir::DefId, args: &GenericArgs) -> stable_mir::ty::Ty {
|
||||
/// Returns the type of given definition instantiated with the given arguments.
|
||||
pub fn def_ty_with_args(
|
||||
&self,
|
||||
item: stable_mir::DefId,
|
||||
args: &GenericArgs,
|
||||
) -> stable_mir::ty::Ty {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let args = args.internal(&mut *tables, tcx);
|
||||
|
|
@ -544,33 +596,38 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn mir_const_pretty(&self, cnst: &stable_mir::ty::MirConst) -> String {
|
||||
/// Returns literal value of a const as a string.
|
||||
pub fn mir_const_pretty(&self, cnst: &stable_mir::ty::MirConst) -> String {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
cnst.internal(&mut *tables, tcx).to_string()
|
||||
}
|
||||
|
||||
fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
|
||||
/// `Span` of an item.
|
||||
pub fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
tables.tcx.def_span(tables[def_id]).stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String {
|
||||
/// Obtain the representation of a type.
|
||||
pub fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String {
|
||||
let tables = self.0.borrow_mut();
|
||||
tables.types[ty].to_string()
|
||||
}
|
||||
|
||||
fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
|
||||
/// Obtain the representation of a type.
|
||||
pub fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
tables.types[ty].kind().stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn ty_const_pretty(&self, ct: stable_mir::ty::TyConstId) -> String {
|
||||
pub fn ty_const_pretty(&self, ct: stable_mir::ty::TyConstId) -> String {
|
||||
let tables = self.0.borrow_mut();
|
||||
tables.ty_consts[ct].to_string()
|
||||
}
|
||||
|
||||
fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> stable_mir::ty::Ty {
|
||||
/// Get the discriminant Ty for this Ty if there's one.
|
||||
pub fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> stable_mir::ty::Ty {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let internal_kind = ty.internal(&mut *tables, tcx);
|
||||
|
|
@ -578,7 +635,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
internal_ty.discriminant_ty(tables.tcx).stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn instance_body(&self, def: InstanceDef) -> Option<Body> {
|
||||
/// Get the body of an Instance which is already monomorphized.
|
||||
pub fn instance_body(&self, def: InstanceDef) -> Option<Body> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let instance = tables.instances[def];
|
||||
tables
|
||||
|
|
@ -586,63 +644,74 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.then(|| BodyBuilder::new(tables.tcx, instance).build(&mut *tables))
|
||||
}
|
||||
|
||||
fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
|
||||
/// Get the instance type with generic instantiations applied and lifetimes erased.
|
||||
pub fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let instance = tables.instances[def];
|
||||
assert!(!instance.has_non_region_param(), "{instance:?} needs further instantiation");
|
||||
instance.ty(tables.tcx, ty::TypingEnv::fully_monomorphized()).stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn instance_args(&self, def: InstanceDef) -> GenericArgs {
|
||||
/// Get the instantiation types.
|
||||
pub fn instance_args(&self, def: InstanceDef) -> GenericArgs {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let instance = tables.instances[def];
|
||||
instance.args.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error> {
|
||||
/// Get an instance ABI.
|
||||
pub 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 fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error> {
|
||||
/// Get the ABI of a function pointer.
|
||||
pub fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let sig = fn_ptr.internal(&mut *tables, tcx);
|
||||
Ok(tables.fn_abi_of_fn_ptr(sig, List::empty())?.stable(&mut *tables))
|
||||
}
|
||||
|
||||
fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
|
||||
/// Get the instance.
|
||||
pub 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();
|
||||
tables.create_def_id(def_id)
|
||||
}
|
||||
|
||||
fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol {
|
||||
/// Get the instance mangled name.
|
||||
pub fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol {
|
||||
let tables = self.0.borrow_mut();
|
||||
let instance = tables.instances[instance];
|
||||
tables.tcx.symbol_name(instance).name.to_string()
|
||||
}
|
||||
|
||||
fn is_empty_drop_shim(&self, def: InstanceDef) -> bool {
|
||||
/// Check if this is an empty DropGlue shim.
|
||||
pub fn is_empty_drop_shim(&self, def: InstanceDef) -> bool {
|
||||
let tables = self.0.borrow_mut();
|
||||
let instance = tables.instances[def];
|
||||
matches!(instance.def, ty::InstanceKind::DropGlue(_, None))
|
||||
}
|
||||
|
||||
fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool {
|
||||
/// Check if this is an empty AsyncDropGlueCtor shim.
|
||||
pub fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool {
|
||||
let tables = self.0.borrow_mut();
|
||||
let instance = tables.instances[def];
|
||||
matches!(instance.def, ty::InstanceKind::AsyncDropGlueCtorShim(_, None))
|
||||
}
|
||||
|
||||
fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance {
|
||||
/// Convert a non-generic crate item into an instance.
|
||||
/// This function will panic if the item is generic.
|
||||
pub fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let def_id = tables[def_id];
|
||||
Instance::mono(tables.tcx, def_id).stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool {
|
||||
/// Item requires monomorphization.
|
||||
pub fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool {
|
||||
let tables = self.0.borrow();
|
||||
let def_id = tables[def_id];
|
||||
let generics = tables.tcx.generics_of(def_id);
|
||||
|
|
@ -650,7 +719,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
result
|
||||
}
|
||||
|
||||
fn resolve_instance(
|
||||
/// Resolve an instance from the given function definition and generic arguments.
|
||||
pub fn resolve_instance(
|
||||
&self,
|
||||
def: stable_mir::ty::FnDef,
|
||||
args: &stable_mir::ty::GenericArgs,
|
||||
|
|
@ -670,7 +740,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance {
|
||||
/// Resolve an instance for drop_in_place for the given type.
|
||||
pub fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let internal_ty = ty.internal(&mut *tables, tcx);
|
||||
|
|
@ -678,7 +749,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
instance.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn resolve_for_fn_ptr(
|
||||
/// Resolve instance for a function pointer.
|
||||
pub fn resolve_for_fn_ptr(
|
||||
&self,
|
||||
def: FnDef,
|
||||
args: &GenericArgs,
|
||||
|
|
@ -696,7 +768,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn resolve_closure(
|
||||
/// Resolve instance for a closure with the requested type.
|
||||
pub fn resolve_closure(
|
||||
&self,
|
||||
def: ClosureDef,
|
||||
args: &GenericArgs,
|
||||
|
|
@ -713,7 +786,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
)
|
||||
}
|
||||
|
||||
fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error> {
|
||||
/// Try to evaluate an instance into a constant.
|
||||
pub fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let instance = tables.instances[def];
|
||||
let tcx = tables.tcx;
|
||||
|
|
@ -733,21 +807,24 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
.map_err(|e| e.stable(&mut *tables))?
|
||||
}
|
||||
|
||||
fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
|
||||
/// Evaluate a static's initializer.
|
||||
pub fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let def_id = def.0.internal(&mut *tables, tcx);
|
||||
tables.tcx.eval_static_initializer(def_id).stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc {
|
||||
/// Retrieve global allocation for the given allocation ID.
|
||||
pub fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let alloc_id = alloc.internal(&mut *tables, tcx);
|
||||
tables.tcx.global_alloc(alloc_id).stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn vtable_allocation(
|
||||
/// Retrieve the id for the virtual table.
|
||||
pub fn vtable_allocation(
|
||||
&self,
|
||||
global_alloc: &GlobalAlloc,
|
||||
) -> Option<stable_mir::mir::alloc::AllocId> {
|
||||
|
|
@ -765,7 +842,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
Some(alloc_id.stable(&mut *tables))
|
||||
}
|
||||
|
||||
fn krate(&self, def_id: stable_mir::DefId) -> Crate {
|
||||
pub fn krate(&self, def_id: stable_mir::DefId) -> Crate {
|
||||
let tables = self.0.borrow();
|
||||
smir_crate(tables.tcx, tables[def_id].krate)
|
||||
}
|
||||
|
|
@ -773,7 +850,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
/// Retrieve the instance name for diagnostic messages.
|
||||
///
|
||||
/// This will return the specialized name, e.g., `Vec<char>::new`.
|
||||
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
|
||||
pub fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
|
||||
let tables = self.0.borrow_mut();
|
||||
let instance = tables.instances[def];
|
||||
if trimmed {
|
||||
|
|
@ -787,7 +864,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
|
||||
/// Get the layout of a type.
|
||||
pub fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let ty = ty.internal(&mut *tables, tcx);
|
||||
|
|
@ -795,19 +873,22 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
Ok(layout.stable(&mut *tables))
|
||||
}
|
||||
|
||||
fn layout_shape(&self, id: Layout) -> LayoutShape {
|
||||
/// Get the layout shape.
|
||||
pub fn layout_shape(&self, id: Layout) -> LayoutShape {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
id.internal(&mut *tables, tcx).0.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn place_pretty(&self, place: &Place) -> String {
|
||||
/// Get a debug string representation of a place.
|
||||
pub fn place_pretty(&self, place: &Place) -> String {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
format!("{:?}", place.internal(&mut *tables, tcx))
|
||||
}
|
||||
|
||||
fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty {
|
||||
/// Get the resulting type of binary operation.
|
||||
pub fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let rhs_internal = rhs.internal(&mut *tables, tcx);
|
||||
|
|
@ -816,7 +897,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
ty.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty {
|
||||
/// Get the resulting type of unary operation.
|
||||
pub fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let arg_internal = arg.internal(&mut *tables, tcx);
|
||||
|
|
@ -824,7 +906,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
ty.stable(&mut *tables)
|
||||
}
|
||||
|
||||
fn associated_items(&self, def_id: stable_mir::DefId) -> stable_mir::AssocItems {
|
||||
/// Get all associated items of a definition.
|
||||
pub fn associated_items(&self, def_id: stable_mir::DefId) -> stable_mir::AssocItems {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let def_id = tables[def_id];
|
||||
|
|
@ -840,8 +923,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) 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::callconv::FnAbi<'tcx, ty::Ty<'tcx>>, Error>;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use crate::stable_mir;
|
|||
|
||||
mod alloc;
|
||||
mod builder;
|
||||
pub(crate) mod context;
|
||||
pub mod context;
|
||||
mod convert;
|
||||
|
||||
pub struct Tables<'tcx> {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
use std::cell::Cell;
|
||||
|
||||
use rustc_smir::context::SmirCtxt;
|
||||
use stable_mir::abi::{FnAbi, Layout, LayoutShape};
|
||||
use stable_mir::crate_def::Attribute;
|
||||
use stable_mir::mir::alloc::{AllocId, GlobalAlloc};
|
||||
|
|
@ -22,47 +23,116 @@ use stable_mir::{
|
|||
ItemKind, Symbol, TraitDecls, mir,
|
||||
};
|
||||
|
||||
use crate::stable_mir;
|
||||
use crate::{rustc_smir, stable_mir};
|
||||
|
||||
/// Stable public API for querying compiler information.
|
||||
///
|
||||
/// All queries are delegated to an internal [`SmirCtxt`] that provides
|
||||
/// similar APIs but based on internal rustc constructs.
|
||||
///
|
||||
/// Do not use this directly. This is currently used in the macro expansion.
|
||||
pub(crate) struct SmirInterface<'tcx> {
|
||||
pub(crate) cx: SmirCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> SmirInterface<'tcx> {
|
||||
pub(crate) fn entry_fn(&self) -> Option<CrateItem> {
|
||||
self.cx.entry_fn()
|
||||
}
|
||||
|
||||
/// This trait defines the interface between stable_mir and the Rust compiler.
|
||||
/// Do not use this directly.
|
||||
pub trait Context {
|
||||
fn entry_fn(&self) -> Option<CrateItem>;
|
||||
/// Retrieve all items of the local crate that have a MIR associated with them.
|
||||
fn all_local_items(&self) -> CrateItems;
|
||||
pub(crate) fn all_local_items(&self) -> CrateItems {
|
||||
self.cx.all_local_items()
|
||||
}
|
||||
|
||||
/// Retrieve the body of a function.
|
||||
/// This function will panic if the body is not available.
|
||||
fn mir_body(&self, item: DefId) -> mir::Body;
|
||||
pub(crate) fn mir_body(&self, item: DefId) -> mir::Body {
|
||||
self.cx.mir_body(item)
|
||||
}
|
||||
|
||||
/// Check whether the body of a function is available.
|
||||
fn has_body(&self, item: DefId) -> bool;
|
||||
fn foreign_modules(&self, crate_num: CrateNum) -> Vec<ForeignModuleDef>;
|
||||
pub(crate) fn has_body(&self, item: DefId) -> bool {
|
||||
self.cx.has_body(item)
|
||||
}
|
||||
|
||||
pub(crate) fn foreign_modules(&self, crate_num: CrateNum) -> Vec<ForeignModuleDef> {
|
||||
self.cx.foreign_modules(crate_num)
|
||||
}
|
||||
|
||||
/// Retrieve all functions defined in this crate.
|
||||
fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef>;
|
||||
pub(crate) fn crate_functions(&self, crate_num: CrateNum) -> Vec<FnDef> {
|
||||
self.cx.crate_functions(crate_num)
|
||||
}
|
||||
|
||||
/// Retrieve all static items defined in this crate.
|
||||
fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef>;
|
||||
fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule;
|
||||
fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef>;
|
||||
fn all_trait_decls(&self) -> TraitDecls;
|
||||
fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls;
|
||||
fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
|
||||
fn all_trait_impls(&self) -> ImplTraitDecls;
|
||||
fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls;
|
||||
fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
|
||||
fn generics_of(&self, def_id: DefId) -> Generics;
|
||||
fn predicates_of(&self, def_id: DefId) -> GenericPredicates;
|
||||
fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates;
|
||||
pub(crate) fn crate_statics(&self, crate_num: CrateNum) -> Vec<StaticDef> {
|
||||
self.cx.crate_statics(crate_num)
|
||||
}
|
||||
|
||||
pub(crate) fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule {
|
||||
self.cx.foreign_module(mod_def)
|
||||
}
|
||||
|
||||
pub(crate) fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec<ForeignDef> {
|
||||
self.cx.foreign_items(mod_def)
|
||||
}
|
||||
|
||||
pub(crate) fn all_trait_decls(&self) -> TraitDecls {
|
||||
self.cx.all_trait_decls()
|
||||
}
|
||||
|
||||
pub(crate) fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls {
|
||||
self.cx.trait_decls(crate_num)
|
||||
}
|
||||
|
||||
pub(crate) fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl {
|
||||
self.cx.trait_decl(trait_def)
|
||||
}
|
||||
|
||||
pub(crate) fn all_trait_impls(&self) -> ImplTraitDecls {
|
||||
self.cx.all_trait_impls()
|
||||
}
|
||||
|
||||
pub(crate) fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls {
|
||||
self.cx.trait_impls(crate_num)
|
||||
}
|
||||
|
||||
pub(crate) fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait {
|
||||
self.cx.trait_impl(trait_impl)
|
||||
}
|
||||
|
||||
pub(crate) fn generics_of(&self, def_id: DefId) -> Generics {
|
||||
self.cx.generics_of(def_id)
|
||||
}
|
||||
|
||||
pub(crate) fn predicates_of(&self, def_id: DefId) -> GenericPredicates {
|
||||
self.cx.predicates_of(def_id)
|
||||
}
|
||||
|
||||
pub(crate) fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates {
|
||||
self.cx.explicit_predicates_of(def_id)
|
||||
}
|
||||
|
||||
/// Get information about the local crate.
|
||||
fn local_crate(&self) -> Crate;
|
||||
pub(crate) fn local_crate(&self) -> Crate {
|
||||
self.cx.local_crate()
|
||||
}
|
||||
|
||||
/// Retrieve a list of all external crates.
|
||||
fn external_crates(&self) -> Vec<Crate>;
|
||||
pub(crate) fn external_crates(&self) -> Vec<Crate> {
|
||||
self.cx.external_crates()
|
||||
}
|
||||
|
||||
/// Find a crate with the given name.
|
||||
fn find_crates(&self, name: &str) -> Vec<Crate>;
|
||||
pub(crate) fn find_crates(&self, name: &str) -> Vec<Crate> {
|
||||
self.cx.find_crates(name)
|
||||
}
|
||||
|
||||
/// Returns the name of given `DefId`
|
||||
fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol;
|
||||
/// Returns the name of given `DefId`.
|
||||
pub(crate) fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol {
|
||||
self.cx.def_name(def_id, trimmed)
|
||||
}
|
||||
|
||||
/// Return registered tool attributes with the given attribute name.
|
||||
///
|
||||
|
|
@ -71,218 +141,362 @@ pub trait Context {
|
|||
///
|
||||
/// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`.
|
||||
/// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
|
||||
fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute>;
|
||||
pub(crate) fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute> {
|
||||
self.cx.tool_attrs(def_id, attr)
|
||||
}
|
||||
|
||||
/// Get all tool attributes of a definition.
|
||||
fn all_tool_attrs(&self, def_id: DefId) -> Vec<Attribute>;
|
||||
pub(crate) fn all_tool_attrs(&self, def_id: DefId) -> Vec<Attribute> {
|
||||
self.cx.all_tool_attrs(def_id)
|
||||
}
|
||||
|
||||
/// Returns printable, human readable form of `Span`
|
||||
fn span_to_string(&self, span: Span) -> String;
|
||||
/// Returns printable, human readable form of `Span`.
|
||||
pub(crate) fn span_to_string(&self, span: Span) -> String {
|
||||
self.cx.span_to_string(span)
|
||||
}
|
||||
|
||||
/// Return filename from given `Span`, for diagnostic purposes
|
||||
fn get_filename(&self, span: &Span) -> Filename;
|
||||
/// Return filename from given `Span`, for diagnostic purposes.
|
||||
pub(crate) fn get_filename(&self, span: &Span) -> Filename {
|
||||
self.cx.get_filename(span)
|
||||
}
|
||||
|
||||
/// Return lines corresponding to this `Span`
|
||||
fn get_lines(&self, span: &Span) -> LineInfo;
|
||||
/// Return lines corresponding to this `Span`.
|
||||
pub(crate) fn get_lines(&self, span: &Span) -> LineInfo {
|
||||
self.cx.get_lines(span)
|
||||
}
|
||||
|
||||
/// Returns the `kind` of given `DefId`
|
||||
fn item_kind(&self, item: CrateItem) -> ItemKind;
|
||||
/// Returns the `kind` of given `DefId`.
|
||||
pub(crate) fn item_kind(&self, item: CrateItem) -> ItemKind {
|
||||
self.cx.item_kind(item)
|
||||
}
|
||||
|
||||
/// Returns whether this is a foreign item.
|
||||
fn is_foreign_item(&self, item: DefId) -> bool;
|
||||
pub(crate) fn is_foreign_item(&self, item: DefId) -> bool {
|
||||
self.cx.is_foreign_item(item)
|
||||
}
|
||||
|
||||
/// Returns the kind of a given foreign item.
|
||||
fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind;
|
||||
pub(crate) fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind {
|
||||
self.cx.foreign_item_kind(def)
|
||||
}
|
||||
|
||||
/// Returns the kind of a given algebraic data type
|
||||
fn adt_kind(&self, def: AdtDef) -> AdtKind;
|
||||
/// Returns the kind of a given algebraic data type.
|
||||
pub(crate) fn adt_kind(&self, def: AdtDef) -> AdtKind {
|
||||
self.cx.adt_kind(def)
|
||||
}
|
||||
|
||||
/// Returns if the ADT is a box.
|
||||
fn adt_is_box(&self, def: AdtDef) -> bool;
|
||||
pub(crate) fn adt_is_box(&self, def: AdtDef) -> bool {
|
||||
self.cx.adt_is_box(def)
|
||||
}
|
||||
|
||||
/// Returns whether this ADT is simd.
|
||||
fn adt_is_simd(&self, def: AdtDef) -> bool;
|
||||
pub(crate) fn adt_is_simd(&self, def: AdtDef) -> bool {
|
||||
self.cx.adt_is_simd(def)
|
||||
}
|
||||
|
||||
/// Returns whether this definition is a C string.
|
||||
fn adt_is_cstr(&self, def: AdtDef) -> bool;
|
||||
pub(crate) fn adt_is_cstr(&self, def: AdtDef) -> bool {
|
||||
self.cx.adt_is_cstr(def)
|
||||
}
|
||||
|
||||
/// Retrieve the function signature for the given generic arguments.
|
||||
fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig;
|
||||
pub(crate) fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
|
||||
self.cx.fn_sig(def, args)
|
||||
}
|
||||
|
||||
/// Retrieve the intrinsic definition if the item corresponds one.
|
||||
fn intrinsic(&self, item: DefId) -> Option<IntrinsicDef>;
|
||||
pub(crate) fn intrinsic(&self, item: DefId) -> Option<IntrinsicDef> {
|
||||
self.cx.intrinsic(item)
|
||||
}
|
||||
|
||||
/// Retrieve the plain function name of an intrinsic.
|
||||
fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol;
|
||||
pub(crate) fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol {
|
||||
self.cx.intrinsic_name(def)
|
||||
}
|
||||
|
||||
/// Retrieve the closure signature for the given generic arguments.
|
||||
fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig;
|
||||
pub(crate) fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
|
||||
self.cx.closure_sig(args)
|
||||
}
|
||||
|
||||
/// The number of variants in this ADT.
|
||||
fn adt_variants_len(&self, def: AdtDef) -> usize;
|
||||
pub(crate) fn adt_variants_len(&self, def: AdtDef) -> usize {
|
||||
self.cx.adt_variants_len(def)
|
||||
}
|
||||
|
||||
/// The name of a variant.
|
||||
fn variant_name(&self, def: VariantDef) -> Symbol;
|
||||
fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef>;
|
||||
pub(crate) fn variant_name(&self, def: VariantDef) -> Symbol {
|
||||
self.cx.variant_name(def)
|
||||
}
|
||||
|
||||
pub(crate) fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef> {
|
||||
self.cx.variant_fields(def)
|
||||
}
|
||||
|
||||
/// Evaluate constant as a target usize.
|
||||
fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error>;
|
||||
fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error>;
|
||||
pub(crate) fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error> {
|
||||
self.cx.eval_target_usize(cnst)
|
||||
}
|
||||
|
||||
pub(crate) fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error> {
|
||||
self.cx.eval_target_usize_ty(cnst)
|
||||
}
|
||||
|
||||
/// Create a new zero-sized constant.
|
||||
fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error>;
|
||||
pub(crate) fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error> {
|
||||
self.cx.try_new_const_zst(ty)
|
||||
}
|
||||
|
||||
/// Create a new constant that represents the given string value.
|
||||
fn new_const_str(&self, value: &str) -> MirConst;
|
||||
pub(crate) fn new_const_str(&self, value: &str) -> MirConst {
|
||||
self.cx.new_const_str(value)
|
||||
}
|
||||
|
||||
/// Create a new constant that represents the given boolean value.
|
||||
fn new_const_bool(&self, value: bool) -> MirConst;
|
||||
pub(crate) fn new_const_bool(&self, value: bool) -> MirConst {
|
||||
self.cx.new_const_bool(value)
|
||||
}
|
||||
|
||||
/// Create a new constant that represents the given value.
|
||||
fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error>;
|
||||
fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<TyConst, Error>;
|
||||
pub(crate) fn try_new_const_uint(
|
||||
&self,
|
||||
value: u128,
|
||||
uint_ty: UintTy,
|
||||
) -> Result<MirConst, Error> {
|
||||
self.cx.try_new_const_uint(value, uint_ty)
|
||||
}
|
||||
|
||||
pub(crate) fn try_new_ty_const_uint(
|
||||
&self,
|
||||
value: u128,
|
||||
uint_ty: UintTy,
|
||||
) -> Result<TyConst, Error> {
|
||||
self.cx.try_new_ty_const_uint(value, uint_ty)
|
||||
}
|
||||
|
||||
/// Create a new type from the given kind.
|
||||
fn new_rigid_ty(&self, kind: RigidTy) -> Ty;
|
||||
pub(crate) fn new_rigid_ty(&self, kind: RigidTy) -> Ty {
|
||||
self.cx.new_rigid_ty(kind)
|
||||
}
|
||||
|
||||
/// Create a new box type, `Box<T>`, for the given inner type `T`.
|
||||
fn new_box_ty(&self, ty: Ty) -> Ty;
|
||||
pub(crate) fn new_box_ty(&self, ty: Ty) -> Ty {
|
||||
self.cx.new_box_ty(ty)
|
||||
}
|
||||
|
||||
/// Returns the type of given crate item.
|
||||
fn def_ty(&self, item: DefId) -> Ty;
|
||||
pub(crate) fn def_ty(&self, item: DefId) -> Ty {
|
||||
self.cx.def_ty(item)
|
||||
}
|
||||
|
||||
/// Returns the type of given definition instantiated with the given arguments.
|
||||
fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty;
|
||||
pub(crate) fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty {
|
||||
self.cx.def_ty_with_args(item, args)
|
||||
}
|
||||
|
||||
/// Returns literal value of a const as a string.
|
||||
fn mir_const_pretty(&self, cnst: &MirConst) -> String;
|
||||
pub(crate) fn mir_const_pretty(&self, cnst: &MirConst) -> String {
|
||||
self.cx.mir_const_pretty(cnst)
|
||||
}
|
||||
|
||||
/// `Span` of an item
|
||||
fn span_of_an_item(&self, def_id: DefId) -> Span;
|
||||
/// `Span` of an item.
|
||||
pub(crate) fn span_of_an_item(&self, def_id: DefId) -> Span {
|
||||
self.cx.span_of_an_item(def_id)
|
||||
}
|
||||
|
||||
fn ty_const_pretty(&self, ct: TyConstId) -> String;
|
||||
pub(crate) fn ty_const_pretty(&self, ct: TyConstId) -> String {
|
||||
self.cx.ty_const_pretty(ct)
|
||||
}
|
||||
|
||||
/// Obtain the representation of a type.
|
||||
fn ty_pretty(&self, ty: Ty) -> String;
|
||||
pub(crate) fn ty_pretty(&self, ty: Ty) -> String {
|
||||
self.cx.ty_pretty(ty)
|
||||
}
|
||||
|
||||
/// Obtain the representation of a type.
|
||||
fn ty_kind(&self, ty: Ty) -> TyKind;
|
||||
pub(crate) fn ty_kind(&self, ty: Ty) -> TyKind {
|
||||
self.cx.ty_kind(ty)
|
||||
}
|
||||
|
||||
// Get the discriminant Ty for this Ty if there's one.
|
||||
fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty;
|
||||
/// Get the discriminant Ty for this Ty if there's one.
|
||||
pub(crate) fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty {
|
||||
self.cx.rigid_ty_discriminant_ty(ty)
|
||||
}
|
||||
|
||||
/// Get the body of an Instance which is already monomorphized.
|
||||
fn instance_body(&self, instance: InstanceDef) -> Option<Body>;
|
||||
pub(crate) fn instance_body(&self, instance: InstanceDef) -> Option<Body> {
|
||||
self.cx.instance_body(instance)
|
||||
}
|
||||
|
||||
/// Get the instance type with generic instantiations applied and lifetimes erased.
|
||||
fn instance_ty(&self, instance: InstanceDef) -> Ty;
|
||||
pub(crate) fn instance_ty(&self, instance: InstanceDef) -> Ty {
|
||||
self.cx.instance_ty(instance)
|
||||
}
|
||||
|
||||
/// Get the instantiation types.
|
||||
fn instance_args(&self, def: InstanceDef) -> GenericArgs;
|
||||
pub(crate) fn instance_args(&self, def: InstanceDef) -> GenericArgs {
|
||||
self.cx.instance_args(def)
|
||||
}
|
||||
|
||||
/// Get the instance.
|
||||
fn instance_def_id(&self, instance: InstanceDef) -> DefId;
|
||||
pub(crate) fn instance_def_id(&self, instance: InstanceDef) -> DefId {
|
||||
self.cx.instance_def_id(instance)
|
||||
}
|
||||
|
||||
/// Get the instance mangled name.
|
||||
fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol;
|
||||
pub(crate) fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol {
|
||||
self.cx.instance_mangled_name(instance)
|
||||
}
|
||||
|
||||
/// Check if this is an empty DropGlue shim.
|
||||
fn is_empty_drop_shim(&self, def: InstanceDef) -> bool;
|
||||
pub(crate) fn is_empty_drop_shim(&self, def: InstanceDef) -> bool {
|
||||
self.cx.is_empty_drop_shim(def)
|
||||
}
|
||||
|
||||
/// Check if this is an empty AsyncDropGlueCtor shim.
|
||||
fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool;
|
||||
pub(crate) fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool {
|
||||
self.cx.is_empty_async_drop_ctor_shim(def)
|
||||
}
|
||||
|
||||
/// Convert a non-generic crate item into an instance.
|
||||
/// This function will panic if the item is generic.
|
||||
fn mono_instance(&self, def_id: DefId) -> Instance;
|
||||
pub(crate) fn mono_instance(&self, def_id: DefId) -> Instance {
|
||||
self.cx.mono_instance(def_id)
|
||||
}
|
||||
|
||||
/// Item requires monomorphization.
|
||||
fn requires_monomorphization(&self, def_id: DefId) -> bool;
|
||||
pub(crate) fn requires_monomorphization(&self, def_id: DefId) -> bool {
|
||||
self.cx.requires_monomorphization(def_id)
|
||||
}
|
||||
|
||||
/// Resolve an instance from the given function definition and generic arguments.
|
||||
fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
|
||||
pub(crate) fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance> {
|
||||
self.cx.resolve_instance(def, args)
|
||||
}
|
||||
|
||||
/// Resolve an instance for drop_in_place for the given type.
|
||||
fn resolve_drop_in_place(&self, ty: Ty) -> Instance;
|
||||
pub(crate) fn resolve_drop_in_place(&self, ty: Ty) -> Instance {
|
||||
self.cx.resolve_drop_in_place(ty)
|
||||
}
|
||||
|
||||
/// Resolve instance for a function pointer.
|
||||
fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
|
||||
pub(crate) fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option<Instance> {
|
||||
self.cx.resolve_for_fn_ptr(def, args)
|
||||
}
|
||||
|
||||
/// Resolve instance for a closure with the requested type.
|
||||
fn resolve_closure(
|
||||
pub(crate) fn resolve_closure(
|
||||
&self,
|
||||
def: ClosureDef,
|
||||
args: &GenericArgs,
|
||||
kind: ClosureKind,
|
||||
) -> Option<Instance>;
|
||||
) -> Option<Instance> {
|
||||
self.cx.resolve_closure(def, args, kind)
|
||||
}
|
||||
|
||||
/// Evaluate a static's initializer.
|
||||
fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error>;
|
||||
pub(crate) fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
|
||||
self.cx.eval_static_initializer(def)
|
||||
}
|
||||
|
||||
/// Try to evaluate an instance into a constant.
|
||||
fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error>;
|
||||
pub(crate) fn eval_instance(
|
||||
&self,
|
||||
def: InstanceDef,
|
||||
const_ty: Ty,
|
||||
) -> Result<Allocation, Error> {
|
||||
self.cx.eval_instance(def, const_ty)
|
||||
}
|
||||
|
||||
/// Retrieve global allocation for the given allocation ID.
|
||||
fn global_alloc(&self, id: AllocId) -> GlobalAlloc;
|
||||
pub(crate) fn global_alloc(&self, id: AllocId) -> GlobalAlloc {
|
||||
self.cx.global_alloc(id)
|
||||
}
|
||||
|
||||
/// Retrieve the id for the virtual table.
|
||||
fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
|
||||
fn krate(&self, def_id: DefId) -> Crate;
|
||||
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;
|
||||
pub(crate) fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId> {
|
||||
self.cx.vtable_allocation(global_alloc)
|
||||
}
|
||||
|
||||
pub(crate) fn krate(&self, def_id: DefId) -> Crate {
|
||||
self.cx.krate(def_id)
|
||||
}
|
||||
|
||||
pub(crate) fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
|
||||
self.cx.instance_name(def, trimmed)
|
||||
}
|
||||
|
||||
/// Return information about the target machine.
|
||||
fn target_info(&self) -> MachineInfo;
|
||||
pub(crate) fn target_info(&self) -> MachineInfo {
|
||||
self.cx.target_info()
|
||||
}
|
||||
|
||||
/// Get an instance ABI.
|
||||
fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error>;
|
||||
pub(crate) fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error> {
|
||||
self.cx.instance_abi(def)
|
||||
}
|
||||
|
||||
/// Get the ABI of a function pointer.
|
||||
fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error>;
|
||||
pub(crate) fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result<FnAbi, Error> {
|
||||
self.cx.fn_ptr_abi(fn_ptr)
|
||||
}
|
||||
|
||||
/// Get the layout of a type.
|
||||
fn ty_layout(&self, ty: Ty) -> Result<Layout, Error>;
|
||||
pub(crate) fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
|
||||
self.cx.ty_layout(ty)
|
||||
}
|
||||
|
||||
/// Get the layout shape.
|
||||
fn layout_shape(&self, id: Layout) -> LayoutShape;
|
||||
pub(crate) fn layout_shape(&self, id: Layout) -> LayoutShape {
|
||||
self.cx.layout_shape(id)
|
||||
}
|
||||
|
||||
/// Get a debug string representation of a place.
|
||||
fn place_pretty(&self, place: &Place) -> String;
|
||||
pub(crate) fn place_pretty(&self, place: &Place) -> String {
|
||||
self.cx.place_pretty(place)
|
||||
}
|
||||
|
||||
/// Get the resulting type of binary operation.
|
||||
fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty;
|
||||
pub(crate) fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty {
|
||||
self.cx.binop_ty(bin_op, rhs, lhs)
|
||||
}
|
||||
|
||||
/// Get the resulting type of unary operation.
|
||||
fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty;
|
||||
pub(crate) fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty {
|
||||
self.cx.unop_ty(un_op, arg)
|
||||
}
|
||||
|
||||
/// Get all associated items of a definition.
|
||||
fn associated_items(&self, def_id: DefId) -> AssocItems;
|
||||
pub(crate) fn associated_items(&self, def_id: DefId) -> AssocItems {
|
||||
self.cx.associated_items(def_id)
|
||||
}
|
||||
}
|
||||
|
||||
// A thread local variable that stores a pointer to the tables mapping between TyCtxt
|
||||
// datastructures and stable MIR datastructures
|
||||
// A thread local variable that stores a pointer to [`SmirInterface`].
|
||||
scoped_tls::scoped_thread_local!(static TLV: Cell<*const ()>);
|
||||
|
||||
pub fn run<F, T>(context: &dyn Context, f: F) -> Result<T, Error>
|
||||
pub(crate) fn run<'tcx, T, F>(interface: &SmirInterface<'tcx>, f: F) -> Result<T, Error>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
{
|
||||
if TLV.is_set() {
|
||||
Err(Error::from("StableMIR already running"))
|
||||
} else {
|
||||
let ptr: *const () = (&raw const context) as _;
|
||||
let ptr: *const () = (interface as *const SmirInterface<'tcx>) as *const ();
|
||||
TLV.set(&Cell::new(ptr), || Ok(f()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute the given function with access the compiler [Context].
|
||||
/// Execute the given function with access the [`SmirInterface`].
|
||||
///
|
||||
/// I.e., This function will load the current context and calls a function with it.
|
||||
/// I.e., This function will load the current interface and calls a function with it.
|
||||
/// Do not nest these, as that will ICE.
|
||||
pub(crate) fn with<R>(f: impl FnOnce(&dyn Context) -> R) -> R {
|
||||
pub(crate) fn with<R>(f: impl FnOnce(&SmirInterface<'_>) -> R) -> R {
|
||||
assert!(TLV.is_set());
|
||||
TLV.with(|tlv| {
|
||||
let ptr = tlv.get();
|
||||
assert!(!ptr.is_null());
|
||||
f(unsafe { *(ptr as *const &dyn Context) })
|
||||
f(unsafe { &*(ptr as *const SmirInterface<'_>) })
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ pub struct ArgAttributes {
|
|||
/// (corresponding to LLVM's dereferenceable_or_null attributes, i.e., it is okay for this to be
|
||||
/// set on a null pointer, but all non-null pointers must be dereferenceable).
|
||||
pub pointee_size: Size,
|
||||
/// The minimum alignment of the pointee, if any.
|
||||
pub pointee_align: Option<Align>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,9 @@ use std::path::{Path, PathBuf};
|
|||
use std::str::FromStr;
|
||||
use std::{fmt, io};
|
||||
|
||||
use rustc_abi::{Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors};
|
||||
use rustc_abi::{
|
||||
Align, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
|
|
@ -3599,6 +3601,25 @@ impl Target {
|
|||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns whether this target is known to have unreliable alignment:
|
||||
/// native C code for the target fails to align some data to the degree
|
||||
/// required by the C standard. We can't *really* do anything about that
|
||||
/// since unsafe Rust code may assume alignment any time, but we can at least
|
||||
/// inhibit some optimizations, and we suppress the alignment checks that
|
||||
/// would detect this unsoundness.
|
||||
///
|
||||
/// Every target that returns less than `Align::MAX` here is still has a soundness bug.
|
||||
pub fn max_reliable_alignment(&self) -> Align {
|
||||
// FIXME(#112480) MSVC on x86-32 is unsound and fails to properly align many types with
|
||||
// more-than-4-byte-alignment on the stack. This makes alignments larger than 4 generally
|
||||
// unreliable on 32bit Windows.
|
||||
if self.is_like_windows && self.arch == "x86" {
|
||||
Align::from_bytes(4).unwrap()
|
||||
} else {
|
||||
Align::MAX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Either a target tuple string or a path to a JSON file.
|
||||
|
|
|
|||
|
|
@ -516,7 +516,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
|||
("zawrs", Unstable(sym::riscv_target_feature), &[]),
|
||||
("zba", Stable, &[]),
|
||||
("zbb", Stable, &[]),
|
||||
("zbc", Stable, &[]),
|
||||
("zbc", Stable, &["zbkc"]), // Zbc ⊃ Zbkc
|
||||
("zbkb", Stable, &[]),
|
||||
("zbkc", Stable, &[]),
|
||||
("zbkx", Stable, &[]),
|
||||
|
|
@ -545,20 +545,20 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
|||
("zknd", Stable, &[]),
|
||||
("zkne", Stable, &[]),
|
||||
("zknh", Stable, &[]),
|
||||
("zkr", Stable, &["zicsr"]),
|
||||
("zkr", Stable, &[]),
|
||||
("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
|
||||
("zksed", Stable, &[]),
|
||||
("zksh", Stable, &[]),
|
||||
("zkt", Stable, &[]),
|
||||
("ztso", Unstable(sym::riscv_target_feature), &[]),
|
||||
("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]),
|
||||
("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), // Zvbb ⊃ Zvkb
|
||||
("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]),
|
||||
("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]),
|
||||
("zve32x", Unstable(sym::riscv_target_feature), &["zvl32b", "zicsr"]),
|
||||
("zve64d", Unstable(sym::riscv_target_feature), &["zve64f", "d"]),
|
||||
("zve64f", Unstable(sym::riscv_target_feature), &["zve32f", "zve64x"]),
|
||||
("zve64x", Unstable(sym::riscv_target_feature), &["zve32x", "zvl64b"]),
|
||||
("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zfhmin"]),
|
||||
("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zve32f", "zfhmin"]), // Zvfh ⊃ Zvfhmin
|
||||
("zvfhmin", Unstable(sym::riscv_target_feature), &["zve32f"]),
|
||||
("zvkb", Unstable(sym::riscv_target_feature), &["zve32x"]),
|
||||
("zvkg", Unstable(sym::riscv_target_feature), &["zve32x"]),
|
||||
|
|
@ -567,7 +567,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
|||
("zvkned", Unstable(sym::riscv_target_feature), &["zve32x"]),
|
||||
("zvkng", Unstable(sym::riscv_target_feature), &["zvkn", "zvkg"]),
|
||||
("zvknha", Unstable(sym::riscv_target_feature), &["zve32x"]),
|
||||
("zvknhb", Unstable(sym::riscv_target_feature), &["zve64x"]),
|
||||
("zvknhb", Unstable(sym::riscv_target_feature), &["zvknha", "zve64x"]), // Zvknhb ⊃ Zvknha
|
||||
("zvks", Unstable(sym::riscv_target_feature), &["zvksed", "zvksh", "zvkb", "zvkt"]),
|
||||
("zvksc", Unstable(sym::riscv_target_feature), &["zvks", "zvbc"]),
|
||||
("zvksed", Unstable(sym::riscv_target_feature), &["zve32x"]),
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_errors::{
|
|||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
|
||||
use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, IsAnonInPath, Node};
|
||||
use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath};
|
||||
use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, GenericArg, Region, Ty, TyCtxt};
|
||||
|
|
@ -551,19 +551,6 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
|
|||
|
||||
impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
|
||||
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
|
||||
let make_suggestion = |lifetime: &hir::Lifetime| {
|
||||
if lifetime.is_anon_in_path == IsAnonInPath::Yes
|
||||
&& lifetime.ident.span.is_empty()
|
||||
{
|
||||
format!("{}, ", self.suggestion_param_name)
|
||||
} else if lifetime.ident.name == kw::UnderscoreLifetime
|
||||
&& lifetime.ident.span.is_empty()
|
||||
{
|
||||
format!("{} ", self.suggestion_param_name)
|
||||
} else {
|
||||
self.suggestion_param_name.clone()
|
||||
}
|
||||
};
|
||||
match ty.kind {
|
||||
hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
|
||||
for segment in path.segments {
|
||||
|
|
@ -572,7 +559,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
|
|||
matches!(
|
||||
arg,
|
||||
hir::GenericArg::Lifetime(lifetime)
|
||||
if lifetime.is_anon_in_path == IsAnonInPath::Yes
|
||||
if lifetime.is_syntactically_hidden()
|
||||
)
|
||||
}) {
|
||||
self.suggestions.push((
|
||||
|
|
@ -591,10 +578,10 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
|
|||
if let hir::GenericArg::Lifetime(lifetime) = arg
|
||||
&& lifetime.is_anonymous()
|
||||
{
|
||||
self.suggestions.push((
|
||||
lifetime.ident.span,
|
||||
make_suggestion(lifetime),
|
||||
));
|
||||
self.suggestions.push(
|
||||
lifetime
|
||||
.suggestion(&self.suggestion_param_name),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -602,7 +589,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
|
|||
}
|
||||
}
|
||||
hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => {
|
||||
self.suggestions.push((lifetime.ident.span, make_suggestion(lifetime)));
|
||||
self.suggestions.push(lifetime.suggestion(&self.suggestion_param_name));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,8 +117,7 @@ fn relate_mir_and_user_args<'tcx>(
|
|||
CRATE_DEF_ID,
|
||||
ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span),
|
||||
);
|
||||
let instantiated_predicate =
|
||||
ocx.normalize(&cause.clone(), param_env, instantiated_predicate);
|
||||
let instantiated_predicate = ocx.normalize(&cause, param_env, instantiated_predicate);
|
||||
|
||||
ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -240,8 +240,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
if !drcx.args_may_unify(obligation_args, bound_trait_ref.skip_binder().args) {
|
||||
continue;
|
||||
}
|
||||
// FIXME(oli-obk): it is suspicious that we are dropping the constness and
|
||||
// polarity here.
|
||||
let wc = self.where_clause_may_apply(stack, bound_trait_ref)?;
|
||||
if wc.may_apply() {
|
||||
candidates.vec.push(ParamCandidate(bound));
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
//! Core logic responsible for determining what it means for various type system
|
||||
//! primitives to be "well formed". Actually checking whether these primitives are
|
||||
//! well formed is performed elsewhere (e.g. during type checking or item well formedness
|
||||
//! checking).
|
||||
|
||||
use std::iter;
|
||||
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -15,12 +20,13 @@ use tracing::{debug, instrument, trace};
|
|||
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::traits;
|
||||
|
||||
/// Returns the set of obligations needed to make `arg` well-formed.
|
||||
/// If `arg` contains unresolved inference variables, this may include
|
||||
/// further WF obligations. However, if `arg` IS an unresolved
|
||||
/// inference variable, returns `None`, because we are not able to
|
||||
/// make any progress at all. This is to prevent "livelock" where we
|
||||
/// say "$0 is WF if $0 is WF".
|
||||
/// make any progress at all. This is to prevent cycles where we
|
||||
/// say "?0 is WF if ?0 is WF".
|
||||
pub fn obligations<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
|
@ -29,14 +35,14 @@ pub fn obligations<'tcx>(
|
|||
arg: GenericArg<'tcx>,
|
||||
span: Span,
|
||||
) -> Option<PredicateObligations<'tcx>> {
|
||||
// Handle the "livelock" case (see comment above) by bailing out if necessary.
|
||||
// Handle the "cycle" case (see comment above) by bailing out if necessary.
|
||||
let arg = match arg.unpack() {
|
||||
GenericArgKind::Type(ty) => {
|
||||
match ty.kind() {
|
||||
ty::Infer(ty::TyVar(_)) => {
|
||||
let resolved_ty = infcx.shallow_resolve(ty);
|
||||
if resolved_ty == ty {
|
||||
// No progress, bail out to prevent "livelock".
|
||||
// No progress, bail out to prevent cycles.
|
||||
return None;
|
||||
} else {
|
||||
resolved_ty
|
||||
|
|
@ -51,7 +57,7 @@ pub fn obligations<'tcx>(
|
|||
ty::ConstKind::Infer(_) => {
|
||||
let resolved = infcx.shallow_resolve_const(ct);
|
||||
if resolved == ct {
|
||||
// No progress.
|
||||
// No progress, bail out to prevent cycles.
|
||||
return None;
|
||||
} else {
|
||||
resolved
|
||||
|
|
@ -74,7 +80,7 @@ pub fn obligations<'tcx>(
|
|||
recursion_depth,
|
||||
item: None,
|
||||
};
|
||||
wf.compute(arg);
|
||||
wf.add_wf_preds_for_generic_arg(arg);
|
||||
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
|
||||
|
||||
let result = wf.normalize(infcx);
|
||||
|
|
@ -97,7 +103,7 @@ pub fn unnormalized_obligations<'tcx>(
|
|||
|
||||
// However, if `arg` IS an unresolved inference variable, returns `None`,
|
||||
// because we are not able to make any progress at all. This is to prevent
|
||||
// "livelock" where we say "$0 is WF if $0 is WF".
|
||||
// cycles where we say "?0 is WF if ?0 is WF".
|
||||
if arg.is_non_region_infer() {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -115,7 +121,7 @@ pub fn unnormalized_obligations<'tcx>(
|
|||
recursion_depth: 0,
|
||||
item: None,
|
||||
};
|
||||
wf.compute(arg);
|
||||
wf.add_wf_preds_for_generic_arg(arg);
|
||||
Some(wf.out)
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +146,7 @@ pub fn trait_obligations<'tcx>(
|
|||
recursion_depth: 0,
|
||||
item: Some(item),
|
||||
};
|
||||
wf.compute_trait_pred(trait_pred, Elaborate::All);
|
||||
wf.add_wf_preds_for_trait_pred(trait_pred, Elaborate::All);
|
||||
debug!(obligations = ?wf.out);
|
||||
wf.normalize(infcx)
|
||||
}
|
||||
|
|
@ -171,7 +177,7 @@ pub fn clause_obligations<'tcx>(
|
|||
// It's ok to skip the binder here because wf code is prepared for it
|
||||
match clause.kind().skip_binder() {
|
||||
ty::ClauseKind::Trait(t) => {
|
||||
wf.compute_trait_pred(t, Elaborate::None);
|
||||
wf.add_wf_preds_for_trait_pred(t, Elaborate::None);
|
||||
}
|
||||
ty::ClauseKind::HostEffect(..) => {
|
||||
// Technically the well-formedness of this predicate is implied by
|
||||
|
|
@ -179,22 +185,22 @@ pub fn clause_obligations<'tcx>(
|
|||
}
|
||||
ty::ClauseKind::RegionOutlives(..) => {}
|
||||
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
|
||||
wf.compute(ty.into());
|
||||
wf.add_wf_preds_for_generic_arg(ty.into());
|
||||
}
|
||||
ty::ClauseKind::Projection(t) => {
|
||||
wf.compute_alias_term(t.projection_term);
|
||||
wf.compute(t.term.into_arg());
|
||||
wf.add_wf_preds_for_alias_term(t.projection_term);
|
||||
wf.add_wf_preds_for_generic_arg(t.term.into_arg());
|
||||
}
|
||||
ty::ClauseKind::ConstArgHasType(ct, ty) => {
|
||||
wf.compute(ct.into());
|
||||
wf.compute(ty.into());
|
||||
wf.add_wf_preds_for_generic_arg(ct.into());
|
||||
wf.add_wf_preds_for_generic_arg(ty.into());
|
||||
}
|
||||
ty::ClauseKind::WellFormed(arg) => {
|
||||
wf.compute(arg);
|
||||
wf.add_wf_preds_for_generic_arg(arg);
|
||||
}
|
||||
|
||||
ty::ClauseKind::ConstEvaluatable(ct) => {
|
||||
wf.compute(ct.into());
|
||||
wf.add_wf_preds_for_generic_arg(ct.into());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -372,14 +378,18 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
|
||||
fn compute_trait_pred(&mut self, trait_pred: ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
|
||||
fn add_wf_preds_for_trait_pred(
|
||||
&mut self,
|
||||
trait_pred: ty::TraitPredicate<'tcx>,
|
||||
elaborate: Elaborate,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
let trait_ref = trait_pred.trait_ref;
|
||||
|
||||
// Negative trait predicates don't require supertraits to hold, just
|
||||
// that their args are WF.
|
||||
if trait_pred.polarity == ty::PredicatePolarity::Negative {
|
||||
self.compute_negative_trait_pred(trait_ref);
|
||||
self.add_wf_preds_for_negative_trait_pred(trait_ref);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -445,15 +455,15 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
|
||||
// Compute the obligations that are required for `trait_ref` to be WF,
|
||||
// given that it is a *negative* trait predicate.
|
||||
fn compute_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) {
|
||||
fn add_wf_preds_for_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) {
|
||||
for arg in trait_ref.args {
|
||||
self.compute(arg);
|
||||
self.add_wf_preds_for_generic_arg(arg);
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes the obligations required for an alias (except inherent) to be WF
|
||||
/// into `self.out`.
|
||||
fn compute_alias_term(&mut self, data: ty::AliasTerm<'tcx>) {
|
||||
fn add_wf_preds_for_alias_term(&mut self, data: ty::AliasTerm<'tcx>) {
|
||||
// A projection is well-formed if
|
||||
//
|
||||
// (a) its predicates hold (*)
|
||||
|
|
@ -478,13 +488,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
let obligations = self.nominal_obligations(data.def_id, data.args);
|
||||
self.out.extend(obligations);
|
||||
|
||||
self.compute_projection_args(data.args);
|
||||
self.add_wf_preds_for_projection_args(data.args);
|
||||
}
|
||||
|
||||
/// Pushes the obligations required for an inherent alias to be WF
|
||||
/// into `self.out`.
|
||||
// FIXME(inherent_associated_types): Merge this function with `fn compute_alias`.
|
||||
fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
|
||||
fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
|
||||
// An inherent projection is well-formed if
|
||||
//
|
||||
// (a) its predicates hold (*)
|
||||
|
|
@ -511,7 +521,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
data.args.visit_with(self);
|
||||
}
|
||||
|
||||
fn compute_projection_args(&mut self, args: GenericArgsRef<'tcx>) {
|
||||
fn add_wf_preds_for_projection_args(&mut self, args: GenericArgsRef<'tcx>) {
|
||||
let tcx = self.tcx();
|
||||
let cause = self.cause(ObligationCauseCode::WellFormed(None));
|
||||
let param_env = self.param_env;
|
||||
|
|
@ -557,7 +567,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
|
||||
/// Pushes all the predicates needed to validate that `ty` is WF into `out`.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn compute(&mut self, arg: GenericArg<'tcx>) {
|
||||
fn add_wf_preds_for_generic_arg(&mut self, arg: GenericArg<'tcx>) {
|
||||
arg.visit_with(self);
|
||||
debug!(?self.out);
|
||||
}
|
||||
|
|
@ -596,7 +606,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn from_object_ty(
|
||||
fn add_wf_preds_for_dyn_ty(
|
||||
&mut self,
|
||||
ty: Ty<'tcx>,
|
||||
data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
|
|
@ -651,6 +661,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
outlives,
|
||||
));
|
||||
}
|
||||
|
||||
// We don't add any wf predicates corresponding to the trait ref's generic arguments
|
||||
// which allows code like this to compile:
|
||||
// ```rust
|
||||
// trait Trait<T: Sized> {}
|
||||
// fn foo(_: &dyn Trait<[u32]>) {}
|
||||
// ```
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -761,7 +778,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
|||
self.out.extend(obligations);
|
||||
}
|
||||
ty::Alias(ty::Inherent, data) => {
|
||||
self.compute_inherent_projection(data);
|
||||
self.add_wf_preds_for_inherent_projection(data);
|
||||
return; // Subtree handled by compute_inherent_projection.
|
||||
}
|
||||
|
||||
|
|
@ -895,7 +912,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
|||
//
|
||||
// Here, we defer WF checking due to higher-ranked
|
||||
// regions. This is perhaps not ideal.
|
||||
self.from_object_ty(t, data, r);
|
||||
self.add_wf_preds_for_dyn_ty(t, data, r);
|
||||
|
||||
// FIXME(#27579) RFC also considers adding trait
|
||||
// obligations that don't refer to Self and
|
||||
|
|
@ -917,11 +934,11 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
|||
// 1. Check if they have been resolved, and if so proceed with
|
||||
// THAT type.
|
||||
// 2. If not, we've at least simplified things (e.g., we went
|
||||
// from `Vec<$0>: WF` to `$0: WF`), so we can
|
||||
// from `Vec?0>: WF` to `?0: WF`), so we can
|
||||
// register a pending obligation and keep
|
||||
// moving. (Goal is that an "inductive hypothesis"
|
||||
// is satisfied to ensure termination.)
|
||||
// See also the comment on `fn obligations`, describing "livelock"
|
||||
// See also the comment on `fn obligations`, describing cycle
|
||||
// prevention, which happens before this can be reached.
|
||||
ty::Infer(_) => {
|
||||
let cause = self.cause(ObligationCauseCode::WellFormed(None));
|
||||
|
|
|
|||
|
|
@ -347,7 +347,8 @@ fn adjust_for_rust_scalar<'tcx>(
|
|||
None
|
||||
};
|
||||
if let Some(kind) = kind {
|
||||
attrs.pointee_align = Some(pointee.align);
|
||||
attrs.pointee_align =
|
||||
Some(pointee.align.min(cx.tcx().sess.target.max_reliable_alignment()));
|
||||
|
||||
// `Box` are not necessarily dereferenceable for the entire duration of the function as
|
||||
// they can be deallocated at any time. Same for non-frozen shared references (see
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue