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:
bors
2026-02-17 02:03:25 +00:00
265 changed files with 3595 additions and 1607 deletions
-19
View File
@@ -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"
+10 -2
View File
@@ -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
}
}
}
+13 -8
View File
@@ -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))),
}
}
+66 -12
View File
@@ -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 {
+18
View File
@@ -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(),
+1 -1
View File
@@ -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',
-1
View File
@@ -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.
+1 -1
View File
@@ -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(),
+2 -3
View File
@@ -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.
+5 -4
View File
@@ -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,
+25 -1
View File
@@ -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,
+10
View File
@@ -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.
+3 -43
View File
@@ -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 _));
}
+3 -3
View File
@@ -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,
+1 -1
View File
@@ -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),
};
+1 -4
View File
@@ -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,
-1
View File
@@ -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" }
+27 -19
View File
@@ -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, ")")
}
}
+18 -2
View File
@@ -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>>,
+2 -1
View File
@@ -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;
@@ -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]
+1
View File
@@ -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;
+1 -1
View File
@@ -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.
+2 -1
View File
@@ -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) {
+1 -1
View File
@@ -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};
+1 -1
View File
@@ -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};
+1 -4
View File
@@ -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,
+1 -1
View File
@@ -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};
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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};
+1 -1
View File
@@ -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 -1
View File
@@ -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]
+11
View File
@@ -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 `::`")]
+24 -11
View File
@@ -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) };
+1 -1
View File
@@ -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
-19
View File
@@ -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
-8
View File
@@ -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),
}
+1
View File
@@ -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");
+6
View File
@@ -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
+11 -2
View File
@@ -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,
+25 -9
View File
@@ -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),
+64
View File
@@ -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;
+64
View File
@@ -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;
+58
View File
@@ -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;
+58
View File
@@ -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;
+93
View File
@@ -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,
+1
View File
@@ -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
View File
@@ -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})
@@ -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})
+7 -7
View File
@@ -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
View File
@@ -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 { .. } => {
+33 -10
View File
@@ -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(_, _)
+2 -2
View File
@@ -82,8 +82,8 @@ fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
| StaticItem(_)
| ConstantItem(..)
| TraitAliasItem(_)
| RequiredMethodItem(_)
| MethodItem(_, _)
| RequiredMethodItem(..)
| MethodItem(..)
| StructFieldItem(_)
| ForeignFunctionItem(..)
| ForeignStaticItem(..)
-4
View File
@@ -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)),
+21 -49
View File
@@ -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)]);
+1 -1
View File
@@ -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_),
+9 -3
View File
@@ -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,
+1 -1
View File
@@ -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)),
+2 -2
View File
@@ -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(_))
)
}
+17
View File
@@ -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,
+4 -4
View File
@@ -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",
+1 -1
View File
@@ -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