Auto merge of #138611 - matthiaskrgr:rollup-hmjbqva, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #133870 (Stabilize `asm_goto` feature gate) - #137449 (Denote `ControlFlow` as `#[must_use]`) - #137465 (mir_build: Avoid some useless work when visiting "primary" bindings) - #138349 (Emit function declarations for functions with `#[linkage="extern_weak"]`) - #138412 (Install licenses into `share/doc/rust/licenses`) - #138577 (rustdoc-json: Don't also include `#[deprecated]` in `Item::attrs`) - #138588 (Avoid double lowering of idents) Failed merges: - #138321 ([bootstrap] Distribute split debuginfo if present) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
@@ -185,8 +185,6 @@ ast_lowering_underscore_expr_lhs_assign =
|
||||
ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
|
||||
ast_lowering_unstable_inline_assembly_label_operand_with_outputs =
|
||||
using both label and output operands for inline assembly is unstable
|
||||
ast_lowering_unstable_inline_assembly_label_operands =
|
||||
label operands for inline assembly are unstable
|
||||
ast_lowering_unstable_may_unwind = the `may_unwind` option is unstable
|
||||
|
||||
ast_lowering_use_angle_brackets = use angle brackets instead
|
||||
|
||||
@@ -470,22 +470,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
// Feature gate checking for asm goto.
|
||||
// Feature gate checking for `asm_goto_with_outputs`.
|
||||
if let Some((_, op_sp)) =
|
||||
operands.iter().find(|(op, _)| matches!(op, hir::InlineAsmOperand::Label { .. }))
|
||||
{
|
||||
if !self.tcx.features().asm_goto() {
|
||||
feature_err(
|
||||
sess,
|
||||
sym::asm_goto,
|
||||
*op_sp,
|
||||
fluent::ast_lowering_unstable_inline_assembly_label_operands,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
// In addition, check if an output operand is used.
|
||||
// This is gated behind an additional feature.
|
||||
// Check if an output operand is used.
|
||||
let output_operand_used = operands.iter().any(|(op, _)| {
|
||||
matches!(
|
||||
op,
|
||||
|
||||
@@ -1720,7 +1720,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let bounds = self.lower_param_bounds(bounds, itctx);
|
||||
|
||||
let ident = self.lower_ident(ident);
|
||||
let param_span = ident.span;
|
||||
|
||||
// Reconstruct the span of the entire predicate from the individual generic bounds.
|
||||
@@ -1739,6 +1738,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let def_id = self.local_def_id(id).to_def_id();
|
||||
let hir_id = self.next_id();
|
||||
let res = Res::Def(DefKind::TyParam, def_id);
|
||||
let ident = self.lower_ident(ident);
|
||||
let ty_path = self.arena.alloc(hir::Path {
|
||||
span: param_span,
|
||||
res,
|
||||
@@ -1757,7 +1757,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
})
|
||||
}
|
||||
GenericParamKind::Lifetime => {
|
||||
let ident = self.lower_ident(ident);
|
||||
let lt_id = self.next_node_id();
|
||||
let lifetime = self.new_named_lifetime(id, lt_id, ident);
|
||||
hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate {
|
||||
|
||||
@@ -1769,38 +1769,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
|
||||
fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime {
|
||||
let ident = self.lower_ident(l.ident);
|
||||
self.new_named_lifetime(l.id, l.id, ident)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn new_named_lifetime_with_res(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
ident: Ident,
|
||||
res: LifetimeRes,
|
||||
) -> &'hir hir::Lifetime {
|
||||
let res = match res {
|
||||
LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param),
|
||||
LifetimeRes::Fresh { param, .. } => {
|
||||
let param = self.local_def_id(param);
|
||||
hir::LifetimeName::Param(param)
|
||||
}
|
||||
LifetimeRes::Infer => hir::LifetimeName::Infer,
|
||||
LifetimeRes::Static { .. } => hir::LifetimeName::Static,
|
||||
LifetimeRes::Error => hir::LifetimeName::Error,
|
||||
res => panic!(
|
||||
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
|
||||
res, ident, ident.span
|
||||
),
|
||||
};
|
||||
|
||||
debug!(?res);
|
||||
self.arena.alloc(hir::Lifetime {
|
||||
hir_id: self.lower_node_id(id),
|
||||
ident: self.lower_ident(ident),
|
||||
res,
|
||||
})
|
||||
self.new_named_lifetime(l.id, l.id, l.ident)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
@@ -1811,7 +1780,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
ident: Ident,
|
||||
) -> &'hir hir::Lifetime {
|
||||
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
|
||||
self.new_named_lifetime_with_res(new_id, ident, res)
|
||||
let res = match res {
|
||||
LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param),
|
||||
LifetimeRes::Fresh { param, .. } => {
|
||||
let param = self.local_def_id(param);
|
||||
hir::LifetimeName::Param(param)
|
||||
}
|
||||
LifetimeRes::Infer => hir::LifetimeName::Infer,
|
||||
LifetimeRes::Static { .. } => hir::LifetimeName::Static,
|
||||
LifetimeRes::Error => hir::LifetimeName::Error,
|
||||
LifetimeRes::ElidedAnchor { .. } => {
|
||||
panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span);
|
||||
}
|
||||
};
|
||||
|
||||
debug!(?res);
|
||||
self.arena.alloc(hir::Lifetime {
|
||||
hir_id: self.lower_node_id(new_id),
|
||||
ident: self.lower_ident(ident),
|
||||
res,
|
||||
})
|
||||
}
|
||||
|
||||
fn lower_generic_params_mut(
|
||||
|
||||
@@ -5,6 +5,7 @@ use rustc_abi::{
|
||||
};
|
||||
use rustc_codegen_ssa::common;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
@@ -12,9 +13,9 @@ use rustc_middle::mir::interpret::{
|
||||
Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer, Scalar as InterpScalar,
|
||||
read_target_uint,
|
||||
};
|
||||
use rustc_middle::mir::mono::MonoItem;
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_middle::mir::mono::{Linkage, MonoItem};
|
||||
use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
|
||||
use rustc_middle::ty::{self, Instance};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
@@ -171,8 +172,27 @@ fn check_and_apply_linkage<'ll, 'tcx>(
|
||||
if let Some(linkage) = attrs.import_linkage {
|
||||
debug!("get_static: sym={} linkage={:?}", sym, linkage);
|
||||
|
||||
// Declare a symbol `foo` with the desired linkage.
|
||||
let g1 = cx.declare_global(sym, cx.type_i8());
|
||||
// Declare a symbol `foo`. If `foo` is an extern_weak symbol, we declare
|
||||
// an extern_weak function, otherwise a global with the desired linkage.
|
||||
let g1 = if matches!(attrs.import_linkage, Some(Linkage::ExternalWeak)) {
|
||||
// An `extern_weak` function is represented as an `Option<unsafe extern ...>`,
|
||||
// we extract the function signature and declare it as an extern_weak function
|
||||
// instead of an extern_weak i8.
|
||||
let instance = Instance::mono(cx.tcx, def_id);
|
||||
if let ty::Adt(struct_def, args) = instance.ty(cx.tcx, cx.typing_env()).kind()
|
||||
&& cx.tcx.is_lang_item(struct_def.did(), LangItem::Option)
|
||||
&& let ty::FnPtr(sig, header) = args.type_at(0).kind()
|
||||
{
|
||||
let fn_sig = sig.with(*header);
|
||||
|
||||
let fn_abi = cx.fn_abi_of_fn_ptr(fn_sig, ty::List::empty());
|
||||
cx.declare_fn(sym, &fn_abi, None)
|
||||
} else {
|
||||
cx.declare_global(sym, cx.type_i8())
|
||||
}
|
||||
} else {
|
||||
cx.declare_global(sym, cx.type_i8())
|
||||
};
|
||||
llvm::set_linkage(g1, base::linkage_to_llvm(linkage));
|
||||
|
||||
// Declare an internal global `extern_with_linkage_foo` which
|
||||
|
||||
@@ -2136,7 +2136,7 @@ fn add_library_search_dirs(
|
||||
}
|
||||
|
||||
let fallback = Some(NativeLibSearchFallback { self_contained_components, apple_sdk_root });
|
||||
walk_native_lib_search_dirs(sess, fallback, |dir, is_framework| {
|
||||
let _ = walk_native_lib_search_dirs(sess, fallback, |dir, is_framework| {
|
||||
if is_framework {
|
||||
cmd.framework_path(dir);
|
||||
} else {
|
||||
|
||||
@@ -62,6 +62,8 @@ declare_features! (
|
||||
(accepted, arbitrary_enum_discriminant, "1.66.0", Some(60553)),
|
||||
/// Allows using `const` operands in inline assembly.
|
||||
(accepted, asm_const, "1.82.0", Some(93332)),
|
||||
/// Allows using `label` operands in inline assembly.
|
||||
(accepted, asm_goto, "CURRENT_RUSTC_VERSION", Some(119364)),
|
||||
/// Allows using `sym` operands in inline assembly.
|
||||
(accepted, asm_sym, "1.66.0", Some(93333)),
|
||||
/// Allows the definition of associated constants in `trait` or `impl` blocks.
|
||||
|
||||
@@ -372,8 +372,6 @@ declare_features! (
|
||||
(unstable, asm_experimental_arch, "1.58.0", Some(93335)),
|
||||
/// Enables experimental register support in inline assembly.
|
||||
(unstable, asm_experimental_reg, "1.85.0", Some(133416)),
|
||||
/// Allows using `label` operands in inline assembly.
|
||||
(unstable, asm_goto, "1.78.0", Some(119364)),
|
||||
/// Allows using `label` operands in inline assembly together with output operands.
|
||||
(unstable, asm_goto_with_outputs, "1.85.0", Some(119364)),
|
||||
/// Allows the `may_unwind` option in inline assembly.
|
||||
|
||||
@@ -533,7 +533,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
intravisit::walk_pat(self, p);
|
||||
let _ = intravisit::walk_pat(self, p);
|
||||
}
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
@@ -556,7 +556,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
method_name,
|
||||
sugg_let: None,
|
||||
};
|
||||
let_visitor.visit_body(&body);
|
||||
let _ = let_visitor.visit_body(&body);
|
||||
if let Some(sugg_let) = let_visitor.sugg_let
|
||||
&& let Some(self_ty) = self.node_ty_opt(sugg_let.init_hir_id)
|
||||
{
|
||||
|
||||
@@ -33,8 +33,8 @@ use crate::mir::interpret::{AllocRange, Scalar};
|
||||
use crate::ty::codec::{TyDecoder, TyEncoder};
|
||||
use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths};
|
||||
use crate::ty::{
|
||||
self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt,
|
||||
TypeVisitableExt, TypingEnv, UserTypeAnnotationIndex,
|
||||
self, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypeVisitableExt,
|
||||
TypingEnv, UserTypeAnnotationIndex,
|
||||
};
|
||||
|
||||
mod basic_blocks;
|
||||
@@ -1482,53 +1482,10 @@ pub struct UserTypeProjections {
|
||||
pub contents: Vec<UserTypeProjection>,
|
||||
}
|
||||
|
||||
impl<'tcx> UserTypeProjections {
|
||||
pub fn none() -> Self {
|
||||
UserTypeProjections { contents: vec![] }
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.contents.is_empty()
|
||||
}
|
||||
|
||||
impl UserTypeProjections {
|
||||
pub fn projections(&self) -> impl Iterator<Item = &UserTypeProjection> + ExactSizeIterator {
|
||||
self.contents.iter()
|
||||
}
|
||||
|
||||
pub fn push_user_type(mut self, base_user_type: UserTypeAnnotationIndex) -> Self {
|
||||
self.contents.push(UserTypeProjection { base: base_user_type, projs: vec![] });
|
||||
self
|
||||
}
|
||||
|
||||
fn map_projections(mut self, f: impl FnMut(UserTypeProjection) -> UserTypeProjection) -> Self {
|
||||
self.contents = self.contents.into_iter().map(f).collect();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn index(self) -> Self {
|
||||
self.map_projections(|pat_ty_proj| pat_ty_proj.index())
|
||||
}
|
||||
|
||||
pub fn subslice(self, from: u64, to: u64) -> Self {
|
||||
self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to))
|
||||
}
|
||||
|
||||
pub fn deref(self) -> Self {
|
||||
self.map_projections(|pat_ty_proj| pat_ty_proj.deref())
|
||||
}
|
||||
|
||||
pub fn leaf(self, field: FieldIdx) -> Self {
|
||||
self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field))
|
||||
}
|
||||
|
||||
pub fn variant(
|
||||
self,
|
||||
adt_def: AdtDef<'tcx>,
|
||||
variant_index: VariantIdx,
|
||||
field_index: FieldIdx,
|
||||
) -> Self {
|
||||
self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field_index))
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes the effect of a user-supplied type annotation on the
|
||||
@@ -1553,42 +1510,6 @@ pub struct UserTypeProjection {
|
||||
pub projs: Vec<ProjectionKind>,
|
||||
}
|
||||
|
||||
impl UserTypeProjection {
|
||||
pub(crate) fn index(mut self) -> Self {
|
||||
self.projs.push(ProjectionElem::Index(()));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn subslice(mut self, from: u64, to: u64) -> Self {
|
||||
self.projs.push(ProjectionElem::Subslice { from, to, from_end: true });
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn deref(mut self) -> Self {
|
||||
self.projs.push(ProjectionElem::Deref);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn leaf(mut self, field: FieldIdx) -> Self {
|
||||
self.projs.push(ProjectionElem::Field(field, ()));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn variant(
|
||||
mut self,
|
||||
adt_def: AdtDef<'_>,
|
||||
variant_index: VariantIdx,
|
||||
field_index: FieldIdx,
|
||||
) -> Self {
|
||||
self.projs.push(ProjectionElem::Downcast(
|
||||
Some(adt_def.variant(variant_index).name),
|
||||
variant_index,
|
||||
));
|
||||
self.projs.push(ProjectionElem::Field(field_index, ()));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
#[derive(HashStable)]
|
||||
#[encodable]
|
||||
|
||||
@@ -783,8 +783,12 @@ pub enum PatKind<'tcx> {
|
||||
var: LocalVarId,
|
||||
ty: Ty<'tcx>,
|
||||
subpattern: Option<Box<Pat<'tcx>>>,
|
||||
|
||||
/// Is this the leftmost occurrence of the binding, i.e., is `var` the
|
||||
/// `HirId` of this pattern?
|
||||
///
|
||||
/// (The same binding can occur multiple times in different branches of
|
||||
/// an or-pattern, but only one of them will be primary.)
|
||||
is_primary: bool,
|
||||
},
|
||||
|
||||
|
||||
@@ -199,19 +199,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
None,
|
||||
Some((Some(&destination), initializer_span)),
|
||||
);
|
||||
this.visit_primary_bindings(
|
||||
pattern,
|
||||
UserTypeProjections::none(),
|
||||
&mut |this, _, _, node, span, _, _| {
|
||||
this.storage_live_binding(
|
||||
block,
|
||||
node,
|
||||
span,
|
||||
OutsideGuard,
|
||||
ScheduleDrops::Yes,
|
||||
);
|
||||
},
|
||||
);
|
||||
this.visit_primary_bindings(pattern, &mut |this, node, span| {
|
||||
this.storage_live_binding(
|
||||
block,
|
||||
node,
|
||||
span,
|
||||
OutsideGuard,
|
||||
ScheduleDrops::Yes,
|
||||
);
|
||||
});
|
||||
let else_block_span = this.thir[*else_block].span;
|
||||
let (matching, failure) =
|
||||
this.in_if_then_scope(last_remainder_scope, else_block_span, |this| {
|
||||
@@ -295,20 +291,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
});
|
||||
|
||||
debug!("ast_block_stmts: pattern={:?}", pattern);
|
||||
this.visit_primary_bindings(
|
||||
pattern,
|
||||
UserTypeProjections::none(),
|
||||
&mut |this, _, _, node, span, _, _| {
|
||||
this.storage_live_binding(
|
||||
block,
|
||||
node,
|
||||
span,
|
||||
OutsideGuard,
|
||||
ScheduleDrops::Yes,
|
||||
);
|
||||
this.schedule_drop_for_binding(node, span, OutsideGuard);
|
||||
},
|
||||
)
|
||||
this.visit_primary_bindings(pattern, &mut |this, node, span| {
|
||||
this.storage_live_binding(
|
||||
block,
|
||||
node,
|
||||
span,
|
||||
OutsideGuard,
|
||||
ScheduleDrops::Yes,
|
||||
);
|
||||
this.schedule_drop_for_binding(node, span, OutsideGuard);
|
||||
})
|
||||
}
|
||||
|
||||
// Enter the visibility scope, after evaluating the initializer.
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
//! This also includes code for pattern bindings in `let` statements and
|
||||
//! function parameters.
|
||||
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::borrow::Borrow;
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_abi::VariantIdx;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
@@ -19,6 +24,7 @@ use tracing::{debug, instrument};
|
||||
|
||||
use crate::builder::ForGuard::{self, OutsideGuard, RefWithinGuard};
|
||||
use crate::builder::expr::as_place::PlaceBuilder;
|
||||
use crate::builder::matches::user_ty::ProjectedUserTypesNode;
|
||||
use crate::builder::scope::DropKind;
|
||||
use crate::builder::{
|
||||
BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode,
|
||||
@@ -27,13 +33,9 @@ use crate::builder::{
|
||||
// helper functions, broken out by category:
|
||||
mod match_pair;
|
||||
mod test;
|
||||
mod user_ty;
|
||||
mod util;
|
||||
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::borrow::Borrow;
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Arguments to [`Builder::then_else_break_inner`] that are usually forwarded
|
||||
/// to recursive invocations.
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -755,24 +757,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
guard: Option<ExprId>,
|
||||
opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
|
||||
) -> Option<SourceScope> {
|
||||
self.visit_primary_bindings(
|
||||
self.visit_primary_bindings_special(
|
||||
pattern,
|
||||
UserTypeProjections::none(),
|
||||
&mut |this, name, mode, var, span, ty, user_ty| {
|
||||
if visibility_scope.is_none() {
|
||||
visibility_scope =
|
||||
Some(this.new_source_scope(scope_span, LintLevel::Inherited));
|
||||
}
|
||||
&ProjectedUserTypesNode::None,
|
||||
&mut |this, name, mode, var, span, ty, user_tys| {
|
||||
let vis_scope = *visibility_scope
|
||||
.get_or_insert_with(|| this.new_source_scope(scope_span, LintLevel::Inherited));
|
||||
let source_info = SourceInfo { span, scope: this.source_scope };
|
||||
let visibility_scope = visibility_scope.unwrap();
|
||||
let user_tys = user_tys.build_user_type_projections();
|
||||
|
||||
this.declare_binding(
|
||||
source_info,
|
||||
visibility_scope,
|
||||
vis_scope,
|
||||
name,
|
||||
mode,
|
||||
var,
|
||||
ty,
|
||||
user_ty,
|
||||
user_tys,
|
||||
ArmHasGuard(guard.is_some()),
|
||||
opt_match_place.map(|(x, y)| (x.cloned(), y)),
|
||||
pattern.span,
|
||||
@@ -848,13 +849,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Visit all of the primary bindings in a patterns, that is, visit the
|
||||
/// leftmost occurrence of each variable bound in a pattern. A variable
|
||||
/// will occur more than once in an or-pattern.
|
||||
/// Visits all of the "primary" bindings in a pattern, i.e. the leftmost
|
||||
/// occurrence of each variable bound by the pattern.
|
||||
/// See [`PatKind::Binding::is_primary`] for more context.
|
||||
///
|
||||
/// This variant provides only the limited subset of binding data needed
|
||||
/// by its callers, and should be a "pure" visit without side-effects.
|
||||
pub(super) fn visit_primary_bindings(
|
||||
&mut self,
|
||||
pattern: &Pat<'tcx>,
|
||||
pattern_user_ty: UserTypeProjections,
|
||||
f: &mut impl FnMut(&mut Self, LocalVarId, Span),
|
||||
) {
|
||||
pattern.walk_always(|pat| {
|
||||
if let PatKind::Binding { var, is_primary: true, .. } = pat.kind {
|
||||
f(self, var, pat.span);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Visits all of the "primary" bindings in a pattern, while preparing
|
||||
/// additional user-type-annotation data needed by `declare_bindings`.
|
||||
///
|
||||
/// This also has the side-effect of pushing all user type annotations
|
||||
/// onto `canonical_user_type_annotations`, so that they end up in MIR
|
||||
/// even if they aren't associated with any bindings.
|
||||
#[instrument(level = "debug", skip(self, f))]
|
||||
fn visit_primary_bindings_special(
|
||||
&mut self,
|
||||
pattern: &Pat<'tcx>,
|
||||
user_tys: &ProjectedUserTypesNode<'_>,
|
||||
f: &mut impl FnMut(
|
||||
&mut Self,
|
||||
Symbol,
|
||||
@@ -862,20 +885,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
LocalVarId,
|
||||
Span,
|
||||
Ty<'tcx>,
|
||||
UserTypeProjections,
|
||||
&ProjectedUserTypesNode<'_>,
|
||||
),
|
||||
) {
|
||||
debug!(
|
||||
"visit_primary_bindings: pattern={:?} pattern_user_ty={:?}",
|
||||
pattern, pattern_user_ty
|
||||
);
|
||||
// Avoid having to write the full method name at each recursive call.
|
||||
let visit_subpat = |this: &mut Self, subpat, user_tys: &_, f: &mut _| {
|
||||
this.visit_primary_bindings_special(subpat, user_tys, f)
|
||||
};
|
||||
|
||||
match pattern.kind {
|
||||
PatKind::Binding { name, mode, var, ty, ref subpattern, is_primary, .. } => {
|
||||
if is_primary {
|
||||
f(self, name, mode, var, pattern.span, ty, pattern_user_ty.clone());
|
||||
f(self, name, mode, var, pattern.span, ty, user_tys);
|
||||
}
|
||||
if let Some(subpattern) = subpattern.as_ref() {
|
||||
self.visit_primary_bindings(subpattern, pattern_user_ty, f);
|
||||
visit_subpat(self, subpattern, user_tys, f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -884,17 +908,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let from = u64::try_from(prefix.len()).unwrap();
|
||||
let to = u64::try_from(suffix.len()).unwrap();
|
||||
for subpattern in prefix.iter() {
|
||||
self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
|
||||
visit_subpat(self, subpattern, &user_tys.index(), f);
|
||||
}
|
||||
if let Some(subpattern) = slice {
|
||||
self.visit_primary_bindings(
|
||||
subpattern,
|
||||
pattern_user_ty.clone().subslice(from, to),
|
||||
f,
|
||||
);
|
||||
visit_subpat(self, subpattern, &user_tys.subslice(from, to), f);
|
||||
}
|
||||
for subpattern in suffix.iter() {
|
||||
self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f);
|
||||
visit_subpat(self, subpattern, &user_tys.index(), f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -905,11 +925,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
| PatKind::Error(_) => {}
|
||||
|
||||
PatKind::Deref { ref subpattern } => {
|
||||
self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
|
||||
visit_subpat(self, subpattern, &user_tys.deref(), f);
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { ref subpattern, .. } => {
|
||||
self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f);
|
||||
visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f);
|
||||
}
|
||||
|
||||
PatKind::AscribeUserType {
|
||||
@@ -925,28 +945,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// Note that the variance doesn't apply here, as we are tracking the effect
|
||||
// of `user_ty` on any bindings contained with subpattern.
|
||||
|
||||
// Caution: Pushing this user type here is load-bearing even for
|
||||
// patterns containing no bindings, to ensure that the type ends
|
||||
// up represented in MIR _somewhere_.
|
||||
let base_user_ty = self.canonical_user_type_annotations.push(annotation.clone());
|
||||
let subpattern_user_ty = pattern_user_ty.push_user_type(base_user_ty);
|
||||
self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
|
||||
let subpattern_user_tys = user_tys.push_user_type(base_user_ty);
|
||||
visit_subpat(self, subpattern, &subpattern_user_tys, f)
|
||||
}
|
||||
|
||||
PatKind::ExpandedConstant { ref subpattern, .. } => {
|
||||
self.visit_primary_bindings(subpattern, pattern_user_ty, f)
|
||||
visit_subpat(self, subpattern, user_tys, f)
|
||||
}
|
||||
|
||||
PatKind::Leaf { ref subpatterns } => {
|
||||
for subpattern in subpatterns {
|
||||
let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field);
|
||||
debug!("visit_primary_bindings: subpattern_user_ty={:?}", subpattern_user_ty);
|
||||
self.visit_primary_bindings(&subpattern.pattern, subpattern_user_ty, f);
|
||||
let subpattern_user_tys = user_tys.leaf(subpattern.field);
|
||||
debug!("visit_primary_bindings: subpattern_user_tys={subpattern_user_tys:?}");
|
||||
visit_subpat(self, &subpattern.pattern, &subpattern_user_tys, f);
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Variant { adt_def, args: _, variant_index, ref subpatterns } => {
|
||||
for subpattern in subpatterns {
|
||||
let subpattern_user_ty =
|
||||
pattern_user_ty.clone().variant(adt_def, variant_index, subpattern.field);
|
||||
self.visit_primary_bindings(&subpattern.pattern, subpattern_user_ty, f);
|
||||
let subpattern_user_tys =
|
||||
user_tys.variant(adt_def, variant_index, subpattern.field);
|
||||
visit_subpat(self, &subpattern.pattern, &subpattern_user_tys, f);
|
||||
}
|
||||
}
|
||||
PatKind::Or { ref pats } => {
|
||||
@@ -955,7 +978,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// `let (x | y) = ...`, the primary binding of `y` occurs in
|
||||
// the right subpattern
|
||||
for subpattern in pats.iter() {
|
||||
self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f);
|
||||
visit_subpat(self, subpattern, user_tys, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2747,7 +2770,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
mode: BindingMode,
|
||||
var_id: LocalVarId,
|
||||
var_ty: Ty<'tcx>,
|
||||
user_ty: UserTypeProjections,
|
||||
user_ty: Option<Box<UserTypeProjections>>,
|
||||
has_guard: ArmHasGuard,
|
||||
opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
|
||||
pat_span: Span,
|
||||
@@ -2757,7 +2780,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let local = LocalDecl {
|
||||
mutability: mode.1,
|
||||
ty: var_ty,
|
||||
user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) },
|
||||
user_ty,
|
||||
source_info,
|
||||
local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::Var(
|
||||
VarBindingForm {
|
||||
|
||||
140
compiler/rustc_mir_build/src/builder/matches/user_ty.rs
Normal file
140
compiler/rustc_mir_build/src/builder/matches/user_ty.rs
Normal file
@@ -0,0 +1,140 @@
|
||||
//! Helper code for building a linked list of user-type projections on the
|
||||
//! stack while visiting a THIR pattern.
|
||||
//!
|
||||
//! This avoids having to repeatedly clone a partly-built [`UserTypeProjections`]
|
||||
//! at every step of the traversal, which is what the previous code was doing.
|
||||
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::iter;
|
||||
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
use rustc_middle::mir::{ProjectionElem, UserTypeProjection, UserTypeProjections};
|
||||
use rustc_middle::ty::{AdtDef, UserTypeAnnotationIndex};
|
||||
use rustc_span::Symbol;
|
||||
|
||||
/// One of a list of "operations" that can be used to lazily build projections
|
||||
/// of user-specified types.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum ProjectedUserTypesOp {
|
||||
PushUserType { base: UserTypeAnnotationIndex },
|
||||
|
||||
Index,
|
||||
Subslice { from: u64, to: u64 },
|
||||
Deref,
|
||||
Leaf { field: FieldIdx },
|
||||
Variant { name: Symbol, variant: VariantIdx, field: FieldIdx },
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ProjectedUserTypesNode<'a> {
|
||||
None,
|
||||
Chain { parent: &'a Self, op: ProjectedUserTypesOp },
|
||||
}
|
||||
|
||||
impl<'a> ProjectedUserTypesNode<'a> {
|
||||
pub(crate) fn push_user_type(&'a self, base: UserTypeAnnotationIndex) -> Self {
|
||||
// Pushing a base user type always causes the chain to become non-empty.
|
||||
Self::Chain { parent: self, op: ProjectedUserTypesOp::PushUserType { base } }
|
||||
}
|
||||
|
||||
/// Push another projection op onto the chain, but only if it is already non-empty.
|
||||
fn maybe_push(&'a self, op_fn: impl FnOnce() -> ProjectedUserTypesOp) -> Self {
|
||||
match self {
|
||||
Self::None => Self::None,
|
||||
Self::Chain { .. } => Self::Chain { parent: self, op: op_fn() },
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn index(&'a self) -> Self {
|
||||
self.maybe_push(|| ProjectedUserTypesOp::Index)
|
||||
}
|
||||
|
||||
pub(crate) fn subslice(&'a self, from: u64, to: u64) -> Self {
|
||||
self.maybe_push(|| ProjectedUserTypesOp::Subslice { from, to })
|
||||
}
|
||||
|
||||
pub(crate) fn deref(&'a self) -> Self {
|
||||
self.maybe_push(|| ProjectedUserTypesOp::Deref)
|
||||
}
|
||||
|
||||
pub(crate) fn leaf(&'a self, field: FieldIdx) -> Self {
|
||||
self.maybe_push(|| ProjectedUserTypesOp::Leaf { field })
|
||||
}
|
||||
|
||||
pub(crate) fn variant(
|
||||
&'a self,
|
||||
adt_def: AdtDef<'_>,
|
||||
variant: VariantIdx,
|
||||
field: FieldIdx,
|
||||
) -> Self {
|
||||
self.maybe_push(|| {
|
||||
let name = adt_def.variant(variant).name;
|
||||
ProjectedUserTypesOp::Variant { name, variant, field }
|
||||
})
|
||||
}
|
||||
|
||||
/// Traverses the chain of nodes to yield each op in the chain.
|
||||
/// Because this walks from child node to parent node, the ops are
|
||||
/// naturally yielded in "reverse" order.
|
||||
fn iter_ops_reversed(&'a self) -> impl Iterator<Item = &'a ProjectedUserTypesOp> {
|
||||
let mut next = self;
|
||||
iter::from_fn(move || match next {
|
||||
Self::None => None,
|
||||
Self::Chain { parent, op } => {
|
||||
next = parent;
|
||||
Some(op)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Assembles this chain of user-type projections into a proper data structure.
|
||||
pub(crate) fn build_user_type_projections(&self) -> Option<Box<UserTypeProjections>> {
|
||||
// If we know there's nothing to do, just return None immediately.
|
||||
if matches!(self, Self::None) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let ops_reversed = self.iter_ops_reversed().cloned().collect::<Vec<_>>();
|
||||
// The "first" op should always be `PushUserType`.
|
||||
// Other projections are only added if there is at least one user type.
|
||||
assert_matches!(ops_reversed.last(), Some(ProjectedUserTypesOp::PushUserType { .. }));
|
||||
|
||||
let mut projections = vec![];
|
||||
for op in ops_reversed.into_iter().rev() {
|
||||
match op {
|
||||
ProjectedUserTypesOp::PushUserType { base } => {
|
||||
projections.push(UserTypeProjection { base, projs: vec![] })
|
||||
}
|
||||
|
||||
ProjectedUserTypesOp::Index => {
|
||||
for p in &mut projections {
|
||||
p.projs.push(ProjectionElem::Index(()))
|
||||
}
|
||||
}
|
||||
ProjectedUserTypesOp::Subslice { from, to } => {
|
||||
for p in &mut projections {
|
||||
p.projs.push(ProjectionElem::Subslice { from, to, from_end: true })
|
||||
}
|
||||
}
|
||||
ProjectedUserTypesOp::Deref => {
|
||||
for p in &mut projections {
|
||||
p.projs.push(ProjectionElem::Deref)
|
||||
}
|
||||
}
|
||||
ProjectedUserTypesOp::Leaf { field } => {
|
||||
for p in &mut projections {
|
||||
p.projs.push(ProjectionElem::Field(field, ()))
|
||||
}
|
||||
}
|
||||
ProjectedUserTypesOp::Variant { name, variant, field } => {
|
||||
for p in &mut projections {
|
||||
p.projs.push(ProjectionElem::Downcast(Some(name), variant));
|
||||
p.projs.push(ProjectionElem::Field(field, ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(Box::new(UserTypeProjections { contents: projections }))
|
||||
}
|
||||
}
|
||||
@@ -1361,12 +1361,12 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
|
||||
GenericParamDefKind::Lifetime => {}
|
||||
GenericParamDefKind::Type { has_default, .. } => {
|
||||
if has_default {
|
||||
self.visit(self.tcx.type_of(param.def_id).instantiate_identity());
|
||||
let _ = self.visit(self.tcx.type_of(param.def_id).instantiate_identity());
|
||||
}
|
||||
}
|
||||
// FIXME(generic_const_exprs): May want to look inside const here
|
||||
GenericParamDefKind::Const { .. } => {
|
||||
self.visit(self.tcx.type_of(param.def_id).instantiate_identity());
|
||||
let _ = self.visit(self.tcx.type_of(param.def_id).instantiate_identity());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1381,19 +1381,19 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
|
||||
// consider the ones that the user wrote. This is important
|
||||
// for the inferred outlives rules; see
|
||||
// `tests/ui/rfc-2093-infer-outlives/privacy.rs`.
|
||||
self.visit_predicates(self.tcx.explicit_predicates_of(self.item_def_id));
|
||||
let _ = self.visit_predicates(self.tcx.explicit_predicates_of(self.item_def_id));
|
||||
self
|
||||
}
|
||||
|
||||
fn bounds(&mut self) -> &mut Self {
|
||||
self.in_primary_interface = false;
|
||||
self.visit_clauses(self.tcx.explicit_item_bounds(self.item_def_id).skip_binder());
|
||||
let _ = self.visit_clauses(self.tcx.explicit_item_bounds(self.item_def_id).skip_binder());
|
||||
self
|
||||
}
|
||||
|
||||
fn ty(&mut self) -> &mut Self {
|
||||
self.in_primary_interface = true;
|
||||
self.visit(self.tcx.type_of(self.item_def_id).instantiate_identity());
|
||||
let _ = self.visit(self.tcx.type_of(self.item_def_id).instantiate_identity());
|
||||
self
|
||||
}
|
||||
|
||||
@@ -1785,7 +1785,7 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
|
||||
|
||||
let module = tcx.hir_module_items(module_def_id);
|
||||
for def_id in module.definitions() {
|
||||
rustc_ty_utils::sig_types::walk_types(tcx, def_id, &mut visitor);
|
||||
let _ = rustc_ty_utils::sig_types::walk_types(tcx, def_id, &mut visitor);
|
||||
|
||||
if let Some(body_id) = tcx.hir_maybe_body_owned_by(def_id) {
|
||||
visitor.visit_nested_body(body_id.id());
|
||||
@@ -1798,7 +1798,11 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
|
||||
let trait_ref = tcx.impl_trait_ref(id.owner_id.def_id).unwrap();
|
||||
let trait_ref = trait_ref.instantiate_identity();
|
||||
visitor.span = item.path.span;
|
||||
visitor.visit_def_id(trait_ref.def_id, "trait", &trait_ref.print_only_trait_path());
|
||||
let _ = visitor.visit_def_id(
|
||||
trait_ref.def_id,
|
||||
"trait",
|
||||
&trait_ref.print_only_trait_path(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
|
||||
match arg.kind {
|
||||
hir::TyKind::BareFn(_) => {
|
||||
self.current_index.shift_in(1);
|
||||
intravisit::walk_ty(self, arg);
|
||||
let _ = intravisit::walk_ty(self, arg);
|
||||
self.current_index.shift_out(1);
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
@@ -85,7 +85,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
|
||||
hir::TyKind::TraitObject(bounds, ..) => {
|
||||
for bound in bounds {
|
||||
self.current_index.shift_in(1);
|
||||
self.visit_poly_trait_ref(bound);
|
||||
let _ = self.visit_poly_trait_ref(bound);
|
||||
self.current_index.shift_out(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -743,7 +743,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
||||
) {
|
||||
debug!("assemble_candidates_from_trait_def(..)");
|
||||
let mut ambiguous = false;
|
||||
selcx.for_each_item_bound(
|
||||
let _ = selcx.for_each_item_bound(
|
||||
obligation.predicate.self_ty(),
|
||||
|selcx, clause, _| {
|
||||
let Some(clause) = clause.as_projection_clause() else {
|
||||
|
||||
@@ -176,7 +176,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// normalization, so try to deduplicate when possible to avoid
|
||||
// unnecessary ambiguity.
|
||||
let mut distinct_normalized_bounds = FxHashSet::default();
|
||||
self.for_each_item_bound::<!>(
|
||||
let _ = self.for_each_item_bound::<!>(
|
||||
placeholder_trait_predicate.self_ty(),
|
||||
|selcx, bound, idx| {
|
||||
let Some(bound) = bound.as_trait_clause() else {
|
||||
|
||||
@@ -112,7 +112,7 @@ where
|
||||
pub fn bind_with_vars(value: T, bound_vars: I::BoundVarKinds) -> Binder<I, T> {
|
||||
if cfg!(debug_assertions) {
|
||||
let mut validator = ValidateBoundVars::new(bound_vars);
|
||||
value.visit_with(&mut validator);
|
||||
let _ = value.visit_with(&mut validator);
|
||||
}
|
||||
Binder { value, bound_vars }
|
||||
}
|
||||
@@ -196,7 +196,7 @@ impl<I: Interner, T> Binder<I, T> {
|
||||
let value = f(value);
|
||||
if cfg!(debug_assertions) {
|
||||
let mut validator = ValidateBoundVars::new(bound_vars);
|
||||
value.visit_with(&mut validator);
|
||||
let _ = value.visit_with(&mut validator);
|
||||
}
|
||||
Binder { value, bound_vars }
|
||||
}
|
||||
@@ -209,7 +209,7 @@ impl<I: Interner, T> Binder<I, T> {
|
||||
let value = f(value)?;
|
||||
if cfg!(debug_assertions) {
|
||||
let mut validator = ValidateBoundVars::new(bound_vars);
|
||||
value.visit_with(&mut validator);
|
||||
let _ = value.visit_with(&mut validator);
|
||||
}
|
||||
Ok(Binder { value, bound_vars })
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ use crate::{convert, ops};
|
||||
/// [`Continue`]: ControlFlow::Continue
|
||||
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
|
||||
#[rustc_diagnostic_item = "ControlFlow"]
|
||||
#[must_use]
|
||||
// ControlFlow should not implement PartialOrd or Ord, per RFC 3058:
|
||||
// https://rust-lang.github.io/rfcs/3058-try-trait-v2.html#traits-for-controlflow
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
||||
@@ -519,7 +519,7 @@ impl Step for Rustc {
|
||||
|
||||
// The REUSE-managed license files
|
||||
let license = |path: &Path| {
|
||||
builder.install(path, &image.join("share/doc/rust/licences"), 0o644);
|
||||
builder.install(path, &image.join("share/doc/rust/licenses"), 0o644);
|
||||
};
|
||||
for entry in t!(std::fs::read_dir(builder.src.join("LICENSES"))).flatten() {
|
||||
license(&entry.path());
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# `asm_goto_with_outputs`
|
||||
|
||||
The tracking issue for this feature is: [#119364]
|
||||
|
||||
[#119364]: https://github.com/rust-lang/rust/issues/119364
|
||||
|
||||
------------------------
|
||||
|
||||
This feature allows label operands to be used together with output operands.
|
||||
|
||||
Example:
|
||||
```rust,ignore (partial-example, x86-only)
|
||||
|
||||
unsafe {
|
||||
let a: usize;
|
||||
asm!(
|
||||
"mov {}, 1"
|
||||
"jmp {}",
|
||||
out(reg) a,
|
||||
label {
|
||||
println!("Jumped from asm {}!", a);
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
The output operands are assigned before the label blocks are executed.
|
||||
@@ -1,32 +0,0 @@
|
||||
# `asm_goto`
|
||||
|
||||
The tracking issue for this feature is: [#119364]
|
||||
|
||||
[#119364]: https://github.com/rust-lang/rust/issues/119364
|
||||
|
||||
------------------------
|
||||
|
||||
This feature adds a `label <block>` operand type to `asm!`.
|
||||
|
||||
Example:
|
||||
```rust,ignore (partial-example, x86-only)
|
||||
|
||||
unsafe {
|
||||
asm!(
|
||||
"jmp {}",
|
||||
label {
|
||||
println!("Jumped from asm!");
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
The block must have unit type or diverge. The block starts a new safety context,
|
||||
so despite outer `unsafe`, you need extra unsafe to perform unsafe operations
|
||||
within `label <block>`.
|
||||
|
||||
When `label <block>` is used together with `noreturn` option, it means that the
|
||||
assembly will not fallthrough. It's allowed to jump to a label within the
|
||||
assembly. In this case, the entire `asm!` expression will have an unit type as
|
||||
opposed to diverging, if not all label blocks diverge. The `asm!` expression
|
||||
still diverges if `noreturn` option is used and all label blocks diverge.
|
||||
@@ -5,7 +5,7 @@ use std::{fmt, iter};
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use rustc_abi::{ExternAbi, VariantIdx};
|
||||
use rustc_attr_parsing::{ConstStability, Deprecation, Stability, StableSince};
|
||||
use rustc_attr_parsing::{AttributeKind, ConstStability, Deprecation, Stability, StableSince};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
|
||||
@@ -756,12 +756,7 @@ impl Item {
|
||||
Some(tcx.visibility(def_id))
|
||||
}
|
||||
|
||||
pub(crate) fn attributes(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
cache: &Cache,
|
||||
keep_as_is: bool,
|
||||
) -> Vec<String> {
|
||||
pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
|
||||
const ALLOWED_ATTRIBUTES: &[Symbol] =
|
||||
&[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
|
||||
|
||||
@@ -772,8 +767,14 @@ impl Item {
|
||||
.other_attrs
|
||||
.iter()
|
||||
.filter_map(|attr| {
|
||||
if keep_as_is {
|
||||
Some(rustc_hir_pretty::attribute_to_string(&tcx, attr))
|
||||
if is_json {
|
||||
if matches!(attr, hir::Attribute::Parsed(AttributeKind::Deprecation { .. })) {
|
||||
// rustdoc-json stores this in `Item::deprecation`, so we
|
||||
// don't want it it `Item::attrs`.
|
||||
None
|
||||
} else {
|
||||
Some(rustc_hir_pretty::attribute_to_string(&tcx, attr))
|
||||
}
|
||||
} else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
|
||||
Some(
|
||||
rustc_hir_pretty::attribute_to_string(&tcx, attr)
|
||||
@@ -786,7 +787,9 @@ impl Item {
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
if !keep_as_is
|
||||
|
||||
// Add #[repr(...)]
|
||||
if !is_json
|
||||
&& let Some(def_id) = self.def_id()
|
||||
&& let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_()
|
||||
{
|
||||
|
||||
@@ -9,41 +9,41 @@ fn empty() {
|
||||
#[test]
|
||||
fn basic() {
|
||||
let mut buf = HtmlWithLimit::new(60);
|
||||
buf.push("Hello ");
|
||||
let _ = buf.push("Hello ");
|
||||
buf.open_tag("em");
|
||||
buf.push("world");
|
||||
let _ = buf.push("world");
|
||||
buf.close_tag();
|
||||
buf.push("!");
|
||||
let _ = buf.push("!");
|
||||
assert_eq!(buf.finish(), "Hello <em>world</em>!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_tags() {
|
||||
let mut buf = HtmlWithLimit::new(60);
|
||||
buf.push("Hello");
|
||||
buf.push(" world!");
|
||||
let _ = buf.push("Hello");
|
||||
let _ = buf.push(" world!");
|
||||
assert_eq!(buf.finish(), "Hello world!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn limit_0() {
|
||||
let mut buf = HtmlWithLimit::new(0);
|
||||
buf.push("Hello ");
|
||||
let _ = buf.push("Hello ");
|
||||
buf.open_tag("em");
|
||||
buf.push("world");
|
||||
let _ = buf.push("world");
|
||||
buf.close_tag();
|
||||
buf.push("!");
|
||||
let _ = buf.push("!");
|
||||
assert_eq!(buf.finish(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exactly_limit() {
|
||||
let mut buf = HtmlWithLimit::new(12);
|
||||
buf.push("Hello ");
|
||||
let _ = buf.push("Hello ");
|
||||
buf.open_tag("em");
|
||||
buf.push("world");
|
||||
let _ = buf.push("world");
|
||||
buf.close_tag();
|
||||
buf.push("!");
|
||||
let _ = buf.push("!");
|
||||
assert_eq!(buf.finish(), "Hello <em>world</em>!");
|
||||
}
|
||||
|
||||
@@ -51,11 +51,11 @@ fn exactly_limit() {
|
||||
fn multiple_nested_tags() {
|
||||
let mut buf = HtmlWithLimit::new(60);
|
||||
buf.open_tag("p");
|
||||
buf.push("This is a ");
|
||||
let _ = buf.push("This is a ");
|
||||
buf.open_tag("em");
|
||||
buf.push("paragraph");
|
||||
let _ = buf.push("paragraph");
|
||||
buf.open_tag("strong");
|
||||
buf.push("!");
|
||||
let _ = buf.push("!");
|
||||
buf.close_tag();
|
||||
buf.close_tag();
|
||||
buf.close_tag();
|
||||
@@ -66,11 +66,11 @@ fn multiple_nested_tags() {
|
||||
fn forgot_to_close_tags() {
|
||||
let mut buf = HtmlWithLimit::new(60);
|
||||
buf.open_tag("p");
|
||||
buf.push("This is a ");
|
||||
let _ = buf.push("This is a ");
|
||||
buf.open_tag("em");
|
||||
buf.push("paragraph");
|
||||
let _ = buf.push("paragraph");
|
||||
buf.open_tag("strong");
|
||||
buf.push("!");
|
||||
let _ = buf.push("!");
|
||||
assert_eq!(buf.finish(), "<p>This is a <em>paragraph<strong>!</strong></em></p>");
|
||||
}
|
||||
|
||||
@@ -78,10 +78,10 @@ fn forgot_to_close_tags() {
|
||||
fn past_the_limit() {
|
||||
let mut buf = HtmlWithLimit::new(20);
|
||||
buf.open_tag("p");
|
||||
(0..10).try_for_each(|n| {
|
||||
let _ = (0..10).try_for_each(|n| {
|
||||
buf.open_tag("strong");
|
||||
buf.push("word#")?;
|
||||
buf.push(&n.to_string())?;
|
||||
let _ = buf.push("word#")?;
|
||||
let _ = buf.push(&n.to_string())?;
|
||||
buf.close_tag();
|
||||
ControlFlow::Continue(())
|
||||
});
|
||||
@@ -100,8 +100,8 @@ fn past_the_limit() {
|
||||
fn quickly_past_the_limit() {
|
||||
let mut buf = HtmlWithLimit::new(6);
|
||||
buf.open_tag("p");
|
||||
buf.push("Hello");
|
||||
buf.push(" World");
|
||||
let _ = buf.push("Hello");
|
||||
let _ = buf.push(" World");
|
||||
// intentionally not closing <p> before finishing
|
||||
assert_eq!(buf.finish(), "<p>Hello</p>");
|
||||
}
|
||||
@@ -110,7 +110,7 @@ fn quickly_past_the_limit() {
|
||||
fn close_too_many() {
|
||||
let mut buf = HtmlWithLimit::new(60);
|
||||
buf.open_tag("p");
|
||||
buf.push("Hello");
|
||||
let _ = buf.push("Hello");
|
||||
buf.close_tag();
|
||||
// This call does not panic because there are valid cases
|
||||
// where `close_tag()` is called with no tags left to close.
|
||||
|
||||
@@ -1568,7 +1568,7 @@ fn markdown_summary_with_limit(
|
||||
|
||||
let mut buf = HtmlWithLimit::new(length_limit);
|
||||
let mut stopped_early = false;
|
||||
p.try_for_each(|event| {
|
||||
let _ = p.try_for_each(|event| {
|
||||
match &event {
|
||||
Event::Text(text) => {
|
||||
let r =
|
||||
|
||||
@@ -129,7 +129,7 @@ impl BreakAfterExprVisitor {
|
||||
};
|
||||
|
||||
get_enclosing_block(cx, hir_id).is_some_and(|block| {
|
||||
visitor.visit_block(block);
|
||||
let _ = visitor.visit_block(block);
|
||||
visitor.break_after_expr
|
||||
})
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
|
||||
// We've checked that `call` is a call to `Stdin::read_line()` with the right receiver,
|
||||
// now let's check if the first use of the string passed to `::read_line()`
|
||||
// is used for operations that will always fail (e.g. parsing "6\n" into a number)
|
||||
for_each_local_use_after_expr(cx, local_id, call.hir_id, |expr| {
|
||||
let _ = for_each_local_use_after_expr(cx, local_id, call.hir_id, |expr| {
|
||||
if let Some(parent) = get_parent_expr(cx, expr) {
|
||||
let data = if let ExprKind::MethodCall(segment, recv, args, span) = parent.kind {
|
||||
if args.is_empty()
|
||||
|
||||
@@ -141,7 +141,7 @@ impl PassByRefOrValue {
|
||||
// Gather all the lifetimes found in the output type which may affect whether
|
||||
// `TRIVIALLY_COPY_PASS_BY_REF` should be linted.
|
||||
let mut output_regions = FxHashSet::default();
|
||||
for_each_top_level_late_bound_region(fn_sig.skip_binder().output(), |region| -> ControlFlow<!> {
|
||||
let _ = for_each_top_level_late_bound_region(fn_sig.skip_binder().output(), |region| -> ControlFlow<!> {
|
||||
output_regions.insert(region);
|
||||
ControlFlow::Continue(())
|
||||
});
|
||||
|
||||
@@ -381,7 +381,7 @@ impl UnconditionalRecursion {
|
||||
implemented_ty_id,
|
||||
method_span,
|
||||
};
|
||||
walk_body(&mut c, body);
|
||||
let _ = walk_body(&mut c, body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,19 +145,19 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
|
||||
let mut result = vec![];
|
||||
if fps.is_empty() {
|
||||
debug!("Unrestricted search for {:?} impls...", trait_);
|
||||
self.for_trait_impls(trait_, self_ty_fp, |impls| {
|
||||
let _ = self.for_trait_impls(trait_, self_ty_fp, |impls| {
|
||||
result.extend(impls.for_trait(trait_).map(id_to_chalk));
|
||||
ControlFlow::Continue(())
|
||||
})
|
||||
});
|
||||
} else {
|
||||
self.for_trait_impls(trait_, self_ty_fp, |impls| {
|
||||
let _ = self.for_trait_impls(trait_, self_ty_fp, |impls| {
|
||||
result.extend(
|
||||
fps.iter().flat_map(move |fp| {
|
||||
impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
|
||||
}),
|
||||
);
|
||||
ControlFlow::Continue(())
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
debug!("impls_for_trait returned {} impls", result.len());
|
||||
|
||||
@@ -116,7 +116,7 @@ pub fn dyn_compatibility_of_trait_query(
|
||||
trait_: TraitId,
|
||||
) -> Option<DynCompatibilityViolation> {
|
||||
let mut res = None;
|
||||
dyn_compatibility_of_trait_with_callback(db, trait_, &mut |osv| {
|
||||
let _ = dyn_compatibility_of_trait_with_callback(db, trait_, &mut |osv| {
|
||||
res = Some(osv);
|
||||
ControlFlow::Break(())
|
||||
});
|
||||
@@ -597,7 +597,7 @@ fn contains_illegal_impl_trait_in_trait(
|
||||
|
||||
let ret = sig.skip_binders().ret();
|
||||
let mut visitor = OpaqueTypeCollector(FxHashSet::default());
|
||||
ret.visit_with(visitor.as_dyn(), DebruijnIndex::INNERMOST);
|
||||
let _ = ret.visit_with(visitor.as_dyn(), DebruijnIndex::INNERMOST);
|
||||
|
||||
// Since we haven't implemented RPITIT in proper way like rustc yet,
|
||||
// just check whether `ret` contains RPIT for now
|
||||
|
||||
@@ -53,7 +53,7 @@ fn check_dyn_compatibility<'a>(
|
||||
continue;
|
||||
};
|
||||
let mut osvs = FxHashSet::default();
|
||||
dyn_compatibility_with_callback(&db, trait_id, &mut |osv| {
|
||||
let _ = dyn_compatibility_with_callback(&db, trait_id, &mut |osv| {
|
||||
osvs.insert(match osv {
|
||||
DynCompatibilityViolation::SizedSelf => SizedSelf,
|
||||
DynCompatibilityViolation::SelfReferential => SelfReferential,
|
||||
|
||||
@@ -1143,7 +1143,7 @@ impl<'a> InferenceContext<'a> {
|
||||
non_assocs: FxHashMap::default(),
|
||||
};
|
||||
for ty in tait_candidates {
|
||||
ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST);
|
||||
let _ = ty.visit_with(collector.as_dyn(), DebruijnIndex::INNERMOST);
|
||||
}
|
||||
|
||||
// Non-assoc TAITs can be define-used everywhere as long as they are
|
||||
|
||||
@@ -1033,7 +1033,7 @@ where
|
||||
T: ?Sized + TypeVisitable<Interner>,
|
||||
{
|
||||
let mut collector = PlaceholderCollector { db, placeholders: FxHashSet::default() };
|
||||
value.visit_with(&mut collector, DebruijnIndex::INNERMOST);
|
||||
let _ = value.visit_with(&mut collector, DebruijnIndex::INNERMOST);
|
||||
collector.placeholders.into_iter().collect()
|
||||
}
|
||||
|
||||
|
||||
@@ -596,7 +596,7 @@ pub(crate) fn iterate_method_candidates<T>(
|
||||
mut callback: impl FnMut(ReceiverAdjustments, AssocItemId, bool) -> Option<T>,
|
||||
) -> Option<T> {
|
||||
let mut slot = None;
|
||||
iterate_method_candidates_dyn(
|
||||
let _ = iterate_method_candidates_dyn(
|
||||
ty,
|
||||
db,
|
||||
env,
|
||||
|
||||
@@ -260,7 +260,7 @@ fn resolve_impl_trait_item(
|
||||
// attributes here. Use path resolution directly instead.
|
||||
//
|
||||
// FIXME: resolve type aliases (which are not yielded by iterate_path_candidates)
|
||||
method_resolution::iterate_path_candidates(
|
||||
let _ = method_resolution::iterate_path_candidates(
|
||||
&canonical,
|
||||
db,
|
||||
environment,
|
||||
|
||||
@@ -2911,7 +2911,7 @@ impl Trait {
|
||||
db: &dyn HirDatabase,
|
||||
) -> Option<Vec<DynCompatibilityViolation>> {
|
||||
let mut violations = vec![];
|
||||
hir_ty::dyn_compatibility::dyn_compatibility_with_callback(db, self.id, &mut |violation| {
|
||||
let _ = hir_ty::dyn_compatibility::dyn_compatibility_with_callback(db, self.id, &mut |violation| {
|
||||
violations.push(violation);
|
||||
ControlFlow::Continue(())
|
||||
});
|
||||
@@ -5497,7 +5497,7 @@ impl Type {
|
||||
.generic_def()
|
||||
.map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d));
|
||||
|
||||
method_resolution::iterate_method_candidates_dyn(
|
||||
let _ = method_resolution::iterate_method_candidates_dyn(
|
||||
&canonical,
|
||||
db,
|
||||
environment,
|
||||
@@ -5584,7 +5584,7 @@ impl Type {
|
||||
.generic_def()
|
||||
.map_or_else(|| TraitEnvironment::empty(krate.id), |d| db.trait_environment(d));
|
||||
|
||||
method_resolution::iterate_path_candidates(
|
||||
let _ = method_resolution::iterate_path_candidates(
|
||||
&canonical,
|
||||
db,
|
||||
environment,
|
||||
|
||||
@@ -750,7 +750,7 @@ impl FunctionBody {
|
||||
ast::Stmt::Item(_) => (),
|
||||
ast::Stmt::LetStmt(stmt) => {
|
||||
if let Some(pat) = stmt.pat() {
|
||||
walk_pat(&pat, &mut |pat| {
|
||||
let _ = walk_pat(&pat, &mut |pat| {
|
||||
cb(pat);
|
||||
std::ops::ControlFlow::<(), ()>::Continue(())
|
||||
});
|
||||
|
||||
@@ -121,7 +121,7 @@ pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) {
|
||||
match ast::Stmt::cast(node.clone()) {
|
||||
Some(ast::Stmt::LetStmt(l)) => {
|
||||
if let Some(pat) = l.pat() {
|
||||
walk_pat(&pat, &mut |pat| {
|
||||
let _ = walk_pat(&pat, &mut |pat| {
|
||||
cb(pat);
|
||||
ControlFlow::<(), ()>::Continue(())
|
||||
});
|
||||
@@ -159,7 +159,7 @@ pub fn walk_patterns_in_expr(start: &ast::Expr, cb: &mut dyn FnMut(ast::Pat)) {
|
||||
}
|
||||
} else if let Some(pat) = ast::Pat::cast(node) {
|
||||
preorder.skip_subtree();
|
||||
walk_pat(&pat, &mut |pat| {
|
||||
let _ = walk_pat(&pat, &mut |pat| {
|
||||
cb(pat);
|
||||
ControlFlow::<(), ()>::Continue(())
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//@ only-x86_64
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(asm_goto, asm_goto_with_outputs)]
|
||||
#![feature(asm_goto_with_outputs)]
|
||||
|
||||
use std::arch::asm;
|
||||
|
||||
|
||||
24
tests/codegen/sanitizer/cfi/external_weak_symbols.rs
Normal file
24
tests/codegen/sanitizer/cfi/external_weak_symbols.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
// Verifies that type metadata identifiers for for weakly-linked symbols are
|
||||
// emitted correctly.
|
||||
//
|
||||
//@ needs-sanitizer-cfi
|
||||
//@ compile-flags: -Clinker-plugin-lto -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static
|
||||
#![crate_type = "bin"]
|
||||
#![feature(linkage)]
|
||||
|
||||
unsafe extern "C" {
|
||||
#[linkage = "extern_weak"]
|
||||
static FOO: Option<unsafe extern "C" fn(f64) -> ()>;
|
||||
}
|
||||
// CHECK: @_rust_extern_with_linkage_FOO = internal global ptr @FOO
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
if let Some(method) = FOO {
|
||||
method(4.2);
|
||||
// CHECK: call i1 @llvm.type.test(ptr {{%method|%0}}, metadata !"_ZTSFvdE")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: declare !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} extern_weak void @FOO(double) unnamed_addr #{{[0-9]+}}
|
||||
@@ -0,0 +1,80 @@
|
||||
// MIR for `let_else` after built
|
||||
|
||||
| User Type Annotations
|
||||
| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:35:20: 35:45, inferred_ty: (u32, u64, &char)
|
||||
| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:35:20: 35:45, inferred_ty: (u32, u64, &char)
|
||||
|
|
||||
fn let_else() -> () {
|
||||
let mut _0: ();
|
||||
let mut _1: !;
|
||||
let _2: u32 as UserTypeProjection { base: UserType(0), projs: [Field(0, ())] };
|
||||
let _3: u64 as UserTypeProjection { base: UserType(0), projs: [Field(1, ())] };
|
||||
let _4: &char as UserTypeProjection { base: UserType(0), projs: [Field(2, ())] };
|
||||
let mut _5: (u32, u64, &char);
|
||||
let mut _6: &char;
|
||||
let _7: &char;
|
||||
let _8: char;
|
||||
scope 1 {
|
||||
debug x => _2;
|
||||
debug y => _3;
|
||||
debug z => _4;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
StorageLive(_5);
|
||||
StorageLive(_6);
|
||||
StorageLive(_7);
|
||||
StorageLive(_8);
|
||||
_8 = const 'u';
|
||||
_7 = &_8;
|
||||
_6 = &(*_7);
|
||||
_5 = (const 7_u32, const 12_u64, move _6);
|
||||
StorageDead(_6);
|
||||
PlaceMention(_5);
|
||||
falseEdge -> [real: bb4, imaginary: bb3];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_1 = core::panicking::panic(const "internal error: entered unreachable code") -> bb6;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
bb3: {
|
||||
goto -> bb5;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
AscribeUserType(_5, +, UserTypeProjection { base: UserType(1), projs: [] });
|
||||
_2 = copy (_5.0: u32);
|
||||
_3 = copy (_5.1: u64);
|
||||
_4 = copy (_5.2: &char);
|
||||
StorageDead(_7);
|
||||
StorageDead(_5);
|
||||
_0 = const ();
|
||||
StorageDead(_8);
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_7);
|
||||
StorageDead(_5);
|
||||
StorageDead(_8);
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb6 (cleanup): {
|
||||
resume;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// MIR for `let_else_bindless` after built
|
||||
|
||||
| User Type Annotations
|
||||
| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:40:20: 40:45, inferred_ty: (u32, u64, &char)
|
||||
| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:40:20: 40:45, inferred_ty: (u32, u64, &char)
|
||||
|
|
||||
fn let_else_bindless() -> () {
|
||||
let mut _0: ();
|
||||
let mut _1: !;
|
||||
let mut _2: (u32, u64, &char);
|
||||
let mut _3: &char;
|
||||
let _4: &char;
|
||||
let _5: char;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
StorageLive(_5);
|
||||
_5 = const 'u';
|
||||
_4 = &_5;
|
||||
_3 = &(*_4);
|
||||
_2 = (const 7_u32, const 12_u64, move _3);
|
||||
StorageDead(_3);
|
||||
PlaceMention(_2);
|
||||
falseEdge -> [real: bb4, imaginary: bb3];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_1 = core::panicking::panic(const "internal error: entered unreachable code") -> bb6;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
bb3: {
|
||||
goto -> bb5;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
AscribeUserType(_2, +, UserTypeProjection { base: UserType(1), projs: [] });
|
||||
StorageDead(_4);
|
||||
StorageDead(_2);
|
||||
_0 = const ();
|
||||
StorageDead(_5);
|
||||
return;
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_4);
|
||||
StorageDead(_2);
|
||||
StorageDead(_5);
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb6 (cleanup): {
|
||||
resume;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// MIR for `let_init` after built
|
||||
|
||||
| User Type Annotations
|
||||
| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:25:20: 25:45, inferred_ty: (u32, u64, &char)
|
||||
| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:25:20: 25:45, inferred_ty: (u32, u64, &char)
|
||||
|
|
||||
fn let_init() -> () {
|
||||
let mut _0: ();
|
||||
let _1: u32 as UserTypeProjection { base: UserType(0), projs: [Field(0, ())] };
|
||||
let _2: u64 as UserTypeProjection { base: UserType(0), projs: [Field(1, ())] };
|
||||
let _3: &char as UserTypeProjection { base: UserType(0), projs: [Field(2, ())] };
|
||||
let mut _4: (u32, u64, &char);
|
||||
let mut _5: &char;
|
||||
let _6: &char;
|
||||
let _7: char;
|
||||
scope 1 {
|
||||
debug x => _1;
|
||||
debug y => _2;
|
||||
debug z => _3;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_4);
|
||||
StorageLive(_5);
|
||||
StorageLive(_6);
|
||||
StorageLive(_7);
|
||||
_7 = const 'u';
|
||||
_6 = &_7;
|
||||
_5 = &(*_6);
|
||||
_4 = (const 7_u32, const 12_u64, move _5);
|
||||
StorageDead(_5);
|
||||
PlaceMention(_4);
|
||||
AscribeUserType(_4, +, UserTypeProjection { base: UserType(1), projs: [] });
|
||||
StorageLive(_1);
|
||||
_1 = copy (_4.0: u32);
|
||||
StorageLive(_2);
|
||||
_2 = copy (_4.1: u64);
|
||||
StorageLive(_3);
|
||||
_3 = copy (_4.2: &char);
|
||||
StorageDead(_6);
|
||||
StorageDead(_4);
|
||||
_0 = const ();
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
StorageDead(_7);
|
||||
return;
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForMatchedPlace(None), _4);
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// MIR for `let_init_bindless` after built
|
||||
|
||||
| User Type Annotations
|
||||
| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:30:20: 30:45, inferred_ty: (u32, u64, &char)
|
||||
| 1: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:30:20: 30:45, inferred_ty: (u32, u64, &char)
|
||||
|
|
||||
fn let_init_bindless() -> () {
|
||||
let mut _0: ();
|
||||
let mut _1: (u32, u64, &char);
|
||||
let mut _2: &char;
|
||||
let _3: &char;
|
||||
let _4: char;
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
_4 = const 'u';
|
||||
_3 = &_4;
|
||||
_2 = &(*_3);
|
||||
_1 = (const 7_u32, const 12_u64, move _2);
|
||||
StorageDead(_2);
|
||||
PlaceMention(_1);
|
||||
AscribeUserType(_1, +, UserTypeProjection { base: UserType(1), projs: [] });
|
||||
StorageDead(_3);
|
||||
StorageDead(_1);
|
||||
_0 = const ();
|
||||
StorageDead(_4);
|
||||
return;
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// MIR for `let_uninit` after built
|
||||
|
||||
| User Type Annotations
|
||||
| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:15:20: 15:45, inferred_ty: (u32, u64, &char)
|
||||
|
|
||||
fn let_uninit() -> () {
|
||||
let mut _0: ();
|
||||
let _1: u32 as UserTypeProjection { base: UserType(0), projs: [Field(0, ())] };
|
||||
let _2: u64 as UserTypeProjection { base: UserType(0), projs: [Field(1, ())] };
|
||||
let _3: &char as UserTypeProjection { base: UserType(0), projs: [Field(2, ())] };
|
||||
scope 1 {
|
||||
debug x => _1;
|
||||
debug y => _2;
|
||||
debug z => _3;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
_0 = const ();
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// MIR for `let_uninit_bindless` after built
|
||||
|
||||
| User Type Annotations
|
||||
| 0: user_ty: Canonical { value: Ty((u32, u64, &'static char)), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:20:20: 20:45, inferred_ty: (u32, u64, &char)
|
||||
|
|
||||
fn let_uninit_bindless() -> () {
|
||||
let mut _0: ();
|
||||
scope 1 {
|
||||
}
|
||||
|
||||
bb0: {
|
||||
_0 = const ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// MIR for `match_assoc_const` after built
|
||||
|
||||
| User Type Annotations
|
||||
| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:54:9: 54:44, inferred_ty: u32
|
||||
| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:54:9: 54:44, inferred_ty: u32
|
||||
|
|
||||
fn match_assoc_const() -> () {
|
||||
let mut _0: ();
|
||||
let mut _1: u32;
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = const 8_u32;
|
||||
PlaceMention(_1);
|
||||
switchInt(copy _1) -> [99: bb2, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_0 = const ();
|
||||
goto -> bb6;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
falseEdge -> [real: bb5, imaginary: bb1];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
bb5: {
|
||||
AscribeUserType(_1, -, UserTypeProjection { base: UserType(1), projs: [] });
|
||||
_0 = const ();
|
||||
goto -> bb6;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// MIR for `match_assoc_const_range` after built
|
||||
|
||||
| User Type Annotations
|
||||
| 0: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:62:11: 62:46, inferred_ty: u32
|
||||
| 1: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:62:11: 62:46, inferred_ty: u32
|
||||
| 2: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:63:9: 63:44, inferred_ty: u32
|
||||
| 3: user_ty: Canonical { value: TypeOf(DefId(0:11 ~ user_type_annotations[ee8e]::MyTrait::FOO), UserArgs { args: [MyStruct, 'static], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/user_type_annotations.rs:63:9: 63:44, inferred_ty: u32
|
||||
|
|
||||
fn match_assoc_const_range() -> () {
|
||||
let mut _0: ();
|
||||
let mut _1: u32;
|
||||
let mut _2: bool;
|
||||
let mut _3: bool;
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = const 8_u32;
|
||||
PlaceMention(_1);
|
||||
_3 = Lt(copy _1, const 99_u32);
|
||||
switchInt(move _3) -> [0: bb4, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
_0 = const ();
|
||||
goto -> bb11;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
falseEdge -> [real: bb10, imaginary: bb4];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
_2 = Le(const 99_u32, copy _1);
|
||||
switchInt(move _2) -> [0: bb5, otherwise: bb6];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
falseEdge -> [real: bb9, imaginary: bb1];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
goto -> bb5;
|
||||
}
|
||||
|
||||
bb8: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
bb9: {
|
||||
AscribeUserType(_1, -, UserTypeProjection { base: UserType(3), projs: [] });
|
||||
_0 = const ();
|
||||
goto -> bb11;
|
||||
}
|
||||
|
||||
bb10: {
|
||||
AscribeUserType(_1, -, UserTypeProjection { base: UserType(1), projs: [] });
|
||||
_0 = const ();
|
||||
goto -> bb11;
|
||||
}
|
||||
|
||||
bb11: {
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
66
tests/mir-opt/building/user_type_annotations.rs
Normal file
66
tests/mir-opt/building/user_type_annotations.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
//@ edition: 2024
|
||||
// skip-filecheck
|
||||
|
||||
// This test demonstrates how many user type annotations are recorded in MIR
|
||||
// for various binding constructs. In particular, this makes it possible to see
|
||||
// the number of duplicate user-type-annotation entries, and whether that
|
||||
// number has changed.
|
||||
//
|
||||
// Duplicates are mostly harmless, other than being inefficient.
|
||||
// "Unused" entries that are _not_ duplicates may nevertheless be necessary so
|
||||
// that they are seen by MIR lifetime checks.
|
||||
|
||||
// EMIT_MIR user_type_annotations.let_uninit.built.after.mir
|
||||
fn let_uninit() {
|
||||
let (x, y, z): (u32, u64, &'static char);
|
||||
}
|
||||
|
||||
// EMIT_MIR user_type_annotations.let_uninit_bindless.built.after.mir
|
||||
fn let_uninit_bindless() {
|
||||
let (_, _, _): (u32, u64, &'static char);
|
||||
}
|
||||
|
||||
// EMIT_MIR user_type_annotations.let_init.built.after.mir
|
||||
fn let_init() {
|
||||
let (x, y, z): (u32, u64, &'static char) = (7, 12, &'u');
|
||||
}
|
||||
|
||||
// EMIT_MIR user_type_annotations.let_init_bindless.built.after.mir
|
||||
fn let_init_bindless() {
|
||||
let (_, _, _): (u32, u64, &'static char) = (7, 12, &'u');
|
||||
}
|
||||
|
||||
// EMIT_MIR user_type_annotations.let_else.built.after.mir
|
||||
fn let_else() {
|
||||
let (x, y, z): (u32, u64, &'static char) = (7, 12, &'u') else { unreachable!() };
|
||||
}
|
||||
|
||||
// EMIT_MIR user_type_annotations.let_else_bindless.built.after.mir
|
||||
fn let_else_bindless() {
|
||||
let (_, _, _): (u32, u64, &'static char) = (7, 12, &'u') else { unreachable!() };
|
||||
}
|
||||
|
||||
trait MyTrait<'a> {
|
||||
const FOO: u32;
|
||||
}
|
||||
struct MyStruct {}
|
||||
impl MyTrait<'static> for MyStruct {
|
||||
const FOO: u32 = 99;
|
||||
}
|
||||
|
||||
// EMIT_MIR user_type_annotations.match_assoc_const.built.after.mir
|
||||
fn match_assoc_const() {
|
||||
match 8 {
|
||||
<MyStruct as MyTrait<'static>>::FOO => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// EMIT_MIR user_type_annotations.match_assoc_const_range.built.after.mir
|
||||
fn match_assoc_const_range() {
|
||||
match 8 {
|
||||
..<MyStruct as MyTrait<'static>>::FOO => {}
|
||||
<MyStruct as MyTrait<'static>>::FOO.. => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
38
tests/rustdoc-json/attrs/deprecated.rs
Normal file
38
tests/rustdoc-json/attrs/deprecated.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
//@ is "$.index[*][?(@.name=='not')].attrs" []
|
||||
//@ is "$.index[*][?(@.name=='not')].deprecation" null
|
||||
pub fn not() {}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='raw')].attrs" []
|
||||
//@ is "$.index[*][?(@.name=='raw')].deprecation" '{"since": null, "note": null}'
|
||||
#[deprecated]
|
||||
pub fn raw() {}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='equals_string')].attrs" []
|
||||
//@ is "$.index[*][?(@.name=='equals_string')].deprecation" '{"since": null, "note": "here is a reason"}'
|
||||
#[deprecated = "here is a reason"]
|
||||
pub fn equals_string() {}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='since')].attrs" []
|
||||
//@ is "$.index[*][?(@.name=='since')].deprecation" '{"since": "yoinks ago", "note": null}'
|
||||
#[deprecated(since = "yoinks ago")]
|
||||
pub fn since() {}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='note')].attrs" []
|
||||
//@ is "$.index[*][?(@.name=='note')].deprecation" '{"since": null, "note": "7"}'
|
||||
#[deprecated(note = "7")]
|
||||
pub fn note() {}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='since_and_note')].attrs" []
|
||||
//@ is "$.index[*][?(@.name=='since_and_note')].deprecation" '{"since": "tomorrow", "note": "sorry"}'
|
||||
#[deprecated(since = "tomorrow", note = "sorry")]
|
||||
pub fn since_and_note() {}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='note_and_since')].attrs" []
|
||||
//@ is "$.index[*][?(@.name=='note_and_since')].deprecation" '{"since": "a year from tomorrow", "note": "your welcome"}'
|
||||
#[deprecated(note = "your welcome", since = "a year from tomorrow")]
|
||||
pub fn note_and_since() {}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='neither_but_parens')].attrs" []
|
||||
//@ is "$.index[*][?(@.name=='neither_but_parens')].deprecation" '{"since": null, "note": null}'
|
||||
#[deprecated()]
|
||||
pub fn neither_but_parens() {}
|
||||
@@ -1,6 +1,6 @@
|
||||
//@ only-x86_64
|
||||
|
||||
#![feature(asm_unwind, asm_goto)]
|
||||
#![feature(asm_unwind)]
|
||||
|
||||
use std::arch::{asm, global_asm};
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
//@ needs-asm-support
|
||||
|
||||
#![deny(unreachable_code)]
|
||||
#![feature(asm_goto)]
|
||||
|
||||
use std::arch::asm;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error[E0133]: call to unsafe function `unreachable_unchecked` is unsafe and requires unsafe function or block
|
||||
--> $DIR/goto-block-safe.rs:14:17
|
||||
--> $DIR/goto-block-safe.rs:13:17
|
||||
|
|
||||
LL | unsafe {
|
||||
| ------ items do not inherit unsafety from separate enclosing items
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//@ needs-asm-support
|
||||
|
||||
#![deny(unreachable_code)]
|
||||
#![feature(asm_goto, asm_goto_with_outputs)]
|
||||
#![feature(asm_goto_with_outputs)]
|
||||
|
||||
use std::arch::asm;
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
//@ only-x86_64
|
||||
|
||||
use std::arch::asm;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
asm!("jmp {}", label {});
|
||||
//~^ ERROR label operands for inline assembly are unstable
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
error[E0658]: label operands for inline assembly are unstable
|
||||
--> $DIR/feature-gate-asm_goto.rs:7:24
|
||||
|
|
||||
LL | asm!("jmp {}", label {});
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #119364 <https://github.com/rust-lang/rust/issues/119364> for more information
|
||||
= help: add `#![feature(asm_goto)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
@@ -1,7 +1,5 @@
|
||||
//@ only-x86_64
|
||||
|
||||
#![feature(asm_goto)]
|
||||
|
||||
use std::arch::asm;
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error[E0658]: using both label and output operands for inline assembly is unstable
|
||||
--> $DIR/feature-gate-asm_goto_with_outputs.rs:10:52
|
||||
--> $DIR/feature-gate-asm_goto_with_outputs.rs:8:52
|
||||
|
|
||||
LL | asm!("mov {}, 1", "jmp {}", out(reg) _out, label {});
|
||||
| ^^^^^^^^
|
||||
|
||||
Reference in New Issue
Block a user