commit
930451e17d
734 changed files with 9701 additions and 4314 deletions
|
|
@ -31,8 +31,8 @@ bootstrapping, the compiler architecture, source code representation, and more.
|
|||
|
||||
## [Getting help](https://rustc-dev-guide.rust-lang.org/getting-started.html#asking-questions)
|
||||
|
||||
There are many ways you can get help when you're stuck. Rust has many platforms for this:
|
||||
[internals], [rust-zulip], and [rust-discord]. It is recommended to ask for help on
|
||||
There are many ways you can get help when you're stuck. Rust has two platforms for this:
|
||||
[internals] and [rust-zulip]. It is recommended to ask for help on
|
||||
the [rust-zulip], but any of these platforms are great ways to seek help and even
|
||||
find a mentor! You can learn more about asking questions and getting help in the
|
||||
[Asking Questions](https://rustc-dev-guide.rust-lang.org/getting-started.html#asking-questions) chapter of the [rustc-dev-guide].
|
||||
|
|
@ -47,5 +47,4 @@ refer to [this section][contributing-bug-reports] and [open an issue][issue temp
|
|||
[contributing-bug-reports]: https://rustc-dev-guide.rust-lang.org/contributing.html#bug-reports
|
||||
[issue template]: https://github.com/rust-lang/rust/issues/new/choose
|
||||
[internals]: https://internals.rust-lang.org
|
||||
[rust-discord]: http://discord.gg/rust-lang
|
||||
[rust-zulip]: https://rust-lang.zulipchat.com
|
||||
|
|
|
|||
|
|
@ -334,8 +334,10 @@ dependencies = [
|
|||
"anyhow",
|
||||
"build_helper",
|
||||
"curl",
|
||||
"hex",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"sha2",
|
||||
"toml 0.8.23",
|
||||
]
|
||||
|
||||
|
|
@ -5239,9 +5241,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "stringdex"
|
||||
version = "0.0.1-alpha9"
|
||||
version = "0.0.1-alpha10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7081029913fd7d591c0112182aba8c98ae886b4f12edb208130496cd17dc3c15"
|
||||
checksum = "0fa846a7d509d1828a4f90962dc09810e161abcada7fc6a921e92c168d0811d7"
|
||||
dependencies = [
|
||||
"stacker",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -768,8 +768,7 @@
|
|||
# make this default to false.
|
||||
#rust.lld = false in all cases, except on `x86_64-unknown-linux-gnu` as described above, where it is true
|
||||
|
||||
# Indicates whether LLD will be used to link Rust crates during bootstrap on
|
||||
# supported platforms.
|
||||
# Indicates if we should override the linker used to link Rust crates during bootstrap to be LLD.
|
||||
# If set to `true` or `"external"`, a global `lld` binary that has to be in $PATH
|
||||
# will be used.
|
||||
# If set to `"self-contained"`, rust-lld from the snapshot compiler will be used.
|
||||
|
|
@ -777,7 +776,7 @@
|
|||
# On MSVC, LLD will not be used if we're cross linking.
|
||||
#
|
||||
# Explicitly setting the linker for a target will override this option when targeting MSVC.
|
||||
#rust.use-lld = false
|
||||
#rust.bootstrap-override-lld = false
|
||||
|
||||
# Indicates whether some LLVM tools, like llvm-objdump, will be made available in the
|
||||
# sysroot.
|
||||
|
|
@ -950,7 +949,7 @@
|
|||
# Linker to be used to bootstrap Rust code. Note that the
|
||||
# default value is platform specific, and if not specified it may also depend on
|
||||
# what platform is crossing to what platform.
|
||||
# Setting this will override the `use-lld` option for Rust code when targeting MSVC.
|
||||
# Setting this will override the `bootstrap-override-lld` option for Rust code when targeting MSVC.
|
||||
#linker = "cc" (path)
|
||||
|
||||
# Should rustc and the standard library be built with split debuginfo? Default
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
use std::fmt::{self, Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::expand::typetree::TypeTree;
|
||||
use crate::expand::{Decodable, Encodable, HashStable_Generic};
|
||||
use crate::{Ty, TyKind};
|
||||
|
||||
|
|
@ -84,6 +85,8 @@ pub struct AutoDiffItem {
|
|||
/// The name of the function being generated
|
||||
pub target: String,
|
||||
pub attrs: AutoDiffAttrs,
|
||||
pub inputs: Vec<TypeTree>,
|
||||
pub output: TypeTree,
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
|
|
@ -275,14 +278,22 @@ impl AutoDiffAttrs {
|
|||
!matches!(self.mode, DiffMode::Error | DiffMode::Source)
|
||||
}
|
||||
|
||||
pub fn into_item(self, source: String, target: String) -> AutoDiffItem {
|
||||
AutoDiffItem { source, target, attrs: self }
|
||||
pub fn into_item(
|
||||
self,
|
||||
source: String,
|
||||
target: String,
|
||||
inputs: Vec<TypeTree>,
|
||||
output: TypeTree,
|
||||
) -> AutoDiffItem {
|
||||
AutoDiffItem { source, target, inputs, output, attrs: self }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for AutoDiffItem {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Differentiating {} -> {}", self.source, self.target)?;
|
||||
write!(f, " with attributes: {:?}", self.attrs)
|
||||
write!(f, " with attributes: {:?}", self.attrs)?;
|
||||
write!(f, " with inputs: {:?}", self.inputs)?;
|
||||
write!(f, " with output: {:?}", self.output)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ pub enum Kind {
|
|||
Half,
|
||||
Float,
|
||||
Double,
|
||||
F128,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -487,26 +487,6 @@ fn expand_format_args<'hir>(
|
|||
// Generate:
|
||||
// []
|
||||
(vec![], ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(&[]))))
|
||||
} else if argmap.len() == 1 && arguments.len() == 1 {
|
||||
// Only one argument, so we don't need to make the `args` tuple.
|
||||
//
|
||||
// Generate:
|
||||
// super let args = [<core::fmt::Argument>::new_display(&arg)];
|
||||
let args = ctx.arena.alloc_from_iter(argmap.iter().map(
|
||||
|(&(arg_index, ty), &placeholder_span)| {
|
||||
let arg = &arguments[arg_index];
|
||||
let placeholder_span =
|
||||
placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt());
|
||||
let arg = ctx.lower_expr(&arg.expr);
|
||||
let ref_arg = ctx.arena.alloc(ctx.expr_ref(arg.span.with_ctxt(macsp.ctxt()), arg));
|
||||
make_argument(ctx, placeholder_span, ref_arg, ty)
|
||||
},
|
||||
));
|
||||
let args = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
|
||||
let args_ident = Ident::new(sym::args, macsp);
|
||||
let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
|
||||
let let_statement = ctx.stmt_super_let_pat(macsp, args_pat, Some(args));
|
||||
(vec![let_statement], ctx.arena.alloc(ctx.expr_ident_mut(macsp, args_ident, args_hir_id)))
|
||||
} else {
|
||||
// Generate:
|
||||
// super let args = (&arg0, &arg1, &…);
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
gate_doc!(
|
||||
"experimental" {
|
||||
cfg => doc_cfg
|
||||
cfg_hide => doc_cfg_hide
|
||||
auto_cfg => doc_cfg
|
||||
masked => doc_masked
|
||||
notable_trait => doc_notable_trait
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,40 +1,4 @@
|
|||
use std::num::IntErrorKind;
|
||||
|
||||
use rustc_hir::limit::Limit;
|
||||
|
||||
use super::prelude::*;
|
||||
use crate::session_diagnostics::LimitInvalid;
|
||||
|
||||
impl<S: Stage> AcceptContext<'_, '_, S> {
|
||||
fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> {
|
||||
let Some(limit) = nv.value_as_str() else {
|
||||
self.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
||||
return None;
|
||||
};
|
||||
|
||||
let error_str = match limit.as_str().parse() {
|
||||
Ok(i) => return Some(Limit::new(i)),
|
||||
Err(e) => match e.kind() {
|
||||
IntErrorKind::PosOverflow => "`limit` is too large",
|
||||
IntErrorKind::Empty => "`limit` must be a non-negative integer",
|
||||
IntErrorKind::InvalidDigit => "not a valid integer",
|
||||
IntErrorKind::NegOverflow => {
|
||||
panic!(
|
||||
"`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
|
||||
)
|
||||
}
|
||||
IntErrorKind::Zero => {
|
||||
panic!("zero is a valid `limit` so should have returned Ok() when parsing")
|
||||
}
|
||||
kind => panic!("unimplemented IntErrorKind variant: {:?}", kind),
|
||||
},
|
||||
};
|
||||
|
||||
self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CrateNameParser;
|
||||
|
||||
|
|
|
|||
60
compiler/rustc_attr_parsing/src/attributes/debugger.rs
Normal file
60
compiler/rustc_attr_parsing/src/attributes/debugger.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
use rustc_hir::attrs::{DebugVisualizer, DebuggerVisualizerType};
|
||||
|
||||
use super::prelude::*;
|
||||
|
||||
pub(crate) struct DebuggerViualizerParser;
|
||||
|
||||
impl<S: Stage> CombineAttributeParser<S> for DebuggerViualizerParser {
|
||||
const PATH: &[Symbol] = &[sym::debugger_visualizer];
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
List: &[r#"natvis_file = "...", gdb_script_file = "...""#],
|
||||
"https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute"
|
||||
);
|
||||
|
||||
type Item = DebugVisualizer;
|
||||
const CONVERT: ConvertFn<Self::Item> = |v, _| AttributeKind::DebuggerVisualizer(v);
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||
let Some(l) = args.list() else {
|
||||
cx.expected_list(args.span().unwrap_or(cx.attr_span));
|
||||
return None;
|
||||
};
|
||||
let Some(single) = l.single() else {
|
||||
cx.expected_single_argument(l.span);
|
||||
return None;
|
||||
};
|
||||
let Some(mi) = single.meta_item() else {
|
||||
cx.expected_name_value(single.span(), None);
|
||||
return None;
|
||||
};
|
||||
let path = mi.path().word_sym();
|
||||
let visualizer_type = match path {
|
||||
Some(sym::natvis_file) => DebuggerVisualizerType::Natvis,
|
||||
Some(sym::gdb_script_file) => DebuggerVisualizerType::GdbPrettyPrinter,
|
||||
_ => {
|
||||
cx.expected_specific_argument(
|
||||
mi.path().span(),
|
||||
&[sym::natvis_file, sym::gdb_script_file],
|
||||
);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let Some(path) = mi.args().name_value() else {
|
||||
cx.expected_name_value(single.span(), path);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(path) = path.value_as_str() else {
|
||||
cx.expected_string_literal(path.value_span, Some(path.value_as_lit()));
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(DebugVisualizer { span: mi.span(), visualizer_type, path })
|
||||
}
|
||||
}
|
||||
|
|
@ -36,6 +36,7 @@ pub(crate) mod cfg_old;
|
|||
pub(crate) mod codegen_attrs;
|
||||
pub(crate) mod confusables;
|
||||
pub(crate) mod crate_level;
|
||||
pub(crate) mod debugger;
|
||||
pub(crate) mod deprecation;
|
||||
pub(crate) mod dummy;
|
||||
pub(crate) mod inline;
|
||||
|
|
|
|||
|
|
@ -49,3 +49,21 @@ impl<S: Stage> SingleAttributeParser<S> for RustcObjectLifetimeDefaultParser {
|
|||
Some(AttributeKind::RustcObjectLifetimeDefault)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcSimdMonomorphizeLaneLimitParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcSimdMonomorphizeLaneLimitParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let ArgParser::NameValue(nv) = args else {
|
||||
cx.expected_name_value(cx.attr_span, None);
|
||||
return None;
|
||||
};
|
||||
Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
use std::num::IntErrorKind;
|
||||
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_ast::attr::AttributeExt;
|
||||
use rustc_feature::is_builtin_attr_name;
|
||||
use rustc_hir::RustcVersion;
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::parser::{ArgParser, NameValueParser};
|
||||
use crate::session_diagnostics::LimitInvalid;
|
||||
|
||||
/// Parse a rustc version number written inside string literal in an attribute,
|
||||
/// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are
|
||||
|
|
@ -85,3 +89,34 @@ pub(crate) fn parse_single_integer<S: Stage>(
|
|||
};
|
||||
Some(num.0)
|
||||
}
|
||||
|
||||
impl<S: Stage> AcceptContext<'_, '_, S> {
|
||||
pub(crate) fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> {
|
||||
let Some(limit) = nv.value_as_str() else {
|
||||
self.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
||||
return None;
|
||||
};
|
||||
|
||||
let error_str = match limit.as_str().parse() {
|
||||
Ok(i) => return Some(Limit::new(i)),
|
||||
Err(e) => match e.kind() {
|
||||
IntErrorKind::PosOverflow => "`limit` is too large",
|
||||
IntErrorKind::Empty => "`limit` must be a non-negative integer",
|
||||
IntErrorKind::InvalidDigit => "not a valid integer",
|
||||
IntErrorKind::NegOverflow => {
|
||||
panic!(
|
||||
"`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
|
||||
)
|
||||
}
|
||||
IntErrorKind::Zero => {
|
||||
panic!("zero is a valid `limit` so should have returned Ok() when parsing")
|
||||
}
|
||||
kind => panic!("unimplemented IntErrorKind variant: {:?}", kind),
|
||||
},
|
||||
};
|
||||
|
||||
self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ use crate::attributes::crate_level::{
|
|||
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
|
||||
RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
|
||||
};
|
||||
use crate::attributes::debugger::DebuggerViualizerParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
use crate::attributes::dummy::DummyParser;
|
||||
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
|
||||
|
|
@ -53,7 +54,7 @@ use crate::attributes::prototype::CustomMirParser;
|
|||
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
|
||||
use crate::attributes::rustc_internal::{
|
||||
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
|
||||
RustcObjectLifetimeDefaultParser,
|
||||
RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser,
|
||||
};
|
||||
use crate::attributes::semantics::MayDangleParser;
|
||||
use crate::attributes::stability::{
|
||||
|
|
@ -163,6 +164,7 @@ attribute_parsers!(
|
|||
// tidy-alphabetical-start
|
||||
Combine<AllowConstFnUnstableParser>,
|
||||
Combine<AllowInternalUnstableParser>,
|
||||
Combine<DebuggerViualizerParser>,
|
||||
Combine<ForceTargetFeatureParser>,
|
||||
Combine<LinkParser>,
|
||||
Combine<ReprParser>,
|
||||
|
|
@ -198,6 +200,7 @@ attribute_parsers!(
|
|||
Single<RustcLayoutScalarValidRangeEnd>,
|
||||
Single<RustcLayoutScalarValidRangeStart>,
|
||||
Single<RustcObjectLifetimeDefaultParser>,
|
||||
Single<RustcSimdMonomorphizeLaneLimitParser>,
|
||||
Single<SanitizeParser>,
|
||||
Single<ShouldPanicParser>,
|
||||
Single<SkipDuringMethodDispatchParser>,
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ impl AllocFnFactory<'_, '_> {
|
|||
body,
|
||||
define_opaque: None,
|
||||
}));
|
||||
let item = self.cx.item(self.span, self.attrs(), kind);
|
||||
let item = self.cx.item(self.span, self.attrs(method), kind);
|
||||
self.cx.stmt_item(self.ty_span, item)
|
||||
}
|
||||
|
||||
|
|
@ -100,8 +100,18 @@ impl AllocFnFactory<'_, '_> {
|
|||
self.cx.expr_call(self.ty_span, method, args)
|
||||
}
|
||||
|
||||
fn attrs(&self) -> AttrVec {
|
||||
thin_vec![self.cx.attr_word(sym::rustc_std_internal_symbol, self.span)]
|
||||
fn attrs(&self, method: &AllocatorMethod) -> AttrVec {
|
||||
let alloc_attr = match method.name {
|
||||
sym::alloc => sym::rustc_allocator,
|
||||
sym::dealloc => sym::rustc_deallocator,
|
||||
sym::realloc => sym::rustc_reallocator,
|
||||
sym::alloc_zeroed => sym::rustc_allocator_zeroed,
|
||||
_ => unreachable!("Unknown allocator method!"),
|
||||
};
|
||||
thin_vec![
|
||||
self.cx.attr_word(sym::rustc_std_internal_symbol, self.span),
|
||||
self.cx.attr_word(alloc_attr, self.span)
|
||||
]
|
||||
}
|
||||
|
||||
fn arg_ty(&self, input: &AllocatorMethodInput, args: &mut ThinVec<Param>) -> Box<Expr> {
|
||||
|
|
|
|||
|
|
@ -439,7 +439,10 @@ pub(crate) struct FullyMonomorphizedLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>);
|
|||
impl<'tcx> LayoutOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
|
||||
#[inline]
|
||||
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
|
||||
if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
|
||||
if let LayoutError::SizeOverflow(_)
|
||||
| LayoutError::InvalidSimd { .. }
|
||||
| LayoutError::ReferencesError(_) = err
|
||||
{
|
||||
self.0.sess.dcx().span_fatal(span, err.to_string())
|
||||
} else {
|
||||
self.0
|
||||
|
|
@ -458,7 +461,9 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for FullyMonomorphizedLayoutCx<'tcx> {
|
|||
span: Span,
|
||||
fn_abi_request: FnAbiRequest<'tcx>,
|
||||
) -> ! {
|
||||
if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
|
||||
if let FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) =
|
||||
err
|
||||
{
|
||||
self.0.sess.dcx().emit_fatal(Spanned { span, node: err })
|
||||
} else {
|
||||
match fn_abi_request {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,10 @@ impl<'tcx> AsmCodegenMethods<'tcx> for GlobalAsmContext<'_, 'tcx> {
|
|||
impl<'tcx> LayoutOfHelpers<'tcx> for GlobalAsmContext<'_, 'tcx> {
|
||||
#[inline]
|
||||
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
|
||||
if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
|
||||
if let LayoutError::SizeOverflow(_)
|
||||
| LayoutError::InvalidSimd { .. }
|
||||
| LayoutError::ReferencesError(_) = err
|
||||
{
|
||||
self.tcx.sess.dcx().span_fatal(span, err.to_string())
|
||||
} else {
|
||||
self.tcx
|
||||
|
|
|
|||
|
|
@ -1383,6 +1383,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
_src_align: Align,
|
||||
size: RValue<'gcc>,
|
||||
flags: MemFlags,
|
||||
_tt: Option<rustc_ast::expand::typetree::FncTree>, // Autodiff TypeTrees are LLVM-only, ignored in GCC backend
|
||||
) {
|
||||
assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memcpy not supported");
|
||||
let size = self.intcast(size, self.type_size_t(), false);
|
||||
|
|
|
|||
|
|
@ -529,7 +529,10 @@ impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
|
|||
impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
#[inline]
|
||||
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
|
||||
if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
|
||||
if let LayoutError::SizeOverflow(_)
|
||||
| LayoutError::InvalidSimd { .. }
|
||||
| LayoutError::ReferencesError(_) = err
|
||||
{
|
||||
self.tcx.dcx().emit_fatal(respan(span, err.into_diagnostic()))
|
||||
} else {
|
||||
self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err })
|
||||
|
|
@ -545,7 +548,9 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
span: Span,
|
||||
fn_abi_request: FnAbiRequest<'tcx>,
|
||||
) -> ! {
|
||||
if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
|
||||
if let FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) =
|
||||
err
|
||||
{
|
||||
self.tcx.dcx().emit_fatal(respan(span, err))
|
||||
} else {
|
||||
match fn_abi_request {
|
||||
|
|
|
|||
|
|
@ -770,6 +770,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||
scratch_align,
|
||||
bx.const_usize(self.layout.size.bytes()),
|
||||
MemFlags::empty(),
|
||||
None,
|
||||
);
|
||||
|
||||
bx.lifetime_end(scratch, scratch_size);
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||
scratch_align,
|
||||
bx.const_usize(copy_bytes),
|
||||
MemFlags::empty(),
|
||||
None,
|
||||
);
|
||||
bx.lifetime_end(llscratch, scratch_size);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -563,6 +563,8 @@ fn enable_autodiff_settings(ad: &[config::AutoDiff]) {
|
|||
config::AutoDiff::Enable => {}
|
||||
// We handle this below
|
||||
config::AutoDiff::NoPostopt => {}
|
||||
// Disables TypeTree generation
|
||||
config::AutoDiff::NoTT => {}
|
||||
}
|
||||
}
|
||||
// This helps with handling enums for now.
|
||||
|
|
|
|||
|
|
@ -95,8 +95,6 @@ impl Drop for OwnedTargetMachine {
|
|||
// SAFETY: constructing ensures we have a valid pointer created by
|
||||
// llvm::LLVMRustCreateTargetMachine OwnedTargetMachine is not copyable so there is no
|
||||
// double free or use after free.
|
||||
unsafe {
|
||||
llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_ptr());
|
||||
}
|
||||
unsafe { llvm::LLVMDisposeTargetMachine(self.tm_unique) };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::borrow::{Borrow, Cow};
|
|||
use std::ops::Deref;
|
||||
use std::{iter, ptr};
|
||||
|
||||
use rustc_ast::expand::typetree::FncTree;
|
||||
pub(crate) mod autodiff;
|
||||
pub(crate) mod gpu_offload;
|
||||
|
||||
|
|
@ -1107,11 +1108,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
src_align: Align,
|
||||
size: &'ll Value,
|
||||
flags: MemFlags,
|
||||
tt: Option<FncTree>,
|
||||
) {
|
||||
assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memcpy not supported");
|
||||
let size = self.intcast(size, self.type_isize(), false);
|
||||
let is_volatile = flags.contains(MemFlags::VOLATILE);
|
||||
unsafe {
|
||||
let memcpy = unsafe {
|
||||
llvm::LLVMRustBuildMemCpy(
|
||||
self.llbuilder,
|
||||
dst,
|
||||
|
|
@ -1120,7 +1122,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
src_align.bytes() as c_uint,
|
||||
size,
|
||||
is_volatile,
|
||||
);
|
||||
)
|
||||
};
|
||||
|
||||
// TypeTree metadata for memcpy is especially important: when Enzyme encounters
|
||||
// a memcpy during autodiff, it needs to know the structure of the data being
|
||||
// copied to properly track derivatives. For example, copying an array of floats
|
||||
// vs. copying a struct with mixed types requires different derivative handling.
|
||||
// The TypeTree tells Enzyme exactly what memory layout to expect.
|
||||
if let Some(tt) = tt {
|
||||
crate::typetree::add_tt(self.cx().llmod, self.cx().llcx, memcpy, tt);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::ptr;
|
||||
|
||||
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
|
||||
use rustc_ast::expand::typetree::FncTree;
|
||||
use rustc_codegen_ssa::common::TypeKind;
|
||||
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods};
|
||||
use rustc_middle::ty::{Instance, PseudoCanonicalInput, TyCtxt, TypingEnv};
|
||||
|
|
@ -294,6 +295,7 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>(
|
|||
fn_args: &[&'ll Value],
|
||||
attrs: AutoDiffAttrs,
|
||||
dest: PlaceRef<'tcx, &'ll Value>,
|
||||
fnc_tree: FncTree,
|
||||
) {
|
||||
// We have to pick the name depending on whether we want forward or reverse mode autodiff.
|
||||
let mut ad_name: String = match attrs.mode {
|
||||
|
|
@ -370,6 +372,10 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>(
|
|||
fn_args,
|
||||
);
|
||||
|
||||
if !fnc_tree.args.is_empty() || !fnc_tree.ret.0.is_empty() {
|
||||
crate::typetree::add_tt(cx.llmod, cx.llcx, fn_to_diff, fnc_tree);
|
||||
}
|
||||
|
||||
let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None);
|
||||
|
||||
builder.store_to_place(call, dest.val);
|
||||
|
|
|
|||
|
|
@ -1044,7 +1044,10 @@ impl<'tcx, 'll> HasTypingEnv<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
|
||||
#[inline]
|
||||
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
|
||||
if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
|
||||
if let LayoutError::SizeOverflow(_)
|
||||
| LayoutError::ReferencesError(_)
|
||||
| LayoutError::InvalidSimd { .. } = err
|
||||
{
|
||||
self.tcx.dcx().emit_fatal(Spanned { span, node: err.into_diagnostic() })
|
||||
} else {
|
||||
self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err })
|
||||
|
|
@ -1061,7 +1064,11 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
|
|||
fn_abi_request: FnAbiRequest<'tcx>,
|
||||
) -> ! {
|
||||
match err {
|
||||
FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::Cycle(_)) => {
|
||||
FnAbiError::Layout(
|
||||
LayoutError::SizeOverflow(_)
|
||||
| LayoutError::Cycle(_)
|
||||
| LayoutError::InvalidSimd { .. },
|
||||
) => {
|
||||
self.tcx.dcx().emit_fatal(Spanned { span, node: err });
|
||||
}
|
||||
_ => match fn_abi_request {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_hir::attrs::DebuggerVisualizerType;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerType;
|
||||
use rustc_session::config::{CrateType, DebugInfo};
|
||||
|
||||
use crate::builder::Builder;
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>(
|
|||
.try_to_target_usize(cx.tcx)
|
||||
.expect("expected monomorphic const in codegen") as c_longlong;
|
||||
|
||||
let subrange = unsafe { llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) };
|
||||
let subrange = unsafe { llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) };
|
||||
let subscripts = &[subrange];
|
||||
|
||||
let di_node = unsafe {
|
||||
|
|
@ -477,8 +477,8 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>(
|
|||
ty::CoroutineClosure(..) => build_closure_env_di_node(cx, unique_type_id),
|
||||
ty::Coroutine(..) => enums::build_coroutine_di_node(cx, unique_type_id),
|
||||
ty::Adt(def, ..) => match def.adt_kind() {
|
||||
AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id),
|
||||
AdtKind::Union => build_union_type_di_node(cx, unique_type_id),
|
||||
AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id, span),
|
||||
AdtKind::Union => build_union_type_di_node(cx, unique_type_id, span),
|
||||
AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id, span),
|
||||
},
|
||||
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
|
||||
|
|
@ -1076,6 +1076,7 @@ fn visibility_di_flags<'ll, 'tcx>(
|
|||
fn build_struct_type_di_node<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
unique_type_id: UniqueTypeId<'tcx>,
|
||||
span: Span,
|
||||
) -> DINodeCreationResult<'ll> {
|
||||
let struct_type = unique_type_id.expect_ty();
|
||||
let ty::Adt(adt_def, _) = struct_type.kind() else {
|
||||
|
|
@ -1083,7 +1084,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
|
|||
};
|
||||
assert!(adt_def.is_struct());
|
||||
let containing_scope = get_namespace_for_item(cx, adt_def.did());
|
||||
let struct_type_and_layout = cx.layout_of(struct_type);
|
||||
let struct_type_and_layout = cx.spanned_layout_of(struct_type, span);
|
||||
let variant_def = adt_def.non_enum_variant();
|
||||
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
Some(file_metadata_from_def_id(cx, Some(adt_def.did())))
|
||||
|
|
@ -1276,6 +1277,7 @@ fn build_closure_env_di_node<'ll, 'tcx>(
|
|||
fn build_union_type_di_node<'ll, 'tcx>(
|
||||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
unique_type_id: UniqueTypeId<'tcx>,
|
||||
span: Span,
|
||||
) -> DINodeCreationResult<'ll> {
|
||||
let union_type = unique_type_id.expect_ty();
|
||||
let (union_def_id, variant_def) = match union_type.kind() {
|
||||
|
|
@ -1283,7 +1285,7 @@ fn build_union_type_di_node<'ll, 'tcx>(
|
|||
_ => bug!("build_union_type_di_node on a non-ADT"),
|
||||
};
|
||||
let containing_scope = get_namespace_for_item(cx, union_def_id);
|
||||
let union_ty_and_layout = cx.layout_of(union_type);
|
||||
let union_ty_and_layout = cx.spanned_layout_of(union_type, span);
|
||||
let type_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
|
||||
let def_location = if cx.sess().opts.unstable_opts.debug_info_type_line_numbers {
|
||||
Some(file_metadata_from_def_id(cx, Some(union_def_id)))
|
||||
|
|
|
|||
|
|
@ -52,15 +52,6 @@ mod utils;
|
|||
use self::create_scope_map::compute_mir_scopes;
|
||||
pub(crate) use self::metadata::build_global_var_di_node;
|
||||
|
||||
// FIXME(Zalathar): These `DW_TAG_*` constants are fake values that were
|
||||
// removed from LLVM in 2015, and are only used by our own `RustWrapper.cpp`
|
||||
// to decide which C++ API to call. Instead, we should just have two separate
|
||||
// FFI functions and choose the correct one on the Rust side.
|
||||
#[allow(non_upper_case_globals)]
|
||||
const DW_TAG_auto_variable: c_uint = 0x100;
|
||||
#[allow(non_upper_case_globals)]
|
||||
const DW_TAG_arg_variable: c_uint = 0x101;
|
||||
|
||||
/// A context object for maintaining all state needed by the debuginfo module.
|
||||
pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
|
||||
llmod: &'ll llvm::Module,
|
||||
|
|
@ -174,35 +165,38 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
|
|||
|
||||
if direct_offset.bytes() > 0 {
|
||||
addr_ops.push(DW_OP_plus_uconst);
|
||||
addr_ops.push(direct_offset.bytes() as u64);
|
||||
addr_ops.push(direct_offset.bytes());
|
||||
}
|
||||
for &offset in indirect_offsets {
|
||||
addr_ops.push(DW_OP_deref);
|
||||
if offset.bytes() > 0 {
|
||||
addr_ops.push(DW_OP_plus_uconst);
|
||||
addr_ops.push(offset.bytes() as u64);
|
||||
addr_ops.push(offset.bytes());
|
||||
}
|
||||
}
|
||||
if let Some(fragment) = fragment {
|
||||
// `DW_OP_LLVM_fragment` takes as arguments the fragment's
|
||||
// offset and size, both of them in bits.
|
||||
addr_ops.push(DW_OP_LLVM_fragment);
|
||||
addr_ops.push(fragment.start.bits() as u64);
|
||||
addr_ops.push((fragment.end - fragment.start).bits() as u64);
|
||||
addr_ops.push(fragment.start.bits());
|
||||
addr_ops.push((fragment.end - fragment.start).bits());
|
||||
}
|
||||
|
||||
let di_builder = DIB(self.cx());
|
||||
let addr_expr = unsafe {
|
||||
llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len())
|
||||
};
|
||||
unsafe {
|
||||
// FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`.
|
||||
llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
|
||||
DIB(self.cx()),
|
||||
llvm::LLVMDIBuilderInsertDeclareRecordAtEnd(
|
||||
di_builder,
|
||||
variable_alloca,
|
||||
dbg_var,
|
||||
addr_ops.as_ptr(),
|
||||
addr_ops.len() as c_uint,
|
||||
addr_expr,
|
||||
dbg_loc,
|
||||
self.llbb(),
|
||||
);
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
|
||||
|
|
@ -630,28 +624,39 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
|
||||
let type_metadata = spanned_type_di_node(self, variable_type, span);
|
||||
|
||||
let (argument_index, dwarf_tag) = match variable_kind {
|
||||
ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
|
||||
LocalVariable => (0, DW_TAG_auto_variable),
|
||||
};
|
||||
let align = self.align_of(variable_type);
|
||||
|
||||
let name = variable_name.as_str();
|
||||
unsafe {
|
||||
llvm::LLVMRustDIBuilderCreateVariable(
|
||||
DIB(self),
|
||||
dwarf_tag,
|
||||
scope_metadata,
|
||||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
file_metadata,
|
||||
loc.line,
|
||||
type_metadata,
|
||||
true,
|
||||
DIFlags::FlagZero,
|
||||
argument_index,
|
||||
align.bits() as u32,
|
||||
)
|
||||
|
||||
match variable_kind {
|
||||
ArgumentVariable(arg_index) => unsafe {
|
||||
llvm::LLVMDIBuilderCreateParameterVariable(
|
||||
DIB(self),
|
||||
scope_metadata,
|
||||
name.as_ptr(),
|
||||
name.len(),
|
||||
arg_index as c_uint,
|
||||
file_metadata,
|
||||
loc.line,
|
||||
type_metadata,
|
||||
llvm::Bool::TRUE, // (preserve descriptor during optimizations)
|
||||
DIFlags::FlagZero,
|
||||
)
|
||||
},
|
||||
LocalVariable => unsafe {
|
||||
llvm::LLVMDIBuilderCreateAutoVariable(
|
||||
DIB(self),
|
||||
scope_metadata,
|
||||
name.as_ptr(),
|
||||
name.len(),
|
||||
file_metadata,
|
||||
loc.line,
|
||||
type_metadata,
|
||||
llvm::Bool::TRUE, // (preserve descriptor during optimizations)
|
||||
DIFlags::FlagZero,
|
||||
align.bits() as u32,
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ pub(crate) fn create_DIArray<'ll>(
|
|||
builder: &DIBuilder<'ll>,
|
||||
arr: &[Option<&'ll DIDescriptor>],
|
||||
) -> &'ll DIArray {
|
||||
unsafe { llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) }
|
||||
unsafe { llvm::LLVMDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len()) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -1212,6 +1212,9 @@ fn codegen_autodiff<'ll, 'tcx>(
|
|||
&mut diff_attrs.input_activity,
|
||||
);
|
||||
|
||||
let fnc_tree =
|
||||
rustc_middle::ty::fnc_typetrees(tcx, fn_source.ty(tcx, TypingEnv::fully_monomorphized()));
|
||||
|
||||
// Build body
|
||||
generate_enzyme_call(
|
||||
bx,
|
||||
|
|
@ -1222,6 +1225,7 @@ fn codegen_autodiff<'ll, 'tcx>(
|
|||
&val_arr,
|
||||
diff_attrs.clone(),
|
||||
result,
|
||||
fnc_tree,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ mod llvm_util;
|
|||
mod mono_item;
|
||||
mod type_;
|
||||
mod type_of;
|
||||
mod typetree;
|
||||
mod va_arg;
|
||||
mod value;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,36 @@
|
|||
use libc::{c_char, c_uint};
|
||||
|
||||
use super::MetadataKindId;
|
||||
use super::ffi::{AttributeKind, BasicBlock, Metadata, Module, Type, Value};
|
||||
use super::ffi::{AttributeKind, BasicBlock, Context, Metadata, Module, Type, Value};
|
||||
use crate::llvm::{Bool, Builder};
|
||||
|
||||
// TypeTree types
|
||||
pub(crate) type CTypeTreeRef = *mut EnzymeTypeTree;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) struct EnzymeTypeTree {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub(crate) enum CConcreteType {
|
||||
DT_Anything = 0,
|
||||
DT_Integer = 1,
|
||||
DT_Pointer = 2,
|
||||
DT_Half = 3,
|
||||
DT_Float = 4,
|
||||
DT_Double = 5,
|
||||
DT_Unknown = 6,
|
||||
DT_FP128 = 9,
|
||||
}
|
||||
|
||||
pub(crate) struct TypeTree {
|
||||
pub(crate) inner: CTypeTreeRef,
|
||||
}
|
||||
|
||||
#[link(name = "llvm-wrapper", kind = "static")]
|
||||
unsafe extern "C" {
|
||||
// Enzyme
|
||||
|
|
@ -68,10 +95,40 @@ pub(crate) mod Enzyme_AD {
|
|||
|
||||
use libc::c_void;
|
||||
|
||||
use super::{CConcreteType, CTypeTreeRef, Context};
|
||||
|
||||
unsafe extern "C" {
|
||||
pub(crate) fn EnzymeSetCLBool(arg1: *mut ::std::os::raw::c_void, arg2: u8);
|
||||
pub(crate) fn EnzymeSetCLString(arg1: *mut ::std::os::raw::c_void, arg2: *const c_char);
|
||||
}
|
||||
|
||||
// TypeTree functions
|
||||
unsafe extern "C" {
|
||||
pub(crate) fn EnzymeNewTypeTree() -> CTypeTreeRef;
|
||||
pub(crate) fn EnzymeNewTypeTreeCT(arg1: CConcreteType, ctx: &Context) -> CTypeTreeRef;
|
||||
pub(crate) fn EnzymeNewTypeTreeTR(arg1: CTypeTreeRef) -> CTypeTreeRef;
|
||||
pub(crate) fn EnzymeFreeTypeTree(CTT: CTypeTreeRef);
|
||||
pub(crate) fn EnzymeMergeTypeTree(arg1: CTypeTreeRef, arg2: CTypeTreeRef) -> bool;
|
||||
pub(crate) fn EnzymeTypeTreeOnlyEq(arg1: CTypeTreeRef, pos: i64);
|
||||
pub(crate) fn EnzymeTypeTreeData0Eq(arg1: CTypeTreeRef);
|
||||
pub(crate) fn EnzymeTypeTreeShiftIndiciesEq(
|
||||
arg1: CTypeTreeRef,
|
||||
data_layout: *const c_char,
|
||||
offset: i64,
|
||||
max_size: i64,
|
||||
add_offset: u64,
|
||||
);
|
||||
pub(crate) fn EnzymeTypeTreeInsertEq(
|
||||
CTT: CTypeTreeRef,
|
||||
indices: *const i64,
|
||||
len: usize,
|
||||
ct: CConcreteType,
|
||||
ctx: &Context,
|
||||
);
|
||||
pub(crate) fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char;
|
||||
pub(crate) fn EnzymeTypeTreeToStringFree(arg1: *const c_char);
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
static mut EnzymePrintPerf: c_void;
|
||||
static mut EnzymePrintActivity: c_void;
|
||||
|
|
@ -141,6 +198,67 @@ pub(crate) use self::Fallback_AD::*;
|
|||
pub(crate) mod Fallback_AD {
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use libc::c_char;
|
||||
|
||||
use super::{CConcreteType, CTypeTreeRef, Context};
|
||||
|
||||
// TypeTree function fallbacks
|
||||
pub(crate) unsafe fn EnzymeNewTypeTree() -> CTypeTreeRef {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn EnzymeNewTypeTreeCT(arg1: CConcreteType, ctx: &Context) -> CTypeTreeRef {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn EnzymeNewTypeTreeTR(arg1: CTypeTreeRef) -> CTypeTreeRef {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn EnzymeFreeTypeTree(CTT: CTypeTreeRef) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn EnzymeMergeTypeTree(arg1: CTypeTreeRef, arg2: CTypeTreeRef) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn EnzymeTypeTreeOnlyEq(arg1: CTypeTreeRef, pos: i64) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn EnzymeTypeTreeData0Eq(arg1: CTypeTreeRef) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn EnzymeTypeTreeShiftIndiciesEq(
|
||||
arg1: CTypeTreeRef,
|
||||
data_layout: *const c_char,
|
||||
offset: i64,
|
||||
max_size: i64,
|
||||
add_offset: u64,
|
||||
) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn EnzymeTypeTreeInsertEq(
|
||||
CTT: CTypeTreeRef,
|
||||
indices: *const i64,
|
||||
len: usize,
|
||||
ct: CConcreteType,
|
||||
ctx: &Context,
|
||||
) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn EnzymeTypeTreeToString(arg1: CTypeTreeRef) -> *const c_char {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn EnzymeTypeTreeToStringFree(arg1: *const c_char) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub(crate) fn set_inline(val: bool) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
@ -169,3 +287,89 @@ pub(crate) mod Fallback_AD {
|
|||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeTree {
|
||||
pub(crate) fn new() -> TypeTree {
|
||||
let inner = unsafe { EnzymeNewTypeTree() };
|
||||
TypeTree { inner }
|
||||
}
|
||||
|
||||
pub(crate) fn from_type(t: CConcreteType, ctx: &Context) -> TypeTree {
|
||||
let inner = unsafe { EnzymeNewTypeTreeCT(t, ctx) };
|
||||
TypeTree { inner }
|
||||
}
|
||||
|
||||
pub(crate) fn merge(self, other: Self) -> Self {
|
||||
unsafe {
|
||||
EnzymeMergeTypeTree(self.inner, other.inner);
|
||||
}
|
||||
drop(other);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn shift(
|
||||
self,
|
||||
layout: &str,
|
||||
offset: isize,
|
||||
max_size: isize,
|
||||
add_offset: usize,
|
||||
) -> Self {
|
||||
let layout = std::ffi::CString::new(layout).unwrap();
|
||||
|
||||
unsafe {
|
||||
EnzymeTypeTreeShiftIndiciesEq(
|
||||
self.inner,
|
||||
layout.as_ptr(),
|
||||
offset as i64,
|
||||
max_size as i64,
|
||||
add_offset as u64,
|
||||
);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, indices: &[i64], ct: CConcreteType, ctx: &Context) {
|
||||
unsafe {
|
||||
EnzymeTypeTreeInsertEq(self.inner, indices.as_ptr(), indices.len(), ct, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for TypeTree {
|
||||
fn clone(&self) -> Self {
|
||||
let inner = unsafe { EnzymeNewTypeTreeTR(self.inner) };
|
||||
TypeTree { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TypeTree {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let ptr = unsafe { EnzymeTypeTreeToString(self.inner) };
|
||||
let cstr = unsafe { std::ffi::CStr::from_ptr(ptr) };
|
||||
match cstr.to_str() {
|
||||
Ok(x) => write!(f, "{}", x)?,
|
||||
Err(err) => write!(f, "could not parse: {}", err)?,
|
||||
}
|
||||
|
||||
// delete C string pointer
|
||||
unsafe {
|
||||
EnzymeTypeTreeToStringFree(ptr);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for TypeTree {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
<Self as std::fmt::Display>::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TypeTree {
|
||||
fn drop(&mut self) {
|
||||
unsafe { EnzymeFreeTypeTree(self.inner) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ use rustc_target::spec::SymbolVisibility;
|
|||
use super::RustString;
|
||||
use super::debuginfo::{
|
||||
DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags,
|
||||
DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram, DISubrange,
|
||||
DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind, DebugNameTableKind,
|
||||
DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram,
|
||||
DITemplateTypeParameter, DIType, DebugEmissionKind, DebugNameTableKind,
|
||||
};
|
||||
use crate::llvm;
|
||||
|
||||
|
|
@ -807,6 +807,8 @@ unsafe extern "C" {
|
|||
pub(crate) type Metadata;
|
||||
pub(crate) type BasicBlock;
|
||||
pub(crate) type Comdat;
|
||||
/// `&'ll DbgRecord` represents `LLVMDbgRecordRef`.
|
||||
pub(crate) type DbgRecord;
|
||||
}
|
||||
#[repr(C)]
|
||||
pub(crate) struct Builder<'a>(InvariantOpaque<'a>);
|
||||
|
|
@ -891,7 +893,6 @@ pub(crate) mod debuginfo {
|
|||
pub(crate) type DIVariable = DIDescriptor;
|
||||
pub(crate) type DIGlobalVariableExpression = DIDescriptor;
|
||||
pub(crate) type DIArray = DIDescriptor;
|
||||
pub(crate) type DISubrange = DIDescriptor;
|
||||
pub(crate) type DIEnumerator = DIDescriptor;
|
||||
pub(crate) type DITemplateTypeParameter = DIDescriptor;
|
||||
|
||||
|
|
@ -1053,6 +1054,8 @@ unsafe extern "C" {
|
|||
SLen: c_uint,
|
||||
) -> MetadataKindId;
|
||||
|
||||
pub(crate) fn LLVMDisposeTargetMachine(T: ptr::NonNull<TargetMachine>);
|
||||
|
||||
// Create modules.
|
||||
pub(crate) fn LLVMModuleCreateWithNameInContext(
|
||||
ModuleID: *const c_char,
|
||||
|
|
@ -1990,6 +1993,59 @@ unsafe extern "C" {
|
|||
Scope: Option<&'ll Metadata>,
|
||||
AlignInBits: u32, // (optional; default is 0)
|
||||
) -> &'ll Metadata;
|
||||
|
||||
pub(crate) fn LLVMDIBuilderGetOrCreateSubrange<'ll>(
|
||||
Builder: &DIBuilder<'ll>,
|
||||
LowerBound: i64,
|
||||
Count: i64,
|
||||
) -> &'ll Metadata;
|
||||
|
||||
pub(crate) fn LLVMDIBuilderGetOrCreateArray<'ll>(
|
||||
Builder: &DIBuilder<'ll>,
|
||||
Data: *const Option<&'ll Metadata>,
|
||||
NumElements: size_t,
|
||||
) -> &'ll Metadata;
|
||||
|
||||
pub(crate) fn LLVMDIBuilderCreateExpression<'ll>(
|
||||
Builder: &DIBuilder<'ll>,
|
||||
Addr: *const u64,
|
||||
Length: size_t,
|
||||
) -> &'ll Metadata;
|
||||
|
||||
pub(crate) fn LLVMDIBuilderInsertDeclareRecordAtEnd<'ll>(
|
||||
Builder: &DIBuilder<'ll>,
|
||||
Storage: &'ll Value,
|
||||
VarInfo: &'ll Metadata,
|
||||
Expr: &'ll Metadata,
|
||||
DebugLoc: &'ll Metadata,
|
||||
Block: &'ll BasicBlock,
|
||||
) -> &'ll DbgRecord;
|
||||
|
||||
pub(crate) fn LLVMDIBuilderCreateAutoVariable<'ll>(
|
||||
Builder: &DIBuilder<'ll>,
|
||||
Scope: &'ll Metadata,
|
||||
Name: *const c_uchar, // See "PTR_LEN_STR".
|
||||
NameLen: size_t,
|
||||
File: &'ll Metadata,
|
||||
LineNo: c_uint,
|
||||
Ty: &'ll Metadata,
|
||||
AlwaysPreserve: llvm::Bool, // "If true, this descriptor will survive optimizations."
|
||||
Flags: DIFlags,
|
||||
AlignInBits: u32,
|
||||
) -> &'ll Metadata;
|
||||
|
||||
pub(crate) fn LLVMDIBuilderCreateParameterVariable<'ll>(
|
||||
Builder: &DIBuilder<'ll>,
|
||||
Scope: &'ll Metadata,
|
||||
Name: *const c_uchar, // See "PTR_LEN_STR".
|
||||
NameLen: size_t,
|
||||
ArgNo: c_uint,
|
||||
File: &'ll Metadata,
|
||||
LineNo: c_uint,
|
||||
Ty: &'ll Metadata,
|
||||
AlwaysPreserve: llvm::Bool, // "If true, this descriptor will survive optimizations."
|
||||
Flags: DIFlags,
|
||||
) -> &'ll Metadata;
|
||||
}
|
||||
|
||||
#[link(name = "llvm-wrapper", kind = "static")]
|
||||
|
|
@ -2356,43 +2412,6 @@ unsafe extern "C" {
|
|||
AlignInBits: u32,
|
||||
) -> &'a DIGlobalVariableExpression;
|
||||
|
||||
pub(crate) fn LLVMRustDIBuilderCreateVariable<'a>(
|
||||
Builder: &DIBuilder<'a>,
|
||||
Tag: c_uint,
|
||||
Scope: &'a DIDescriptor,
|
||||
Name: *const c_char,
|
||||
NameLen: size_t,
|
||||
File: &'a DIFile,
|
||||
LineNo: c_uint,
|
||||
Ty: &'a DIType,
|
||||
AlwaysPreserve: bool,
|
||||
Flags: DIFlags,
|
||||
ArgNo: c_uint,
|
||||
AlignInBits: u32,
|
||||
) -> &'a DIVariable;
|
||||
|
||||
pub(crate) fn LLVMRustDIBuilderGetOrCreateSubrange<'a>(
|
||||
Builder: &DIBuilder<'a>,
|
||||
Lo: i64,
|
||||
Count: i64,
|
||||
) -> &'a DISubrange;
|
||||
|
||||
pub(crate) fn LLVMRustDIBuilderGetOrCreateArray<'a>(
|
||||
Builder: &DIBuilder<'a>,
|
||||
Ptr: *const Option<&'a DIDescriptor>,
|
||||
Count: c_uint,
|
||||
) -> &'a DIArray;
|
||||
|
||||
pub(crate) fn LLVMRustDIBuilderInsertDeclareAtEnd<'a>(
|
||||
Builder: &DIBuilder<'a>,
|
||||
Val: &'a Value,
|
||||
VarInfo: &'a DIVariable,
|
||||
AddrOps: *const u64,
|
||||
AddrOpsCount: c_uint,
|
||||
DL: &'a DILocation,
|
||||
InsertAtEnd: &'a BasicBlock,
|
||||
);
|
||||
|
||||
pub(crate) fn LLVMRustDIBuilderCreateEnumerator<'a>(
|
||||
Builder: &DIBuilder<'a>,
|
||||
Name: *const c_char,
|
||||
|
|
@ -2499,7 +2518,6 @@ unsafe extern "C" {
|
|||
UseWasmEH: bool,
|
||||
) -> *mut TargetMachine;
|
||||
|
||||
pub(crate) fn LLVMRustDisposeTargetMachine(T: *mut TargetMachine);
|
||||
pub(crate) fn LLVMRustAddLibraryInfo<'a>(
|
||||
PM: &PassManager<'a>,
|
||||
M: &'a Module,
|
||||
|
|
|
|||
122
compiler/rustc_codegen_llvm/src/typetree.rs
Normal file
122
compiler/rustc_codegen_llvm/src/typetree.rs
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
use rustc_ast::expand::typetree::FncTree;
|
||||
#[cfg(feature = "llvm_enzyme")]
|
||||
use {
|
||||
crate::attributes,
|
||||
rustc_ast::expand::typetree::TypeTree as RustTypeTree,
|
||||
std::ffi::{CString, c_char, c_uint},
|
||||
};
|
||||
|
||||
use crate::llvm::{self, Value};
|
||||
|
||||
#[cfg(feature = "llvm_enzyme")]
|
||||
fn to_enzyme_typetree(
|
||||
rust_typetree: RustTypeTree,
|
||||
_data_layout: &str,
|
||||
llcx: &llvm::Context,
|
||||
) -> llvm::TypeTree {
|
||||
let mut enzyme_tt = llvm::TypeTree::new();
|
||||
process_typetree_recursive(&mut enzyme_tt, &rust_typetree, &[], llcx);
|
||||
enzyme_tt
|
||||
}
|
||||
#[cfg(feature = "llvm_enzyme")]
|
||||
fn process_typetree_recursive(
|
||||
enzyme_tt: &mut llvm::TypeTree,
|
||||
rust_typetree: &RustTypeTree,
|
||||
parent_indices: &[i64],
|
||||
llcx: &llvm::Context,
|
||||
) {
|
||||
for rust_type in &rust_typetree.0 {
|
||||
let concrete_type = match rust_type.kind {
|
||||
rustc_ast::expand::typetree::Kind::Anything => llvm::CConcreteType::DT_Anything,
|
||||
rustc_ast::expand::typetree::Kind::Integer => llvm::CConcreteType::DT_Integer,
|
||||
rustc_ast::expand::typetree::Kind::Pointer => llvm::CConcreteType::DT_Pointer,
|
||||
rustc_ast::expand::typetree::Kind::Half => llvm::CConcreteType::DT_Half,
|
||||
rustc_ast::expand::typetree::Kind::Float => llvm::CConcreteType::DT_Float,
|
||||
rustc_ast::expand::typetree::Kind::Double => llvm::CConcreteType::DT_Double,
|
||||
rustc_ast::expand::typetree::Kind::F128 => llvm::CConcreteType::DT_FP128,
|
||||
rustc_ast::expand::typetree::Kind::Unknown => llvm::CConcreteType::DT_Unknown,
|
||||
};
|
||||
|
||||
let mut indices = parent_indices.to_vec();
|
||||
if !parent_indices.is_empty() {
|
||||
indices.push(rust_type.offset as i64);
|
||||
} else if rust_type.offset == -1 {
|
||||
indices.push(-1);
|
||||
} else {
|
||||
indices.push(rust_type.offset as i64);
|
||||
}
|
||||
|
||||
enzyme_tt.insert(&indices, concrete_type, llcx);
|
||||
|
||||
if rust_type.kind == rustc_ast::expand::typetree::Kind::Pointer
|
||||
&& !rust_type.child.0.is_empty()
|
||||
{
|
||||
process_typetree_recursive(enzyme_tt, &rust_type.child, &indices, llcx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "llvm_enzyme")]
|
||||
pub(crate) fn add_tt<'ll>(
|
||||
llmod: &'ll llvm::Module,
|
||||
llcx: &'ll llvm::Context,
|
||||
fn_def: &'ll Value,
|
||||
tt: FncTree,
|
||||
) {
|
||||
let inputs = tt.args;
|
||||
let ret_tt: RustTypeTree = tt.ret;
|
||||
|
||||
let llvm_data_layout: *const c_char = unsafe { llvm::LLVMGetDataLayoutStr(&*llmod) };
|
||||
let llvm_data_layout =
|
||||
std::str::from_utf8(unsafe { std::ffi::CStr::from_ptr(llvm_data_layout) }.to_bytes())
|
||||
.expect("got a non-UTF8 data-layout from LLVM");
|
||||
|
||||
let attr_name = "enzyme_type";
|
||||
let c_attr_name = CString::new(attr_name).unwrap();
|
||||
|
||||
for (i, input) in inputs.iter().enumerate() {
|
||||
unsafe {
|
||||
let enzyme_tt = to_enzyme_typetree(input.clone(), llvm_data_layout, llcx);
|
||||
let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner);
|
||||
let c_str = std::ffi::CStr::from_ptr(c_str);
|
||||
|
||||
let attr = llvm::LLVMCreateStringAttribute(
|
||||
llcx,
|
||||
c_attr_name.as_ptr(),
|
||||
c_attr_name.as_bytes().len() as c_uint,
|
||||
c_str.as_ptr(),
|
||||
c_str.to_bytes().len() as c_uint,
|
||||
);
|
||||
|
||||
attributes::apply_to_llfn(fn_def, llvm::AttributePlace::Argument(i as u32), &[attr]);
|
||||
llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let enzyme_tt = to_enzyme_typetree(ret_tt, llvm_data_layout, llcx);
|
||||
let c_str = llvm::EnzymeTypeTreeToString(enzyme_tt.inner);
|
||||
let c_str = std::ffi::CStr::from_ptr(c_str);
|
||||
|
||||
let ret_attr = llvm::LLVMCreateStringAttribute(
|
||||
llcx,
|
||||
c_attr_name.as_ptr(),
|
||||
c_attr_name.as_bytes().len() as c_uint,
|
||||
c_str.as_ptr(),
|
||||
c_str.to_bytes().len() as c_uint,
|
||||
);
|
||||
|
||||
attributes::apply_to_llfn(fn_def, llvm::AttributePlace::ReturnValue, &[ret_attr]);
|
||||
llvm::EnzymeTypeTreeToStringFree(c_str.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "llvm_enzyme"))]
|
||||
pub(crate) fn add_tt<'ll>(
|
||||
_llmod: &'ll llvm::Module,
|
||||
_llcx: &'ll llvm::Context,
|
||||
_fn_def: &'ll Value,
|
||||
_tt: FncTree,
|
||||
) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
@ -738,6 +738,7 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>(
|
|||
src_align,
|
||||
bx.const_u32(layout.layout.size().bytes() as u32),
|
||||
MemFlags::empty(),
|
||||
None,
|
||||
);
|
||||
tmp
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
|||
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
|
||||
use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_hir::attrs::OptimizeAttr;
|
||||
use rustc_hir::attrs::{DebuggerVisualizerType, OptimizeAttr};
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{ItemId, Target};
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
use rustc_middle::middle::dependency_format::Dependencies;
|
||||
use rustc_middle::middle::exported_symbols::{self, SymbolExportKind};
|
||||
use rustc_middle::middle::lang_items;
|
||||
|
|
|
|||
|
|
@ -1626,6 +1626,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
align,
|
||||
bx.const_usize(copy_bytes),
|
||||
MemFlags::empty(),
|
||||
None,
|
||||
);
|
||||
// ...and then load it with the ABI type.
|
||||
llval = load_cast(bx, cast, llscratch, scratch_align);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
if allow_overlap {
|
||||
bx.memmove(dst, align, src, align, size, flags);
|
||||
} else {
|
||||
bx.memcpy(dst, align, src, align, size, flags);
|
||||
bx.memcpy(dst, align, src, align, size, flags, None);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let align = pointee_layout.align;
|
||||
let dst = dst_val.immediate();
|
||||
let src = src_val.immediate();
|
||||
bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty());
|
||||
bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty(), None);
|
||||
}
|
||||
mir::StatementKind::FakeRead(..)
|
||||
| mir::StatementKind::Retag { .. }
|
||||
|
|
|
|||
|
|
@ -451,6 +451,7 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
src_align: Align,
|
||||
size: Self::Value,
|
||||
flags: MemFlags,
|
||||
tt: Option<rustc_ast::expand::typetree::FncTree>,
|
||||
);
|
||||
fn memmove(
|
||||
&mut self,
|
||||
|
|
@ -507,7 +508,7 @@ pub trait BuilderMethods<'a, 'tcx>:
|
|||
temp.val.store_with_flags(self, dst.with_type(layout), flags);
|
||||
} else if !layout.is_zst() {
|
||||
let bytes = self.const_usize(layout.size.bytes());
|
||||
self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags);
|
||||
self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags, None);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -636,6 +636,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
dest,
|
||||
rustc_apfloat::Round::NearestTiesToEven,
|
||||
)?,
|
||||
sym::fmaf16 => self.fma_intrinsic::<Half>(args, dest)?,
|
||||
sym::fmaf32 => self.fma_intrinsic::<Single>(args, dest)?,
|
||||
sym::fmaf64 => self.fma_intrinsic::<Double>(args, dest)?,
|
||||
sym::fmaf128 => self.fma_intrinsic::<Quad>(args, dest)?,
|
||||
sym::fmuladdf16 => self.float_muladd_intrinsic::<Half>(args, dest)?,
|
||||
sym::fmuladdf32 => self.float_muladd_intrinsic::<Single>(args, dest)?,
|
||||
sym::fmuladdf64 => self.float_muladd_intrinsic::<Double>(args, dest)?,
|
||||
sym::fmuladdf128 => self.float_muladd_intrinsic::<Quad>(args, dest)?,
|
||||
|
||||
// Unsupported intrinsic: skip the return_to_block below.
|
||||
_ => return interp_ok(false),
|
||||
|
|
@ -1035,4 +1043,42 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
self.write_scalar(res, dest)?;
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
fn fma_intrinsic<F>(
|
||||
&mut self,
|
||||
args: &[OpTy<'tcx, M::Provenance>],
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, ()>
|
||||
where
|
||||
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
|
||||
{
|
||||
let a: F = self.read_scalar(&args[0])?.to_float()?;
|
||||
let b: F = self.read_scalar(&args[1])?.to_float()?;
|
||||
let c: F = self.read_scalar(&args[2])?.to_float()?;
|
||||
|
||||
let res = a.mul_add(b, c).value;
|
||||
let res = self.adjust_nan(res, &[a, b, c]);
|
||||
self.write_scalar(res, dest)?;
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
fn float_muladd_intrinsic<F>(
|
||||
&mut self,
|
||||
args: &[OpTy<'tcx, M::Provenance>],
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, ()>
|
||||
where
|
||||
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
|
||||
{
|
||||
let a: F = self.read_scalar(&args[0])?.to_float()?;
|
||||
let b: F = self.read_scalar(&args[1])?.to_float()?;
|
||||
let c: F = self.read_scalar(&args[2])?.to_float()?;
|
||||
|
||||
let fuse = M::float_fuse_mul_add(self);
|
||||
|
||||
let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value };
|
||||
let res = self.adjust_nan(res, &[a, b, c]);
|
||||
self.write_scalar(res, dest)?;
|
||||
interp_ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -289,6 +289,9 @@ pub trait Machine<'tcx>: Sized {
|
|||
a
|
||||
}
|
||||
|
||||
/// Determines whether the `fmuladd` intrinsics fuse the multiply-add or use separate operations.
|
||||
fn float_fuse_mul_add(_ecx: &mut InterpCx<'tcx, Self>) -> bool;
|
||||
|
||||
/// Called before a basic block terminator is executed.
|
||||
#[inline]
|
||||
fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
|
||||
|
|
@ -672,6 +675,11 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
|
|||
match fn_val {}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn float_fuse_mul_add(_ecx: &mut InterpCx<$tcx, Self>) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ub_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> {
|
||||
// We can't look at `tcx.sess` here as that can differ across crates, which can lead to
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![cfg_attr(bootstrap, feature(strict_overflow_ops))]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(array_try_map)]
|
||||
#![feature(assert_matches)]
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ pub(crate) fn const_caller_location_provider(
|
|||
trace!("const_caller_location: {}:{}:{}", file, line, col);
|
||||
let mut ecx = mk_eval_cx_to_read_const_val(
|
||||
tcx,
|
||||
rustc_span::DUMMY_SP, // FIXME: use a proper span here?
|
||||
rustc_span::DUMMY_SP, // This interpreter cannot fail, so the span is irrelevant.
|
||||
ty::TypingEnv::fully_monomorphized(),
|
||||
CanAccessMutGlobal::No,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -324,16 +324,16 @@ pub trait BangProcMacro {
|
|||
|
||||
impl<F> BangProcMacro for F
|
||||
where
|
||||
F: Fn(TokenStream) -> TokenStream,
|
||||
F: Fn(&mut ExtCtxt<'_>, Span, TokenStream) -> Result<TokenStream, ErrorGuaranteed>,
|
||||
{
|
||||
fn expand<'cx>(
|
||||
&self,
|
||||
_ecx: &'cx mut ExtCtxt<'_>,
|
||||
_span: Span,
|
||||
ecx: &'cx mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
ts: TokenStream,
|
||||
) -> Result<TokenStream, ErrorGuaranteed> {
|
||||
// FIXME setup implicit context in TLS before calling self.
|
||||
Ok(self(ts))
|
||||
self(ecx, span, ts)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -999,17 +999,14 @@ impl SyntaxExtension {
|
|||
|
||||
/// A dummy bang macro `foo!()`.
|
||||
pub fn dummy_bang(edition: Edition) -> SyntaxExtension {
|
||||
fn expander<'cx>(
|
||||
cx: &'cx mut ExtCtxt<'_>,
|
||||
fn expand(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
_: TokenStream,
|
||||
) -> MacroExpanderResult<'cx> {
|
||||
ExpandResult::Ready(DummyResult::any(
|
||||
span,
|
||||
cx.dcx().span_delayed_bug(span, "expanded a dummy bang macro"),
|
||||
))
|
||||
_ts: TokenStream,
|
||||
) -> Result<TokenStream, ErrorGuaranteed> {
|
||||
Err(ecx.dcx().span_delayed_bug(span, "expanded a dummy bang macro"))
|
||||
}
|
||||
SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Arc::new(expander)), edition)
|
||||
SyntaxExtension::default(SyntaxExtensionKind::Bang(Arc::new(expand)), edition)
|
||||
}
|
||||
|
||||
/// A dummy derive macro `#[derive(Foo)]`.
|
||||
|
|
|
|||
|
|
@ -971,7 +971,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
});
|
||||
}
|
||||
},
|
||||
SyntaxExtensionKind::LegacyBang(..) => {
|
||||
SyntaxExtensionKind::Bang(..) => {
|
||||
let msg = "expanded a dummy glob delegation";
|
||||
let guar = self.cx.dcx().span_delayed_bug(span, msg);
|
||||
return ExpandResult::Ready(fragment_kind.dummy(span, guar));
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ use super::diagnostics::{FailedMacro, failed_to_match_macro};
|
|||
use super::macro_parser::{NamedMatches, NamedParseResult};
|
||||
use super::{SequenceRepetition, diagnostics};
|
||||
use crate::base::{
|
||||
AttrProcMacro, DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult,
|
||||
SyntaxExtension, SyntaxExtensionKind, TTMacroExpander,
|
||||
AttrProcMacro, BangProcMacro, DummyResult, ExpandResult, ExtCtxt, MacResult,
|
||||
MacroExpanderResult, SyntaxExtension, SyntaxExtensionKind, TTMacroExpander,
|
||||
};
|
||||
use crate::errors;
|
||||
use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment};
|
||||
|
|
@ -267,16 +267,16 @@ impl AttrProcMacro for MacroRulesMacroExpander {
|
|||
}
|
||||
}
|
||||
|
||||
struct DummyExpander(ErrorGuaranteed);
|
||||
struct DummyBang(ErrorGuaranteed);
|
||||
|
||||
impl TTMacroExpander for DummyExpander {
|
||||
impl BangProcMacro for DummyBang {
|
||||
fn expand<'cx>(
|
||||
&self,
|
||||
_: &'cx mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
_: Span,
|
||||
_: TokenStream,
|
||||
) -> ExpandResult<Box<dyn MacResult + 'cx>, ()> {
|
||||
ExpandResult::Ready(DummyResult::any(span, self.0))
|
||||
) -> Result<TokenStream, ErrorGuaranteed> {
|
||||
Err(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -664,7 +664,7 @@ pub fn compile_declarative_macro(
|
|||
SyntaxExtension::new(sess, kind, span, Vec::new(), edition, ident.name, attrs, is_local)
|
||||
};
|
||||
let dummy_syn_ext =
|
||||
|guar| (mk_syn_ext(SyntaxExtensionKind::LegacyBang(Arc::new(DummyExpander(guar)))), 0);
|
||||
|guar| (mk_syn_ext(SyntaxExtensionKind::Bang(Arc::new(DummyBang(guar)))), 0);
|
||||
|
||||
let macro_rules = macro_def.macro_rules;
|
||||
let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) };
|
||||
|
|
@ -894,12 +894,12 @@ fn check_redundant_vis_repetition(
|
|||
seq: &SequenceRepetition,
|
||||
span: &DelimSpan,
|
||||
) {
|
||||
let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne;
|
||||
let is_vis = seq.tts.first().map_or(false, |tt| {
|
||||
matches!(tt, mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. })
|
||||
});
|
||||
|
||||
if is_vis && is_zero_or_one {
|
||||
if seq.kleene.op == KleeneOp::ZeroOrOne
|
||||
&& matches!(
|
||||
seq.tts.first(),
|
||||
Some(mbe::TokenTree::MetaVarDecl { kind: NonterminalKind::Vis, .. })
|
||||
)
|
||||
{
|
||||
err.note("a `vis` fragment can already be empty");
|
||||
err.multipart_suggestion(
|
||||
"remove the `$(` and `)?`",
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ declare_features! (
|
|||
(accepted, extended_key_value_attributes, "1.54.0", Some(78835)),
|
||||
/// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions
|
||||
/// for functions with varargs.
|
||||
(accepted, extended_varargs_abi_support, "CURRENT_RUSTC_VERSION", Some(100189)),
|
||||
(accepted, extended_varargs_abi_support, "1.91.0", Some(100189)),
|
||||
/// Allows resolving absolute paths as paths from other crates.
|
||||
(accepted, extern_absolute_paths, "1.30.0", Some(44660)),
|
||||
/// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude.
|
||||
|
|
@ -400,7 +400,7 @@ declare_features! (
|
|||
/// Allows use of `&foo[a..b]` as a slicing syntax.
|
||||
(accepted, slicing_syntax, "1.0.0", None),
|
||||
/// Allows use of `sse4a` target feature.
|
||||
(accepted, sse4a_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)),
|
||||
(accepted, sse4a_target_feature, "1.91.0", Some(44839)),
|
||||
/// Allows elision of `'static` lifetimes in `static`s and `const`s.
|
||||
(accepted, static_in_const, "1.17.0", Some(35897)),
|
||||
/// Allows the definition recursive static items.
|
||||
|
|
@ -414,7 +414,7 @@ declare_features! (
|
|||
/// Allows the use of `#[target_feature]` on safe functions.
|
||||
(accepted, target_feature_11, "1.86.0", Some(69098)),
|
||||
/// Allows use of `tbm` target feature.
|
||||
(accepted, tbm_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)),
|
||||
(accepted, tbm_target_feature, "1.91.0", Some(44839)),
|
||||
/// Allows `fn main()` with return types which implements `Termination` (RFC 1937).
|
||||
(accepted, termination_trait, "1.26.0", Some(43301)),
|
||||
/// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937).
|
||||
|
|
|
|||
|
|
@ -1211,6 +1211,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
|
||||
niche optimizations in the standard library",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_simd_monomorphize_lane_limit, Normal, template!(NameValueStr: "N"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"the `#[rustc_simd_monomorphize_lane_limit]` attribute is just used by std::simd \
|
||||
for better error messages",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
|
|
|
|||
|
|
@ -101,6 +101,10 @@ declare_features! (
|
|||
Some("never properly implemented; requires significant design work"), 127655),
|
||||
/// Allows deriving traits as per `SmartPointer` specification
|
||||
(removed, derive_smart_pointer, "1.84.0", Some(123430), Some("replaced by `CoercePointee`"), 131284),
|
||||
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
|
||||
(removed, doc_auto_cfg, "1.58.0", Some(43781), Some("merged into `doc_cfg`"), 138907),
|
||||
/// Allows `#[doc(cfg_hide(...))]`.
|
||||
(removed, doc_cfg_hide, "1.57.0", Some(43781), Some("merged into `doc_cfg`"), 138907),
|
||||
/// Allows using `#[doc(keyword = "...")]`.
|
||||
(removed, doc_keyword, "1.58.0", Some(51315),
|
||||
Some("merged into `#![feature(rustdoc_internals)]`"), 90420),
|
||||
|
|
@ -192,7 +196,7 @@ declare_features! (
|
|||
(removed, no_debug, "1.43.0", Some(29721), Some("removed due to lack of demand"), 69667),
|
||||
// Allows the use of `no_sanitize` attribute.
|
||||
/// The feature was renamed to `sanitize` and the attribute to `#[sanitize(xyz = "on|off")]`
|
||||
(removed, no_sanitize, "CURRENT_RUSTC_VERSION", Some(39699), Some(r#"renamed to sanitize(xyz = "on|off")"#), 142681),
|
||||
(removed, no_sanitize, "1.91.0", Some(39699), Some(r#"renamed to sanitize(xyz = "on|off")"#), 142681),
|
||||
/// Note: this feature was previously recorded in a separate
|
||||
/// `STABLE_REMOVED` list because it, uniquely, was once stable but was
|
||||
/// then removed. But there was no utility storing it separately, so now
|
||||
|
|
@ -203,7 +207,7 @@ declare_features! (
|
|||
(removed, object_safe_for_dispatch, "1.83.0", Some(43561),
|
||||
Some("renamed to `dyn_compatible_for_dispatch`"), 131511),
|
||||
/// Allows using `#[omit_gdb_pretty_printer_section]`.
|
||||
(removed, omit_gdb_pretty_printer_section, "CURRENT_RUSTC_VERSION", None, None, 144738),
|
||||
(removed, omit_gdb_pretty_printer_section, "1.91.0", None, None, 144738),
|
||||
/// Allows using `#[on_unimplemented(..)]` on traits.
|
||||
/// (Moved to `rustc_attrs`.)
|
||||
(removed, on_unimplemented, "1.40.0", None, None, 65794),
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ declare_features! (
|
|||
(unstable, m68k_target_feature, "1.85.0", Some(134328)),
|
||||
(unstable, mips_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, movrs_target_feature, "1.88.0", Some(137976)),
|
||||
(unstable, nvptx_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)),
|
||||
(unstable, nvptx_target_feature, "1.91.0", Some(44839)),
|
||||
(unstable, powerpc_target_feature, "1.27.0", Some(44839)),
|
||||
(unstable, prfchw_target_feature, "1.78.0", Some(44839)),
|
||||
(unstable, riscv_target_feature, "1.45.0", Some(44839)),
|
||||
|
|
@ -471,17 +471,13 @@ declare_features! (
|
|||
/// Allows deref patterns.
|
||||
(incomplete, deref_patterns, "1.79.0", Some(87121)),
|
||||
/// Allows deriving the From trait on single-field structs.
|
||||
(unstable, derive_from, "CURRENT_RUSTC_VERSION", Some(144889)),
|
||||
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
|
||||
(unstable, doc_auto_cfg, "1.58.0", Some(43781)),
|
||||
(unstable, derive_from, "1.91.0", Some(144889)),
|
||||
/// Allows `#[doc(cfg(...))]`.
|
||||
(unstable, doc_cfg, "1.21.0", Some(43781)),
|
||||
/// Allows `#[doc(cfg_hide(...))]`.
|
||||
(unstable, doc_cfg_hide, "1.57.0", Some(43781)),
|
||||
/// Allows `#[doc(masked)]`.
|
||||
(unstable, doc_masked, "1.21.0", Some(44027)),
|
||||
/// Allows features to allow target_feature to better interact with traits.
|
||||
(incomplete, effective_target_features, "CURRENT_RUSTC_VERSION", Some(143352)),
|
||||
(incomplete, effective_target_features, "1.91.0", Some(143352)),
|
||||
/// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }`
|
||||
(incomplete, ergonomic_clones, "1.87.0", Some(132290)),
|
||||
/// Allows exhaustive pattern matching on types that contain uninhabited types.
|
||||
|
|
@ -554,9 +550,9 @@ declare_features! (
|
|||
/// Allows fused `loop`/`match` for direct intraprocedural jumps.
|
||||
(incomplete, loop_match, "1.90.0", Some(132306)),
|
||||
/// Allow `macro_rules!` attribute rules
|
||||
(unstable, macro_attr, "CURRENT_RUSTC_VERSION", Some(83527)),
|
||||
(unstable, macro_attr, "1.91.0", Some(143547)),
|
||||
/// Allow `macro_rules!` derive rules
|
||||
(unstable, macro_derive, "CURRENT_RUSTC_VERSION", Some(143549)),
|
||||
(unstable, macro_derive, "1.91.0", Some(143549)),
|
||||
/// Give access to additional metadata about declarative macro meta-variables.
|
||||
(unstable, macro_metavar_expr, "1.61.0", Some(83527)),
|
||||
/// Provides a way to concatenate identifiers using metavariable expressions.
|
||||
|
|
@ -613,7 +609,7 @@ declare_features! (
|
|||
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
|
||||
/// Allows the use of raw-dylibs on ELF platforms
|
||||
(incomplete, raw_dylib_elf, "1.87.0", Some(135694)),
|
||||
(unstable, reborrow, "CURRENT_RUSTC_VERSION", Some(145612)),
|
||||
(unstable, reborrow, "1.91.0", Some(145612)),
|
||||
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
|
||||
(incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)),
|
||||
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant
|
||||
|
|
@ -627,13 +623,13 @@ declare_features! (
|
|||
/// Allows `extern "rust-cold"`.
|
||||
(unstable, rust_cold_cc, "1.63.0", Some(97544)),
|
||||
/// Allows the use of the `sanitize` attribute.
|
||||
(unstable, sanitize, "CURRENT_RUSTC_VERSION", Some(39699)),
|
||||
(unstable, sanitize, "1.91.0", Some(39699)),
|
||||
/// Allows the use of SIMD types in functions declared in `extern` blocks.
|
||||
(unstable, simd_ffi, "1.0.0", Some(27731)),
|
||||
/// Allows specialization of implementations (RFC 1210).
|
||||
(incomplete, specialization, "1.7.0", Some(31844)),
|
||||
/// Allows using `#[rustc_align_static(...)]` on static items.
|
||||
(unstable, static_align, "CURRENT_RUSTC_VERSION", Some(146177)),
|
||||
(unstable, static_align, "1.91.0", Some(146177)),
|
||||
/// Allows attributes on expressions and non-item statements.
|
||||
(unstable, stmt_expr_attributes, "1.6.0", Some(15701)),
|
||||
/// Allows lints part of the strict provenance effort.
|
||||
|
|
@ -645,7 +641,7 @@ declare_features! (
|
|||
/// Allows subtrait items to shadow supertrait items.
|
||||
(unstable, supertrait_item_shadowing, "1.86.0", Some(89151)),
|
||||
/// Allows the use of target_feature when a function is marked inline(always).
|
||||
(unstable, target_feature_inline_always, "CURRENT_RUSTC_VERSION", Some(145574)),
|
||||
(unstable, target_feature_inline_always, "1.91.0", Some(145574)),
|
||||
/// Allows using `#[thread_local]` on `static` items.
|
||||
(unstable, thread_local, "1.0.0", Some(29594)),
|
||||
/// Allows defining `trait X = A + B;` alias items.
|
||||
|
|
|
|||
|
|
@ -363,6 +363,20 @@ pub struct LinkEntry {
|
|||
pub import_name_type: Option<(PeImportNameType, Span)>,
|
||||
}
|
||||
|
||||
#[derive(HashStable_Generic, PrintAttribute)]
|
||||
#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
|
||||
pub enum DebuggerVisualizerType {
|
||||
Natvis,
|
||||
GdbPrettyPrinter,
|
||||
}
|
||||
|
||||
#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
|
||||
pub struct DebugVisualizer {
|
||||
pub span: Span,
|
||||
pub visualizer_type: DebuggerVisualizerType,
|
||||
pub path: Symbol,
|
||||
}
|
||||
|
||||
/// Represents parsed *built-in* inert attributes.
|
||||
///
|
||||
/// ## Overview
|
||||
|
|
@ -485,7 +499,10 @@ pub enum AttributeKind {
|
|||
/// Represents `#[custom_mir]`.
|
||||
CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span),
|
||||
|
||||
///Represents `#[rustc_deny_explicit_impl]`.
|
||||
/// Represents `#[debugger_visualizer]`.
|
||||
DebuggerVisualizer(ThinVec<DebugVisualizer>),
|
||||
|
||||
/// Represents `#[rustc_deny_explicit_impl]`.
|
||||
DenyExplicitImpl(Span),
|
||||
|
||||
/// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
|
||||
|
|
@ -651,6 +668,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_object_lifetime_default]`.
|
||||
RustcObjectLifetimeDefault,
|
||||
|
||||
/// Represents `#[rustc_simd_monomorphize_lane_limit = "N"]`.
|
||||
RustcSimdMonomorphizeLaneLimit(Limit),
|
||||
|
||||
/// Represents `#[sanitize]`
|
||||
///
|
||||
/// the on set and off set are distjoint since there's a third option: unset.
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ impl AttributeKind {
|
|||
Coverage(..) => No,
|
||||
CrateName { .. } => No,
|
||||
CustomMir(_, _, _) => Yes,
|
||||
DebuggerVisualizer(..) => No,
|
||||
DenyExplicitImpl(..) => No,
|
||||
Deprecation { .. } => Yes,
|
||||
DoNotImplementViaObject(..) => No,
|
||||
|
|
@ -88,6 +89,7 @@ impl AttributeKind {
|
|||
RustcLayoutScalarValidRangeEnd(..) => Yes,
|
||||
RustcLayoutScalarValidRangeStart(..) => Yes,
|
||||
RustcObjectLifetimeDefault => No,
|
||||
RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
|
||||
Sanitize { .. } => No,
|
||||
ShouldPanic { .. } => No,
|
||||
SkipDuringMethodDispatch { .. } => No,
|
||||
|
|
|
|||
|
|
@ -440,6 +440,7 @@ language_item_table! {
|
|||
|
||||
// Reborrowing related lang-items
|
||||
Reborrow, sym::reborrow, reborrow, Target::Trait, GenericRequirement::Exact(0);
|
||||
CoerceShared, sym::coerce_shared, coerce_shared, Target::Trait, GenericRequirement::Exact(0);
|
||||
}
|
||||
|
||||
/// The requirement imposed on the generics of a lang item
|
||||
|
|
|
|||
|
|
@ -219,6 +219,7 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError
|
|||
}
|
||||
Unknown(..)
|
||||
| SizeOverflow(..)
|
||||
| InvalidSimd { .. }
|
||||
| NormalizationFailure(..)
|
||||
| ReferencesError(..)
|
||||
| Cycle(..) => {
|
||||
|
|
|
|||
|
|
@ -1633,8 +1633,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expected: Expectation<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let rcvr_t = self.check_expr(rcvr);
|
||||
// no need to check for bot/err -- callee does that
|
||||
let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t);
|
||||
let rcvr_t = self.try_structurally_resolve_type(rcvr.span, rcvr_t);
|
||||
|
||||
match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args) {
|
||||
Ok(method) => {
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
// Commit the autoderefs by calling `autoderef` again, but this
|
||||
// time writing the results into the various typeck results.
|
||||
let mut autoderef = self.autoderef(self.call_expr.span, unadjusted_self_ty);
|
||||
let Some((ty, n)) = autoderef.nth(pick.autoderefs) else {
|
||||
let Some((mut target, n)) = autoderef.nth(pick.autoderefs) else {
|
||||
return Ty::new_error_with_message(
|
||||
self.tcx,
|
||||
DUMMY_SP,
|
||||
|
|
@ -182,8 +182,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
assert_eq!(n, pick.autoderefs);
|
||||
|
||||
let mut adjustments = self.adjust_steps(&autoderef);
|
||||
let mut target = self.structurally_resolve_type(autoderef.span(), ty);
|
||||
|
||||
match pick.autoref_or_ptr_adjustment {
|
||||
Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
|
||||
let region = self.next_region_var(RegionVariableOrigin::Autoref(self.span));
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_hir::def::DefKind;
|
|||
use rustc_hir_analysis::autoderef::{self, Autoderef};
|
||||
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
||||
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCauseCode;
|
||||
use rustc_infer::traits::{ObligationCauseCode, PredicateObligation, query};
|
||||
use rustc_middle::middle::stability;
|
||||
use rustc_middle::ty::elaborate::supertrait_def_ids;
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type};
|
||||
|
|
@ -30,7 +30,8 @@ use rustc_span::edit_distance::{
|
|||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
|
||||
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::query::CanonicalTyGoal;
|
||||
use rustc_trait_selection::solve::Goal;
|
||||
use rustc_trait_selection::traits::query::CanonicalMethodAutoderefStepsGoal;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::query::method_autoderef::{
|
||||
CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult,
|
||||
|
|
@ -389,10 +390,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
OP: FnOnce(ProbeContext<'_, 'tcx>) -> Result<R, MethodError<'tcx>>,
|
||||
{
|
||||
let mut orig_values = OriginalQueryValues::default();
|
||||
let query_input = self.canonicalize_query(
|
||||
ParamEnvAnd { param_env: self.param_env, value: self_ty },
|
||||
&mut orig_values,
|
||||
);
|
||||
let predefined_opaques_in_body = if self.next_trait_solver() {
|
||||
self.tcx.mk_predefined_opaques_in_body_from_iter(
|
||||
self.inner.borrow_mut().opaque_types().iter_opaque_types().map(|(k, v)| (k, v.ty)),
|
||||
)
|
||||
} else {
|
||||
ty::List::empty()
|
||||
};
|
||||
let value = query::MethodAutoderefSteps { predefined_opaques_in_body, self_ty };
|
||||
let query_input = self
|
||||
.canonicalize_query(ParamEnvAnd { param_env: self.param_env, value }, &mut orig_values);
|
||||
|
||||
let steps = match mode {
|
||||
Mode::MethodCall => self.tcx.method_autoderef_steps(query_input),
|
||||
|
|
@ -403,13 +410,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// special handling for this "trivial case" is a good idea.
|
||||
|
||||
let infcx = &self.infcx;
|
||||
let (ParamEnvAnd { param_env: _, value: self_ty }, var_values) =
|
||||
let (ParamEnvAnd { param_env: _, value }, var_values) =
|
||||
infcx.instantiate_canonical(span, &query_input.canonical);
|
||||
let query::MethodAutoderefSteps { predefined_opaques_in_body: _, self_ty } = value;
|
||||
debug!(?self_ty, ?query_input, "probe_op: Mode::Path");
|
||||
MethodAutoderefStepsResult {
|
||||
steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
|
||||
self_ty: self
|
||||
.make_query_response_ignoring_pending_obligations(var_values, self_ty),
|
||||
self_ty_is_opaque: false,
|
||||
autoderefs: 0,
|
||||
from_unsafe_deref: false,
|
||||
unsize: false,
|
||||
|
|
@ -479,6 +488,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ty::Infer(ty::TyVar(_)) => {
|
||||
let raw_ptr_call = bad_ty.reached_raw_pointer
|
||||
&& !self.tcx.features().arbitrary_self_types();
|
||||
// FIXME: Ideally we'd use the span of the self-expr here,
|
||||
// not of the method path.
|
||||
let mut err = self.err_ctxt().emit_inference_failure_err(
|
||||
self.body_id,
|
||||
span,
|
||||
|
|
@ -553,12 +564,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
pub(crate) fn method_autoderef_steps<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: CanonicalTyGoal<'tcx>,
|
||||
goal: CanonicalMethodAutoderefStepsGoal<'tcx>,
|
||||
) -> MethodAutoderefStepsResult<'tcx> {
|
||||
debug!("method_autoderef_steps({:?})", goal);
|
||||
|
||||
let (ref infcx, goal, inference_vars) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &goal);
|
||||
let ParamEnvAnd { param_env, value: self_ty } = goal;
|
||||
let ParamEnvAnd {
|
||||
param_env,
|
||||
value: query::MethodAutoderefSteps { predefined_opaques_in_body, self_ty },
|
||||
} = goal;
|
||||
for (key, ty) in predefined_opaques_in_body {
|
||||
let prev =
|
||||
infcx.register_hidden_type_in_storage(key, ty::OpaqueHiddenType { span: DUMMY_SP, ty });
|
||||
// It may be possible that two entries in the opaque type storage end up
|
||||
// with the same key after resolving contained inference variables.
|
||||
//
|
||||
// We could put them in the duplicate list but don't have to. The opaques we
|
||||
// encounter here are already tracked in the caller, so there's no need to
|
||||
// also store them here. We'd take them out when computing the query response
|
||||
// and then discard them, as they're already present in the input.
|
||||
//
|
||||
// Ideally we'd drop duplicate opaque type definitions when computing
|
||||
// the canonical input. This is more annoying to implement and may cause a
|
||||
// perf regression, so we do it inside of the query for now.
|
||||
if let Some(prev) = prev {
|
||||
debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`");
|
||||
}
|
||||
}
|
||||
|
||||
// We accept not-yet-defined opaque types in the autoderef
|
||||
// chain to support recursive calls. We do error if the final
|
||||
// infer var is not an opaque.
|
||||
let self_ty_is_opaque = |ty: Ty<'_>| {
|
||||
if let &ty::Infer(ty::TyVar(vid)) = ty.kind() {
|
||||
infcx.has_opaques_with_sub_unified_hidden_type(vid)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
// If arbitrary self types is not enabled, we follow the chain of
|
||||
// `Deref<Target=T>`. If arbitrary self types is enabled, we instead
|
||||
|
|
@ -593,6 +636,7 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||
let step = CandidateStep {
|
||||
self_ty: infcx
|
||||
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
||||
self_ty_is_opaque: self_ty_is_opaque(ty),
|
||||
autoderefs: d,
|
||||
from_unsafe_deref: reached_raw_pointer,
|
||||
unsize: false,
|
||||
|
|
@ -613,6 +657,7 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||
let step = CandidateStep {
|
||||
self_ty: infcx
|
||||
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
||||
self_ty_is_opaque: self_ty_is_opaque(ty),
|
||||
autoderefs: d,
|
||||
from_unsafe_deref: reached_raw_pointer,
|
||||
unsize: false,
|
||||
|
|
@ -629,7 +674,11 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||
};
|
||||
let final_ty = autoderef_via_deref.final_ty();
|
||||
let opt_bad_ty = match final_ty.kind() {
|
||||
ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
|
||||
ty::Infer(ty::TyVar(_)) if !self_ty_is_opaque(final_ty) => Some(MethodAutoderefBadTy {
|
||||
reached_raw_pointer,
|
||||
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
|
||||
}),
|
||||
ty::Error(_) => Some(MethodAutoderefBadTy {
|
||||
reached_raw_pointer,
|
||||
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
|
||||
}),
|
||||
|
|
@ -640,6 +689,7 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||
inference_vars,
|
||||
Ty::new_slice(infcx.tcx, *elem_ty),
|
||||
),
|
||||
self_ty_is_opaque: false,
|
||||
autoderefs,
|
||||
// this could be from an unsafe deref if we had
|
||||
// a *mut/const [T; N]
|
||||
|
|
@ -655,7 +705,8 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||
};
|
||||
|
||||
debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
|
||||
|
||||
// Need to empty the opaque types storage before it gets dropped.
|
||||
let _ = infcx.take_opaque_types();
|
||||
MethodAutoderefStepsResult {
|
||||
steps: tcx.arena.alloc_from_iter(steps),
|
||||
opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)),
|
||||
|
|
@ -1203,7 +1254,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
!step.self_ty.value.references_error() && !step.from_unsafe_deref
|
||||
})
|
||||
.find_map(|step| {
|
||||
let InferOk { value: self_ty, obligations: _ } = self
|
||||
let InferOk { value: self_ty, obligations: instantiate_self_ty_obligations } = self
|
||||
.fcx
|
||||
.probe_instantiate_query_response(
|
||||
self.span,
|
||||
|
|
@ -1214,7 +1265,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
|
||||
});
|
||||
|
||||
let by_value_pick = self.pick_by_value_method(step, self_ty, pick_diag_hints);
|
||||
let by_value_pick = self.pick_by_value_method(
|
||||
step,
|
||||
self_ty,
|
||||
&instantiate_self_ty_obligations,
|
||||
pick_diag_hints,
|
||||
);
|
||||
|
||||
// Check for shadowing of a by-reference method by a by-value method (see comments on check_for_shadowing)
|
||||
if let Some(by_value_pick) = by_value_pick {
|
||||
|
|
@ -1225,6 +1281,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
by_value_pick,
|
||||
step,
|
||||
self_ty,
|
||||
&instantiate_self_ty_obligations,
|
||||
mutbl,
|
||||
track_unstable_candidates,
|
||||
) {
|
||||
|
|
@ -1239,6 +1296,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
let autoref_pick = self.pick_autorefd_method(
|
||||
step,
|
||||
self_ty,
|
||||
&instantiate_self_ty_obligations,
|
||||
hir::Mutability::Not,
|
||||
pick_diag_hints,
|
||||
None,
|
||||
|
|
@ -1252,6 +1310,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
autoref_pick,
|
||||
step,
|
||||
self_ty,
|
||||
&instantiate_self_ty_obligations,
|
||||
hir::Mutability::Mut,
|
||||
track_unstable_candidates,
|
||||
) {
|
||||
|
|
@ -1288,12 +1347,27 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
self.pick_autorefd_method(
|
||||
step,
|
||||
self_ty,
|
||||
&instantiate_self_ty_obligations,
|
||||
hir::Mutability::Mut,
|
||||
pick_diag_hints,
|
||||
None,
|
||||
)
|
||||
.or_else(|| self.pick_const_ptr_method(step, self_ty, pick_diag_hints))
|
||||
.or_else(|| self.pick_reborrow_pin_method(step, self_ty, pick_diag_hints))
|
||||
.or_else(|| {
|
||||
self.pick_const_ptr_method(
|
||||
step,
|
||||
self_ty,
|
||||
&instantiate_self_ty_obligations,
|
||||
pick_diag_hints,
|
||||
)
|
||||
})
|
||||
.or_else(|| {
|
||||
self.pick_reborrow_pin_method(
|
||||
step,
|
||||
self_ty,
|
||||
&instantiate_self_ty_obligations,
|
||||
pick_diag_hints,
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1317,6 +1391,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
possible_shadower: &Pick<'tcx>,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
mutbl: hir::Mutability,
|
||||
track_unstable_candidates: bool,
|
||||
) -> Result<(), MethodError<'tcx>> {
|
||||
|
|
@ -1381,6 +1456,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
let potentially_shadowed_pick = self.pick_autorefd_method(
|
||||
step,
|
||||
self_ty,
|
||||
instantiate_self_ty_obligations,
|
||||
mutbl,
|
||||
&mut pick_diag_hints,
|
||||
Some(&pick_constraints),
|
||||
|
|
@ -1407,13 +1483,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
&self,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
if step.unsize {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.pick_method(self_ty, pick_diag_hints, None).map(|r| {
|
||||
self.pick_method(self_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map(|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
|
||||
|
|
@ -1450,6 +1527,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
&self,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
mutbl: hir::Mutability,
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
pick_constraints: Option<&PickConstraintsForShadowed>,
|
||||
|
|
@ -1466,7 +1544,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
let region = tcx.lifetimes.re_erased;
|
||||
|
||||
let autoref_ty = Ty::new_ref(tcx, region, self_ty, mutbl);
|
||||
self.pick_method(autoref_ty, pick_diag_hints, pick_constraints).map(|r| {
|
||||
self.pick_method(
|
||||
autoref_ty,
|
||||
instantiate_self_ty_obligations,
|
||||
pick_diag_hints,
|
||||
pick_constraints,
|
||||
)
|
||||
.map(|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment =
|
||||
|
|
@ -1482,6 +1566,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
&self,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
if !self.tcx.features().pin_ergonomics() {
|
||||
|
|
@ -1503,14 +1588,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
|
||||
let region = self.tcx.lifetimes.re_erased;
|
||||
let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not);
|
||||
self.pick_method(autopin_ty, pick_diag_hints, None).map(|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment =
|
||||
Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not));
|
||||
pick
|
||||
})
|
||||
})
|
||||
self.pick_method(autopin_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map(
|
||||
|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment =
|
||||
Some(AutorefOrPtrAdjustment::ReborrowPin(hir::Mutability::Not));
|
||||
pick
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
|
||||
|
|
@ -1520,6 +1607,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
&self,
|
||||
step: &CandidateStep<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
// Don't convert an unsized reference to ptr
|
||||
|
|
@ -1532,18 +1620,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
};
|
||||
|
||||
let const_ptr_ty = Ty::new_imm_ptr(self.tcx, ty);
|
||||
self.pick_method(const_ptr_ty, pick_diag_hints, None).map(|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
|
||||
pick
|
||||
})
|
||||
})
|
||||
self.pick_method(const_ptr_ty, instantiate_self_ty_obligations, pick_diag_hints, None).map(
|
||||
|r| {
|
||||
r.map(|mut pick| {
|
||||
pick.autoderefs = step.autoderefs;
|
||||
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
|
||||
pick
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn pick_method(
|
||||
&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
pick_constraints: Option<&PickConstraintsForShadowed>,
|
||||
) -> Option<PickResult<'tcx>> {
|
||||
|
|
@ -1553,8 +1644,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
|
||||
{
|
||||
debug!("searching {} candidates", kind);
|
||||
let res =
|
||||
self.consider_candidates(self_ty, candidates, pick_diag_hints, pick_constraints);
|
||||
let res = self.consider_candidates(
|
||||
self_ty,
|
||||
instantiate_self_ty_obligations,
|
||||
candidates,
|
||||
pick_diag_hints,
|
||||
pick_constraints,
|
||||
);
|
||||
if let Some(pick) = res {
|
||||
return Some(pick);
|
||||
}
|
||||
|
|
@ -1563,6 +1659,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
if self.private_candidate.get().is_none() {
|
||||
if let Some(Ok(pick)) = self.consider_candidates(
|
||||
self_ty,
|
||||
instantiate_self_ty_obligations,
|
||||
&self.private_candidates,
|
||||
&mut PickDiagHints {
|
||||
unstable_candidates: None,
|
||||
|
|
@ -1579,6 +1676,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
fn consider_candidates(
|
||||
&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
candidates: &[Candidate<'tcx>],
|
||||
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
|
||||
pick_constraints: Option<&PickConstraintsForShadowed>,
|
||||
|
|
@ -1595,6 +1693,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
probe,
|
||||
self.consider_probe(
|
||||
self_ty,
|
||||
instantiate_self_ty_obligations,
|
||||
probe,
|
||||
&mut pick_diag_hints.unsatisfied_predicates,
|
||||
),
|
||||
|
|
@ -1779,10 +1878,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, possibly_unsatisfied_predicates), ret)]
|
||||
#[instrument(level = "debug", skip(self, possibly_unsatisfied_predicates), ret)]
|
||||
fn consider_probe(
|
||||
&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
instantiate_self_ty_obligations: &[PredicateObligation<'tcx>],
|
||||
probe: &Candidate<'tcx>,
|
||||
possibly_unsatisfied_predicates: &mut Vec<(
|
||||
ty::Predicate<'tcx>,
|
||||
|
|
@ -1790,8 +1890,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
Option<ObligationCause<'tcx>>,
|
||||
)>,
|
||||
) -> ProbeResult {
|
||||
debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe);
|
||||
|
||||
self.probe(|snapshot| {
|
||||
let outer_universe = self.universe();
|
||||
|
||||
|
|
@ -1799,6 +1897,21 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
let cause = &self.misc(self.span);
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(self);
|
||||
|
||||
// Subtle: we're not *really* instantiating the current self type while
|
||||
// probing, but instead fully recompute the autoderef steps once we've got
|
||||
// a final `Pick`. We can't nicely handle these obligations outside of a probe.
|
||||
//
|
||||
// We simply handle them for each candidate here for now. That's kinda scuffed
|
||||
// and ideally we just put them into the `FnCtxt` right away. We need to consider
|
||||
// them to deal with defining uses in `method_autoderef_steps`.
|
||||
if self.next_trait_solver() {
|
||||
ocx.register_obligations(instantiate_self_ty_obligations.iter().cloned());
|
||||
let errors = ocx.select_where_possible();
|
||||
if !errors.is_empty() {
|
||||
unreachable!("unexpected autoderef error {errors:?}");
|
||||
}
|
||||
}
|
||||
|
||||
let mut trait_predicate = None;
|
||||
let (mut xform_self_ty, mut xform_ret_ty);
|
||||
|
||||
|
|
@ -2041,6 +2154,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if self.infcx.next_trait_solver() {
|
||||
if self.should_reject_candidate_due_to_opaque_treated_as_rigid(trait_predicate) {
|
||||
result = ProbeResult::NoMatch;
|
||||
}
|
||||
}
|
||||
|
||||
// Previously, method probe used `evaluate_predicate` to determine if a predicate
|
||||
// was impossible to satisfy. This did a leak check, so we must also do a leak
|
||||
// check here to prevent backwards-incompatible ambiguity being introduced. See
|
||||
|
|
@ -2054,6 +2173,80 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Trait candidates for not-yet-defined opaque types are a somewhat hacky.
|
||||
///
|
||||
/// We want to only accept trait methods if they were hold even if the
|
||||
/// opaque types were rigid. To handle this, we both check that for trait
|
||||
/// candidates the goal were to hold even when treating opaques as rigid,
|
||||
/// see [OpaqueTypesJank](rustc_trait_selection::solve::OpaqueTypesJank).
|
||||
///
|
||||
/// We also check that all opaque types encountered as self types in the
|
||||
/// autoderef chain don't get constrained when applying the candidate.
|
||||
/// Importantly, this also handles calling methods taking `&self` on
|
||||
/// `impl Trait` to reject the "by-self" candidate.
|
||||
///
|
||||
/// This needs to happen at the end of `consider_probe` as we need to take
|
||||
/// all the constraints from that into account.
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn should_reject_candidate_due_to_opaque_treated_as_rigid(
|
||||
&self,
|
||||
trait_predicate: Option<ty::Predicate<'tcx>>,
|
||||
) -> bool {
|
||||
// This function is what hacky and doesn't perfectly do what we want it to.
|
||||
// It's not soundness critical and we should be able to freely improve this
|
||||
// in the future.
|
||||
//
|
||||
// Some concrete edge cases include the fact that `goal_may_hold_opaque_types_jank`
|
||||
// also fails if there are any constraints opaques which are never used as a self
|
||||
// type. We also allow where-bounds which are currently ambiguous but end up
|
||||
// constraining an opaque later on.
|
||||
|
||||
// Check whether the trait candidate would not be applicable if the
|
||||
// opaque type were rigid.
|
||||
if let Some(predicate) = trait_predicate {
|
||||
let goal = Goal { param_env: self.param_env, predicate };
|
||||
if !self.infcx.goal_may_hold_opaque_types_jank(goal) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether any opaque types in the autoderef chain have been
|
||||
// constrained.
|
||||
for step in self.steps {
|
||||
if step.self_ty_is_opaque {
|
||||
debug!(?step.autoderefs, ?step.self_ty, "self_type_is_opaque");
|
||||
let constrained_opaque = self.probe(|_| {
|
||||
// If we fail to instantiate the self type of this
|
||||
// step, this part of the deref-chain is no longer
|
||||
// reachable. In this case we don't care about opaque
|
||||
// types there.
|
||||
let Ok(ok) = self.fcx.probe_instantiate_query_response(
|
||||
self.span,
|
||||
self.orig_steps_var_values,
|
||||
&step.self_ty,
|
||||
) else {
|
||||
debug!("failed to instantiate self_ty");
|
||||
return false;
|
||||
};
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
let self_ty = ocx.register_infer_ok_obligations(ok);
|
||||
if !ocx.select_where_possible().is_empty() {
|
||||
debug!("failed to prove instantiate self_ty obligations");
|
||||
return false;
|
||||
}
|
||||
|
||||
!self.resolve_vars_if_possible(self_ty).is_ty_var()
|
||||
});
|
||||
if constrained_opaque {
|
||||
debug!("opaque type has been constrained");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Sometimes we get in a situation where we have multiple probes that are all impls of the
|
||||
/// same trait, but we don't know which impl to use. In this case, since in all cases the
|
||||
/// external interface of the method can be determined from the trait, it's ok not to decide.
|
||||
|
|
|
|||
|
|
@ -1003,8 +1003,10 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
debug_assert!(!r.is_bound(), "Should not be resolving bound region.");
|
||||
self.fcx.tcx.lifetimes.re_erased
|
||||
match r.kind() {
|
||||
ty::ReBound(..) => r,
|
||||
_ => self.fcx.tcx.lifetimes.re_erased,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
|
|
|
|||
|
|
@ -130,12 +130,6 @@ impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeFrom<I> {
|
|||
impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeInclusive<I> {
|
||||
type Output = core::range::RangeInclusive<usize>;
|
||||
#[inline]
|
||||
#[cfg(bootstrap)]
|
||||
fn into_slice_idx(self) -> Self::Output {
|
||||
core::range::RangeInclusive { start: self.start.index(), end: self.end.index() }
|
||||
}
|
||||
#[inline]
|
||||
#[cfg(not(bootstrap))]
|
||||
fn into_slice_idx(self) -> Self::Output {
|
||||
core::range::RangeInclusive { start: self.start.index(), last: self.last.index() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,11 +85,29 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
where
|
||||
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
// While we ignore region constraints and pending obligations,
|
||||
// we do return constrained opaque types to avoid unconstrained
|
||||
// inference variables in the response. This is important as we want
|
||||
// to check that opaques in deref steps stay unconstrained.
|
||||
//
|
||||
// This doesn't handle the more general case for non-opaques as
|
||||
// ambiguous `Projection` obligations have same the issue.
|
||||
let opaque_types = if self.next_trait_solver() {
|
||||
self.inner
|
||||
.borrow_mut()
|
||||
.opaque_type_storage
|
||||
.iter_opaque_types()
|
||||
.map(|(k, v)| (k, v.ty))
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
self.canonicalize_response(QueryResponse {
|
||||
var_values: inference_vars,
|
||||
region_constraints: QueryRegionConstraints::default(),
|
||||
certainty: Certainty::Proven, // Ambiguities are OK!
|
||||
opaque_types: vec![],
|
||||
opaque_types,
|
||||
value: answer,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -765,7 +765,7 @@ fn test_unstable_options_tracking_hash() {
|
|||
tracked!(allow_features, Some(vec![String::from("lang_items")]));
|
||||
tracked!(always_encode_mir, true);
|
||||
tracked!(assume_incomplete_release, true);
|
||||
tracked!(autodiff, vec![AutoDiff::Enable]);
|
||||
tracked!(autodiff, vec![AutoDiff::Enable, AutoDiff::NoTT]);
|
||||
tracked!(binary_dep_depinfo, true);
|
||||
tracked!(box_noalias, false);
|
||||
tracked!(
|
||||
|
|
|
|||
|
|
@ -386,8 +386,8 @@ fn get_codegen_sysroot(
|
|||
.collect::<Vec<_>>()
|
||||
.join("\n* ");
|
||||
let err = format!(
|
||||
"failed to find a `codegen-backends` folder \
|
||||
in the sysroot candidates:\n* {candidates}"
|
||||
"failed to find a `codegen-backends` folder in the sysroot candidates:\n\
|
||||
* {candidates}"
|
||||
);
|
||||
early_dcx.early_fatal(err);
|
||||
});
|
||||
|
|
@ -396,10 +396,8 @@ fn get_codegen_sysroot(
|
|||
|
||||
let d = sysroot.read_dir().unwrap_or_else(|e| {
|
||||
let err = format!(
|
||||
"failed to load default codegen backend, couldn't \
|
||||
read `{}`: {}",
|
||||
"failed to load default codegen backend, couldn't read `{}`: {e}",
|
||||
sysroot.display(),
|
||||
e
|
||||
);
|
||||
early_dcx.early_fatal(err);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2309,10 +2309,10 @@ declare_lint! {
|
|||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #![cfg_attr(not(bootstrap), feature(sanitize))]
|
||||
/// #![feature(sanitize)]
|
||||
///
|
||||
/// #[inline(always)]
|
||||
/// #[cfg_attr(not(bootstrap), sanitize(address = "off"))]
|
||||
/// #[sanitize(address = "off")]
|
||||
/// fn x() {}
|
||||
///
|
||||
/// fn main() {
|
||||
|
|
@ -4837,16 +4837,13 @@ declare_lint! {
|
|||
///
|
||||
/// ### Example
|
||||
///
|
||||
#[cfg_attr(not(bootstrap), doc = "```rust,compile_fail")]
|
||||
#[cfg_attr(bootstrap, doc = "```rust")]
|
||||
/// ```rust,compile_fail
|
||||
/// #![doc = in_root!()]
|
||||
///
|
||||
/// macro_rules! in_root { () => { "" } }
|
||||
///
|
||||
/// fn main() {}
|
||||
#[cfg_attr(not(bootstrap), doc = "```")]
|
||||
#[cfg_attr(bootstrap, doc = "```")]
|
||||
// ^ Needed to avoid tidy warning about odd number of backticks
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
|
|
|
|||
|
|
@ -359,10 +359,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
|
|||
return wrap(TM);
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) {
|
||||
delete unwrap(TM);
|
||||
}
|
||||
|
||||
// Unfortunately, the LLVM C API doesn't provide a way to create the
|
||||
// TargetLibraryInfo pass, so we use this method to do so.
|
||||
extern "C" void LLVMRustAddLibraryInfo(LLVMPassManagerRef PMR, LLVMModuleRef M,
|
||||
|
|
@ -573,25 +569,43 @@ extern "C" LLVMRustResult LLVMRustOptimize(
|
|||
}
|
||||
|
||||
std::optional<PGOOptions> PGOOpt;
|
||||
#if LLVM_VERSION_LT(22, 0)
|
||||
auto FS = vfs::getRealFileSystem();
|
||||
#endif
|
||||
if (PGOGenPath) {
|
||||
assert(!PGOUsePath && !PGOSampleUsePath);
|
||||
PGOOpt = PGOOptions(
|
||||
#if LLVM_VERSION_GE(22, 0)
|
||||
PGOGenPath, "", "", "", PGOOptions::IRInstr, PGOOptions::NoCSAction,
|
||||
#else
|
||||
PGOGenPath, "", "", "", FS, PGOOptions::IRInstr, PGOOptions::NoCSAction,
|
||||
#endif
|
||||
PGOOptions::ColdFuncOpt::Default, DebugInfoForProfiling);
|
||||
} else if (PGOUsePath) {
|
||||
assert(!PGOSampleUsePath);
|
||||
PGOOpt = PGOOptions(
|
||||
#if LLVM_VERSION_GE(22, 0)
|
||||
PGOUsePath, "", "", "", PGOOptions::IRUse, PGOOptions::NoCSAction,
|
||||
#else
|
||||
PGOUsePath, "", "", "", FS, PGOOptions::IRUse, PGOOptions::NoCSAction,
|
||||
#endif
|
||||
PGOOptions::ColdFuncOpt::Default, DebugInfoForProfiling);
|
||||
} else if (PGOSampleUsePath) {
|
||||
PGOOpt =
|
||||
#if LLVM_VERSION_GE(22, 0)
|
||||
PGOOptions(PGOSampleUsePath, "", "", "", PGOOptions::SampleUse,
|
||||
#else
|
||||
PGOOptions(PGOSampleUsePath, "", "", "", FS, PGOOptions::SampleUse,
|
||||
#endif
|
||||
PGOOptions::NoCSAction, PGOOptions::ColdFuncOpt::Default,
|
||||
DebugInfoForProfiling);
|
||||
} else if (DebugInfoForProfiling) {
|
||||
PGOOpt = PGOOptions(
|
||||
#if LLVM_VERSION_GE(22, 0)
|
||||
"", "", "", "", PGOOptions::NoAction, PGOOptions::NoCSAction,
|
||||
#else
|
||||
"", "", "", "", FS, PGOOptions::NoAction, PGOOptions::NoCSAction,
|
||||
#endif
|
||||
PGOOptions::ColdFuncOpt::Default, DebugInfoForProfiling);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -990,14 +990,6 @@ extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind,
|
|||
unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD));
|
||||
}
|
||||
|
||||
extern "C" LLVMDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) {
|
||||
return wrap(new DIBuilder(*unwrap(M)));
|
||||
}
|
||||
|
||||
extern "C" void LLVMRustDIBuilderDispose(LLVMDIBuilderRef Builder) {
|
||||
delete unwrap(Builder);
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit(
|
||||
LLVMDIBuilderRef Builder, unsigned Lang, LLVMMetadataRef FileRef,
|
||||
const char *Producer, size_t ProducerLen, bool isOptimized,
|
||||
|
|
@ -1129,51 +1121,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable(
|
|||
return wrap(VarExpr);
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable(
|
||||
LLVMDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope,
|
||||
const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo,
|
||||
LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMDIFlags Flags, unsigned ArgNo,
|
||||
uint32_t AlignInBits) {
|
||||
if (Tag == 0x100) { // DW_TAG_auto_variable
|
||||
return wrap(unwrap(Builder)->createAutoVariable(
|
||||
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen),
|
||||
unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), AlwaysPreserve,
|
||||
fromRust(Flags), AlignInBits));
|
||||
} else {
|
||||
return wrap(unwrap(Builder)->createParameterVariable(
|
||||
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ArgNo,
|
||||
unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), AlwaysPreserve,
|
||||
fromRust(Flags)));
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDIBuilderGetOrCreateSubrange(LLVMDIBuilderRef Builder, int64_t Lo,
|
||||
int64_t Count) {
|
||||
return wrap(unwrap(Builder)->getOrCreateSubrange(Lo, Count));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDIBuilderGetOrCreateArray(LLVMDIBuilderRef Builder,
|
||||
LLVMMetadataRef *Ptr, unsigned Count) {
|
||||
Metadata **DataValue = unwrap(Ptr);
|
||||
return wrap(unwrap(Builder)
|
||||
->getOrCreateArray(ArrayRef<Metadata *>(DataValue, Count))
|
||||
.get());
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
LLVMRustDIBuilderInsertDeclareAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef V,
|
||||
LLVMMetadataRef VarInfo, uint64_t *AddrOps,
|
||||
unsigned AddrOpsCount, LLVMMetadataRef DL,
|
||||
LLVMBasicBlockRef InsertAtEnd) {
|
||||
unwrap(Builder)->insertDeclare(
|
||||
unwrap(V), unwrap<DILocalVariable>(VarInfo),
|
||||
unwrap(Builder)->createExpression(
|
||||
llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)),
|
||||
DebugLoc(cast<MDNode>(unwrap(DL))), unwrap(InsertAtEnd));
|
||||
}
|
||||
|
||||
extern "C" LLVMMetadataRef
|
||||
LLVMRustDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, const char *Name,
|
||||
size_t NameLen, const uint64_t Value[2],
|
||||
|
|
@ -1685,6 +1632,14 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler(
|
|||
RemarkStreamer(std::move(RemarkStreamer)),
|
||||
LlvmRemarkStreamer(std::move(LlvmRemarkStreamer)) {}
|
||||
|
||||
#if LLVM_VERSION_GE(22, 0)
|
||||
~RustDiagnosticHandler() {
|
||||
if (RemarkStreamer) {
|
||||
RemarkStreamer->releaseSerializer();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual bool handleDiagnostics(const DiagnosticInfo &DI) override {
|
||||
// If this diagnostic is one of the optimization remark kinds, we can
|
||||
// check if it's enabled before emitting it. This can avoid many
|
||||
|
|
@ -1779,9 +1734,14 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler(
|
|||
// Do not delete the file after we gather remarks
|
||||
RemarkFile->keep();
|
||||
|
||||
#if LLVM_VERSION_GE(22, 0)
|
||||
auto RemarkSerializer = remarks::createRemarkSerializer(
|
||||
llvm::remarks::Format::YAML, RemarkFile->os());
|
||||
#else
|
||||
auto RemarkSerializer = remarks::createRemarkSerializer(
|
||||
llvm::remarks::Format::YAML, remarks::SerializerMode::Separate,
|
||||
RemarkFile->os());
|
||||
#endif
|
||||
if (Error E = RemarkSerializer.takeError()) {
|
||||
std::string Error = std::string("Cannot create remark serializer: ") +
|
||||
toString(std::move(E));
|
||||
|
|
@ -1852,3 +1812,15 @@ extern "C" void LLVMRustSetNoSanitizeHWAddress(LLVMValueRef Global) {
|
|||
MD.NoHWAddress = true;
|
||||
GV.setSanitizerMetadata(MD);
|
||||
}
|
||||
|
||||
#ifdef ENZYME
|
||||
extern "C" {
|
||||
extern llvm::cl::opt<unsigned> EnzymeMaxTypeDepth;
|
||||
}
|
||||
|
||||
extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() { return EnzymeMaxTypeDepth; }
|
||||
#else
|
||||
extern "C" size_t LLVMRustEnzymeGetMaxTypeDepth() {
|
||||
return 6; // Default fallback depth
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use syn::punctuated::Punctuated;
|
|||
use syn::spanned::Spanned;
|
||||
use syn::{
|
||||
AttrStyle, Attribute, Block, Error, Expr, Ident, Pat, ReturnType, Token, Type, braced,
|
||||
parenthesized, parse_macro_input, parse_quote, token,
|
||||
parenthesized, parse_macro_input, token,
|
||||
};
|
||||
|
||||
mod kw {
|
||||
|
|
|
|||
|
|
@ -1555,7 +1555,7 @@ impl<'a> CrateMetadataRef<'a> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn def_path_hash_to_def_index(self, hash: DefPathHash) -> DefIndex {
|
||||
fn def_path_hash_to_def_index(self, hash: DefPathHash) -> Option<DefIndex> {
|
||||
self.def_path_hash_map.def_path_hash_to_def_index(&hash)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -691,8 +691,8 @@ fn provide_cstore_hooks(providers: &mut Providers) {
|
|||
.get(&stable_crate_id)
|
||||
.unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}"));
|
||||
assert_ne!(cnum, LOCAL_CRATE);
|
||||
let def_index = cstore.get_crate_data(cnum).def_path_hash_to_def_index(hash);
|
||||
DefId { krate: cnum, index: def_index }
|
||||
let def_index = cstore.get_crate_data(cnum).def_path_hash_to_def_index(hash)?;
|
||||
Some(DefId { krate: cnum, index: def_index })
|
||||
};
|
||||
|
||||
providers.hooks.expn_hash_to_expn_id = |tcx, cnum, index_guess, hash| {
|
||||
|
|
|
|||
|
|
@ -12,11 +12,12 @@ pub(crate) enum DefPathHashMapRef<'tcx> {
|
|||
|
||||
impl DefPathHashMapRef<'_> {
|
||||
#[inline]
|
||||
pub(crate) fn def_path_hash_to_def_index(&self, def_path_hash: &DefPathHash) -> DefIndex {
|
||||
pub(crate) fn def_path_hash_to_def_index(
|
||||
&self,
|
||||
def_path_hash: &DefPathHash,
|
||||
) -> Option<DefIndex> {
|
||||
match *self {
|
||||
DefPathHashMapRef::OwnedFromMetadata(ref map) => {
|
||||
map.get(&def_path_hash.local_hash()).unwrap()
|
||||
}
|
||||
DefPathHashMapRef::OwnedFromMetadata(ref map) => map.get(&def_path_hash.local_hash()),
|
||||
DefPathHashMapRef::BorrowedFromTcx(_) => {
|
||||
panic!("DefPathHashMap::BorrowedFromTcx variant only exists for serialization")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,12 @@ middle_layout_references_error =
|
|||
middle_layout_size_overflow =
|
||||
values of the type `{$ty}` are too big for the target architecture
|
||||
|
||||
middle_layout_simd_too_many =
|
||||
the SIMD type `{$ty}` has more elements than the limit {$max_lanes}
|
||||
|
||||
middle_layout_simd_zero_length =
|
||||
the SIMD type `{$ty}` has zero elements
|
||||
|
||||
middle_layout_too_generic = the type `{$ty}` does not have a fixed layout
|
||||
|
||||
middle_layout_unknown =
|
||||
|
|
|
|||
|
|
@ -109,7 +109,6 @@ macro_rules! arena_types {
|
|||
rustc_middle::ty::EarlyBinder<'tcx, rustc_middle::ty::Ty<'tcx>>
|
||||
>,
|
||||
[] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<rustc_middle::ty::TyCtxt<'tcx>>,
|
||||
[] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<rustc_middle::ty::TyCtxt<'tcx>>,
|
||||
[decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap,
|
||||
[] stripped_cfg_items: rustc_hir::attrs::StrippedCfgItem,
|
||||
[] mod_child: rustc_middle::metadata::ModChild,
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ pub(crate) struct OpaqueHiddenTypeMismatch<'tcx> {
|
|||
pub sub: TypeMismatchReason,
|
||||
}
|
||||
|
||||
// FIXME(autodiff): I should get used somewhere
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_unsupported_union)]
|
||||
pub struct UnsupportedUnion {
|
||||
|
|
@ -143,6 +142,12 @@ pub enum LayoutError<'tcx> {
|
|||
#[diag(middle_layout_size_overflow)]
|
||||
Overflow { ty: Ty<'tcx> },
|
||||
|
||||
#[diag(middle_layout_simd_too_many)]
|
||||
SimdTooManyLanes { ty: Ty<'tcx>, max_lanes: u64 },
|
||||
|
||||
#[diag(middle_layout_simd_zero_length)]
|
||||
SimdZeroLength { ty: Ty<'tcx> },
|
||||
|
||||
#[diag(middle_layout_normalization_failure)]
|
||||
NormalizationFailure { ty: Ty<'tcx>, failure_ty: String },
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ declare_hooks! {
|
|||
/// session, if it still exists. This is used during incremental compilation to
|
||||
/// turn a deserialized `DefPathHash` into its current `DefId`.
|
||||
/// Will fetch a DefId from a DefPathHash for a foreign crate.
|
||||
hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> DefId;
|
||||
hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> Option<DefId>;
|
||||
|
||||
/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
|
||||
/// can just link to the upstream crate and therefore don't need a mono item.
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::direct_use_of_rustc_type_ir)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![cfg_attr(bootstrap, feature(round_char_boundary))]
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(allocator_api)]
|
||||
|
|
|
|||
|
|
@ -1,15 +1,9 @@
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_hir::attrs::DebuggerVisualizerType;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable};
|
||||
|
||||
#[derive(HashStable)]
|
||||
#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
|
||||
pub enum DebuggerVisualizerType {
|
||||
Natvis,
|
||||
GdbPrettyPrinter,
|
||||
}
|
||||
|
||||
/// A single debugger visualizer file.
|
||||
#[derive(HashStable)]
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ use crate::query::plumbing::{
|
|||
};
|
||||
use crate::traits::query::{
|
||||
CanonicalAliasGoal, CanonicalDropckOutlivesGoal, CanonicalImpliedOutlivesBoundsGoal,
|
||||
CanonicalPredicateGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal,
|
||||
CanonicalMethodAutoderefStepsGoal, CanonicalPredicateGoal, CanonicalTypeOpAscribeUserTypeGoal,
|
||||
CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, DropckConstraint,
|
||||
DropckOutlivesResult, MethodAutoderefStepsResult, NoSolution, NormalizationResult,
|
||||
OutlivesBound,
|
||||
|
|
@ -2559,9 +2559,9 @@ rustc_queries! {
|
|||
}
|
||||
|
||||
query method_autoderef_steps(
|
||||
goal: CanonicalTyGoal<'tcx>
|
||||
goal: CanonicalMethodAutoderefStepsGoal<'tcx>
|
||||
) -> MethodAutoderefStepsResult<'tcx> {
|
||||
desc { "computing autoderef types for `{}`", goal.canonical.value.value }
|
||||
desc { "computing autoderef types for `{}`", goal.canonical.value.value.self_ty }
|
||||
}
|
||||
|
||||
/// Used by `-Znext-solver` to compute proof trees.
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use rustc_span::Span;
|
|||
|
||||
use crate::error::DropCheckOverflow;
|
||||
use crate::infer::canonical::{Canonical, CanonicalQueryInput, QueryResponse};
|
||||
use crate::traits::solve;
|
||||
pub use crate::traits::solve::NoSolution;
|
||||
use crate::ty::{self, GenericArg, Ty, TyCtxt};
|
||||
|
||||
|
|
@ -67,7 +68,16 @@ pub mod type_op {
|
|||
pub type CanonicalAliasGoal<'tcx> =
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>;
|
||||
|
||||
pub type CanonicalTyGoal<'tcx> = CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
|
||||
pub type CanonicalMethodAutoderefStepsGoal<'tcx> =
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, MethodAutoderefSteps<'tcx>>>;
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct MethodAutoderefSteps<'tcx> {
|
||||
/// The list of opaque types currently in the storage.
|
||||
///
|
||||
/// Only used by the new solver for now.
|
||||
pub predefined_opaques_in_body: solve::PredefinedOpaques<'tcx>,
|
||||
pub self_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
pub type CanonicalPredicateGoal<'tcx> =
|
||||
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>;
|
||||
|
|
@ -144,6 +154,7 @@ impl<'tcx> FromIterator<DropckConstraint<'tcx>> for DropckConstraint<'tcx> {
|
|||
#[derive(Debug, HashStable)]
|
||||
pub struct CandidateStep<'tcx> {
|
||||
pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
|
||||
pub self_ty_is_opaque: bool,
|
||||
pub autoderefs: usize,
|
||||
/// `true` if the type results from a dereference of a raw pointer.
|
||||
/// when assembling candidates, we include these steps, but not when
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_type_ir as ir;
|
|||
pub use rustc_type_ir::solve::*;
|
||||
|
||||
use crate::ty::{
|
||||
self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor,
|
||||
self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor,
|
||||
try_visit,
|
||||
};
|
||||
|
||||
|
|
@ -15,16 +15,7 @@ pub type CandidateSource<'tcx> = ir::solve::CandidateSource<TyCtxt<'tcx>>;
|
|||
pub type CanonicalInput<'tcx, P = ty::Predicate<'tcx>> = ir::solve::CanonicalInput<TyCtxt<'tcx>, P>;
|
||||
pub type CanonicalResponse<'tcx> = ir::solve::CanonicalResponse<TyCtxt<'tcx>>;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)]
|
||||
pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<TyCtxt<'tcx>>>);
|
||||
|
||||
impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> {
|
||||
type Target = PredefinedOpaquesData<TyCtxt<'tcx>>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
pub type PredefinedOpaques<'tcx> = &'tcx ty::List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)]
|
||||
pub struct ExternalConstraints<'tcx>(
|
||||
|
|
@ -93,35 +84,3 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
|
|||
self.normalization_nested_goals.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Having to clone `region_constraints` for folding feels bad and
|
||||
// probably isn't great wrt performance.
|
||||
//
|
||||
// Not sure how to fix this, maybe we should also intern `opaque_types` and
|
||||
// `region_constraints` here or something.
|
||||
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
|
||||
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
|
||||
self,
|
||||
folder: &mut F,
|
||||
) -> Result<Self, F::Error> {
|
||||
Ok(FallibleTypeFolder::cx(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData {
|
||||
opaque_types: self
|
||||
.opaque_types
|
||||
.iter()
|
||||
.map(|opaque| opaque.try_fold_with(folder))
|
||||
.collect::<Result<_, F::Error>>()?,
|
||||
}))
|
||||
}
|
||||
|
||||
fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
|
||||
TypeFolder::cx(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData {
|
||||
opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
|
||||
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
|
||||
self.opaque_types.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ use crate::thir::Thir;
|
|||
use crate::traits;
|
||||
use crate::traits::solve::{
|
||||
self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, PredefinedOpaques,
|
||||
PredefinedOpaquesData, QueryResult, inspect,
|
||||
QueryResult, inspect,
|
||||
};
|
||||
use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
|
||||
use crate::ty::{
|
||||
|
|
@ -116,7 +116,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
|
||||
fn mk_predefined_opaques_in_body(
|
||||
self,
|
||||
data: PredefinedOpaquesData<Self>,
|
||||
data: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)],
|
||||
) -> Self::PredefinedOpaques {
|
||||
self.mk_predefined_opaques_in_body(data)
|
||||
}
|
||||
|
|
@ -941,7 +941,7 @@ pub struct CtxtInterners<'tcx> {
|
|||
layout: InternedSet<'tcx, LayoutData<FieldIdx, VariantIdx>>,
|
||||
adt_def: InternedSet<'tcx, AdtDefData>,
|
||||
external_constraints: InternedSet<'tcx, ExternalConstraintsData<TyCtxt<'tcx>>>,
|
||||
predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<TyCtxt<'tcx>>>,
|
||||
predefined_opaques_in_body: InternedSet<'tcx, List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>>,
|
||||
fields: InternedSet<'tcx, List<FieldIdx>>,
|
||||
local_def_ids: InternedSet<'tcx, List<LocalDefId>>,
|
||||
captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>,
|
||||
|
|
@ -2012,7 +2012,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
if stable_crate_id == self.stable_crate_id(LOCAL_CRATE) {
|
||||
Some(self.untracked.definitions.read().local_def_path_hash_to_def_id(hash)?.to_def_id())
|
||||
} else {
|
||||
Some(self.def_path_hash_to_def_id_extern(hash, stable_crate_id))
|
||||
self.def_path_hash_to_def_id_extern(hash, stable_crate_id)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2748,8 +2748,6 @@ direct_interners! {
|
|||
adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
|
||||
external_constraints: pub mk_external_constraints(ExternalConstraintsData<TyCtxt<'tcx>>):
|
||||
ExternalConstraints -> ExternalConstraints<'tcx>,
|
||||
predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<TyCtxt<'tcx>>):
|
||||
PredefinedOpaques -> PredefinedOpaques<'tcx>,
|
||||
}
|
||||
|
||||
macro_rules! slice_interners {
|
||||
|
|
@ -2786,6 +2784,7 @@ slice_interners!(
|
|||
offset_of: pub mk_offset_of((VariantIdx, FieldIdx)),
|
||||
patterns: pub mk_patterns(Pattern<'tcx>),
|
||||
outlives: pub mk_outlives(ty::ArgOutlivesPredicate<'tcx>),
|
||||
predefined_opaques_in_body: pub mk_predefined_opaques_in_body((ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)),
|
||||
);
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
|
|
@ -3129,6 +3128,14 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
T::collect_and_apply(iter, |xs| self.mk_poly_existential_predicates(xs))
|
||||
}
|
||||
|
||||
pub fn mk_predefined_opaques_in_body_from_iter<I, T>(self, iter: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>), PredefinedOpaques<'tcx>>,
|
||||
{
|
||||
T::collect_and_apply(iter, |xs| self.mk_predefined_opaques_in_body(xs))
|
||||
}
|
||||
|
||||
pub fn mk_clauses_from_iter<I, T>(self, iter: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
|
|
|
|||
|
|
@ -218,6 +218,15 @@ impl fmt::Display for ValidityRequirement {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
|
||||
pub enum SimdLayoutError {
|
||||
/// The vector has 0 lanes.
|
||||
ZeroLength,
|
||||
/// The vector has more lanes than supported or permitted by
|
||||
/// #\[rustc_simd_monomorphize_lane_limit\].
|
||||
TooManyLanes(u64),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
|
||||
pub enum LayoutError<'tcx> {
|
||||
/// A type doesn't have a sensible layout.
|
||||
|
|
@ -230,6 +239,8 @@ pub enum LayoutError<'tcx> {
|
|||
Unknown(Ty<'tcx>),
|
||||
/// The size of a type exceeds [`TargetDataLayout::obj_size_bound`].
|
||||
SizeOverflow(Ty<'tcx>),
|
||||
/// A SIMD vector has invalid layout, such as zero-length or too many lanes.
|
||||
InvalidSimd { ty: Ty<'tcx>, kind: SimdLayoutError },
|
||||
/// The layout can vary due to a generic parameter.
|
||||
///
|
||||
/// Unlike `Unknown`, this variant is a "soft" error and indicates that the layout
|
||||
|
|
@ -257,6 +268,10 @@ impl<'tcx> LayoutError<'tcx> {
|
|||
match self {
|
||||
Unknown(_) => middle_layout_unknown,
|
||||
SizeOverflow(_) => middle_layout_size_overflow,
|
||||
InvalidSimd { kind: SimdLayoutError::TooManyLanes(_), .. } => {
|
||||
middle_layout_simd_too_many
|
||||
}
|
||||
InvalidSimd { kind: SimdLayoutError::ZeroLength, .. } => middle_layout_simd_zero_length,
|
||||
TooGeneric(_) => middle_layout_too_generic,
|
||||
NormalizationFailure(_, _) => middle_layout_normalization_failure,
|
||||
Cycle(_) => middle_layout_cycle,
|
||||
|
|
@ -271,6 +286,10 @@ impl<'tcx> LayoutError<'tcx> {
|
|||
match self {
|
||||
Unknown(ty) => E::Unknown { ty },
|
||||
SizeOverflow(ty) => E::Overflow { ty },
|
||||
InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => {
|
||||
E::SimdTooManyLanes { ty, max_lanes }
|
||||
}
|
||||
InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => E::SimdZeroLength { ty },
|
||||
TooGeneric(ty) => E::TooGeneric { ty },
|
||||
NormalizationFailure(ty, e) => {
|
||||
E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() }
|
||||
|
|
@ -293,6 +312,12 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
|
|||
LayoutError::SizeOverflow(ty) => {
|
||||
write!(f, "values of the type `{ty}` are too big for the target architecture")
|
||||
}
|
||||
LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => {
|
||||
write!(f, "the SIMD type `{ty}` has more elements than the limit {max_lanes}")
|
||||
}
|
||||
LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => {
|
||||
write!(f, "the SIMD type `{ty}` has zero elements")
|
||||
}
|
||||
LayoutError::NormalizationFailure(t, e) => write!(
|
||||
f,
|
||||
"unable to determine layout for `{}` because `{}` cannot be normalized",
|
||||
|
|
@ -374,6 +399,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
|
|||
e @ LayoutError::Cycle(_)
|
||||
| e @ LayoutError::Unknown(_)
|
||||
| e @ LayoutError::SizeOverflow(_)
|
||||
| e @ LayoutError::InvalidSimd { .. }
|
||||
| e @ LayoutError::NormalizationFailure(..)
|
||||
| e @ LayoutError::ReferencesError(_),
|
||||
) => return Err(e),
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ pub use generic_args::{GenericArgKind, TermKind, *};
|
|||
pub use generics::*;
|
||||
pub use intrinsic::IntrinsicDef;
|
||||
use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx};
|
||||
use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree};
|
||||
use rustc_ast::node_id::NodeMap;
|
||||
pub use rustc_ast_ir::{Movability, Mutability, try_visit};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
||||
|
|
@ -62,7 +63,7 @@ pub use rustc_type_ir::solve::SizedTraitKind;
|
|||
pub use rustc_type_ir::*;
|
||||
#[allow(hidden_glob_reexports, unused_imports)]
|
||||
use rustc_type_ir::{InferCtxtLike, Interner};
|
||||
use tracing::{debug, instrument};
|
||||
use tracing::{debug, instrument, trace};
|
||||
pub use vtable::*;
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
|
|
@ -2216,3 +2217,225 @@ pub struct DestructuredConst<'tcx> {
|
|||
pub variant: Option<VariantIdx>,
|
||||
pub fields: &'tcx [ty::Const<'tcx>],
|
||||
}
|
||||
|
||||
/// Generate TypeTree information for autodiff.
|
||||
/// This function creates TypeTree metadata that describes the memory layout
|
||||
/// of function parameters and return types for Enzyme autodiff.
|
||||
pub fn fnc_typetrees<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>) -> FncTree {
|
||||
// Check if TypeTrees are disabled via NoTT flag
|
||||
if tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::NoTT) {
|
||||
return FncTree { args: vec![], ret: TypeTree::new() };
|
||||
}
|
||||
|
||||
// Check if this is actually a function type
|
||||
if !fn_ty.is_fn() {
|
||||
return FncTree { args: vec![], ret: TypeTree::new() };
|
||||
}
|
||||
|
||||
// Get the function signature
|
||||
let fn_sig = fn_ty.fn_sig(tcx);
|
||||
let sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
|
||||
|
||||
// Create TypeTrees for each input parameter
|
||||
let mut args = vec![];
|
||||
for ty in sig.inputs().iter() {
|
||||
let type_tree = typetree_from_ty(tcx, *ty);
|
||||
args.push(type_tree);
|
||||
}
|
||||
|
||||
// Create TypeTree for return type
|
||||
let ret = typetree_from_ty(tcx, sig.output());
|
||||
|
||||
FncTree { args, ret }
|
||||
}
|
||||
|
||||
/// Generate TypeTree for a specific type.
|
||||
/// This function analyzes a Rust type and creates appropriate TypeTree metadata.
|
||||
pub fn typetree_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> TypeTree {
|
||||
let mut visited = Vec::new();
|
||||
typetree_from_ty_inner(tcx, ty, 0, &mut visited)
|
||||
}
|
||||
|
||||
/// Maximum recursion depth for TypeTree generation to prevent stack overflow
|
||||
/// from pathological deeply nested types. Combined with cycle detection.
|
||||
const MAX_TYPETREE_DEPTH: usize = 6;
|
||||
|
||||
/// Internal recursive function for TypeTree generation with cycle detection and depth limiting.
|
||||
fn typetree_from_ty_inner<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
depth: usize,
|
||||
visited: &mut Vec<Ty<'tcx>>,
|
||||
) -> TypeTree {
|
||||
if depth >= MAX_TYPETREE_DEPTH {
|
||||
trace!("typetree depth limit {} reached for type: {}", MAX_TYPETREE_DEPTH, ty);
|
||||
return TypeTree::new();
|
||||
}
|
||||
|
||||
if visited.contains(&ty) {
|
||||
return TypeTree::new();
|
||||
}
|
||||
|
||||
visited.push(ty);
|
||||
let result = typetree_from_ty_impl(tcx, ty, depth, visited);
|
||||
visited.pop();
|
||||
result
|
||||
}
|
||||
|
||||
/// Implementation of TypeTree generation logic.
|
||||
fn typetree_from_ty_impl<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
depth: usize,
|
||||
visited: &mut Vec<Ty<'tcx>>,
|
||||
) -> TypeTree {
|
||||
typetree_from_ty_impl_inner(tcx, ty, depth, visited, false)
|
||||
}
|
||||
|
||||
/// Internal implementation with context about whether this is for a reference target.
|
||||
fn typetree_from_ty_impl_inner<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
depth: usize,
|
||||
visited: &mut Vec<Ty<'tcx>>,
|
||||
is_reference_target: bool,
|
||||
) -> TypeTree {
|
||||
if ty.is_scalar() {
|
||||
let (kind, size) = if ty.is_integral() || ty.is_char() || ty.is_bool() {
|
||||
(Kind::Integer, ty.primitive_size(tcx).bytes_usize())
|
||||
} else if ty.is_floating_point() {
|
||||
match ty {
|
||||
x if x == tcx.types.f16 => (Kind::Half, 2),
|
||||
x if x == tcx.types.f32 => (Kind::Float, 4),
|
||||
x if x == tcx.types.f64 => (Kind::Double, 8),
|
||||
x if x == tcx.types.f128 => (Kind::F128, 16),
|
||||
_ => (Kind::Integer, 0),
|
||||
}
|
||||
} else {
|
||||
(Kind::Integer, 0)
|
||||
};
|
||||
|
||||
// Use offset 0 for scalars that are direct targets of references (like &f64)
|
||||
// Use offset -1 for scalars used directly (like function return types)
|
||||
let offset = if is_reference_target && !ty.is_array() { 0 } else { -1 };
|
||||
return TypeTree(vec![Type { offset, size, kind, child: TypeTree::new() }]);
|
||||
}
|
||||
|
||||
if ty.is_ref() || ty.is_raw_ptr() || ty.is_box() {
|
||||
let inner_ty = if let Some(inner) = ty.builtin_deref(true) {
|
||||
inner
|
||||
} else {
|
||||
return TypeTree::new();
|
||||
};
|
||||
|
||||
let child = typetree_from_ty_impl_inner(tcx, inner_ty, depth + 1, visited, true);
|
||||
return TypeTree(vec![Type {
|
||||
offset: -1,
|
||||
size: tcx.data_layout.pointer_size().bytes_usize(),
|
||||
kind: Kind::Pointer,
|
||||
child,
|
||||
}]);
|
||||
}
|
||||
|
||||
if ty.is_array() {
|
||||
if let ty::Array(element_ty, len_const) = ty.kind() {
|
||||
let len = len_const.try_to_target_usize(tcx).unwrap_or(0);
|
||||
if len == 0 {
|
||||
return TypeTree::new();
|
||||
}
|
||||
let element_tree =
|
||||
typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false);
|
||||
let mut types = Vec::new();
|
||||
for elem_type in &element_tree.0 {
|
||||
types.push(Type {
|
||||
offset: -1,
|
||||
size: elem_type.size,
|
||||
kind: elem_type.kind,
|
||||
child: elem_type.child.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
return TypeTree(types);
|
||||
}
|
||||
}
|
||||
|
||||
if ty.is_slice() {
|
||||
if let ty::Slice(element_ty) = ty.kind() {
|
||||
let element_tree =
|
||||
typetree_from_ty_impl_inner(tcx, *element_ty, depth + 1, visited, false);
|
||||
return element_tree;
|
||||
}
|
||||
}
|
||||
|
||||
if let ty::Tuple(tuple_types) = ty.kind() {
|
||||
if tuple_types.is_empty() {
|
||||
return TypeTree::new();
|
||||
}
|
||||
|
||||
let mut types = Vec::new();
|
||||
let mut current_offset = 0;
|
||||
|
||||
for tuple_ty in tuple_types.iter() {
|
||||
let element_tree =
|
||||
typetree_from_ty_impl_inner(tcx, tuple_ty, depth + 1, visited, false);
|
||||
|
||||
let element_layout = tcx
|
||||
.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(tuple_ty))
|
||||
.ok()
|
||||
.map(|layout| layout.size.bytes_usize())
|
||||
.unwrap_or(0);
|
||||
|
||||
for elem_type in &element_tree.0 {
|
||||
types.push(Type {
|
||||
offset: if elem_type.offset == -1 {
|
||||
current_offset as isize
|
||||
} else {
|
||||
current_offset as isize + elem_type.offset
|
||||
},
|
||||
size: elem_type.size,
|
||||
kind: elem_type.kind,
|
||||
child: elem_type.child.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
current_offset += element_layout;
|
||||
}
|
||||
|
||||
return TypeTree(types);
|
||||
}
|
||||
|
||||
if let ty::Adt(adt_def, args) = ty.kind() {
|
||||
if adt_def.is_struct() {
|
||||
let struct_layout =
|
||||
tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty));
|
||||
if let Ok(layout) = struct_layout {
|
||||
let mut types = Vec::new();
|
||||
|
||||
for (field_idx, field_def) in adt_def.all_fields().enumerate() {
|
||||
let field_ty = field_def.ty(tcx, args);
|
||||
let field_tree =
|
||||
typetree_from_ty_impl_inner(tcx, field_ty, depth + 1, visited, false);
|
||||
|
||||
let field_offset = layout.fields.offset(field_idx).bytes_usize();
|
||||
|
||||
for elem_type in &field_tree.0 {
|
||||
types.push(Type {
|
||||
offset: if elem_type.offset == -1 {
|
||||
field_offset as isize
|
||||
} else {
|
||||
field_offset as isize + elem_type.offset
|
||||
},
|
||||
size: elem_type.size,
|
||||
kind: elem_type.kind,
|
||||
child: elem_type.child.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return TypeTree(types);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TypeTree::new()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3177,8 +3177,7 @@ define_print! {
|
|||
write!(p, "` can be evaluated")?;
|
||||
}
|
||||
ty::ClauseKind::UnstableFeature(symbol) => {
|
||||
write!(p, "unstable feature: ")?;
|
||||
write!(p, "`{symbol}`")?;
|
||||
write!(p, "feature({symbol}) is enabled")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -796,6 +796,7 @@ macro_rules! list_fold {
|
|||
|
||||
list_fold! {
|
||||
&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> : mk_poly_existential_predicates,
|
||||
&'tcx ty::List<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>: mk_predefined_opaques_in_body,
|
||||
&'tcx ty::List<PlaceElem<'tcx>> : mk_place_elems,
|
||||
&'tcx ty::List<ty::Pattern<'tcx>> : mk_patterns,
|
||||
&'tcx ty::List<ty::ArgOutlivesPredicate<'tcx>> : mk_outlives,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use rustc_middle::middle::region;
|
|||
use rustc_middle::mir::interpret::Scalar;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::cast::{CastTy, mir_cast_kind};
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_middle::ty::{self, Ty, UpvarArgs};
|
||||
|
|
@ -656,6 +657,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
block.and(rvalue)
|
||||
}
|
||||
|
||||
/// Recursively inspect a THIR expression and probe through unsizing
|
||||
/// operations that can be const-folded today.
|
||||
fn check_constness(&self, mut kind: &'a ExprKind<'tcx>) -> bool {
|
||||
loop {
|
||||
debug!(?kind, "check_constness");
|
||||
match kind {
|
||||
&ExprKind::ValueTypeAscription { source: eid, user_ty: _, user_ty_span: _ }
|
||||
| &ExprKind::Use { source: eid }
|
||||
| &ExprKind::PointerCoercion {
|
||||
cast: PointerCoercion::Unsize,
|
||||
source: eid,
|
||||
is_from_as_cast: _,
|
||||
}
|
||||
| &ExprKind::Scope { region_scope: _, lint_level: _, value: eid } => {
|
||||
kind = &self.thir[eid].kind
|
||||
}
|
||||
_ => return matches!(Category::of(&kind), Some(Category::Constant)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_zero_repeat(
|
||||
&mut self,
|
||||
mut block: BasicBlock,
|
||||
|
|
@ -666,7 +688,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let this = self;
|
||||
let value_expr = &this.thir[value];
|
||||
let elem_ty = value_expr.ty;
|
||||
if let Some(Category::Constant) = Category::of(&value_expr.kind) {
|
||||
if this.check_constness(&value_expr.kind) {
|
||||
// Repeating a const does nothing
|
||||
} else {
|
||||
// For a non-const, we may need to generate an appropriate `Drop`
|
||||
|
|
|
|||
|
|
@ -395,12 +395,10 @@ enum NeedsTemporary {
|
|||
Maybe,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// The `BlockAnd` "monad" packages up the new basic block along with a
|
||||
/// produced value (sometimes just unit, of course). The `unpack!`
|
||||
/// macro (and methods below) makes working with `BlockAnd` much more
|
||||
/// convenient.
|
||||
|
||||
#[must_use = "if you don't use one of these results, you're leaving a dangling edge"]
|
||||
struct BlockAnd<T>(BasicBlock, T);
|
||||
|
||||
|
|
@ -438,9 +436,7 @@ macro_rules! unpack {
|
|||
}};
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// the main entry point for building MIR for a function
|
||||
|
||||
/// The main entry point for building MIR for a function.
|
||||
fn construct_fn<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn_def: LocalDefId,
|
||||
|
|
|
|||
|
|
@ -554,6 +554,21 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
visit::walk_expr(self, &self.thir[arg]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Secondly, we allow raw borrows of union field accesses. Peel
|
||||
// any of those off, and recurse normally on the LHS, which should
|
||||
// reject any unsafe operations within.
|
||||
let mut peeled = arg;
|
||||
while let ExprKind::Scope { value: arg, .. } = self.thir[peeled].kind
|
||||
&& let ExprKind::Field { lhs, name: _, variant_index: _ } = self.thir[arg].kind
|
||||
&& let ty::Adt(def, _) = &self.thir[lhs].ty.kind()
|
||||
&& def.is_union()
|
||||
{
|
||||
peeled = lhs;
|
||||
}
|
||||
visit::walk_expr(self, &self.thir[peeled]);
|
||||
// And return so we don't recurse directly onto the union field access(es).
|
||||
return;
|
||||
}
|
||||
ExprKind::Deref { arg } => {
|
||||
if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) =
|
||||
|
|
|
|||
|
|
@ -1275,13 +1275,13 @@ fn report_non_exhaustive_match<'p, 'tcx>(
|
|||
if ty.is_ptr_sized_integral() {
|
||||
if ty.inner() == cx.tcx.types.usize {
|
||||
err.note(format!(
|
||||
"`{ty}` does not have a fixed maximum value, so half-open ranges are \
|
||||
necessary to match exhaustively",
|
||||
"`{ty}::MAX` is not treated as exhaustive, \
|
||||
so half-open ranges are necessary to match exhaustively",
|
||||
));
|
||||
} else if ty.inner() == cx.tcx.types.isize {
|
||||
err.note(format!(
|
||||
"`{ty}` does not have fixed minimum and maximum values, so half-open \
|
||||
ranges are necessary to match exhaustively",
|
||||
"`{ty}::MIN` and `{ty}::MAX` are not treated as exhaustive, \
|
||||
so half-open ranges are necessary to match exhaustively",
|
||||
));
|
||||
}
|
||||
} else if ty.inner() == cx.tcx.types.str_ {
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
|
|||
body,
|
||||
arena,
|
||||
map: Map::new(tcx, body, Some(MAX_PLACES)),
|
||||
loop_headers: loop_headers(body),
|
||||
maybe_loop_headers: maybe_loop_headers(body),
|
||||
opportunities: Vec::new(),
|
||||
};
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
|
|||
|
||||
// Verify that we do not thread through a loop header.
|
||||
for to in opportunities.iter() {
|
||||
assert!(to.chain.iter().all(|&block| !finder.loop_headers.contains(block)));
|
||||
assert!(to.chain.iter().all(|&block| !finder.maybe_loop_headers.contains(block)));
|
||||
}
|
||||
OpportunitySet::new(body, opportunities).apply(body);
|
||||
}
|
||||
|
|
@ -124,7 +124,7 @@ struct TOFinder<'a, 'tcx> {
|
|||
ecx: InterpCx<'tcx, DummyMachine>,
|
||||
body: &'a Body<'tcx>,
|
||||
map: Map<'tcx>,
|
||||
loop_headers: DenseBitSet<BasicBlock>,
|
||||
maybe_loop_headers: DenseBitSet<BasicBlock>,
|
||||
/// We use an arena to avoid cloning the slices when cloning `state`.
|
||||
arena: &'a DroplessArena,
|
||||
opportunities: Vec<ThreadingOpportunity>,
|
||||
|
|
@ -190,7 +190,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
|
|||
#[instrument(level = "trace", skip(self))]
|
||||
fn start_from_switch(&mut self, bb: BasicBlock) {
|
||||
let bbdata = &self.body[bb];
|
||||
if bbdata.is_cleanup || self.loop_headers.contains(bb) {
|
||||
if bbdata.is_cleanup || self.maybe_loop_headers.contains(bb) {
|
||||
return;
|
||||
}
|
||||
let Some((discr, targets)) = bbdata.terminator().kind.as_switch() else { return };
|
||||
|
|
@ -235,7 +235,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
|
|||
depth: usize,
|
||||
) {
|
||||
// Do not thread through loop headers.
|
||||
if self.loop_headers.contains(bb) {
|
||||
if self.maybe_loop_headers.contains(bb) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -833,20 +833,28 @@ enum Update {
|
|||
Decr,
|
||||
}
|
||||
|
||||
/// Compute the set of loop headers in the given body. We define a loop header as a block which has
|
||||
/// at least a predecessor which it dominates. This definition is only correct for reducible CFGs.
|
||||
/// But if the CFG is already irreducible, there is no point in trying much harder.
|
||||
/// is already irreducible.
|
||||
fn loop_headers(body: &Body<'_>) -> DenseBitSet<BasicBlock> {
|
||||
let mut loop_headers = DenseBitSet::new_empty(body.basic_blocks.len());
|
||||
let dominators = body.basic_blocks.dominators();
|
||||
// Only visit reachable blocks.
|
||||
for (bb, bbdata) in traversal::preorder(body) {
|
||||
/// Compute the set of loop headers in the given body. A loop header is usually defined as a block
|
||||
/// which dominates one of its predecessors. This definition is only correct for reducible CFGs.
|
||||
/// However, computing dominators is expensive, so we approximate according to the post-order
|
||||
/// traversal order. A loop header for us is a block which is visited after its predecessor in
|
||||
/// post-order. This is ok as we mostly need a heuristic.
|
||||
fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet<BasicBlock> {
|
||||
let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len());
|
||||
let mut visited = DenseBitSet::new_empty(body.basic_blocks.len());
|
||||
for (bb, bbdata) in traversal::postorder(body) {
|
||||
// Post-order means we visit successors before the block for acyclic CFGs.
|
||||
// If the successor is not visited yet, consider it a loop header.
|
||||
for succ in bbdata.terminator().successors() {
|
||||
if dominators.dominates(succ, bb) {
|
||||
loop_headers.insert(succ);
|
||||
if !visited.contains(succ) {
|
||||
maybe_loop_headers.insert(succ);
|
||||
}
|
||||
}
|
||||
|
||||
// Only mark `bb` as visited after we checked the successors, in case we have a self-loop.
|
||||
// bb1: goto -> bb1;
|
||||
let _new = visited.insert(bb);
|
||||
debug_assert!(_new);
|
||||
}
|
||||
loop_headers
|
||||
|
||||
maybe_loop_headers
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_index::Idx;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::Span;
|
||||
|
|
@ -9,7 +10,7 @@ use tracing::debug;
|
|||
/// and replacement of terminators, and then apply the queued changes all at
|
||||
/// once with `apply`. This is useful for MIR transformation passes.
|
||||
pub(crate) struct MirPatch<'tcx> {
|
||||
term_patch_map: IndexVec<BasicBlock, Option<TerminatorKind<'tcx>>>,
|
||||
term_patch_map: FxHashMap<BasicBlock, TerminatorKind<'tcx>>,
|
||||
new_blocks: Vec<BasicBlockData<'tcx>>,
|
||||
new_statements: Vec<(Location, StatementKind<'tcx>)>,
|
||||
new_locals: Vec<LocalDecl<'tcx>>,
|
||||
|
|
@ -22,17 +23,21 @@ pub(crate) struct MirPatch<'tcx> {
|
|||
terminate_block: Option<(BasicBlock, UnwindTerminateReason)>,
|
||||
body_span: Span,
|
||||
next_local: usize,
|
||||
/// The number of blocks at the start of the transformation. New blocks
|
||||
/// get appended at the end.
|
||||
next_block: usize,
|
||||
}
|
||||
|
||||
impl<'tcx> MirPatch<'tcx> {
|
||||
/// Creates a new, empty patch.
|
||||
pub(crate) fn new(body: &Body<'tcx>) -> Self {
|
||||
let mut result = MirPatch {
|
||||
term_patch_map: IndexVec::from_elem(None, &body.basic_blocks),
|
||||
term_patch_map: Default::default(),
|
||||
new_blocks: vec![],
|
||||
new_statements: vec![],
|
||||
new_locals: vec![],
|
||||
next_local: body.local_decls.len(),
|
||||
next_block: body.basic_blocks.len(),
|
||||
resume_block: None,
|
||||
unreachable_cleanup_block: None,
|
||||
unreachable_no_cleanup_block: None,
|
||||
|
|
@ -141,7 +146,7 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
|
||||
/// Has a replacement of this block's terminator been queued in this patch?
|
||||
pub(crate) fn is_term_patched(&self, bb: BasicBlock) -> bool {
|
||||
self.term_patch_map[bb].is_some()
|
||||
self.term_patch_map.contains_key(&bb)
|
||||
}
|
||||
|
||||
/// Universal getter for block data, either it is in 'old' blocks or in patched ones
|
||||
|
|
@ -194,18 +199,17 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
|
||||
/// Queues the addition of a new basic block.
|
||||
pub(crate) fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock {
|
||||
let block = self.term_patch_map.next_index();
|
||||
let block = BasicBlock::from_usize(self.next_block + self.new_blocks.len());
|
||||
debug!("MirPatch: new_block: {:?}: {:?}", block, data);
|
||||
self.new_blocks.push(data);
|
||||
self.term_patch_map.push(None);
|
||||
block
|
||||
}
|
||||
|
||||
/// Queues the replacement of a block's terminator.
|
||||
pub(crate) fn patch_terminator(&mut self, block: BasicBlock, new: TerminatorKind<'tcx>) {
|
||||
assert!(self.term_patch_map[block].is_none());
|
||||
assert!(!self.term_patch_map.contains_key(&block));
|
||||
debug!("MirPatch: patch_terminator({:?}, {:?})", block, new);
|
||||
self.term_patch_map[block] = Some(new);
|
||||
self.term_patch_map.insert(block, new);
|
||||
}
|
||||
|
||||
/// Queues the insertion of a statement at a given location. The statement
|
||||
|
|
@ -244,6 +248,7 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
self.new_blocks.len(),
|
||||
body.basic_blocks.len()
|
||||
);
|
||||
debug_assert_eq!(self.next_block, body.basic_blocks.len());
|
||||
let bbs = if self.term_patch_map.is_empty() && self.new_blocks.is_empty() {
|
||||
body.basic_blocks.as_mut_preserves_cfg()
|
||||
} else {
|
||||
|
|
@ -251,11 +256,12 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
};
|
||||
bbs.extend(self.new_blocks);
|
||||
body.local_decls.extend(self.new_locals);
|
||||
for (src, patch) in self.term_patch_map.into_iter_enumerated() {
|
||||
if let Some(patch) = patch {
|
||||
debug!("MirPatch: patching block {:?}", src);
|
||||
bbs[src].terminator_mut().kind = patch;
|
||||
}
|
||||
|
||||
// The order in which we patch terminators does not change the result.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
for (src, patch) in self.term_patch_map {
|
||||
debug!("MirPatch: patching block {:?}", src);
|
||||
bbs[src].terminator_mut().kind = patch;
|
||||
}
|
||||
|
||||
let mut new_statements = self.new_statements;
|
||||
|
|
@ -273,8 +279,8 @@ impl<'tcx> MirPatch<'tcx> {
|
|||
}
|
||||
debug!("MirPatch: adding statement {:?} at loc {:?}+{}", stmt, loc, delta);
|
||||
loc.statement_index += delta;
|
||||
let source_info = Self::source_info_for_index(&body[loc.block], loc);
|
||||
body[loc.block]
|
||||
let source_info = Self::source_info_for_index(&bbs[loc.block], loc);
|
||||
bbs[loc.block]
|
||||
.statements
|
||||
.insert(loc.statement_index, Statement::new(source_info, stmt));
|
||||
delta += 1;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use crate::delegate::SolverDelegate;
|
|||
use crate::resolve::eager_resolve_vars;
|
||||
use crate::solve::{
|
||||
CanonicalInput, CanonicalResponse, Certainty, ExternalConstraintsData, Goal,
|
||||
NestedNormalizationGoals, PredefinedOpaquesData, QueryInput, Response, inspect,
|
||||
NestedNormalizationGoals, QueryInput, Response, inspect,
|
||||
};
|
||||
|
||||
pub mod canonicalizer;
|
||||
|
|
@ -53,7 +53,7 @@ impl<I: Interner, T> ResponseT<I> for inspect::State<I, T> {
|
|||
pub(super) fn canonicalize_goal<D, I>(
|
||||
delegate: &D,
|
||||
goal: Goal<I, I::Predicate>,
|
||||
opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>,
|
||||
opaque_types: &[(ty::OpaqueTypeKey<I>, I::Ty)],
|
||||
) -> (Vec<I::GenericArg>, CanonicalInput<I, I::Predicate>)
|
||||
where
|
||||
D: SolverDelegate<Interner = I>,
|
||||
|
|
@ -65,9 +65,7 @@ where
|
|||
&mut orig_values,
|
||||
QueryInput {
|
||||
goal,
|
||||
predefined_opaques_in_body: delegate
|
||||
.cx()
|
||||
.mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }),
|
||||
predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types),
|
||||
},
|
||||
);
|
||||
let query_input = ty::CanonicalQueryInput { canonical, typing_mode: delegate.typing_mode() };
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ where
|
|||
D: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn evaluate_root_goal(
|
||||
&self,
|
||||
goal: Goal<I, I::Predicate>,
|
||||
|
|
@ -206,6 +206,7 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn root_goal_may_hold_opaque_types_jank(
|
||||
&self,
|
||||
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
|
||||
|
|
@ -357,7 +358,7 @@ where
|
|||
f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R,
|
||||
) -> R {
|
||||
let (ref delegate, input, var_values) = D::build_with_canonical(cx, &canonical_input);
|
||||
for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
|
||||
for (key, ty) in input.predefined_opaques_in_body.iter() {
|
||||
let prev = delegate.register_hidden_type_in_storage(key, ty, I::Span::dummy());
|
||||
// It may be possible that two entries in the opaque type storage end up
|
||||
// with the same key after resolving contained inference variables.
|
||||
|
|
@ -467,7 +468,7 @@ where
|
|||
let opaque_types = self.delegate.clone_opaque_types_lookup_table();
|
||||
let (goal, opaque_types) = eager_resolve_vars(self.delegate, (goal, opaque_types));
|
||||
|
||||
let (orig_values, canonical_goal) = canonicalize_goal(self.delegate, goal, opaque_types);
|
||||
let (orig_values, canonical_goal) = canonicalize_goal(self.delegate, goal, &opaque_types);
|
||||
let canonical_result = self.search_graph.evaluate_goal(
|
||||
self.cx(),
|
||||
canonical_goal,
|
||||
|
|
@ -548,7 +549,6 @@ where
|
|||
.canonical
|
||||
.value
|
||||
.predefined_opaques_in_body
|
||||
.opaque_types
|
||||
.len(),
|
||||
stalled_vars,
|
||||
sub_roots,
|
||||
|
|
@ -1557,7 +1557,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree<D: SolverDelegate<Interner = I>,
|
|||
let opaque_types = delegate.clone_opaque_types_lookup_table();
|
||||
let (goal, opaque_types) = eager_resolve_vars(delegate, (goal, opaque_types));
|
||||
|
||||
let (orig_values, canonical_goal) = canonicalize_goal(delegate, goal, opaque_types);
|
||||
let (orig_values, canonical_goal) = canonicalize_goal(delegate, goal, &opaque_types);
|
||||
|
||||
let (canonical_result, final_revision) =
|
||||
delegate.cx().evaluate_root_goal_for_proof_tree_raw(canonical_goal);
|
||||
|
|
|
|||
|
|
@ -381,6 +381,7 @@ where
|
|||
}
|
||||
|
||||
/// The result of evaluating a goal.
|
||||
#[derive_where(Debug; I: Interner)]
|
||||
pub struct GoalEvaluation<I: Interner> {
|
||||
/// The goal we've evaluated. This is the input goal, but potentially with its
|
||||
/// inference variables resolved. This never applies any inference constraints
|
||||
|
|
|
|||
|
|
@ -74,20 +74,28 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn is_initial_provisional_result(
|
||||
cx: Self::Cx,
|
||||
kind: PathKind,
|
||||
input: CanonicalInput<I>,
|
||||
result: QueryResult<I>,
|
||||
) -> bool {
|
||||
Self::initial_provisional_result(cx, kind, input) == result
|
||||
fn is_initial_provisional_result(result: QueryResult<I>) -> Option<PathKind> {
|
||||
match result {
|
||||
Ok(response) => {
|
||||
if has_no_inference_or_external_constraints(response) {
|
||||
if response.value.certainty == Certainty::Yes {
|
||||
return Some(PathKind::Coinductive);
|
||||
} else if response.value.certainty == Certainty::overflow(false) {
|
||||
return Some(PathKind::Unknown);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
Err(NoSolution) => Some(PathKind::Inductive),
|
||||
}
|
||||
}
|
||||
|
||||
fn on_stack_overflow(cx: I, input: CanonicalInput<I>) -> QueryResult<I> {
|
||||
fn stack_overflow_result(cx: I, input: CanonicalInput<I>) -> QueryResult<I> {
|
||||
response_no_constraints(cx, input, Certainty::overflow(true))
|
||||
}
|
||||
|
||||
fn on_fixpoint_overflow(cx: I, input: CanonicalInput<I>) -> QueryResult<I> {
|
||||
fn fixpoint_overflow_result(cx: I, input: CanonicalInput<I>) -> QueryResult<I> {
|
||||
response_no_constraints(cx, input, Certainty::overflow(false))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,15 +93,6 @@ passes_dead_codes =
|
|||
}
|
||||
} never {$participle}
|
||||
|
||||
passes_debug_visualizer_invalid =
|
||||
invalid argument
|
||||
.note_1 = expected: `natvis_file = "..."`
|
||||
.note_2 = OR
|
||||
.note_3 = expected: `gdb_script_file = "..."`
|
||||
|
||||
passes_debug_visualizer_placement =
|
||||
attribute should be applied to a module
|
||||
|
||||
passes_debug_visualizer_unreadable =
|
||||
couldn't read {$file}: {$error}
|
||||
|
||||
|
|
@ -149,8 +140,17 @@ passes_doc_attribute_not_attribute =
|
|||
nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]`
|
||||
.help = only existing builtin attributes are allowed in core/std
|
||||
|
||||
passes_doc_cfg_hide_takes_list =
|
||||
`#[doc(cfg_hide(...))]` takes a list of attributes
|
||||
passes_doc_auto_cfg_expects_hide_or_show =
|
||||
only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]`
|
||||
|
||||
passes_doc_auto_cfg_hide_show_expects_list =
|
||||
`#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items
|
||||
|
||||
passes_doc_auto_cfg_hide_show_unexpected_item =
|
||||
`#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items
|
||||
|
||||
passes_doc_auto_cfg_wrong_literal =
|
||||
expected boolean for `#[doc(auto_cfg = ...)]`
|
||||
|
||||
passes_doc_expect_str =
|
||||
doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use std::collections::hash_map::Entry;
|
|||
use std::slice;
|
||||
|
||||
use rustc_abi::{Align, ExternAbi, Size};
|
||||
use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast};
|
||||
use rustc_ast::{AttrStyle, LitKind, MetaItem, MetaItemInner, MetaItemKind, ast};
|
||||
use rustc_attr_parsing::{AttributeParser, Late};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
|
||||
|
|
@ -256,6 +256,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::MacroEscape( .. )
|
||||
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
|
||||
| AttributeKind::RustcLayoutScalarValidRangeEnd(..)
|
||||
| AttributeKind::RustcSimdMonomorphizeLaneLimit(..)
|
||||
| AttributeKind::ExportStable
|
||||
| AttributeKind::FfiConst(..)
|
||||
| AttributeKind::UnstableFeatureBound(..)
|
||||
|
|
@ -281,6 +282,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::ObjcClass { .. }
|
||||
| AttributeKind::ObjcSelector { .. }
|
||||
| AttributeKind::RustcCoherenceIsCore(..)
|
||||
| AttributeKind::DebuggerVisualizer(..)
|
||||
) => { /* do nothing */ }
|
||||
Attribute::Unparsed(attr_item) => {
|
||||
style = Some(attr_item.style);
|
||||
|
|
@ -301,7 +303,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
&mut doc_aliases,
|
||||
),
|
||||
[sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
|
||||
[sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target),
|
||||
[sym::rustc_no_implicit_autorefs, ..] => {
|
||||
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||
}
|
||||
|
|
@ -1159,16 +1160,59 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes.
|
||||
///
|
||||
fn check_doc_cfg_hide(&self, meta: &MetaItemInner, hir_id: HirId) {
|
||||
if meta.meta_item_list().is_none() {
|
||||
self.tcx.emit_node_span_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
meta.span(),
|
||||
errors::DocCfgHideTakesList,
|
||||
);
|
||||
/// Check that the `#![doc(auto_cfg)]` attribute has the expected input.
|
||||
fn check_doc_auto_cfg(&self, meta: &MetaItem, hir_id: HirId) {
|
||||
match &meta.kind {
|
||||
MetaItemKind::Word => {}
|
||||
MetaItemKind::NameValue(lit) => {
|
||||
if !matches!(lit.kind, LitKind::Bool(_)) {
|
||||
self.tcx.emit_node_span_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
meta.span,
|
||||
errors::DocAutoCfgWrongLiteral,
|
||||
);
|
||||
}
|
||||
}
|
||||
MetaItemKind::List(list) => {
|
||||
for item in list {
|
||||
let Some(attr_name @ (sym::hide | sym::show)) = item.name() else {
|
||||
self.tcx.emit_node_span_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
meta.span,
|
||||
errors::DocAutoCfgExpectsHideOrShow,
|
||||
);
|
||||
continue;
|
||||
};
|
||||
if let Some(list) = item.meta_item_list() {
|
||||
for item in list {
|
||||
let valid = item.meta_item().is_some_and(|meta| {
|
||||
meta.path.segments.len() == 1
|
||||
&& matches!(
|
||||
&meta.kind,
|
||||
MetaItemKind::Word | MetaItemKind::NameValue(_)
|
||||
)
|
||||
});
|
||||
if !valid {
|
||||
self.tcx.emit_node_span_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
item.span(),
|
||||
errors::DocAutoCfgHideShowUnexpectedItem { attr_name },
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.tcx.emit_node_span_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
meta.span,
|
||||
errors::DocAutoCfgHideShowExpectsList { attr_name },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1244,10 +1288,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
self.check_attr_crate_level(attr, style, meta, hir_id);
|
||||
}
|
||||
|
||||
Some(sym::cfg_hide) => {
|
||||
if self.check_attr_crate_level(attr, style, meta, hir_id) {
|
||||
self.check_doc_cfg_hide(meta, hir_id);
|
||||
}
|
||||
Some(sym::auto_cfg) => {
|
||||
self.check_doc_auto_cfg(i_meta, hir_id);
|
||||
}
|
||||
|
||||
Some(sym::inline | sym::no_inline) => {
|
||||
|
|
@ -1782,20 +1824,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
|
||||
fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) {
|
||||
// Here we only check that the #[debugger_visualizer] attribute is attached
|
||||
// to nothing other than a module. All other checks are done in the
|
||||
// `debugger_visualizer` query where they need to be done for decoding
|
||||
// anyway.
|
||||
match target {
|
||||
Target::Mod => {}
|
||||
_ => {
|
||||
self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
|
||||
/// (Allows proc_macro functions)
|
||||
fn check_rustc_allow_const_fn_unstable(
|
||||
|
|
|
|||
|
|
@ -1,67 +1,60 @@
|
|||
//! Detecting usage of the `#[debugger_visualizer]` attribute.
|
||||
|
||||
use rustc_ast::Attribute;
|
||||
use rustc_ast::ast::NodeId;
|
||||
use rustc_ast::{HasNodeId, ItemKind, ast};
|
||||
use rustc_attr_parsing::AttributeParser;
|
||||
use rustc_expand::base::resolve_path;
|
||||
use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
|
||||
use rustc_hir::Attribute;
|
||||
use rustc_hir::attrs::{AttributeKind, DebugVisualizer};
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
use rustc_middle::query::{LocalCrate, Providers};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::sym;
|
||||
use rustc_span::{DUMMY_SP, Span, sym};
|
||||
|
||||
use crate::errors::{DebugVisualizerInvalid, DebugVisualizerUnreadable};
|
||||
use crate::errors::DebugVisualizerUnreadable;
|
||||
|
||||
impl DebuggerVisualizerCollector<'_> {
|
||||
fn check_for_debugger_visualizer(&mut self, attr: &Attribute) {
|
||||
if attr.has_name(sym::debugger_visualizer) {
|
||||
let Some(hints) = attr.meta_item_list() else {
|
||||
self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
|
||||
return;
|
||||
};
|
||||
fn check_for_debugger_visualizer(
|
||||
&mut self,
|
||||
attrs: &[ast::Attribute],
|
||||
span: Span,
|
||||
node_id: NodeId,
|
||||
) {
|
||||
if let Some(Attribute::Parsed(AttributeKind::DebuggerVisualizer(visualizers))) =
|
||||
AttributeParser::parse_limited(
|
||||
&self.sess,
|
||||
attrs,
|
||||
sym::debugger_visualizer,
|
||||
span,
|
||||
node_id,
|
||||
None,
|
||||
)
|
||||
{
|
||||
for DebugVisualizer { span, visualizer_type, path } in visualizers {
|
||||
let file = match resolve_path(&self.sess, path.as_str(), span) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let [hint] = hints.as_slice() else {
|
||||
self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(meta_item) = hint.meta_item() else {
|
||||
self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
|
||||
return;
|
||||
};
|
||||
|
||||
let (visualizer_type, visualizer_path) = match (meta_item.name(), meta_item.value_str())
|
||||
{
|
||||
(Some(sym::natvis_file), Some(value)) => (DebuggerVisualizerType::Natvis, value),
|
||||
(Some(sym::gdb_script_file), Some(value)) => {
|
||||
(DebuggerVisualizerType::GdbPrettyPrinter, value)
|
||||
}
|
||||
(_, _) => {
|
||||
self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span });
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let file = match resolve_path(&self.sess, visualizer_path.as_str(), attr.span) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match self.sess.source_map().load_binary_file(&file) {
|
||||
Ok((source, _)) => {
|
||||
self.visualizers.push(DebuggerVisualizerFile::new(
|
||||
source,
|
||||
visualizer_type,
|
||||
file,
|
||||
));
|
||||
}
|
||||
Err(error) => {
|
||||
self.sess.dcx().emit_err(DebugVisualizerUnreadable {
|
||||
span: meta_item.span,
|
||||
file: &file,
|
||||
error,
|
||||
});
|
||||
match self.sess.source_map().load_binary_file(&file) {
|
||||
Ok((source, _)) => {
|
||||
self.visualizers.push(DebuggerVisualizerFile::new(
|
||||
source,
|
||||
visualizer_type,
|
||||
file,
|
||||
));
|
||||
}
|
||||
Err(error) => {
|
||||
self.sess.dcx().emit_err(DebugVisualizerUnreadable {
|
||||
span,
|
||||
file: &file,
|
||||
error,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -74,9 +67,15 @@ struct DebuggerVisualizerCollector<'a> {
|
|||
}
|
||||
|
||||
impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> {
|
||||
fn visit_attribute(&mut self, attr: &'ast Attribute) {
|
||||
self.check_for_debugger_visualizer(attr);
|
||||
rustc_ast::visit::walk_attribute(self, attr);
|
||||
fn visit_item(&mut self, item: &'ast rustc_ast::Item) -> Self::Result {
|
||||
if let ItemKind::Mod(..) = item.kind {
|
||||
self.check_for_debugger_visualizer(&item.attrs, item.span, item.node_id());
|
||||
}
|
||||
rustc_ast::visit::walk_item(self, item);
|
||||
}
|
||||
fn visit_crate(&mut self, krate: &'ast ast::Crate) -> Self::Result {
|
||||
self.check_for_debugger_visualizer(&krate.attrs, DUMMY_SP, krate.id);
|
||||
rustc_ast::visit::walk_crate(self, krate);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -309,8 +309,24 @@ pub(crate) struct DocTestLiteral;
|
|||
pub(crate) struct DocTestTakesList;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_doc_cfg_hide_takes_list)]
|
||||
pub(crate) struct DocCfgHideTakesList;
|
||||
#[diag(passes_doc_auto_cfg_wrong_literal)]
|
||||
pub(crate) struct DocAutoCfgWrongLiteral;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_doc_auto_cfg_expects_hide_or_show)]
|
||||
pub(crate) struct DocAutoCfgExpectsHideOrShow;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_doc_auto_cfg_hide_show_expects_list)]
|
||||
pub(crate) struct DocAutoCfgHideShowExpectsList {
|
||||
pub attr_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_doc_auto_cfg_hide_show_unexpected_item)]
|
||||
pub(crate) struct DocAutoCfgHideShowUnexpectedItem {
|
||||
pub attr_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_doc_test_unknown_any)]
|
||||
|
|
@ -475,23 +491,6 @@ pub(crate) struct MacroOnlyAttribute {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_debug_visualizer_placement)]
|
||||
pub(crate) struct DebugVisualizerPlacement {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_debug_visualizer_invalid)]
|
||||
#[note(passes_note_1)]
|
||||
#[note(passes_note_2)]
|
||||
#[note(passes_note_3)]
|
||||
pub(crate) struct DebugVisualizerInvalid {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_debug_visualizer_unreadable)]
|
||||
pub(crate) struct DebugVisualizerUnreadable<'a> {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ use tracing::debug;
|
|||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Generic infrastructure used to implement specific visitors below.
|
||||
// Generic infrastructure used to implement specific visitors below.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct LazyDefPathStr<'tcx> {
|
||||
|
|
@ -309,10 +309,7 @@ fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visib
|
|||
if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Visitor used to determine impl visibility and reachability.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct FindMin<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
effective_visibilities: &'a EffectiveVisibilities,
|
||||
|
|
@ -387,10 +384,7 @@ impl VisibilityLike for EffectiveVisibility {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// The embargo visitor, used to determine the exports of the AST.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct EmbargoVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
||||
|
|
@ -849,9 +843,7 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx>
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Visitor, used for EffectiveVisibilities table checking
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
pub struct TestReachabilityVisitor<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
effective_visibilities: &'a EffectiveVisibilities,
|
||||
|
|
@ -909,13 +901,11 @@ impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Name privacy visitor, checks privacy and reports violations.
|
||||
///
|
||||
/// Most of name privacy checks are performed during the main resolution phase,
|
||||
/// or later in type checking when field accesses and associated items are resolved.
|
||||
/// This pass performs remaining checks for fields in struct expressions and patterns.
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct NamePrivacyVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
|
||||
|
|
@ -1120,12 +1110,10 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Type privacy visitor, checks types for privacy and reports violations.
|
||||
///
|
||||
/// Both explicitly written types and inferred types of expressions and patterns are checked.
|
||||
/// Checks are performed on "semantic" types regardless of names and their hygiene.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct TypePrivacyVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
module_def_id: LocalModDefId,
|
||||
|
|
@ -1345,13 +1333,11 @@ impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and
|
||||
/// finds any private components in it.
|
||||
///
|
||||
/// PrivateItemsInPublicInterfacesVisitor ensures there are no private types
|
||||
/// and traits in public interfaces.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct SearchInterfaceForPrivateItemsVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item_def_id: LocalDefId,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
//! unexpanded macros in the fragment are visited and registered.
|
||||
//! Imports are also considered items and placed into modules here, but not resolved yet.
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind};
|
||||
|
|
@ -35,6 +34,7 @@ use crate::Namespace::{MacroNS, TypeNS, ValueNS};
|
|||
use crate::def_collector::collect_definitions;
|
||||
use crate::imports::{ImportData, ImportKind};
|
||||
use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
|
||||
use crate::ref_mut::CmCell;
|
||||
use crate::{
|
||||
BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot,
|
||||
NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Used,
|
||||
|
|
@ -87,7 +87,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
// because they can be fetched by glob imports from those modules, and bring traits
|
||||
// into scope both directly and through glob imports.
|
||||
let key = BindingKey::new_disambiguated(ident, ns, || {
|
||||
parent.underscore_disambiguator.update(|d| d + 1);
|
||||
// FIXME(batched): Will be fixed in batched resolution.
|
||||
parent.underscore_disambiguator.update_unchecked(|d| d + 1);
|
||||
parent.underscore_disambiguator.get()
|
||||
});
|
||||
if self
|
||||
|
|
@ -477,7 +478,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
kind,
|
||||
parent_scope: self.parent_scope,
|
||||
module_path,
|
||||
imported_module: Cell::new(None),
|
||||
imported_module: CmCell::new(None),
|
||||
span,
|
||||
use_span: item.span,
|
||||
use_span_with_attributes: item.span_with_attributes(),
|
||||
|
|
@ -505,7 +506,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
});
|
||||
}
|
||||
}
|
||||
ImportKind::Glob { .. } => current_module.globs.borrow_mut().push(import),
|
||||
ImportKind::Glob { .. } => current_module.globs.borrow_mut(self.r).push(import),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
@ -668,7 +669,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
}
|
||||
ast::UseTreeKind::Glob => {
|
||||
if !ast::attr::contains_name(&item.attrs, sym::prelude_import) {
|
||||
let kind = ImportKind::Glob { max_vis: Cell::new(None), id };
|
||||
let kind = ImportKind::Glob { max_vis: CmCell::new(None), id };
|
||||
self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis);
|
||||
} else {
|
||||
// Resolve the prelude import early.
|
||||
|
|
@ -971,7 +972,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id },
|
||||
root_id: item.id,
|
||||
parent_scope: self.parent_scope,
|
||||
imported_module: Cell::new(module),
|
||||
imported_module: CmCell::new(module),
|
||||
has_attributes: !item.attrs.is_empty(),
|
||||
use_span_with_attributes: item.span_with_attributes(),
|
||||
use_span: item.span,
|
||||
|
|
@ -1103,7 +1104,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
kind: ImportKind::MacroUse { warn_private },
|
||||
root_id: item.id,
|
||||
parent_scope: this.parent_scope,
|
||||
imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
|
||||
imported_module: CmCell::new(Some(ModuleOrUniformRoot::Module(module))),
|
||||
use_span_with_attributes: item.span_with_attributes(),
|
||||
has_attributes: !item.attrs.is_empty(),
|
||||
use_span: item.span,
|
||||
|
|
@ -1196,7 +1197,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
/// directly into its parent scope's module.
|
||||
fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'ra> {
|
||||
let invoc_id = self.visit_invoc(id);
|
||||
self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id);
|
||||
self.parent_scope.module.unexpanded_invocations.borrow_mut(self.r).insert(invoc_id);
|
||||
self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id))
|
||||
}
|
||||
|
||||
|
|
@ -1274,7 +1275,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
|
|||
kind: ImportKind::MacroExport,
|
||||
root_id: item.id,
|
||||
parent_scope: self.parent_scope,
|
||||
imported_module: Cell::new(None),
|
||||
imported_module: CmCell::new(None),
|
||||
has_attributes: false,
|
||||
use_span_with_attributes: span,
|
||||
use_span: span,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue