mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Auto merge of #152739 - Zalathar:rollup-8qaJ8F2, r=Zalathar
Rollup of 11 pull requests Successful merges: - rust-lang/rust#152700 (miri subtree update) - rust-lang/rust#152715 (`rust-analyzer` subtree update) - rust-lang/rust#151783 (Implement RFC 3678: Final trait methods) - rust-lang/rust#152512 (core: Implement feature `float_exact_integer_constants`) - rust-lang/rust#152661 (Avoid ICE in From/TryFrom diagnostic under -Znext-solver) - rust-lang/rust#152703 (Remove `rustc_query_system`) - rust-lang/rust#152206 (misc doc improvements) - rust-lang/rust#152664 (Fix mis-constructed `file_span` when generating scraped examples) - rust-lang/rust#152698 (Suppress unstable-trait notes under `-Zforce-unstable-if-unmarked`) - rust-lang/rust#152727 (`probe_op` silence ambiguity errors if tainted) - rust-lang/rust#152728 (Port #![default_lib_allocator] to the new attribute parser)
This commit is contained in:
-19
@@ -3640,7 +3640,6 @@ dependencies = [
|
||||
"rustc_macros",
|
||||
"rustc_metadata",
|
||||
"rustc_middle",
|
||||
"rustc_query_system",
|
||||
"rustc_sanitizers",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
@@ -4243,7 +4242,6 @@ dependencies = [
|
||||
"rustc_index",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_query_system",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
@@ -4507,23 +4505,6 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_query_system"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_hir",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_resolve"
|
||||
version = "0.0.0"
|
||||
|
||||
@@ -3131,8 +3131,16 @@ pub enum Const {
|
||||
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
|
||||
pub enum Defaultness {
|
||||
/// Item is unmarked. Implicitly determined based off of position.
|
||||
/// For impls, this is `final`; for traits, this is `default`.
|
||||
///
|
||||
/// If you're expanding an item in a built-in macro or parsing an item
|
||||
/// by hand, you probably want to use this.
|
||||
Implicit,
|
||||
/// `default`
|
||||
Default(Span),
|
||||
Final,
|
||||
/// `final`; per RFC 3678, only trait items may be *explicitly* marked final.
|
||||
Final(Span),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||
@@ -4140,7 +4148,7 @@ pub fn defaultness(&self) -> Defaultness {
|
||||
| Self::Fn(box Fn { defaultness, .. })
|
||||
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
|
||||
Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
|
||||
Defaultness::Final
|
||||
Defaultness::Implicit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -939,7 +939,7 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
|
||||
);
|
||||
let trait_item_def_id = hir_id.expect_owner();
|
||||
|
||||
let (ident, generics, kind, has_default) = match &i.kind {
|
||||
let (ident, generics, kind, has_value) = match &i.kind {
|
||||
AssocItemKind::Const(box ConstItem {
|
||||
ident,
|
||||
generics,
|
||||
@@ -1088,13 +1088,17 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
|
||||
}
|
||||
};
|
||||
|
||||
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value, || {
|
||||
hir::Defaultness::Default { has_value }
|
||||
});
|
||||
|
||||
let item = hir::TraitItem {
|
||||
owner_id: trait_item_def_id,
|
||||
ident: self.lower_ident(ident),
|
||||
generics,
|
||||
kind,
|
||||
span: self.lower_span(i.span),
|
||||
defaultness: hir::Defaultness::Default { has_value: has_default },
|
||||
defaultness,
|
||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||
};
|
||||
self.arena.alloc(item)
|
||||
@@ -1122,7 +1126,8 @@ fn lower_trait_impl_header(
|
||||
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
|
||||
// to not cause an assertion failure inside the `lower_defaultness` function.
|
||||
let has_val = true;
|
||||
let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
|
||||
let (defaultness, defaultness_span) =
|
||||
self.lower_defaultness(defaultness, has_val, || hir::Defaultness::Final);
|
||||
let modifiers = TraitBoundModifiers {
|
||||
constness: BoundConstness::Never,
|
||||
asyncness: BoundAsyncness::Normal,
|
||||
@@ -1151,7 +1156,8 @@ fn lower_impl_item(
|
||||
) -> &'hir hir::ImplItem<'hir> {
|
||||
// Since `default impl` is not yet implemented, this is always true in impls.
|
||||
let has_value = true;
|
||||
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
|
||||
let (defaultness, _) =
|
||||
self.lower_defaultness(i.kind.defaultness(), has_value, || hir::Defaultness::Final);
|
||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||
let attrs = self.lower_attrs(
|
||||
hir_id,
|
||||
@@ -1304,15 +1310,14 @@ fn lower_defaultness(
|
||||
&self,
|
||||
d: Defaultness,
|
||||
has_value: bool,
|
||||
implicit: impl FnOnce() -> hir::Defaultness,
|
||||
) -> (hir::Defaultness, Option<Span>) {
|
||||
match d {
|
||||
Defaultness::Implicit => (implicit(), None),
|
||||
Defaultness::Default(sp) => {
|
||||
(hir::Defaultness::Default { has_value }, Some(self.lower_span(sp)))
|
||||
}
|
||||
Defaultness::Final => {
|
||||
assert!(has_value);
|
||||
(hir::Defaultness::Final, None)
|
||||
}
|
||||
Defaultness::Final(sp) => (hir::Defaultness::Final, Some(self.lower_span(sp))),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,28 @@ fn constness(&self) -> Option<Span> {
|
||||
}
|
||||
}
|
||||
|
||||
enum AllowDefault {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
impl AllowDefault {
|
||||
fn when(b: bool) -> Self {
|
||||
if b { Self::Yes } else { Self::No }
|
||||
}
|
||||
}
|
||||
|
||||
enum AllowFinal {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
impl AllowFinal {
|
||||
fn when(b: bool) -> Self {
|
||||
if b { Self::Yes } else { Self::No }
|
||||
}
|
||||
}
|
||||
|
||||
struct AstValidator<'a> {
|
||||
sess: &'a Session,
|
||||
features: &'a Features,
|
||||
@@ -563,10 +585,32 @@ fn check_fn_ptr_safety(&self, span: Span, safety: Safety) {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
|
||||
if let Defaultness::Default(def_span) = defaultness {
|
||||
let span = self.sess.source_map().guess_head_span(span);
|
||||
self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
|
||||
fn check_defaultness(
|
||||
&self,
|
||||
span: Span,
|
||||
defaultness: Defaultness,
|
||||
allow_default: AllowDefault,
|
||||
allow_final: AllowFinal,
|
||||
) {
|
||||
match defaultness {
|
||||
Defaultness::Default(def_span) if matches!(allow_default, AllowDefault::No) => {
|
||||
let span = self.sess.source_map().guess_head_span(span);
|
||||
self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
|
||||
}
|
||||
Defaultness::Final(def_span) if matches!(allow_final, AllowFinal::No) => {
|
||||
let span = self.sess.source_map().guess_head_span(span);
|
||||
self.dcx().emit_err(errors::ForbiddenFinal { span, def_span });
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_final_has_body(&self, item: &Item<AssocItemKind>, defaultness: Defaultness) {
|
||||
if let AssocItemKind::Fn(box Fn { body: None, .. }) = &item.kind
|
||||
&& let Defaultness::Final(def_span) = defaultness
|
||||
{
|
||||
let span = self.sess.source_map().guess_head_span(item.span);
|
||||
self.dcx().emit_err(errors::ForbiddenFinalWithoutBody { span, def_span });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1190,7 +1234,7 @@ fn visit_item(&mut self, item: &'a Item) {
|
||||
},
|
||||
) => {
|
||||
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
||||
|
||||
for EiiImpl { eii_macro_path, .. } in eii_impls {
|
||||
self.visit_path(eii_macro_path);
|
||||
@@ -1360,7 +1404,7 @@ fn visit_item(&mut self, item: &'a Item) {
|
||||
});
|
||||
}
|
||||
ItemKind::Const(box ConstItem { defaultness, ident, rhs_kind, .. }) => {
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
||||
if !rhs_kind.has_expr() {
|
||||
self.dcx().emit_err(errors::ConstWithoutBody {
|
||||
span: item.span,
|
||||
@@ -1398,7 +1442,7 @@ fn visit_item(&mut self, item: &'a Item) {
|
||||
ItemKind::TyAlias(
|
||||
ty_alias @ box TyAlias { defaultness, bounds, after_where_clause, ty, .. },
|
||||
) => {
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
||||
if ty.is_none() {
|
||||
self.dcx().emit_err(errors::TyAliasWithoutBody {
|
||||
span: item.span,
|
||||
@@ -1428,7 +1472,7 @@ fn visit_item(&mut self, item: &'a Item) {
|
||||
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||
match &fi.kind {
|
||||
ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {
|
||||
self.check_defaultness(fi.span, *defaultness);
|
||||
self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
||||
self.check_foreign_fn_bodyless(*ident, body.as_deref());
|
||||
self.check_foreign_fn_headerless(sig.header);
|
||||
self.check_foreign_item_ascii_only(*ident);
|
||||
@@ -1448,7 +1492,7 @@ fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||
ty,
|
||||
..
|
||||
}) => {
|
||||
self.check_defaultness(fi.span, *defaultness);
|
||||
self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
||||
self.check_foreign_kind_bodyless(*ident, "type", ty.as_ref().map(|b| b.span));
|
||||
self.check_type_no_bounds(bounds, "`extern` blocks");
|
||||
self.check_foreign_ty_genericless(generics, after_where_clause);
|
||||
@@ -1707,9 +1751,19 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
|
||||
self.check_nomangle_item_asciionly(ident, item.span);
|
||||
}
|
||||
|
||||
if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() {
|
||||
self.check_defaultness(item.span, item.kind.defaultness());
|
||||
}
|
||||
let defaultness = item.kind.defaultness();
|
||||
self.check_defaultness(
|
||||
item.span,
|
||||
defaultness,
|
||||
// `default` is allowed on all associated items in impls.
|
||||
AllowDefault::when(matches!(ctxt, AssocCtxt::Impl { .. })),
|
||||
// `final` is allowed on all associated *functions* in traits.
|
||||
AllowFinal::when(
|
||||
ctxt == AssocCtxt::Trait && matches!(item.kind, AssocItemKind::Fn(..)),
|
||||
),
|
||||
);
|
||||
|
||||
self.check_final_has_body(item, defaultness);
|
||||
|
||||
if let AssocCtxt::Impl { .. } = ctxt {
|
||||
match &item.kind {
|
||||
|
||||
@@ -159,6 +159,24 @@ pub(crate) struct ForbiddenDefault {
|
||||
pub def_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`final` is only allowed on associated functions in traits")]
|
||||
pub(crate) struct ForbiddenFinal {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label("`final` because of this")]
|
||||
pub def_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`final` is only allowed on associated functions if they have a body")]
|
||||
pub(crate) struct ForbiddenFinalWithoutBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label("`final` because of this")]
|
||||
pub def_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("associated constant in `impl` without body")]
|
||||
pub(crate) struct AssocConstWithoutBody {
|
||||
|
||||
@@ -580,6 +580,7 @@ macro_rules! gate_all {
|
||||
gate_all!(frontmatter, "frontmatters are experimental");
|
||||
gate_all!(coroutines, "coroutine syntax is experimental");
|
||||
gate_all!(const_block_items, "const block items are experimental");
|
||||
gate_all!(final_associated_functions, "`final` on trait functions is experimental");
|
||||
|
||||
if !visitor.features.never_patterns() {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
|
||||
@@ -51,7 +51,7 @@ pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
|
||||
expr.as_deref(),
|
||||
vis,
|
||||
*safety,
|
||||
ast::Defaultness::Final,
|
||||
ast::Defaultness::Implicit,
|
||||
define_opaque.as_deref(),
|
||||
),
|
||||
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
|
||||
@@ -201,7 +201,7 @@ pub(crate) fn print_item(&mut self, item: &ast::Item) {
|
||||
body.as_deref(),
|
||||
&item.vis,
|
||||
ast::Safety::Default,
|
||||
ast::Defaultness::Final,
|
||||
ast::Defaultness::Implicit,
|
||||
define_opaque.as_deref(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -292,3 +292,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitBoundsParser {
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitBounds;
|
||||
}
|
||||
|
||||
pub(crate) struct DefaultLibAllocatorParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for DefaultLibAllocatorParser {
|
||||
const PATH: &[Symbol] = &[sym::default_lib_allocator];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator;
|
||||
}
|
||||
|
||||
@@ -235,6 +235,7 @@ mod late {
|
||||
Single<WithoutArgs<ConstContinueParser>>,
|
||||
Single<WithoutArgs<ConstStabilityIndirectParser>>,
|
||||
Single<WithoutArgs<CoroutineParser>>,
|
||||
Single<WithoutArgs<DefaultLibAllocatorParser>>,
|
||||
Single<WithoutArgs<DenyExplicitImplParser>>,
|
||||
Single<WithoutArgs<DynIncompatibleTraitParser>>,
|
||||
Single<WithoutArgs<EiiForeignItemParser>>,
|
||||
|
||||
@@ -83,7 +83,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
|
||||
|
||||
let body = Some(cx.block_expr(call));
|
||||
let kind = ItemKind::Fn(Box::new(Fn {
|
||||
defaultness: ast::Defaultness::Final,
|
||||
defaultness: ast::Defaultness::Implicit,
|
||||
sig,
|
||||
ident: Ident::from_str_and_span(&global_fn_name(ALLOC_ERROR_HANDLER), span),
|
||||
generics: Generics::default(),
|
||||
|
||||
@@ -334,7 +334,7 @@ pub(crate) fn expand_with_mode(
|
||||
|
||||
// The first element of it is the name of the function to be generated
|
||||
let d_fn = Box::new(ast::Fn {
|
||||
defaultness: ast::Defaultness::Final,
|
||||
defaultness: ast::Defaultness::Implicit,
|
||||
sig: d_sig,
|
||||
ident: first_ident(&meta_item_vec[0]),
|
||||
generics,
|
||||
|
||||
@@ -136,7 +136,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
||||
of_trait: Some(Box::new(ast::TraitImplHeader {
|
||||
safety: ast::Safety::Default,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
defaultness: ast::Defaultness::Implicit,
|
||||
trait_ref,
|
||||
})),
|
||||
constness: ast::Const::No,
|
||||
@@ -159,7 +159,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
||||
of_trait: Some(Box::new(ast::TraitImplHeader {
|
||||
safety: ast::Safety::Default,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
defaultness: ast::Defaultness::Implicit,
|
||||
trait_ref,
|
||||
})),
|
||||
constness: ast::Const::No,
|
||||
|
||||
@@ -614,7 +614,7 @@ fn create_derived_impl(
|
||||
},
|
||||
attrs: ast::AttrVec::new(),
|
||||
kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
|
||||
defaultness: ast::Defaultness::Final,
|
||||
defaultness: ast::Defaultness::Implicit,
|
||||
ident,
|
||||
generics: Generics::default(),
|
||||
after_where_clause: ast::WhereClause::default(),
|
||||
@@ -851,7 +851,7 @@ fn create_derived_impl(
|
||||
of_trait: Some(Box::new(ast::TraitImplHeader {
|
||||
safety: self.safety,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
defaultness: ast::Defaultness::Implicit,
|
||||
trait_ref,
|
||||
})),
|
||||
constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
|
||||
@@ -1073,7 +1073,7 @@ fn create_method(
|
||||
let trait_lo_sp = span.shrink_to_lo();
|
||||
|
||||
let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span };
|
||||
let defaultness = ast::Defaultness::Final;
|
||||
let defaultness = ast::Defaultness::Implicit;
|
||||
|
||||
// Create the method.
|
||||
Box::new(ast::AssocItem {
|
||||
|
||||
@@ -77,7 +77,7 @@ fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt {
|
||||
let sig = FnSig { decl, header, span: self.span };
|
||||
let body = Some(self.cx.block_expr(result));
|
||||
let kind = ItemKind::Fn(Box::new(Fn {
|
||||
defaultness: ast::Defaultness::Final,
|
||||
defaultness: ast::Defaultness::Implicit,
|
||||
sig,
|
||||
ident: Ident::from_str_and_span(&global_fn_name(method.name), self.span),
|
||||
generics: Generics::default(),
|
||||
|
||||
@@ -283,7 +283,7 @@ pub(crate) fn expand_test_or_bench(
|
||||
// const $ident: test::TestDescAndFn =
|
||||
ast::ItemKind::Const(
|
||||
ast::ConstItem {
|
||||
defaultness: ast::Defaultness::Final,
|
||||
defaultness: ast::Defaultness::Implicit,
|
||||
ident: Ident::new(fn_.ident.name, sp),
|
||||
generics: ast::Generics::default(),
|
||||
ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
|
||||
|
||||
@@ -330,7 +330,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box<ast::Item> {
|
||||
|
||||
let decl = ecx.fn_decl(ThinVec::new(), ast::FnRetTy::Ty(main_ret_ty));
|
||||
let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp };
|
||||
let defaultness = ast::Defaultness::Final;
|
||||
let defaultness = ast::Defaultness::Implicit;
|
||||
|
||||
// Honor the reexport_test_harness_main attribute
|
||||
let main_ident = match cx.reexport_test_harness_main {
|
||||
|
||||
@@ -208,7 +208,7 @@ pub(crate) fn codegen_cast(
|
||||
let ret_ty = if to_ty.bits() < 32 { types::I32 } else { to_ty };
|
||||
let name = format!(
|
||||
"__fix{sign}tf{size}i",
|
||||
sign = if from_signed { "" } else { "un" },
|
||||
sign = if to_signed { "" } else { "uns" },
|
||||
size = match ret_ty {
|
||||
types::I32 => 's',
|
||||
types::I64 => 'd',
|
||||
|
||||
@@ -31,7 +31,6 @@ rustc_llvm = { path = "../rustc_llvm" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_metadata = { path = "../rustc_metadata" }
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_query_system = { path = "../rustc_query_system" }
|
||||
rustc_sanitizers = { path = "../rustc_sanitizers" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
The requested ABI is unsupported by the current target.
|
||||
|
||||
The rust compiler maintains for each target a list of unsupported ABIs on
|
||||
that target. If an ABI is present in such a list this usually means that the
|
||||
The Rust compiler maintains a list of unsupported ABIs for each target.
|
||||
If an ABI is present in such a list, this usually means that the
|
||||
target / ABI combination is currently unsupported by llvm.
|
||||
|
||||
If necessary, you can circumvent this check using custom target specifications.
|
||||
|
||||
@@ -729,7 +729,7 @@ pub fn item_const(
|
||||
ty: Box<ast::Ty>,
|
||||
rhs_kind: ast::ConstItemRhsKind,
|
||||
) -> Box<ast::Item> {
|
||||
let defaultness = ast::Defaultness::Final;
|
||||
let defaultness = ast::Defaultness::Implicit;
|
||||
self.item(
|
||||
span,
|
||||
AttrVec::new(),
|
||||
|
||||
@@ -86,8 +86,7 @@ fn feature_list(attr: &Attribute) -> ThinVec<ast::MetaItemInner> {
|
||||
if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| name == f.feature.name) {
|
||||
let pull_note = if let Some(pull) = f.pull {
|
||||
format!(
|
||||
"; see <https://github.com/rust-lang/rust/pull/{}> for more information",
|
||||
pull
|
||||
"; see <https://github.com/rust-lang/rust/pull/{pull}> for more information",
|
||||
)
|
||||
} else {
|
||||
"".to_owned()
|
||||
@@ -123,7 +122,7 @@ fn feature_list(attr: &Attribute) -> ThinVec<ast::MetaItemInner> {
|
||||
|
||||
// If the enabled feature is unstable, record it.
|
||||
if UNSTABLE_LANG_FEATURES.iter().find(|f| name == f.name).is_some() {
|
||||
// When the ICE comes a standard library crate, there's a chance that the person
|
||||
// When the ICE comes from a standard library crate, there's a chance that the person
|
||||
// hitting the ICE may be using -Zbuild-std or similar with an untested target.
|
||||
// The bug is probably in the standard library and not the compiler in that case,
|
||||
// but that doesn't really matter - we want a bug report.
|
||||
|
||||
@@ -64,8 +64,6 @@ pub struct EnabledLibFeature {
|
||||
}
|
||||
|
||||
impl Features {
|
||||
/// `since` should be set for stable features that are nevertheless enabled with a `#[feature]`
|
||||
/// attribute, indicating since when they are stable.
|
||||
pub fn set_enabled_lang_feature(&mut self, lang_feat: EnabledLangFeature) {
|
||||
self.enabled_lang_features.push(lang_feat);
|
||||
self.enabled_features.insert(lang_feat.gate_name);
|
||||
@@ -494,6 +492,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
|
||||
(unstable, ffi_const, "1.45.0", Some(58328)),
|
||||
/// Allows the use of `#[ffi_pure]` on foreign functions.
|
||||
(unstable, ffi_pure, "1.45.0", Some(58329)),
|
||||
/// Allows marking trait functions as `final` to prevent overriding impls
|
||||
(unstable, final_associated_functions, "CURRENT_RUSTC_VERSION", Some(1)),
|
||||
/// Controlling the behavior of fmt::Debug
|
||||
(unstable, fmt_debug, "1.82.0", Some(129709)),
|
||||
/// Allows using `#[align(...)]` on function items
|
||||
@@ -779,8 +779,9 @@ struct FeatureUsage {
|
||||
}
|
||||
}
|
||||
|
||||
/// Some features are not allowed to be used together at the same time, if
|
||||
/// the two are present, produce an error.
|
||||
/// Some features are not allowed to be used together at the same time.
|
||||
///
|
||||
/// If the two are present, produce an error.
|
||||
pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[
|
||||
// Experimental match ergonomics rulesets are incompatible with each other, to simplify the
|
||||
// boolean logic required to tell which typing rules to use.
|
||||
|
||||
@@ -897,6 +897,9 @@ pub enum AttributeKind {
|
||||
/// Represents `#[debugger_visualizer]`.
|
||||
DebuggerVisualizer(ThinVec<DebugVisualizer>),
|
||||
|
||||
/// Represents `#![default_lib_allocator]`
|
||||
DefaultLibAllocator,
|
||||
|
||||
/// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
|
||||
Deprecation { deprecation: Deprecation, span: Span },
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
|
||||
CrateType(_) => No,
|
||||
CustomMir(_, _, _) => Yes,
|
||||
DebuggerVisualizer(..) => No,
|
||||
DefaultLibAllocator => No,
|
||||
Deprecation { .. } => Yes,
|
||||
DoNotRecommend { .. } => Yes,
|
||||
Doc(_) => Yes,
|
||||
|
||||
@@ -1175,13 +1175,35 @@ pub(super) fn check_specialization_validity<'tcx>(
|
||||
|
||||
if let Err(parent_impl) = result {
|
||||
if !tcx.is_impl_trait_in_trait(impl_item) {
|
||||
report_forbidden_specialization(tcx, impl_item, parent_impl);
|
||||
let span = tcx.def_span(impl_item);
|
||||
let ident = tcx.item_ident(impl_item);
|
||||
|
||||
let err = match tcx.span_of_impl(parent_impl) {
|
||||
Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
|
||||
Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
|
||||
};
|
||||
|
||||
tcx.dcx().emit_err(err);
|
||||
} else {
|
||||
tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_overriding_final_trait_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_item: ty::AssocItem,
|
||||
impl_item: ty::AssocItem,
|
||||
) {
|
||||
if trait_item.defaultness(tcx).is_final() {
|
||||
tcx.dcx().emit_err(errors::OverridingFinalTraitFunction {
|
||||
impl_span: tcx.def_span(impl_item.def_id),
|
||||
trait_span: tcx.def_span(trait_item.def_id),
|
||||
ident: tcx.item_ident(impl_item.def_id),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_items_against_trait<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_id: LocalDefId,
|
||||
@@ -1259,6 +1281,8 @@ fn check_impl_items_against_trait<'tcx>(
|
||||
impl_id.to_def_id(),
|
||||
impl_item,
|
||||
);
|
||||
|
||||
check_overriding_final_trait_item(tcx, ty_trait_item, ty_impl_item);
|
||||
}
|
||||
|
||||
if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
|
||||
|
||||
@@ -197,18 +197,6 @@ pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDef
|
||||
}
|
||||
}
|
||||
|
||||
fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) {
|
||||
let span = tcx.def_span(impl_item);
|
||||
let ident = tcx.item_ident(impl_item);
|
||||
|
||||
let err = match tcx.span_of_impl(parent_impl) {
|
||||
Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
|
||||
Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
|
||||
};
|
||||
|
||||
tcx.dcx().emit_err(err);
|
||||
}
|
||||
|
||||
fn missing_items_err(
|
||||
tcx: TyCtxt<'_>,
|
||||
impl_def_id: LocalDefId,
|
||||
|
||||
@@ -892,6 +892,16 @@ pub(crate) enum ImplNotMarkedDefault {
|
||||
#[diag("this item cannot be used as its where bounds are not satisfied for the `Self` type")]
|
||||
pub(crate) struct UselessImplItem;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("cannot override `{$ident}` because it already has a `final` definition in the trait")]
|
||||
pub(crate) struct OverridingFinalTraitFunction {
|
||||
#[primary_span]
|
||||
pub impl_span: Span,
|
||||
#[note("`{$ident}` is marked final here")]
|
||||
pub trait_span: Span,
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("not all trait items implemented, missing: `{$missing_items_msg}`", code = E0046)]
|
||||
pub(crate) struct MissingTraitItem {
|
||||
|
||||
@@ -490,6 +490,7 @@ pub(crate) fn probe_op<OP, R>(
|
||||
.unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
|
||||
let ty = self.resolve_vars_if_possible(ty.value);
|
||||
let guar = match *ty.kind() {
|
||||
_ if let Some(guar) = self.tainted_by_errors() => guar,
|
||||
ty::Infer(ty::TyVar(_)) => {
|
||||
// We want to get the variable name that the method
|
||||
// is being called on. If it is a method call.
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use rustc_errors::{DiagInner, TRACK_DIAGNOSTIC};
|
||||
use rustc_middle::dep_graph::dep_node::default_dep_kind_debug;
|
||||
use rustc_middle::dep_graph::{DepKind, DepNode, TaskDepsRef};
|
||||
use rustc_errors::DiagInner;
|
||||
use rustc_middle::dep_graph::TaskDepsRef;
|
||||
use rustc_middle::ty::tls;
|
||||
|
||||
fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
|
||||
@@ -65,49 +64,10 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->
|
||||
write!(f, ")")
|
||||
}
|
||||
|
||||
/// This is a callback from `rustc_query_system` as it cannot access the implicit state
|
||||
/// in `rustc_middle` otherwise.
|
||||
pub fn dep_kind_debug(kind: DepKind, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
tls::with_opt(|opt_tcx| {
|
||||
if let Some(tcx) = opt_tcx {
|
||||
write!(f, "{}", tcx.dep_kind_vtable(kind).name)
|
||||
} else {
|
||||
default_dep_kind_debug(kind, f)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// This is a callback from `rustc_query_system` as it cannot access the implicit state
|
||||
/// in `rustc_middle` otherwise.
|
||||
pub fn dep_node_debug(node: DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}(", node.kind)?;
|
||||
|
||||
tls::with_opt(|opt_tcx| {
|
||||
if let Some(tcx) = opt_tcx {
|
||||
if let Some(def_id) = node.extract_def_id(tcx) {
|
||||
write!(f, "{}", tcx.def_path_debug_str(def_id))?;
|
||||
} else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(node) {
|
||||
write!(f, "{s}")?;
|
||||
} else {
|
||||
write!(f, "{}", node.hash)?;
|
||||
}
|
||||
} else {
|
||||
write!(f, "{}", node.hash)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
write!(f, ")")
|
||||
}
|
||||
|
||||
/// Sets up the callbacks in prior crates which we want to refer to the
|
||||
/// TyCtxt in.
|
||||
pub fn setup_callbacks() {
|
||||
rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
|
||||
rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
||||
rustc_middle::dep_graph::dep_node::DEP_KIND_DEBUG
|
||||
.swap(&(dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
||||
rustc_middle::dep_graph::dep_node::DEP_NODE_DEBUG
|
||||
.swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
||||
TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _));
|
||||
rustc_errors::TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _));
|
||||
}
|
||||
|
||||
@@ -3659,10 +3659,10 @@
|
||||
/// `stdcall`, `fastcall`, and `cdecl` calling conventions (or their unwind
|
||||
/// variants) on targets that cannot meaningfully be supported for the requested target.
|
||||
///
|
||||
/// For example `stdcall` does not make much sense for a x86_64 or, more apparently, powerpc
|
||||
/// For example, `stdcall` does not make much sense for a x86_64 or, more apparently, powerpc
|
||||
/// code, because this calling convention was never specified for those targets.
|
||||
///
|
||||
/// Historically MSVC toolchains have fallen back to the regular C calling convention for
|
||||
/// Historically, MSVC toolchains have fallen back to the regular C calling convention for
|
||||
/// targets other than x86, but Rust doesn't really see a similar need to introduce a similar
|
||||
/// hack across many more targets.
|
||||
///
|
||||
@@ -3689,7 +3689,7 @@
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// On most of the targets the behaviour of `stdcall` and similar calling conventions is not
|
||||
/// On most of the targets, the behaviour of `stdcall` and similar calling conventions is not
|
||||
/// defined at all, but was previously accepted due to a bug in the implementation of the
|
||||
/// compiler.
|
||||
pub UNSUPPORTED_CALLING_CONVENTIONS,
|
||||
|
||||
@@ -96,7 +96,7 @@ fn hash_stable_derive_with_mode(
|
||||
|
||||
let context: syn::Type = match mode {
|
||||
HashStableMode::Normal => {
|
||||
parse_quote!(::rustc_query_system::ich::StableHashingContext<'__ctx>)
|
||||
parse_quote!(::rustc_middle::ich::StableHashingContext<'__ctx>)
|
||||
}
|
||||
HashStableMode::Generic | HashStableMode::NoContext => parse_quote!(__CTX),
|
||||
};
|
||||
|
||||
@@ -734,10 +734,7 @@ macro_rules! stat {
|
||||
has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
|
||||
has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE),
|
||||
has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
|
||||
has_default_lib_allocator: ast::attr::contains_name(
|
||||
attrs,
|
||||
sym::default_lib_allocator,
|
||||
),
|
||||
has_default_lib_allocator: find_attr!(attrs, AttributeKind::DefaultLibAllocator),
|
||||
externally_implementable_items,
|
||||
proc_macro_data,
|
||||
debugger_visualizers,
|
||||
|
||||
@@ -26,7 +26,6 @@ rustc_hir_pretty = { path = "../rustc_hir_pretty" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_query_system = { path = "../rustc_query_system" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
|
||||
@@ -58,18 +58,17 @@
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
|
||||
use rustc_data_structures::AtomicRef;
|
||||
use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::definitions::DefPathHash;
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_span::Symbol;
|
||||
|
||||
use super::{FingerprintStyle, SerializedDepNodeIndex};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::mir::mono::MonoItem;
|
||||
use crate::ty::TyCtxt;
|
||||
use crate::ty::{TyCtxt, tls};
|
||||
|
||||
/// This serves as an index into arrays built by `make_dep_kind_array`.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
@@ -114,16 +113,15 @@ pub(crate) fn name(self) -> &'static str {
|
||||
pub(crate) const MAX: u16 = DEP_KIND_VARIANTS - 1;
|
||||
}
|
||||
|
||||
pub fn default_dep_kind_debug(kind: DepKind, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("DepKind").field("variant", &kind.variant).finish()
|
||||
}
|
||||
|
||||
pub static DEP_KIND_DEBUG: AtomicRef<fn(DepKind, &mut fmt::Formatter<'_>) -> fmt::Result> =
|
||||
AtomicRef::new(&(default_dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
||||
|
||||
impl fmt::Debug for DepKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(*DEP_KIND_DEBUG)(*self, f)
|
||||
tls::with_opt(|opt_tcx| {
|
||||
if let Some(tcx) = opt_tcx {
|
||||
write!(f, "{}", tcx.dep_kind_vtable(*self).name)
|
||||
} else {
|
||||
f.debug_struct("DepKind").field("variant", &self.variant).finish()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,16 +173,26 @@ pub fn from_def_path_hash<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_dep_node_debug(node: DepNode, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("DepNode").field("kind", &node.kind).field("hash", &node.hash).finish()
|
||||
}
|
||||
|
||||
pub static DEP_NODE_DEBUG: AtomicRef<fn(DepNode, &mut fmt::Formatter<'_>) -> fmt::Result> =
|
||||
AtomicRef::new(&(default_dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
||||
|
||||
impl fmt::Debug for DepNode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
(*DEP_NODE_DEBUG)(*self, f)
|
||||
write!(f, "{:?}(", self.kind)?;
|
||||
|
||||
tls::with_opt(|opt_tcx| {
|
||||
if let Some(tcx) = opt_tcx {
|
||||
if let Some(def_id) = self.extract_def_id(tcx) {
|
||||
write!(f, "{}", tcx.def_path_debug_str(def_id))?;
|
||||
} else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) {
|
||||
write!(f, "{s}")?;
|
||||
} else {
|
||||
write!(f, "{}", self.hash)?;
|
||||
}
|
||||
} else {
|
||||
write!(f, "{}", self.hash)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
use rustc_errors::DiagInner;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_query_system::query::QuerySideEffect;
|
||||
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
|
||||
use rustc_session::Session;
|
||||
use tracing::{debug, instrument};
|
||||
@@ -27,9 +25,27 @@
|
||||
use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
|
||||
use super::{DepKind, DepNode, HasDepContext, WorkProductId, read_deps, with_deps};
|
||||
use crate::dep_graph::edges::EdgesVec;
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::ty::TyCtxt;
|
||||
use crate::verify_ich::incremental_verify_ich;
|
||||
|
||||
/// Tracks 'side effects' for a particular query.
|
||||
/// This struct is saved to disk along with the query result,
|
||||
/// and loaded from disk if we mark the query as green.
|
||||
/// This allows us to 'replay' changes to global state
|
||||
/// that would otherwise only occur if we actually
|
||||
/// executed the query method.
|
||||
///
|
||||
/// Each side effect gets an unique dep node index which is added
|
||||
/// as a dependency of the query which had the effect.
|
||||
#[derive(Debug, Encodable, Decodable)]
|
||||
pub enum QuerySideEffect {
|
||||
/// Stores a diagnostic emitted during query execution.
|
||||
/// This diagnostic will be re-emitted if we mark
|
||||
/// the query as green, as that query will have the side
|
||||
/// effect dep node as a dependency.
|
||||
Diagnostic(DiagInner),
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct DepGraph {
|
||||
data: Option<Arc<DepGraphData>>,
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
label_strs,
|
||||
};
|
||||
pub use self::graph::{
|
||||
DepGraph, DepGraphData, DepNodeIndex, TaskDepsRef, WorkProduct, WorkProductMap, hash_result,
|
||||
DepGraph, DepGraphData, DepNodeIndex, QuerySideEffect, TaskDepsRef, WorkProduct,
|
||||
WorkProductMap, hash_result,
|
||||
};
|
||||
use self::graph::{MarkFrame, print_markframe_trace};
|
||||
pub use self::query::DepGraphQuery;
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
use smallvec::SmallVec;
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
use crate::ich::StableHashingContext;
|
||||
use super::StableHashingContext;
|
||||
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
|
||||
#[inline]
|
||||
@@ -72,6 +72,7 @@
|
||||
pub mod error;
|
||||
pub mod hir;
|
||||
pub mod hooks;
|
||||
pub mod ich;
|
||||
pub mod infer;
|
||||
pub mod lint;
|
||||
pub mod metadata;
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_span::def_id::{CRATE_DEF_ID, LocalDefId};
|
||||
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::ty::{TyCtxt, Visibility};
|
||||
|
||||
/// Represents the levels of effective visibility an item can have.
|
||||
|
||||
@@ -911,7 +911,8 @@ pub struct VarBindingIntroduction {
|
||||
|
||||
mod binding_form_impl {
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
|
||||
use crate::ich::StableHashingContext;
|
||||
|
||||
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> {
|
||||
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
use rustc_hir::attrs::{InlineAttr, Linkage};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LOCAL_CRATE};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::spec::SymbolVisibility;
|
||||
@@ -20,6 +19,7 @@
|
||||
|
||||
use crate::dep_graph::dep_node::{make_compile_codegen_unit, make_compile_mono_item};
|
||||
use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use crate::ty::{self, GenericArgs, Instance, InstanceKind, SymbolName, Ty, TyCtxt};
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
pub use rustc_data_structures::vec_cache::VecCache;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_index::Idx;
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_span::def_id::{DefId, DefIndex};
|
||||
|
||||
use crate::dep_graph::DepNodeIndex;
|
||||
use crate::ich::StableHashingContext;
|
||||
|
||||
/// Traits that all query keys must satisfy.
|
||||
pub trait QueryCacheKey = Hash + Eq + Copy + Debug + for<'a> HashStable<StableHashingContext<'a>>;
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
use rustc_hir::definitions::DefPathHash;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
use rustc_query_system::query::QuerySideEffect;
|
||||
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
use rustc_session::Session;
|
||||
@@ -24,7 +23,7 @@
|
||||
SourceFile, Span, SpanDecoder, SpanEncoder, StableSourceFileId, Symbol,
|
||||
};
|
||||
|
||||
use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
|
||||
use crate::dep_graph::{DepNodeIndex, QuerySideEffect, SerializedDepNodeIndex};
|
||||
use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState};
|
||||
use crate::mir::mono::MonoItem;
|
||||
use crate::mir::{self, interpret};
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::hir_id::OwnerId;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
pub use sealed::IntoQueryParam;
|
||||
|
||||
use crate::dep_graph;
|
||||
use crate::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::queries::{
|
||||
ExternProviders, PerQueryVTables, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates,
|
||||
};
|
||||
@@ -102,9 +102,6 @@ pub enum QueryMode {
|
||||
}
|
||||
|
||||
/// Stores function pointers and other metadata for a particular query.
|
||||
///
|
||||
/// Used indirectly by query plumbing in `rustc_query_system` via a trait,
|
||||
/// and also used directly by query plumbing in `rustc_query_impl`.
|
||||
pub struct QueryVTable<'tcx, C: QueryCache> {
|
||||
pub name: &'static str,
|
||||
pub eval_always: bool,
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
use rustc_hir::{self as hir, LangItem, find_attr};
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_session::DataTypeKind;
|
||||
use rustc_type_ir::solve::AdtDestructorKind;
|
||||
use tracing::{debug, info, trace};
|
||||
@@ -23,6 +22,7 @@
|
||||
use super::{
|
||||
AsyncDestructor, Destructor, FieldDef, GenericPredicates, Ty, TyCtxt, VariantDef, VariantDiscr,
|
||||
};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::mir::interpret::ErrorHandled;
|
||||
use crate::ty;
|
||||
use crate::ty::util::{Discr, IntTypeExt};
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
use rustc_hir::limit::Limit;
|
||||
use rustc_hir::{self as hir, HirId, Node, TraitCandidate, find_attr};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::CrateType;
|
||||
@@ -55,6 +54,7 @@
|
||||
use crate::arena::Arena;
|
||||
use crate::dep_graph::dep_node::make_metadata;
|
||||
use crate::dep_graph::{DepGraph, DepKindVTable, DepNodeIndex};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind};
|
||||
use crate::lint::lint_level;
|
||||
use crate::metadata::ModChild;
|
||||
@@ -1220,7 +1220,7 @@ pub fn needs_metadata(self) -> bool {
|
||||
pub fn needs_crate_hash(self) -> bool {
|
||||
// Why is the crate hash needed for these configurations?
|
||||
// - debug_assertions: for the "fingerprint the result" check in
|
||||
// `rustc_query_system::query::plumbing::execute_job`.
|
||||
// `rustc_query_impl::execution::execute_job`.
|
||||
// - incremental: for query lookups.
|
||||
// - needs_metadata: for putting into crate metadata.
|
||||
// - instrument_coverage: for putting into coverage data (see
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
use rustc_data_structures::stable_hasher::{
|
||||
HashStable, HashingControls, StableHasher, ToStableHashKey,
|
||||
};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use tracing::trace;
|
||||
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::middle::region;
|
||||
use crate::{mir, ty};
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@
|
||||
BlobDecodable, Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable,
|
||||
TypeVisitable, extension,
|
||||
};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
pub use rustc_session::lint::RegisteredTools;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
@@ -112,6 +111,7 @@
|
||||
Rust2024IncompatiblePatInfo, TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind,
|
||||
};
|
||||
use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::metadata::{AmbigModChild, ModChild};
|
||||
use crate::middle::privacy::EffectiveVisibilities;
|
||||
use crate::mir::{Body, CoroutineLayout, CoroutineSavedLocal, SourceInfo};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::cell::Cell;
|
||||
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::dep_graph::{DepGraphData, SerializedDepNodeIndex};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::ty::TyCtxt;
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -3787,6 +3787,17 @@ pub(crate) struct RecoverImportAsUse {
|
||||
pub token_name: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("{$article} {$descr} cannot be `final`")]
|
||||
#[note("only associated functions in traits can be `final`")]
|
||||
pub(crate) struct InappropriateFinal {
|
||||
#[primary_span]
|
||||
#[label("`final` because of this")]
|
||||
pub span: Span,
|
||||
pub article: &'static str,
|
||||
pub descr: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("expected `::`, found `:`")]
|
||||
#[note("import paths are delimited using `::`")]
|
||||
|
||||
@@ -206,14 +206,24 @@ pub(super) fn parse_item_common(
|
||||
})
|
||||
}
|
||||
|
||||
/// Error in-case `default` was parsed in an in-appropriate context.
|
||||
/// Error in-case `default`/`final` was parsed in an in-appropriate context.
|
||||
fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {
|
||||
if let Defaultness::Default(span) = def {
|
||||
self.dcx().emit_err(errors::InappropriateDefault {
|
||||
span,
|
||||
article: kind.article(),
|
||||
descr: kind.descr(),
|
||||
});
|
||||
match def {
|
||||
Defaultness::Default(span) => {
|
||||
self.dcx().emit_err(errors::InappropriateDefault {
|
||||
span,
|
||||
article: kind.article(),
|
||||
descr: kind.descr(),
|
||||
});
|
||||
}
|
||||
Defaultness::Final(span) => {
|
||||
self.dcx().emit_err(errors::InappropriateFinal {
|
||||
span,
|
||||
article: kind.article(),
|
||||
descr: kind.descr(),
|
||||
});
|
||||
}
|
||||
Defaultness::Implicit => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,8 +239,8 @@ fn parse_item_kind(
|
||||
fn_parse_mode: FnParseMode,
|
||||
case: Case,
|
||||
) -> PResult<'a, Option<ItemKind>> {
|
||||
let check_pub = def == &Defaultness::Final;
|
||||
let mut def_ = || mem::replace(def, Defaultness::Final);
|
||||
let check_pub = def == &Defaultness::Implicit;
|
||||
let mut def_ = || mem::replace(def, Defaultness::Implicit);
|
||||
|
||||
let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) {
|
||||
self.parse_use_item()?
|
||||
@@ -1005,8 +1015,11 @@ fn parse_defaultness(&mut self) -> Defaultness {
|
||||
{
|
||||
self.bump(); // `default`
|
||||
Defaultness::Default(self.prev_token_uninterpolated_span())
|
||||
} else if self.eat_keyword(exp!(Final)) {
|
||||
self.psess.gated_spans.gate(sym::final_associated_functions, self.prev_token.span);
|
||||
Defaultness::Final(self.prev_token_uninterpolated_span())
|
||||
} else {
|
||||
Defaultness::Final
|
||||
Defaultness::Implicit
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1130,7 +1143,7 @@ fn parse_assoc_item(
|
||||
}) => {
|
||||
self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span });
|
||||
AssocItemKind::Const(Box::new(ConstItem {
|
||||
defaultness: Defaultness::Final,
|
||||
defaultness: Defaultness::Implicit,
|
||||
ident,
|
||||
generics: Generics::default(),
|
||||
ty,
|
||||
|
||||
@@ -91,6 +91,7 @@ pub enum TokenType {
|
||||
KwElse,
|
||||
KwEnum,
|
||||
KwExtern,
|
||||
KwFinal,
|
||||
KwFn,
|
||||
KwFor,
|
||||
KwGen,
|
||||
@@ -233,6 +234,7 @@ fn from_u32(val: u32) -> TokenType {
|
||||
KwExtern,
|
||||
KwFn,
|
||||
KwFor,
|
||||
KwFinal,
|
||||
KwGen,
|
||||
KwIf,
|
||||
KwImpl,
|
||||
@@ -309,6 +311,7 @@ pub(super) fn is_keyword(&self) -> Option<Symbol> {
|
||||
TokenType::KwExtern => Some(kw::Extern),
|
||||
TokenType::KwFn => Some(kw::Fn),
|
||||
TokenType::KwFor => Some(kw::For),
|
||||
TokenType::KwFinal => Some(kw::Final),
|
||||
TokenType::KwGen => Some(kw::Gen),
|
||||
TokenType::KwIf => Some(kw::If),
|
||||
TokenType::KwImpl => Some(kw::Impl),
|
||||
@@ -524,6 +527,7 @@ macro_rules! exp {
|
||||
(Extern) => { exp!(@kw, Extern, KwExtern) };
|
||||
(Fn) => { exp!(@kw, Fn, KwFn) };
|
||||
(For) => { exp!(@kw, For, KwFor) };
|
||||
(Final) => { exp!(@kw, Final, KwFinal) };
|
||||
(Gen) => { exp!(@kw, Gen, KwGen) };
|
||||
(If) => { exp!(@kw, If, KwIf) };
|
||||
(Impl) => { exp!(@kw, Impl, KwImpl) };
|
||||
|
||||
@@ -246,6 +246,7 @@ fn check_attributes(
|
||||
| AttributeKind::CrateName { .. }
|
||||
| AttributeKind::CrateType(..)
|
||||
| AttributeKind::DebuggerVisualizer(..)
|
||||
| AttributeKind::DefaultLibAllocator
|
||||
// `#[doc]` is actually a lot more than just doc comments, so is checked below
|
||||
| AttributeKind::DocComment {..}
|
||||
| AttributeKind::EiiDeclaration { .. }
|
||||
@@ -399,7 +400,6 @@ fn check_attributes(
|
||||
| sym::deny
|
||||
| sym::forbid
|
||||
// internal
|
||||
| sym::default_lib_allocator
|
||||
| sym::rustc_inherit_overflow_checks
|
||||
| sym::rustc_on_unimplemented
|
||||
| sym::rustc_doc_primitive
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
[package]
|
||||
name = "rustc_query_system"
|
||||
version = "0.0.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
# tidy-alphabetical-end
|
||||
@@ -1,8 +0,0 @@
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(bootstrap, feature(assert_matches))]
|
||||
#![feature(min_specialization)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
pub mod ich;
|
||||
pub mod query;
|
||||
@@ -1,3 +0,0 @@
|
||||
For more information about how the query system works, see the [rustc dev guide].
|
||||
|
||||
[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/query.html
|
||||
@@ -1,22 +0,0 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use rustc_errors::DiagInner;
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
|
||||
/// Tracks 'side effects' for a particular query.
|
||||
/// This struct is saved to disk along with the query result,
|
||||
/// and loaded from disk if we mark the query as green.
|
||||
/// This allows us to 'replay' changes to global state
|
||||
/// that would otherwise only occur if we actually
|
||||
/// executed the query method.
|
||||
///
|
||||
/// Each side effect gets an unique dep node index which is added
|
||||
/// as a dependency of the query which had the effect.
|
||||
#[derive(Debug, Encodable, Decodable)]
|
||||
pub enum QuerySideEffect {
|
||||
/// Stores a diagnostic emitted during query execution.
|
||||
/// This diagnostic will be re-emitted if we mark
|
||||
/// the query as green, as that query will have the side
|
||||
/// effect dep node as a dependency.
|
||||
Diagnostic(DiagInner),
|
||||
}
|
||||
@@ -1096,6 +1096,7 @@
|
||||
fields,
|
||||
file,
|
||||
file_options,
|
||||
final_associated_functions,
|
||||
flags,
|
||||
float,
|
||||
float_to_int_unchecked,
|
||||
|
||||
@@ -282,23 +282,31 @@ pub fn report_selection_error(
|
||||
if self.tcx.is_diagnostic_item(sym::From, trait_def_id)
|
||||
|| self.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id)
|
||||
{
|
||||
let found_ty = leaf_trait_predicate.skip_binder().trait_ref.args.type_at(1);
|
||||
let ty = main_trait_predicate.skip_binder().self_ty();
|
||||
if let Some(cast_ty) = self.find_explicit_cast_type(
|
||||
obligation.param_env,
|
||||
found_ty,
|
||||
ty,
|
||||
) {
|
||||
let found_ty_str = self.tcx.short_string(found_ty, &mut long_ty_file);
|
||||
let cast_ty_str = self.tcx.short_string(cast_ty, &mut long_ty_file);
|
||||
err.help(
|
||||
format!(
|
||||
let trait_ref = leaf_trait_predicate.skip_binder().trait_ref;
|
||||
|
||||
// Defensive: next-solver may produce fewer args than expected.
|
||||
if trait_ref.args.len() > 1 {
|
||||
let found_ty = trait_ref.args.type_at(1);
|
||||
let ty = main_trait_predicate.skip_binder().self_ty();
|
||||
|
||||
if let Some(cast_ty) = self.find_explicit_cast_type(
|
||||
obligation.param_env,
|
||||
found_ty,
|
||||
ty,
|
||||
) {
|
||||
let found_ty_str =
|
||||
self.tcx.short_string(found_ty, &mut long_ty_file);
|
||||
let cast_ty_str =
|
||||
self.tcx.short_string(cast_ty, &mut long_ty_file);
|
||||
|
||||
err.help(format!(
|
||||
"consider casting the `{found_ty_str}` value to `{cast_ty_str}`",
|
||||
),
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*err.long_ty_path() = long_ty_file;
|
||||
|
||||
let mut suggested = false;
|
||||
|
||||
@@ -5608,15 +5608,17 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>(
|
||||
None => String::new(),
|
||||
};
|
||||
if let ty::PredicatePolarity::Positive = trait_predicate.polarity() {
|
||||
// If the trait in question is unstable, mention that fact in the diagnostic.
|
||||
// But if we're building with `-Zforce-unstable-if-unmarked` then _any_ trait
|
||||
// not explicitly marked stable is considered unstable, so the extra text is
|
||||
// unhelpful noise. See <https://github.com/rust-lang/rust/issues/152692>.
|
||||
let mention_unstable = !tcx.sess.opts.unstable_opts.force_unstable_if_unmarked
|
||||
&& try { tcx.lookup_stability(trait_predicate.def_id())?.level.is_stable() }
|
||||
== Some(false);
|
||||
let unstable = if mention_unstable { "nightly-only, unstable " } else { "" };
|
||||
|
||||
format!(
|
||||
"{pre_message}the {}trait `{}` is not implemented for{desc} `{}`",
|
||||
if tcx.lookup_stability(trait_predicate.def_id()).map(|s| s.level.is_stable())
|
||||
== Some(false)
|
||||
{
|
||||
"nightly-only, unstable "
|
||||
} else {
|
||||
""
|
||||
},
|
||||
"{pre_message}the {unstable}trait `{}` is not implemented for{desc} `{}`",
|
||||
trait_predicate.print_modifiers_and_trait_path(),
|
||||
tcx.short_string(trait_predicate.self_ty().skip_binder(), long_ty_path),
|
||||
)
|
||||
|
||||
@@ -314,6 +314,11 @@ pub fn dyn_compatibility_violations_for_assoc_item(
|
||||
trait_def_id: DefId,
|
||||
item: ty::AssocItem,
|
||||
) -> Vec<DynCompatibilityViolation> {
|
||||
// `final` assoc functions don't prevent a trait from being dyn-compatible
|
||||
if tcx.defaultness(item.def_id).is_final() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
// Any item that has a `Self: Sized` requisite is otherwise exempt from the regulations.
|
||||
if tcx.generics_require_sized_self(item.def_id) {
|
||||
return Vec::new();
|
||||
|
||||
@@ -210,6 +210,11 @@ fn own_existential_vtable_entries_iter(
|
||||
debug!("own_existential_vtable_entry: trait_method={:?}", trait_method);
|
||||
let def_id = trait_method.def_id;
|
||||
|
||||
// Final methods should not be included in the vtable.
|
||||
if trait_method.defaultness(tcx).is_final() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Some methods cannot be called on an object; skip those.
|
||||
if !is_vtable_safe_method(tcx, trait_def_id, trait_method) {
|
||||
debug!("own_existential_vtable_entry: not vtable safe");
|
||||
|
||||
@@ -237,6 +237,12 @@ fn resolve_associated_item<'tcx>(
|
||||
}
|
||||
traits::ImplSource::Builtin(BuiltinImplSource::Object(_), _) => {
|
||||
let trait_ref = ty::TraitRef::from_assoc(tcx, trait_id, rcvr_args);
|
||||
|
||||
// `final` methods should be called directly.
|
||||
if tcx.defaultness(trait_item_id).is_final() {
|
||||
return Ok(Some(ty::Instance::new_raw(trait_item_id, rcvr_args)));
|
||||
}
|
||||
|
||||
if trait_ref.has_non_region_infer() || trait_ref.has_non_region_param() {
|
||||
// We only resolve totally substituted vtable entries.
|
||||
None
|
||||
|
||||
@@ -42,7 +42,9 @@ fn lift_to_interner(self, cx: U) -> Option<Self::Lifted> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A complete reference to a trait. These take numerous guises in syntax,
|
||||
/// A complete reference to a trait.
|
||||
///
|
||||
/// These take numerous guises in syntax,
|
||||
/// but perhaps the most recognizable form is in a where-clause:
|
||||
/// ```ignore (illustrative)
|
||||
/// T: Foo<U>
|
||||
@@ -241,7 +243,9 @@ pub fn as_str(self) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
/// Polarity for a trait predicate. May either be negative or positive.
|
||||
/// Polarity for a trait predicate.
|
||||
///
|
||||
/// May either be negative or positive.
|
||||
/// Distinguished from [`ImplPolarity`] since we never compute goals with
|
||||
/// "reservation" level.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
@@ -327,6 +331,7 @@ pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> I::Clause {
|
||||
}
|
||||
|
||||
/// An existential reference to a trait, where `Self` is erased.
|
||||
///
|
||||
/// For example, the trait object `Trait<'a, 'b, X, Y>` is:
|
||||
/// ```ignore (illustrative)
|
||||
/// exists T. T: Trait<'a, 'b, X, Y>
|
||||
@@ -442,6 +447,7 @@ pub fn new(
|
||||
}
|
||||
|
||||
/// Extracts the underlying existential trait reference from this projection.
|
||||
///
|
||||
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
|
||||
/// then this function would return an `exists T. T: Iterator` existential trait
|
||||
/// reference.
|
||||
@@ -493,14 +499,17 @@ pub fn item_def_id(&self) -> I::DefId {
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
|
||||
pub enum AliasTermKind {
|
||||
/// A projection `<Type as Trait>::AssocType`.
|
||||
///
|
||||
/// Can get normalized away if monomorphic enough.
|
||||
ProjectionTy,
|
||||
/// An associated type in an inherent `impl`
|
||||
InherentTy,
|
||||
/// An opaque type (usually from `impl Trait` in type aliases or function return types)
|
||||
///
|
||||
/// Can only be normalized away in PostAnalysis mode or its defining scope.
|
||||
OpaqueTy,
|
||||
/// A free type alias that actually checks its trait bounds.
|
||||
///
|
||||
/// Currently only used if the type alias references opaque types.
|
||||
/// Can always be normalized away.
|
||||
FreeTy,
|
||||
|
||||
@@ -29,14 +29,17 @@
|
||||
)]
|
||||
pub enum AliasTyKind {
|
||||
/// A projection `<Type as Trait>::AssocType`.
|
||||
///
|
||||
/// Can get normalized away if monomorphic enough.
|
||||
Projection,
|
||||
/// An associated type in an inherent `impl`
|
||||
Inherent,
|
||||
/// An opaque type (usually from `impl Trait` in type aliases or function return types)
|
||||
///
|
||||
/// Can only be normalized away in PostAnalysis mode or its defining scope.
|
||||
Opaque,
|
||||
/// A type alias that actually checks its trait bounds.
|
||||
///
|
||||
/// Currently only used if the type alias references opaque types.
|
||||
/// Can always be normalized away.
|
||||
Free,
|
||||
@@ -99,7 +102,9 @@ pub enum TyKind<I: Interner> {
|
||||
/// An array with the given length. Written as `[T; N]`.
|
||||
Array(I::Ty, I::Const),
|
||||
|
||||
/// A pattern newtype. Takes any type and restricts its valid values to its pattern.
|
||||
/// A pattern newtype.
|
||||
///
|
||||
/// Takes any type and restricts its valid values to its pattern.
|
||||
/// This will also change the layout to take advantage of this restriction.
|
||||
/// Only `Copy` and `Clone` will automatically get implemented for pattern types.
|
||||
/// Auto-traits treat this as if it were an aggregate with a single nested type.
|
||||
@@ -116,8 +121,9 @@ pub enum TyKind<I: Interner> {
|
||||
/// `&'a mut T` or `&'a T`.
|
||||
Ref(I::Region, I::Ty, Mutability),
|
||||
|
||||
/// The anonymous type of a function declaration/definition. Each
|
||||
/// function has a unique type.
|
||||
/// The anonymous type of a function declaration/definition.
|
||||
///
|
||||
/// Each function has a unique type.
|
||||
///
|
||||
/// For the function `fn foo() -> i32 { 3 }` this type would be
|
||||
/// shown to the user as `fn() -> i32 {foo}`.
|
||||
@@ -129,7 +135,9 @@ pub enum TyKind<I: Interner> {
|
||||
/// ```
|
||||
FnDef(I::FunctionId, I::GenericArgs),
|
||||
|
||||
/// A pointer to a function. Written as `fn() -> i32`.
|
||||
/// A pointer to a function.
|
||||
///
|
||||
/// Written as `fn() -> i32`.
|
||||
///
|
||||
/// Note that both functions and closures start out as either
|
||||
/// [FnDef] or [Closure] which can be then be coerced to this variant.
|
||||
@@ -179,6 +187,7 @@ pub enum TyKind<I: Interner> {
|
||||
Coroutine(I::CoroutineId, I::GenericArgs),
|
||||
|
||||
/// A type representing the types stored inside a coroutine.
|
||||
///
|
||||
/// This should only appear as part of the `CoroutineArgs`.
|
||||
///
|
||||
/// Unlike upvars, the witness can reference lifetimes from
|
||||
@@ -210,6 +219,7 @@ pub enum TyKind<I: Interner> {
|
||||
Tuple(I::Tys),
|
||||
|
||||
/// A projection, opaque type, free type alias, or inherent associated type.
|
||||
///
|
||||
/// All of these types are represented as pairs of def-id and args, and can
|
||||
/// be normalized, so they are grouped conceptually.
|
||||
Alias(AliasTyKind, AliasTy<I>),
|
||||
@@ -253,8 +263,9 @@ pub enum TyKind<I: Interner> {
|
||||
/// inside of the type.
|
||||
Infer(InferTy),
|
||||
|
||||
/// A placeholder for a type which could not be computed; this is
|
||||
/// propagated to avoid useless error messages.
|
||||
/// A placeholder for a type which could not be computed.
|
||||
///
|
||||
/// This is propagated to avoid useless error messages.
|
||||
Error(I::ErrorGuaranteed),
|
||||
}
|
||||
|
||||
@@ -282,7 +293,9 @@ pub fn fn_sig(self, interner: I) -> ty::Binder<I, ty::FnSig<I>> {
|
||||
}
|
||||
|
||||
/// Returns `true` when the outermost type cannot be further normalized,
|
||||
/// resolved, or instantiated. This includes all primitive types, but also
|
||||
/// resolved, or instantiated.
|
||||
///
|
||||
/// This includes all primitive types, but also
|
||||
/// things like ADTs and trait objects, since even if their arguments or
|
||||
/// nested types may be further simplified, the outermost [`ty::TyKind`] or
|
||||
/// type constructor remains the same.
|
||||
@@ -481,6 +494,7 @@ pub fn trait_def_id(self, interner: I) -> I::DefId {
|
||||
}
|
||||
|
||||
/// Extracts the underlying trait reference and own args from this projection.
|
||||
///
|
||||
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
|
||||
/// then this function would return a `T: StreamingIterator` trait reference and
|
||||
/// `['a]` as the own args.
|
||||
@@ -490,6 +504,7 @@ pub fn trait_ref_and_own_args(self, interner: I) -> (ty::TraitRef<I>, I::Generic
|
||||
}
|
||||
|
||||
/// Extracts the underlying trait reference from this projection.
|
||||
///
|
||||
/// For example, if this is a projection of `<T as Iterator>::Item`,
|
||||
/// then this function would return a `T: Iterator` trait reference.
|
||||
///
|
||||
@@ -593,8 +608,9 @@ pub enum InferTy {
|
||||
FloatVar(FloatVid),
|
||||
|
||||
/// A [`FreshTy`][Self::FreshTy] is one that is generated as a replacement
|
||||
/// for an unbound type variable. This is convenient for caching etc. See
|
||||
/// `TypeFreshener` for more details.
|
||||
/// for an unbound type variable.
|
||||
///
|
||||
/// This is convenient for caching etc. See `TypeFreshener` for more details.
|
||||
///
|
||||
/// Compare with [`TyVar`][Self::TyVar].
|
||||
FreshTy(u32),
|
||||
|
||||
@@ -275,6 +275,70 @@ impl f128 {
|
||||
#[unstable(feature = "f128", issue = "116909")]
|
||||
pub const NEG_INFINITY: f128 = -1.0_f128 / 0.0_f128;
|
||||
|
||||
/// Maximum integer that can be represented exactly in an [`f128`] value,
|
||||
/// with no other integer converting to the same floating point value.
|
||||
///
|
||||
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
|
||||
/// there is a "one-to-one" mapping between [`i128`] and [`f128`] values.
|
||||
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f128`] and back to
|
||||
/// [`i128`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f128`] value
|
||||
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
|
||||
/// "one-to-one" mapping.
|
||||
///
|
||||
/// [`MAX_EXACT_INTEGER`]: f128::MAX_EXACT_INTEGER
|
||||
/// [`MIN_EXACT_INTEGER`]: f128::MIN_EXACT_INTEGER
|
||||
/// ```
|
||||
/// #![feature(f128)]
|
||||
/// #![feature(float_exact_integer_constants)]
|
||||
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
|
||||
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
|
||||
/// # #[cfg(target_has_reliable_f128)] {
|
||||
/// let max_exact_int = f128::MAX_EXACT_INTEGER;
|
||||
/// assert_eq!(max_exact_int, max_exact_int as f128 as i128);
|
||||
/// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f128 as i128);
|
||||
/// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f128 as i128);
|
||||
///
|
||||
/// // Beyond `f128::MAX_EXACT_INTEGER`, multiple integers can map to one float value
|
||||
/// assert_eq!((max_exact_int + 1) as f128, (max_exact_int + 2) as f128);
|
||||
/// # }}
|
||||
/// ```
|
||||
// #[unstable(feature = "f128", issue = "116909")]
|
||||
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
|
||||
pub const MAX_EXACT_INTEGER: i128 = (1 << Self::MANTISSA_DIGITS) - 1;
|
||||
|
||||
/// Minimum integer that can be represented exactly in an [`f128`] value,
|
||||
/// with no other integer converting to the same floating point value.
|
||||
///
|
||||
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
|
||||
/// there is a "one-to-one" mapping between [`i128`] and [`f128`] values.
|
||||
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f128`] and back to
|
||||
/// [`i128`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f128`] value
|
||||
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
|
||||
/// "one-to-one" mapping.
|
||||
///
|
||||
/// This constant is equivalent to `-MAX_EXACT_INTEGER`.
|
||||
///
|
||||
/// [`MAX_EXACT_INTEGER`]: f128::MAX_EXACT_INTEGER
|
||||
/// [`MIN_EXACT_INTEGER`]: f128::MIN_EXACT_INTEGER
|
||||
/// ```
|
||||
/// #![feature(f128)]
|
||||
/// #![feature(float_exact_integer_constants)]
|
||||
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
|
||||
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
|
||||
/// # #[cfg(target_has_reliable_f128)] {
|
||||
/// let min_exact_int = f128::MIN_EXACT_INTEGER;
|
||||
/// assert_eq!(min_exact_int, min_exact_int as f128 as i128);
|
||||
/// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f128 as i128);
|
||||
/// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f128 as i128);
|
||||
///
|
||||
/// // Below `f128::MIN_EXACT_INTEGER`, multiple integers can map to one float value
|
||||
/// assert_eq!((min_exact_int - 1) as f128, (min_exact_int - 2) as f128);
|
||||
/// # }}
|
||||
/// ```
|
||||
// #[unstable(feature = "f128", issue = "116909")]
|
||||
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
|
||||
pub const MIN_EXACT_INTEGER: i128 = -Self::MAX_EXACT_INTEGER;
|
||||
|
||||
/// Sign bit
|
||||
pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
|
||||
|
||||
|
||||
@@ -269,6 +269,70 @@ impl f16 {
|
||||
#[unstable(feature = "f16", issue = "116909")]
|
||||
pub const NEG_INFINITY: f16 = -1.0_f16 / 0.0_f16;
|
||||
|
||||
/// Maximum integer that can be represented exactly in an [`f16`] value,
|
||||
/// with no other integer converting to the same floating point value.
|
||||
///
|
||||
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
|
||||
/// there is a "one-to-one" mapping between [`i16`] and [`f16`] values.
|
||||
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f16`] and back to
|
||||
/// [`i16`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f16`] value
|
||||
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
|
||||
/// "one-to-one" mapping.
|
||||
///
|
||||
/// [`MAX_EXACT_INTEGER`]: f16::MAX_EXACT_INTEGER
|
||||
/// [`MIN_EXACT_INTEGER`]: f16::MIN_EXACT_INTEGER
|
||||
/// ```
|
||||
/// #![feature(f16)]
|
||||
/// #![feature(float_exact_integer_constants)]
|
||||
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
|
||||
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
|
||||
/// # #[cfg(target_has_reliable_f16)] {
|
||||
/// let max_exact_int = f16::MAX_EXACT_INTEGER;
|
||||
/// assert_eq!(max_exact_int, max_exact_int as f16 as i16);
|
||||
/// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f16 as i16);
|
||||
/// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f16 as i16);
|
||||
///
|
||||
/// // Beyond `f16::MAX_EXACT_INTEGER`, multiple integers can map to one float value
|
||||
/// assert_eq!((max_exact_int + 1) as f16, (max_exact_int + 2) as f16);
|
||||
/// # }}
|
||||
/// ```
|
||||
// #[unstable(feature = "f16", issue = "116909")]
|
||||
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
|
||||
pub const MAX_EXACT_INTEGER: i16 = (1 << Self::MANTISSA_DIGITS) - 1;
|
||||
|
||||
/// Minimum integer that can be represented exactly in an [`f16`] value,
|
||||
/// with no other integer converting to the same floating point value.
|
||||
///
|
||||
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
|
||||
/// there is a "one-to-one" mapping between [`i16`] and [`f16`] values.
|
||||
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f16`] and back to
|
||||
/// [`i16`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f16`] value
|
||||
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
|
||||
/// "one-to-one" mapping.
|
||||
///
|
||||
/// This constant is equivalent to `-MAX_EXACT_INTEGER`.
|
||||
///
|
||||
/// [`MAX_EXACT_INTEGER`]: f16::MAX_EXACT_INTEGER
|
||||
/// [`MIN_EXACT_INTEGER`]: f16::MIN_EXACT_INTEGER
|
||||
/// ```
|
||||
/// #![feature(f16)]
|
||||
/// #![feature(float_exact_integer_constants)]
|
||||
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
|
||||
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
|
||||
/// # #[cfg(target_has_reliable_f16)] {
|
||||
/// let min_exact_int = f16::MIN_EXACT_INTEGER;
|
||||
/// assert_eq!(min_exact_int, min_exact_int as f16 as i16);
|
||||
/// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f16 as i16);
|
||||
/// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f16 as i16);
|
||||
///
|
||||
/// // Below `f16::MIN_EXACT_INTEGER`, multiple integers can map to one float value
|
||||
/// assert_eq!((min_exact_int - 1) as f16, (min_exact_int - 2) as f16);
|
||||
/// # }}
|
||||
/// ```
|
||||
// #[unstable(feature = "f16", issue = "116909")]
|
||||
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
|
||||
pub const MIN_EXACT_INTEGER: i16 = -Self::MAX_EXACT_INTEGER;
|
||||
|
||||
/// Sign bit
|
||||
pub(crate) const SIGN_MASK: u16 = 0x8000;
|
||||
|
||||
|
||||
@@ -513,6 +513,64 @@ impl f32 {
|
||||
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
|
||||
pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32;
|
||||
|
||||
/// Maximum integer that can be represented exactly in an [`f32`] value,
|
||||
/// with no other integer converting to the same floating point value.
|
||||
///
|
||||
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
|
||||
/// there is a "one-to-one" mapping between [`i32`] and [`f32`] values.
|
||||
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f32`] and back to
|
||||
/// [`i32`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f32`] value
|
||||
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
|
||||
/// "one-to-one" mapping.
|
||||
///
|
||||
/// [`MAX_EXACT_INTEGER`]: f32::MAX_EXACT_INTEGER
|
||||
/// [`MIN_EXACT_INTEGER`]: f32::MIN_EXACT_INTEGER
|
||||
/// ```
|
||||
/// #![feature(float_exact_integer_constants)]
|
||||
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
|
||||
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
|
||||
/// let max_exact_int = f32::MAX_EXACT_INTEGER;
|
||||
/// assert_eq!(max_exact_int, max_exact_int as f32 as i32);
|
||||
/// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f32 as i32);
|
||||
/// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f32 as i32);
|
||||
///
|
||||
/// // Beyond `f32::MAX_EXACT_INTEGER`, multiple integers can map to one float value
|
||||
/// assert_eq!((max_exact_int + 1) as f32, (max_exact_int + 2) as f32);
|
||||
/// # }
|
||||
/// ```
|
||||
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
|
||||
pub const MAX_EXACT_INTEGER: i32 = (1 << Self::MANTISSA_DIGITS) - 1;
|
||||
|
||||
/// Minimum integer that can be represented exactly in an [`f32`] value,
|
||||
/// with no other integer converting to the same floating point value.
|
||||
///
|
||||
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
|
||||
/// there is a "one-to-one" mapping between [`i32`] and [`f32`] values.
|
||||
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f32`] and back to
|
||||
/// [`i32`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f32`] value
|
||||
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
|
||||
/// "one-to-one" mapping.
|
||||
///
|
||||
/// This constant is equivalent to `-MAX_EXACT_INTEGER`.
|
||||
///
|
||||
/// [`MAX_EXACT_INTEGER`]: f32::MAX_EXACT_INTEGER
|
||||
/// [`MIN_EXACT_INTEGER`]: f32::MIN_EXACT_INTEGER
|
||||
/// ```
|
||||
/// #![feature(float_exact_integer_constants)]
|
||||
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
|
||||
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
|
||||
/// let min_exact_int = f32::MIN_EXACT_INTEGER;
|
||||
/// assert_eq!(min_exact_int, min_exact_int as f32 as i32);
|
||||
/// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f32 as i32);
|
||||
/// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f32 as i32);
|
||||
///
|
||||
/// // Below `f32::MIN_EXACT_INTEGER`, multiple integers can map to one float value
|
||||
/// assert_eq!((min_exact_int - 1) as f32, (min_exact_int - 2) as f32);
|
||||
/// # }
|
||||
/// ```
|
||||
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
|
||||
pub const MIN_EXACT_INTEGER: i32 = -Self::MAX_EXACT_INTEGER;
|
||||
|
||||
/// Sign bit
|
||||
pub(crate) const SIGN_MASK: u32 = 0x8000_0000;
|
||||
|
||||
|
||||
@@ -512,6 +512,64 @@ impl f64 {
|
||||
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
|
||||
pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64;
|
||||
|
||||
/// Maximum integer that can be represented exactly in an [`f64`] value,
|
||||
/// with no other integer converting to the same floating point value.
|
||||
///
|
||||
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
|
||||
/// there is a "one-to-one" mapping between [`i64`] and [`f64`] values.
|
||||
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f64`] and back to
|
||||
/// [`i64`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f64`] value
|
||||
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
|
||||
/// "one-to-one" mapping.
|
||||
///
|
||||
/// [`MAX_EXACT_INTEGER`]: f64::MAX_EXACT_INTEGER
|
||||
/// [`MIN_EXACT_INTEGER`]: f64::MIN_EXACT_INTEGER
|
||||
/// ```
|
||||
/// #![feature(float_exact_integer_constants)]
|
||||
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
|
||||
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
|
||||
/// let max_exact_int = f64::MAX_EXACT_INTEGER;
|
||||
/// assert_eq!(max_exact_int, max_exact_int as f64 as i64);
|
||||
/// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f64 as i64);
|
||||
/// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f64 as i64);
|
||||
///
|
||||
/// // Beyond `f64::MAX_EXACT_INTEGER`, multiple integers can map to one float value
|
||||
/// assert_eq!((max_exact_int + 1) as f64, (max_exact_int + 2) as f64);
|
||||
/// # }
|
||||
/// ```
|
||||
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
|
||||
pub const MAX_EXACT_INTEGER: i64 = (1 << Self::MANTISSA_DIGITS) - 1;
|
||||
|
||||
/// Minimum integer that can be represented exactly in an [`f64`] value,
|
||||
/// with no other integer converting to the same floating point value.
|
||||
///
|
||||
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
|
||||
/// there is a "one-to-one" mapping between [`i64`] and [`f64`] values.
|
||||
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f64`] and back to
|
||||
/// [`i64`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f64`] value
|
||||
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
|
||||
/// "one-to-one" mapping.
|
||||
///
|
||||
/// This constant is equivalent to `-MAX_EXACT_INTEGER`.
|
||||
///
|
||||
/// [`MAX_EXACT_INTEGER`]: f64::MAX_EXACT_INTEGER
|
||||
/// [`MIN_EXACT_INTEGER`]: f64::MIN_EXACT_INTEGER
|
||||
/// ```
|
||||
/// #![feature(float_exact_integer_constants)]
|
||||
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
|
||||
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
|
||||
/// let min_exact_int = f64::MIN_EXACT_INTEGER;
|
||||
/// assert_eq!(min_exact_int, min_exact_int as f64 as i64);
|
||||
/// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f64 as i64);
|
||||
/// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f64 as i64);
|
||||
///
|
||||
/// // Below `f64::MIN_EXACT_INTEGER`, multiple integers can map to one float value
|
||||
/// assert_eq!((min_exact_int - 1) as f64, (min_exact_int - 2) as f64);
|
||||
/// # }
|
||||
/// ```
|
||||
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
|
||||
pub const MIN_EXACT_INTEGER: i64 = -Self::MAX_EXACT_INTEGER;
|
||||
|
||||
/// Sign bit
|
||||
pub(crate) const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ trait TestableFloat: Sized {
|
||||
const BITS: u32;
|
||||
/// Unsigned int with the same size, for converting to/from bits.
|
||||
type Int;
|
||||
/// Signed int with the same size.
|
||||
type SInt;
|
||||
/// Set the default tolerance for float comparison based on the type.
|
||||
const APPROX: Self;
|
||||
/// Allow looser tolerance for f32 on miri
|
||||
@@ -61,6 +63,7 @@ trait TestableFloat: Sized {
|
||||
impl TestableFloat for f16 {
|
||||
const BITS: u32 = 16;
|
||||
type Int = u16;
|
||||
type SInt = i16;
|
||||
const APPROX: Self = 1e-3;
|
||||
const POWF_APPROX: Self = 5e-1;
|
||||
const _180_TO_RADIANS_APPROX: Self = 1e-2;
|
||||
@@ -101,6 +104,7 @@ impl TestableFloat for f16 {
|
||||
impl TestableFloat for f32 {
|
||||
const BITS: u32 = 32;
|
||||
type Int = u32;
|
||||
type SInt = i32;
|
||||
const APPROX: Self = 1e-6;
|
||||
/// Miri adds some extra errors to float functions; make sure the tests still pass.
|
||||
/// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides.
|
||||
@@ -143,6 +147,7 @@ impl TestableFloat for f32 {
|
||||
impl TestableFloat for f64 {
|
||||
const BITS: u32 = 64;
|
||||
type Int = u64;
|
||||
type SInt = i64;
|
||||
const APPROX: Self = 1e-6;
|
||||
const GAMMA_APPROX_LOOSE: Self = 1e-4;
|
||||
const LNGAMMA_APPROX_LOOSE: Self = 1e-4;
|
||||
@@ -170,6 +175,7 @@ impl TestableFloat for f64 {
|
||||
impl TestableFloat for f128 {
|
||||
const BITS: u32 = 128;
|
||||
type Int = u128;
|
||||
type SInt = i128;
|
||||
const APPROX: Self = 1e-9;
|
||||
const EXP_APPROX: Self = 1e-12;
|
||||
const LN_APPROX: Self = 1e-12;
|
||||
@@ -2003,6 +2009,93 @@ fn s_nan() -> Float {
|
||||
}
|
||||
}
|
||||
|
||||
// Test the `float_exact_integer_constants` feature
|
||||
float_test! {
|
||||
name: max_exact_integer_constant,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||
f128: #[cfg(any(miri, target_has_reliable_f128))],
|
||||
},
|
||||
test<Float> {
|
||||
// The maximum integer that converts to a unique floating point
|
||||
// value.
|
||||
const MAX_EXACT_INTEGER: <Float as TestableFloat>::SInt = Float::MAX_EXACT_INTEGER;
|
||||
|
||||
let max_minus_one = (MAX_EXACT_INTEGER - 1) as Float as <Float as TestableFloat>::SInt;
|
||||
let max_plus_one = (MAX_EXACT_INTEGER + 1) as Float as <Float as TestableFloat>::SInt;
|
||||
let max_plus_two = (MAX_EXACT_INTEGER + 2) as Float as <Float as TestableFloat>::SInt;
|
||||
|
||||
// This does an extra round trip back to float for the second operand in
|
||||
// order to print the results if there is a mismatch
|
||||
assert_biteq!((MAX_EXACT_INTEGER - 1) as Float, max_minus_one as Float);
|
||||
assert_biteq!(MAX_EXACT_INTEGER as Float, MAX_EXACT_INTEGER as Float as <Float as TestableFloat>::SInt as Float);
|
||||
assert_biteq!((MAX_EXACT_INTEGER + 1) as Float, max_plus_one as Float);
|
||||
// The first non-unique conversion, where `max_plus_two` roundtrips to
|
||||
// `max_plus_one`
|
||||
assert_biteq!((MAX_EXACT_INTEGER + 1) as Float, (MAX_EXACT_INTEGER + 2) as Float);
|
||||
assert_biteq!((MAX_EXACT_INTEGER + 2) as Float, max_plus_one as Float);
|
||||
assert_biteq!((MAX_EXACT_INTEGER + 2) as Float, max_plus_two as Float);
|
||||
|
||||
// Lossless roundtrips, for integers
|
||||
assert!(MAX_EXACT_INTEGER - 1 == max_minus_one);
|
||||
assert!(MAX_EXACT_INTEGER == MAX_EXACT_INTEGER as Float as <Float as TestableFloat>::SInt);
|
||||
assert!(MAX_EXACT_INTEGER + 1 == max_plus_one);
|
||||
// The first non-unique conversion, where `max_plus_two` roundtrips to
|
||||
// one less than the starting value
|
||||
assert!(MAX_EXACT_INTEGER + 2 != max_plus_two);
|
||||
|
||||
// max-1 | max+0 | max+1 | max+2
|
||||
// After roundtripping, +1 and +2 will equal each other
|
||||
assert!(max_minus_one != MAX_EXACT_INTEGER);
|
||||
assert!(MAX_EXACT_INTEGER != max_plus_one);
|
||||
assert!(max_plus_one == max_plus_two);
|
||||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: min_exact_integer_constant,
|
||||
attrs: {
|
||||
f16: #[cfg(any(miri, target_has_reliable_f16))],
|
||||
f128: #[cfg(any(miri, target_has_reliable_f128))],
|
||||
},
|
||||
test<Float> {
|
||||
// The minimum integer that converts to a unique floating point
|
||||
// value.
|
||||
const MIN_EXACT_INTEGER: <Float as TestableFloat>::SInt = Float::MIN_EXACT_INTEGER;
|
||||
|
||||
// Same logic as the `max` test, but we work our way leftward
|
||||
// across the number line from (min_exact + 1) to (min_exact - 2).
|
||||
let min_plus_one = (MIN_EXACT_INTEGER + 1) as Float as <Float as TestableFloat>::SInt;
|
||||
let min_minus_one = (MIN_EXACT_INTEGER - 1) as Float as <Float as TestableFloat>::SInt;
|
||||
let min_minus_two = (MIN_EXACT_INTEGER - 2) as Float as <Float as TestableFloat>::SInt;
|
||||
|
||||
// This does an extra round trip back to float for the second operand in
|
||||
// order to print the results if there is a mismatch
|
||||
assert_biteq!((MIN_EXACT_INTEGER + 1) as Float, min_plus_one as Float);
|
||||
assert_biteq!(MIN_EXACT_INTEGER as Float, MIN_EXACT_INTEGER as Float as <Float as TestableFloat>::SInt as Float);
|
||||
assert_biteq!((MIN_EXACT_INTEGER - 1) as Float, min_minus_one as Float);
|
||||
// The first non-unique conversion, which roundtrips to one
|
||||
// greater than the starting value.
|
||||
assert_biteq!((MIN_EXACT_INTEGER - 1) as Float, (MIN_EXACT_INTEGER - 2) as Float);
|
||||
assert_biteq!((MIN_EXACT_INTEGER - 2) as Float, min_minus_one as Float);
|
||||
assert_biteq!((MIN_EXACT_INTEGER - 2) as Float, min_minus_two as Float);
|
||||
|
||||
// Lossless roundtrips, for integers
|
||||
assert!(MIN_EXACT_INTEGER + 1 == min_plus_one);
|
||||
assert!(MIN_EXACT_INTEGER == MIN_EXACT_INTEGER as Float as <Float as TestableFloat>::SInt);
|
||||
assert!(MIN_EXACT_INTEGER - 1 == min_minus_one);
|
||||
// The first non-unique conversion, which roundtrips to one
|
||||
// greater than the starting value.
|
||||
assert!(MIN_EXACT_INTEGER - 2 != min_minus_two);
|
||||
|
||||
// min-2 | min-1 | min | min+1
|
||||
// After roundtripping, -2 and -1 will equal each other.
|
||||
assert!(min_plus_one != MIN_EXACT_INTEGER);
|
||||
assert!(MIN_EXACT_INTEGER != min_minus_one);
|
||||
assert!(min_minus_one == min_minus_two);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(f128): Uncomment and adapt these tests once the From<{u64,i64}> impls are added.
|
||||
// float_test! {
|
||||
// name: from_u64_i64,
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#![feature(f128)]
|
||||
#![feature(float_algebraic)]
|
||||
#![feature(float_bits_const)]
|
||||
#![feature(float_exact_integer_constants)]
|
||||
#![feature(float_gamma)]
|
||||
#![feature(float_minimum_maximum)]
|
||||
#![feature(flt2dec)]
|
||||
|
||||
+6
-6
@@ -25,7 +25,7 @@ labels_blocking_approval = [
|
||||
"S-waiting-on-t-rustdoc-frontend",
|
||||
"S-waiting-on-t-clippy",
|
||||
# PR manually set to blocked
|
||||
"S-blocked"
|
||||
"S-blocked",
|
||||
]
|
||||
|
||||
# If CI runs quicker than this duration, consider it to be a failure
|
||||
@@ -41,7 +41,7 @@ approved = [
|
||||
"-S-waiting-on-author",
|
||||
"-S-waiting-on-crater",
|
||||
"-S-waiting-on-review",
|
||||
"-S-waiting-on-team"
|
||||
"-S-waiting-on-team",
|
||||
]
|
||||
unapproved = [
|
||||
"+S-waiting-on-author",
|
||||
@@ -49,16 +49,16 @@ unapproved = [
|
||||
"-S-waiting-on-bors",
|
||||
"-S-waiting-on-crater",
|
||||
"-S-waiting-on-review",
|
||||
"-S-waiting-on-team"
|
||||
"-S-waiting-on-team",
|
||||
]
|
||||
try_failed = [
|
||||
"+S-waiting-on-author",
|
||||
"-S-waiting-on-review",
|
||||
"-S-waiting-on-crater"
|
||||
"-S-waiting-on-crater",
|
||||
]
|
||||
auto_build_succeeded = [
|
||||
"+merged-by-bors",
|
||||
"-S-waiting-on-bors"
|
||||
"-S-waiting-on-bors",
|
||||
]
|
||||
auto_build_failed = [
|
||||
"+S-waiting-on-review",
|
||||
@@ -66,5 +66,5 @@ auto_build_failed = [
|
||||
"-S-waiting-on-bors",
|
||||
"-S-waiting-on-author",
|
||||
"-S-waiting-on-crater",
|
||||
"-S-waiting-on-team"
|
||||
"-S-waiting-on-team",
|
||||
]
|
||||
|
||||
@@ -79,7 +79,6 @@ expression: bench
|
||||
- Set({bench::compiler/rustc_public})
|
||||
- Set({bench::compiler/rustc_public_bridge})
|
||||
- Set({bench::compiler/rustc_query_impl})
|
||||
- Set({bench::compiler/rustc_query_system})
|
||||
- Set({bench::compiler/rustc_resolve})
|
||||
- Set({bench::compiler/rustc_sanitizers})
|
||||
- Set({bench::compiler/rustc_serialize})
|
||||
|
||||
@@ -61,7 +61,6 @@ expression: build compiler
|
||||
- Set({build::compiler/rustc_public})
|
||||
- Set({build::compiler/rustc_public_bridge})
|
||||
- Set({build::compiler/rustc_query_impl})
|
||||
- Set({build::compiler/rustc_query_system})
|
||||
- Set({build::compiler/rustc_resolve})
|
||||
- Set({build::compiler/rustc_sanitizers})
|
||||
- Set({build::compiler/rustc_serialize})
|
||||
|
||||
@@ -63,7 +63,6 @@ expression: check
|
||||
- Set({check::compiler/rustc_public})
|
||||
- Set({check::compiler/rustc_public_bridge})
|
||||
- Set({check::compiler/rustc_query_impl})
|
||||
- Set({check::compiler/rustc_query_system})
|
||||
- Set({check::compiler/rustc_resolve})
|
||||
- Set({check::compiler/rustc_sanitizers})
|
||||
- Set({check::compiler/rustc_serialize})
|
||||
|
||||
@@ -63,7 +63,6 @@ expression: check compiler
|
||||
- Set({check::compiler/rustc_public})
|
||||
- Set({check::compiler/rustc_public_bridge})
|
||||
- Set({check::compiler/rustc_query_impl})
|
||||
- Set({check::compiler/rustc_query_system})
|
||||
- Set({check::compiler/rustc_resolve})
|
||||
- Set({check::compiler/rustc_sanitizers})
|
||||
- Set({check::compiler/rustc_serialize})
|
||||
|
||||
-1
@@ -63,7 +63,6 @@ expression: check compiletest --include-default-paths
|
||||
- Set({check::compiler/rustc_public})
|
||||
- Set({check::compiler/rustc_public_bridge})
|
||||
- Set({check::compiler/rustc_query_impl})
|
||||
- Set({check::compiler/rustc_query_system})
|
||||
- Set({check::compiler/rustc_resolve})
|
||||
- Set({check::compiler/rustc_sanitizers})
|
||||
- Set({check::compiler/rustc_serialize})
|
||||
|
||||
@@ -78,7 +78,6 @@ expression: clippy
|
||||
- Set({clippy::compiler/rustc_public})
|
||||
- Set({clippy::compiler/rustc_public_bridge})
|
||||
- Set({clippy::compiler/rustc_query_impl})
|
||||
- Set({clippy::compiler/rustc_query_system})
|
||||
- Set({clippy::compiler/rustc_resolve})
|
||||
- Set({clippy::compiler/rustc_sanitizers})
|
||||
- Set({clippy::compiler/rustc_serialize})
|
||||
|
||||
@@ -63,7 +63,6 @@ expression: fix
|
||||
- Set({fix::compiler/rustc_public})
|
||||
- Set({fix::compiler/rustc_public_bridge})
|
||||
- Set({fix::compiler/rustc_query_impl})
|
||||
- Set({fix::compiler/rustc_query_system})
|
||||
- Set({fix::compiler/rustc_resolve})
|
||||
- Set({fix::compiler/rustc_sanitizers})
|
||||
- Set({fix::compiler/rustc_serialize})
|
||||
|
||||
@@ -129,7 +129,6 @@ expression: test
|
||||
- Set({test::compiler/rustc_public})
|
||||
- Set({test::compiler/rustc_public_bridge})
|
||||
- Set({test::compiler/rustc_query_impl})
|
||||
- Set({test::compiler/rustc_query_system})
|
||||
- Set({test::compiler/rustc_resolve})
|
||||
- Set({test::compiler/rustc_sanitizers})
|
||||
- Set({test::compiler/rustc_serialize})
|
||||
|
||||
@@ -128,7 +128,6 @@ expression: test --skip=coverage
|
||||
- Set({test::compiler/rustc_public})
|
||||
- Set({test::compiler/rustc_public_bridge})
|
||||
- Set({test::compiler/rustc_query_impl})
|
||||
- Set({test::compiler/rustc_query_system})
|
||||
- Set({test::compiler/rustc_resolve})
|
||||
- Set({test::compiler/rustc_sanitizers})
|
||||
- Set({test::compiler/rustc_serialize})
|
||||
|
||||
@@ -92,7 +92,6 @@ expression: test --skip=tests
|
||||
- Set({test::compiler/rustc_public})
|
||||
- Set({test::compiler/rustc_public_bridge})
|
||||
- Set({test::compiler/rustc_query_impl})
|
||||
- Set({test::compiler/rustc_query_system})
|
||||
- Set({test::compiler/rustc_resolve})
|
||||
- Set({test::compiler/rustc_sanitizers})
|
||||
- Set({test::compiler/rustc_serialize})
|
||||
|
||||
@@ -72,7 +72,6 @@ expression: test --skip=tests --skip=coverage-map --skip=coverage-run --skip=lib
|
||||
- Set({test::compiler/rustc_public})
|
||||
- Set({test::compiler/rustc_public_bridge})
|
||||
- Set({test::compiler/rustc_query_impl})
|
||||
- Set({test::compiler/rustc_query_system})
|
||||
- Set({test::compiler/rustc_resolve})
|
||||
- Set({test::compiler/rustc_sanitizers})
|
||||
- Set({test::compiler/rustc_serialize})
|
||||
|
||||
@@ -1815,7 +1815,7 @@ fn check_compiler_no_explicit_stage() {
|
||||
insta::assert_snapshot!(
|
||||
ctx.config("check")
|
||||
.path("compiler")
|
||||
.render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (74 crates)");
|
||||
.render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (73 crates)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1841,7 +1841,7 @@ fn check_compiler_stage_1() {
|
||||
ctx.config("check")
|
||||
.path("compiler")
|
||||
.stage(1)
|
||||
.render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (74 crates)");
|
||||
.render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (73 crates)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1851,11 +1851,11 @@ fn check_compiler_stage_2() {
|
||||
ctx.config("check")
|
||||
.path("compiler")
|
||||
.stage(2)
|
||||
.render_steps(), @r"
|
||||
.render_steps(), @"
|
||||
[build] llvm <host>
|
||||
[build] rustc 0 <host> -> rustc 1 <host>
|
||||
[build] rustc 1 <host> -> std 1 <host>
|
||||
[check] rustc 1 <host> -> rustc 2 <host> (74 crates)
|
||||
[check] rustc 1 <host> -> rustc 2 <host> (73 crates)
|
||||
");
|
||||
}
|
||||
|
||||
@@ -1866,12 +1866,12 @@ fn check_cross_compile() {
|
||||
ctx.config("check")
|
||||
.targets(&[TEST_TRIPLE_1])
|
||||
.hosts(&[TEST_TRIPLE_1])
|
||||
.render_steps(), @r"
|
||||
.render_steps(), @"
|
||||
[build] llvm <host>
|
||||
[build] rustc 0 <host> -> rustc 1 <host>
|
||||
[build] rustc 1 <host> -> std 1 <host>
|
||||
[check] rustc 1 <host> -> std 1 <target1>
|
||||
[check] rustc 1 <host> -> rustc 2 <target1> (74 crates)
|
||||
[check] rustc 1 <host> -> rustc 2 <target1> (73 crates)
|
||||
[check] rustc 1 <host> -> rustc 2 <target1>
|
||||
[check] rustc 1 <host> -> Rustdoc 2 <target1>
|
||||
[check] rustc 1 <host> -> rustc_codegen_cranelift 2 <target1>
|
||||
@@ -1967,7 +1967,7 @@ fn check_library_skip_without_download_rustc() {
|
||||
ctx.config("check")
|
||||
.paths(&["library", "compiler"])
|
||||
.args(&args)
|
||||
.render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (74 crates)");
|
||||
.render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (73 crates)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -178,7 +178,7 @@ fn try_mark_green(tcx, current_node) -> bool {
|
||||
|
||||
> NOTE:
|
||||
> The actual implementation can be found in
|
||||
> [`compiler/rustc_query_system/src/dep_graph/graph.rs`][try_mark_green]
|
||||
> [`compiler/rustc_middle/src/dep_graph/graph.rs`][try_mark_green]
|
||||
|
||||
By using red-green marking we can avoid the devastating cumulative effect of
|
||||
having false positives during change detection. Whenever a query is executed
|
||||
@@ -534,4 +534,4 @@ information.
|
||||
|
||||
|
||||
[query-model]: ./query-evaluation-model-in-detail.html
|
||||
[try_mark_green]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_query_system/dep_graph/graph.rs.html
|
||||
[try_mark_green]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/dep_graph/graph.rs.html
|
||||
|
||||
+13
-11
@@ -1222,11 +1222,11 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
|
||||
}
|
||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
|
||||
let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body));
|
||||
MethodItem(m, None)
|
||||
MethodItem(m, Defaultness::from_trait_item(trait_item.defaultness))
|
||||
}
|
||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(idents)) => {
|
||||
let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Idents(idents));
|
||||
RequiredMethodItem(m)
|
||||
RequiredMethodItem(m, Defaultness::from_trait_item(trait_item.defaultness))
|
||||
}
|
||||
hir::TraitItemKind::Type(bounds, Some(default)) => {
|
||||
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
|
||||
@@ -1271,7 +1271,7 @@ pub(crate) fn clean_impl_item<'tcx>(
|
||||
hir::ImplItemImplKind::Inherent { .. } => hir::Defaultness::Final,
|
||||
hir::ImplItemImplKind::Trait { defaultness, .. } => defaultness,
|
||||
};
|
||||
MethodItem(m, Some(defaultness))
|
||||
MethodItem(m, Defaultness::from_impl_item(defaultness))
|
||||
}
|
||||
hir::ImplItemKind::Type(hir_ty) => {
|
||||
let type_ = clean_ty(hir_ty, cx);
|
||||
@@ -1353,18 +1353,20 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
|
||||
}
|
||||
}
|
||||
|
||||
let provided = match assoc_item.container {
|
||||
ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true,
|
||||
ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(),
|
||||
let defaultness = assoc_item.defaultness(tcx);
|
||||
let (provided, defaultness) = match assoc_item.container {
|
||||
ty::AssocContainer::Trait => {
|
||||
(defaultness.has_value(), Defaultness::from_trait_item(defaultness))
|
||||
}
|
||||
ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {
|
||||
(true, Defaultness::from_impl_item(defaultness))
|
||||
}
|
||||
};
|
||||
|
||||
if provided {
|
||||
let defaultness = match assoc_item.container {
|
||||
ty::AssocContainer::TraitImpl(_) => Some(assoc_item.defaultness(tcx)),
|
||||
ty::AssocContainer::InherentImpl | ty::AssocContainer::Trait => None,
|
||||
};
|
||||
MethodItem(item, defaultness)
|
||||
} else {
|
||||
RequiredMethodItem(item)
|
||||
RequiredMethodItem(item, defaultness)
|
||||
}
|
||||
}
|
||||
ty::AssocKind::Type { .. } => {
|
||||
|
||||
@@ -61,6 +61,29 @@ pub(crate) enum ItemId {
|
||||
Blanket { impl_id: DefId, for_: DefId },
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub(crate) enum Defaultness {
|
||||
Implicit,
|
||||
Default,
|
||||
Final,
|
||||
}
|
||||
|
||||
impl Defaultness {
|
||||
pub(crate) fn from_trait_item(defaultness: hir::Defaultness) -> Self {
|
||||
match defaultness {
|
||||
hir::Defaultness::Default { .. } => Self::Implicit,
|
||||
hir::Defaultness::Final => Self::Final,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_impl_item(defaultness: hir::Defaultness) -> Self {
|
||||
match defaultness {
|
||||
hir::Defaultness::Default { .. } => Self::Default,
|
||||
hir::Defaultness::Final => Self::Implicit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ItemId {
|
||||
#[inline]
|
||||
pub(crate) fn is_local(self) -> bool {
|
||||
@@ -707,12 +730,12 @@ pub(crate) fn type_(&self) -> ItemType {
|
||||
ItemType::from(self)
|
||||
}
|
||||
|
||||
pub(crate) fn is_default(&self) -> bool {
|
||||
pub(crate) fn defaultness(&self) -> Option<Defaultness> {
|
||||
match self.kind {
|
||||
ItemKind::MethodItem(_, Some(defaultness)) => {
|
||||
defaultness.has_value() && !defaultness.is_final()
|
||||
ItemKind::MethodItem(_, defaultness) | ItemKind::RequiredMethodItem(_, defaultness) => {
|
||||
Some(defaultness)
|
||||
}
|
||||
_ => false,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -774,8 +797,8 @@ fn build_fn_header(
|
||||
}
|
||||
}
|
||||
ItemKind::FunctionItem(_)
|
||||
| ItemKind::MethodItem(_, _)
|
||||
| ItemKind::RequiredMethodItem(_) => {
|
||||
| ItemKind::MethodItem(..)
|
||||
| ItemKind::RequiredMethodItem(..) => {
|
||||
let def_id = self.def_id().unwrap();
|
||||
build_fn_header(def_id, tcx, tcx.asyncness(def_id))
|
||||
}
|
||||
@@ -859,11 +882,11 @@ pub(crate) enum ItemKind {
|
||||
TraitAliasItem(TraitAlias),
|
||||
ImplItem(Box<Impl>),
|
||||
/// A required method in a trait declaration meaning it's only a function signature.
|
||||
RequiredMethodItem(Box<Function>),
|
||||
RequiredMethodItem(Box<Function>, Defaultness),
|
||||
/// A method in a trait impl or a provided method in a trait declaration.
|
||||
///
|
||||
/// Compared to [RequiredMethodItem], it also contains a method body.
|
||||
MethodItem(Box<Function>, Option<hir::Defaultness>),
|
||||
MethodItem(Box<Function>, Defaultness),
|
||||
StructFieldItem(Type),
|
||||
VariantItem(Variant),
|
||||
/// `fn`s from an extern block
|
||||
@@ -921,8 +944,8 @@ pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
|
||||
| StaticItem(_)
|
||||
| ConstantItem(_)
|
||||
| TraitAliasItem(_)
|
||||
| RequiredMethodItem(_)
|
||||
| MethodItem(_, _)
|
||||
| RequiredMethodItem(..)
|
||||
| MethodItem(..)
|
||||
| StructFieldItem(_)
|
||||
| ForeignFunctionItem(_, _)
|
||||
| ForeignStaticItem(_, _)
|
||||
|
||||
@@ -82,8 +82,8 @@ fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
|
||||
| StaticItem(_)
|
||||
| ConstantItem(..)
|
||||
| TraitAliasItem(_)
|
||||
| RequiredMethodItem(_)
|
||||
| MethodItem(_, _)
|
||||
| RequiredMethodItem(..)
|
||||
| MethodItem(..)
|
||||
| StructFieldItem(_)
|
||||
| ForeignFunctionItem(..)
|
||||
| ForeignStaticItem(..)
|
||||
|
||||
@@ -1566,10 +1566,6 @@ pub(crate) fn print_abi_with_space(abi: ExternAbi) -> impl Display {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn print_default_space(v: bool) -> &'static str {
|
||||
if v { "default " } else { "" }
|
||||
}
|
||||
|
||||
fn print_generic_arg(generic_arg: &clean::GenericArg, cx: &Context<'_>) -> impl Display {
|
||||
fmt::from_fn(move |f| match generic_arg {
|
||||
clean::GenericArg::Lifetime(lt) => f.write_str(print_lifetime(lt)),
|
||||
|
||||
@@ -59,14 +59,14 @@
|
||||
use rustc_hir::{ConstStability, Mutability, RustcVersion, StabilityLevel, StableSince};
|
||||
use rustc_middle::ty::print::PrintTraitRefExt;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_span::symbol::{Symbol, sym};
|
||||
use rustc_span::{BytePos, DUMMY_SP, FileName};
|
||||
use tracing::{debug, info};
|
||||
|
||||
pub(crate) use self::context::*;
|
||||
pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources};
|
||||
pub(crate) use self::write_shared::*;
|
||||
use crate::clean::{self, ItemId, RenderedLink};
|
||||
use crate::clean::{self, Defaultness, ItemId, RenderedLink};
|
||||
use crate::display::{Joined as _, MaybeDisplay as _};
|
||||
use crate::error::Error;
|
||||
use crate::formats::Impl;
|
||||
@@ -75,8 +75,8 @@
|
||||
use crate::html::escape::Escape;
|
||||
use crate::html::format::{
|
||||
Ending, HrefError, HrefInfo, PrintWithSpace, full_print_fn_decl, href, print_abi_with_space,
|
||||
print_constness_with_space, print_default_space, print_generic_bounds, print_generics,
|
||||
print_impl, print_path, print_type, print_where_clause, visibility_print_with_space,
|
||||
print_constness_with_space, print_generic_bounds, print_generics, print_impl, print_path,
|
||||
print_type, print_where_clause, visibility_print_with_space,
|
||||
};
|
||||
use crate::html::markdown::{
|
||||
HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
|
||||
@@ -1110,7 +1110,11 @@ fn assoc_method(
|
||||
let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
|
||||
let name = meth.name.as_ref().unwrap();
|
||||
let vis = visibility_print_with_space(meth, cx).to_string();
|
||||
let defaultness = print_default_space(meth.is_default());
|
||||
let defaultness = match meth.defaultness().expect("Expected assoc method to have defaultness") {
|
||||
Defaultness::Implicit => "",
|
||||
Defaultness::Final => "final ",
|
||||
Defaultness::Default => "default ",
|
||||
};
|
||||
// FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove
|
||||
// this condition.
|
||||
let constness = match render_mode {
|
||||
@@ -1261,7 +1265,7 @@ fn render_assoc_item(
|
||||
) -> impl fmt::Display {
|
||||
fmt::from_fn(move |f| match &item.kind {
|
||||
clean::StrippedItem(..) => Ok(()),
|
||||
clean::RequiredMethodItem(m) | clean::MethodItem(m, _) => {
|
||||
clean::RequiredMethodItem(m, _) | clean::MethodItem(m, _) => {
|
||||
assoc_method(item, &m.generics, &m.decl, link, parent, cx, render_mode).fmt(f)
|
||||
}
|
||||
clean::RequiredAssocConstItem(generics, ty) => assoc_const(
|
||||
@@ -1586,7 +1590,7 @@ fn render_deref_methods(
|
||||
fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
|
||||
let self_type_opt = match item.kind {
|
||||
clean::MethodItem(ref method, _) => method.decl.receiver_type(),
|
||||
clean::RequiredMethodItem(ref method) => method.decl.receiver_type(),
|
||||
clean::RequiredMethodItem(ref method, _) => method.decl.receiver_type(),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
@@ -1856,7 +1860,7 @@ fn doc_impl_item(
|
||||
deprecation_class = "";
|
||||
}
|
||||
match &item.kind {
|
||||
clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
|
||||
clean::MethodItem(..) | clean::RequiredMethodItem(..) => {
|
||||
// Only render when the method is not static or we allow static methods
|
||||
if render_method_item {
|
||||
let id = cx.derive_id(format!("{item_type}.{name}"));
|
||||
@@ -2034,7 +2038,9 @@ fn doc_impl_item(
|
||||
if !impl_.is_negative_trait_impl() {
|
||||
for impl_item in &impl_.items {
|
||||
match impl_item.kind {
|
||||
clean::MethodItem(..) | clean::RequiredMethodItem(_) => methods.push(impl_item),
|
||||
clean::MethodItem(..) | clean::RequiredMethodItem(..) => {
|
||||
methods.push(impl_item)
|
||||
}
|
||||
clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => {
|
||||
assoc_types.push(impl_item)
|
||||
}
|
||||
@@ -2779,46 +2785,12 @@ fn render_call_locations<W: fmt::Write>(
|
||||
let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES;
|
||||
let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
|
||||
|
||||
let source_map = tcx.sess.source_map();
|
||||
let files = source_map.files();
|
||||
let local = tcx.sess.local_crate_source_file().unwrap();
|
||||
|
||||
let get_file_start_pos = || {
|
||||
let crate_src = local.clone().into_local_path()?;
|
||||
let abs_crate_src = crate_src.canonicalize().ok()?;
|
||||
let crate_root = abs_crate_src.parent()?.parent()?;
|
||||
let rel_path = path.strip_prefix(crate_root).ok()?;
|
||||
files
|
||||
.iter()
|
||||
.find(|file| match &file.name {
|
||||
FileName::Real(real) => real.local_path().map_or(false, |p| p == rel_path),
|
||||
_ => false,
|
||||
})
|
||||
.map(|file| file.start_pos)
|
||||
};
|
||||
|
||||
// Look for the example file in the source map if it exists, otherwise
|
||||
// return a span to the local crate's source file
|
||||
let Some(file_span) = get_file_start_pos()
|
||||
.or_else(|| {
|
||||
files
|
||||
.iter()
|
||||
.find(|file| match &file.name {
|
||||
FileName::Real(file_name) => file_name == &local,
|
||||
_ => false,
|
||||
})
|
||||
.map(|file| file.start_pos)
|
||||
})
|
||||
.map(|start_pos| {
|
||||
rustc_span::Span::with_root_ctxt(
|
||||
start_pos + BytePos(byte_min),
|
||||
start_pos + BytePos(byte_max),
|
||||
)
|
||||
})
|
||||
else {
|
||||
// if the fallback span can't be built, don't render the code for this example
|
||||
return false;
|
||||
};
|
||||
// For scraped examples, we don't need a real span from the SourceMap.
|
||||
// The URL is already provided in ScrapedInfo, and sources::print_src
|
||||
// will use that directly. We use DUMMY_SP as a placeholder.
|
||||
// Note: DUMMY_SP is safe here because href_from_span won't be called
|
||||
// for scraped examples.
|
||||
let file_span = rustc_span::DUMMY_SP;
|
||||
|
||||
let mut decoration_info = FxIndexMap::default();
|
||||
decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
|
||||
|
||||
@@ -1977,7 +1977,7 @@ pub(crate) fn get_function_type_for_search(
|
||||
clean::ForeignFunctionItem(ref f, _)
|
||||
| clean::FunctionItem(ref f)
|
||||
| clean::MethodItem(ref f, _)
|
||||
| clean::RequiredMethodItem(ref f) => {
|
||||
| clean::RequiredMethodItem(ref f, _) => {
|
||||
get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
|
||||
}
|
||||
clean::ConstantItem(ref c) => make_nullary_fn(&c.type_),
|
||||
|
||||
@@ -344,9 +344,15 @@ pub(crate) fn print_src(
|
||||
lines += line_info.start_line as usize;
|
||||
}
|
||||
let code = fmt::from_fn(move |fmt| {
|
||||
let current_href = context
|
||||
.href_from_span(clean::Span::new(file_span), false)
|
||||
.expect("only local crates should have sources emitted");
|
||||
// For scraped examples, use the URL from ScrapedInfo directly.
|
||||
// For regular sources, derive it from the span.
|
||||
let current_href = if let SourceContext::Embedded(info) = source_context {
|
||||
info.url.to_string()
|
||||
} else {
|
||||
context
|
||||
.href_from_span(clean::Span::new(file_span), false)
|
||||
.expect("only local crates should have sources emitted")
|
||||
};
|
||||
highlight::write_code(
|
||||
fmt,
|
||||
s,
|
||||
|
||||
@@ -296,7 +296,7 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum
|
||||
MethodItem(m, _) => {
|
||||
ItemEnum::Function(from_clean_function(m, true, header.unwrap(), renderer))
|
||||
}
|
||||
RequiredMethodItem(m) => {
|
||||
RequiredMethodItem(m, _) => {
|
||||
ItemEnum::Function(from_clean_function(m, false, header.unwrap(), renderer))
|
||||
}
|
||||
ImplItem(i) => ItemEnum::Impl(i.into_json(renderer)),
|
||||
|
||||
@@ -35,8 +35,8 @@ fn visit_inner_recur(&mut self, kind: &'a ItemKind) {
|
||||
| StaticItem(_)
|
||||
| ConstantItem(..)
|
||||
| TraitAliasItem(_)
|
||||
| RequiredMethodItem(_)
|
||||
| MethodItem(_, _)
|
||||
| RequiredMethodItem(..)
|
||||
| MethodItem(..)
|
||||
| StructFieldItem(_)
|
||||
| ForeignFunctionItem(..)
|
||||
| ForeignStaticItem(..)
|
||||
|
||||
@@ -819,7 +819,9 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
|
||||
pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
|
||||
matches!(
|
||||
(l, r),
|
||||
(Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_))
|
||||
(Defaultness::Implicit, Defaultness::Implicit)
|
||||
| (Defaultness::Default(_), Defaultness::Default(_))
|
||||
| (Defaultness::Final(_), Defaultness::Final(_))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,23 @@ process for such contributions:
|
||||
This process is largely informal, and its primary goal is to more clearly communicate expectations.
|
||||
Please get in touch with us if you have any questions!
|
||||
|
||||
## Scope of Miri shims
|
||||
|
||||
Miri has "shims" to implement functionality that is usually implemented in C libraries which are
|
||||
invoked from Rust code, such as opening files or spawning threads, as well as for
|
||||
CPU-vendor-provided SIMD intrinsics. However, the set of C functions that Rust code invokes this way
|
||||
is enormous, and for obvious reasons we have no intention of implementing every C API ever written
|
||||
in Miri.
|
||||
|
||||
At the moment, the general guideline for "could this function have a shim in Miri" is: we will
|
||||
generally only add shims for functions that can be implemented in a portable way using just what is
|
||||
provided by the Rust standard library. The function should also be reasonably widely-used in Rust
|
||||
code to justify the review and maintenance effort (i.e. the easier the function is to implement, the
|
||||
lower the barrier). Other than that, we might make exceptions for certain cases if (a) there is a
|
||||
good case for why Miri should support those APIs, and (b) robust and widely-used portable libraries
|
||||
exist in the Rust ecosystem. We will generally not add shims to Miri that would require Miri to
|
||||
directly interact with platform-specific APIs (such as `libc` or `windows-sys`).
|
||||
|
||||
## Preparing the build environment
|
||||
|
||||
Miri heavily relies on internal and unstable rustc interfaces to execute MIR,
|
||||
|
||||
@@ -562,9 +562,9 @@ checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.20.2"
|
||||
version = "0.20.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110"
|
||||
checksum = "7b88256088d75a56f8ecfa070513a775dd9107f6530ef14919dac831af9cfe2b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@@ -804,9 +804,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.18.2+1.9.1"
|
||||
version = "0.18.3+1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222"
|
||||
checksum = "c9b3acc4b91781bb0b3386669d325163746af5f6e4f73e6d2d630e09a35f3487"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
||||
@@ -39,7 +39,7 @@ serde = { version = "1.0.219", features = ["derive"], optional = true }
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
nix = { version = "0.30.1", features = ["mman", "ptrace", "signal"], optional = true }
|
||||
ipc-channel = { version = "0.20.0", optional = true }
|
||||
capstone = { version = "0.14", optional = true }
|
||||
capstone = { version = "0.14", features = ["arch_x86", "full"], default-features = false, optional = true}
|
||||
|
||||
[target.'cfg(all(target_os = "linux", target_pointer_width = "64", target_endian = "little"))'.dependencies]
|
||||
genmc-sys = { path = "./genmc-sys/", version = "0.1.0", optional = true }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user