Auto merge of #143233 - dianqk:rollup-lcx3278, r=dianqk

Rollup of 14 pull requests

Successful merges:

 - rust-lang/rust#142429 (`tests/ui`: A New Order [13/N])
 - rust-lang/rust#142514 (Miri: handling of SNaN inputs in `f*::pow` operations)
 - rust-lang/rust#143066 (Use let chains in the new solver)
 - rust-lang/rust#143090 (Workaround for memory unsafety in third party DLLs)
 - rust-lang/rust#143118 (`tests/ui`: A New Order [15/N])
 - rust-lang/rust#143159 (Do not freshen `ReError`)
 - rust-lang/rust#143168 (`tests/ui`: A New Order [16/N])
 - rust-lang/rust#143176 (fix typos and improve clarity in documentation)
 - rust-lang/rust#143187 (Add my work email to mailmap)
 - rust-lang/rust#143190 (Use the `new` method for `BasicBlockData` and `Statement`)
 - rust-lang/rust#143195 (`tests/ui`: A New Order [17/N])
 - rust-lang/rust#143196 (Port #[link_section] to the new attribute parsing infrastructure)
 - rust-lang/rust#143199 (Re-disable `tests/run-make/short-ice` on Windows MSVC again)
 - rust-lang/rust#143219 (Show auto trait and blanket impls for `!`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors
2025-06-30 14:28:58 +00:00
125 changed files with 1360 additions and 1065 deletions
+1
View File
@@ -690,6 +690,7 @@ Xinye Tao <xy.tao@outlook.com>
Xuefeng Wu <benewu@gmail.com> Xuefeng Wu <xfwu@thoughtworks.com>
Xuefeng Wu <benewu@gmail.com> XuefengWu <benewu@gmail.com>
York Xiang <bombless@126.com>
Yotam Ofek <yotam.ofek@gmail.com> <yotamofek@microsoft.com>
Youngsoo Son <ysson83@gmail.com> <ysoo.son@samsung.com>
Youngsuk Kim <joseph942010@gmail.com>
Yuki Okushi <jtitor@2k36.org>
@@ -256,6 +256,9 @@ pub enum AttributeKind {
/// Represents `#[link_name]`.
LinkName { name: Symbol, span: Span },
/// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute)
LinkSection { name: Symbol, span: Span },
/// Represents `#[loop_match]`.
LoopMatch(Span),
@@ -24,6 +24,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
DocComment { .. } => Yes,
ExportName { .. } => Yes,
Inline(..) => No,
LinkSection { .. } => No,
MacroTransparency(..) => Yes,
Repr(..) => No,
Stability { .. } => Yes,
+2
View File
@@ -99,6 +99,8 @@ attr_parsing_non_ident_feature =
attr_parsing_null_on_export = `export_name` may not contain null characters
attr_parsing_null_on_link_section = `link_section` may not contain null characters
attr_parsing_repr_ident =
meta item in `repr` must be an identifier
@@ -1,11 +1,12 @@
use rustc_attr_data_structures::AttributeKind;
use rustc_attr_data_structures::AttributeKind::LinkName;
use rustc_attr_data_structures::AttributeKind::{LinkName, LinkSection};
use rustc_feature::{AttributeTemplate, template};
use rustc_span::{Symbol, sym};
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
use crate::session_diagnostics::NullOnLinkSection;
pub(crate) struct LinkNameParser;
@@ -28,3 +29,31 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<At
Some(LinkName { name, span: cx.attr_span })
}
}
pub(crate) struct LinkSectionParser;
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
const PATH: &[Symbol] = &[sym::link_section];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
let Some(name) = nv.value_as_str() else {
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
return None;
};
if name.as_str().contains('\0') {
// `#[link_section = ...]` will be converted to a null-terminated string,
// so it may not contain any null characters.
cx.emit_err(NullOnLinkSection { span: cx.attr_span });
return None;
}
Some(LinkSection { name, span: cx.attr_span })
}
}
+2 -1
View File
@@ -22,7 +22,7 @@
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
use crate::attributes::link_attrs::LinkNameParser;
use crate::attributes::link_attrs::{LinkNameParser, LinkSectionParser};
use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::must_use::MustUseParser;
@@ -123,6 +123,7 @@ mod late {
Single<ExportNameParser>,
Single<InlineParser>,
Single<LinkNameParser>,
Single<LinkSectionParser>,
Single<LoopMatchParser>,
Single<MayDangleParser>,
Single<MustUseParser>,
@@ -452,6 +452,13 @@ pub(crate) struct NullOnExport {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_null_on_link_section, code = E0648)]
pub(crate) struct NullOnLinkSection {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_stability_outside_std, code = E0734)]
pub(crate) struct StabilityOutsideStd {
@@ -124,6 +124,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name),
AttributeKind::LinkSection { name, .. } => {
codegen_fn_attrs.link_section = Some(*name)
}
AttributeKind::NoMangle(attr_span) => {
if tcx.opt_item_name(did.to_def_id()).is_some() {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
@@ -253,16 +256,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}
}
sym::link_section => {
if let Some(val) = attr.value_str() {
if val.as_str().bytes().any(|b| b == 0) {
let msg = format!("illegal null byte in link_section value: `{val}`");
tcx.dcx().span_err(attr.span(), msg);
} else {
codegen_fn_attrs.link_section = Some(val);
}
}
}
sym::link_ordinal => {
link_ordinal_span = Some(attr.span());
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
+4 -4
View File
@@ -354,15 +354,15 @@ fn optimize_use_clone<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let destination_block = target.unwrap();
bb.statements.push(mir::Statement {
source_info: bb.terminator().source_info,
kind: mir::StatementKind::Assign(Box::new((
bb.statements.push(mir::Statement::new(
bb.terminator().source_info,
mir::StatementKind::Assign(Box::new((
*destination,
mir::Rvalue::Use(mir::Operand::Copy(
arg_place.project_deeper(&[mir::ProjectionElem::Deref], tcx),
)),
))),
});
));
bb.terminator_mut().kind = mir::TerminatorKind::Goto { target: destination_block };
}
@@ -3055,7 +3055,7 @@ fn suggest_unwrapping_inner_self(
pub(crate) fn note_unmet_impls_on_type(
&self,
err: &mut Diag<'_>,
errors: Vec<FulfillmentError<'tcx>>,
errors: &[FulfillmentError<'tcx>],
suggest_derive: bool,
) {
let preds: Vec<_> = errors
+3 -19
View File
@@ -322,7 +322,7 @@ fn check_overloaded_binop(
lhs_expr.span,
format!("cannot use `{}` on type `{}`", s, lhs_ty_str),
);
self.note_unmet_impls_on_type(&mut err, errors, false);
self.note_unmet_impls_on_type(&mut err, &errors, false);
(err, None)
}
Op::BinOp(bin_op) => {
@@ -382,7 +382,7 @@ fn check_overloaded_binop(
err.span_label(rhs_expr.span, rhs_ty_str);
}
let suggest_derive = self.can_eq(self.param_env, lhs_ty, rhs_ty);
self.note_unmet_impls_on_type(&mut err, errors, suggest_derive);
self.note_unmet_impls_on_type(&mut err, &errors, suggest_derive);
(err, output_def_id)
}
};
@@ -582,22 +582,6 @@ fn check_overloaded_binop(
// concatenation (e.g., "Hello " + "World!"). This means
// we don't want the note in the else clause to be emitted
} else if lhs_ty.has_non_region_param() {
// Look for a TraitPredicate in the Fulfillment errors,
// and use it to generate a suggestion.
//
// Note that lookup_op_method must be called again but
// with a specific rhs_ty instead of a placeholder so
// the resulting predicate generates a more specific
// suggestion for the user.
let errors = self
.lookup_op_method(
(lhs_expr, lhs_ty),
Some((rhs_expr, rhs_ty)),
lang_item_for_binop(self.tcx, op),
op.span(),
expected,
)
.unwrap_err();
if !errors.is_empty() {
for error in errors {
if let Some(trait_pred) =
@@ -946,7 +930,7 @@ pub(crate) fn check_user_unop(
ty::Str | ty::Never | ty::Char | ty::Tuple(_) | ty::Array(_, _) => {}
ty::Ref(_, lty, _) if *lty.kind() == ty::Str => {}
_ => {
self.note_unmet_impls_on_type(&mut err, errors, true);
self.note_unmet_impls_on_type(&mut err, &errors, true);
}
}
}
+4 -5
View File
@@ -110,17 +110,16 @@ fn cx(&self) -> TyCtxt<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match r.kind() {
ty::ReBound(..) => {
// leave bound regions alone
r
}
// Leave bound regions alone, since they affect selection via the leak check.
ty::ReBound(..) => r,
// Leave error regions alone, since they affect selection b/c of incompleteness.
ty::ReError(_) => r,
ty::ReEarlyParam(..)
| ty::ReLateParam(_)
| ty::ReVar(_)
| ty::RePlaceholder(..)
| ty::ReStatic
| ty::ReError(_)
| ty::ReErased => self.cx().lifetimes.re_erased,
}
}
+9 -1
View File
@@ -1359,7 +1359,15 @@ pub struct BasicBlockData<'tcx> {
impl<'tcx> BasicBlockData<'tcx> {
pub fn new(terminator: Option<Terminator<'tcx>>, is_cleanup: bool) -> BasicBlockData<'tcx> {
BasicBlockData { statements: vec![], terminator, is_cleanup }
BasicBlockData::new_stmts(Vec::new(), terminator, is_cleanup)
}
pub fn new_stmts(
statements: Vec<Statement<'tcx>>,
terminator: Option<Terminator<'tcx>>,
is_cleanup: bool,
) -> BasicBlockData<'tcx> {
BasicBlockData { statements, terminator, is_cleanup }
}
/// Accessor for terminator.
+5 -1
View File
@@ -16,12 +16,16 @@ pub struct Statement<'tcx> {
pub kind: StatementKind<'tcx>,
}
impl Statement<'_> {
impl<'tcx> Statement<'tcx> {
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
/// invalidating statement indices in `Location`s.
pub fn make_nop(&mut self) {
self.kind = StatementKind::Nop
}
pub fn new(source_info: SourceInfo, kind: StatementKind<'tcx>) -> Self {
Statement { source_info, kind }
}
}
impl<'tcx> StatementKind<'tcx> {
+4 -4
View File
@@ -42,7 +42,7 @@ pub(crate) fn push_assign(
) {
self.push(
block,
Statement { source_info, kind: StatementKind::Assign(Box::new((place, rvalue))) },
Statement::new(source_info, StatementKind::Assign(Box::new((place, rvalue)))),
);
}
@@ -88,7 +88,7 @@ pub(crate) fn push_fake_read(
place: Place<'tcx>,
) {
let kind = StatementKind::FakeRead(Box::new((cause, place)));
let stmt = Statement { source_info, kind };
let stmt = Statement::new(source_info, kind);
self.push(block, stmt);
}
@@ -99,7 +99,7 @@ pub(crate) fn push_place_mention(
place: Place<'tcx>,
) {
let kind = StatementKind::PlaceMention(Box::new(place));
let stmt = Statement { source_info, kind };
let stmt = Statement::new(source_info, kind);
self.push(block, stmt);
}
@@ -110,7 +110,7 @@ pub(crate) fn push_place_mention(
/// syntax (e.g. `continue` or `if !`) that would otherwise not appear in MIR.
pub(crate) fn push_coverage_span_marker(&mut self, block: BasicBlock, source_info: SourceInfo) {
let kind = StatementKind::Coverage(coverage::CoverageKind::SpanMarker);
let stmt = Statement { source_info, kind };
let stmt = Statement::new(source_info, kind);
self.push(block, stmt);
}
@@ -61,10 +61,10 @@ fn inject_block_marker(
block: BasicBlock,
) -> BlockMarkerId {
let id = self.next_block_marker_id();
let marker_statement = mir::Statement {
let marker_statement = mir::Statement::new(
source_info,
kind: mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }),
};
mir::StatementKind::Coverage(CoverageKind::BlockMarker { id }),
);
cfg.push(block, marker_statement);
id
@@ -315,10 +315,8 @@ fn parse_block_def(&self, expr_id: ExprId, is_cleanup: bool) -> PResult<BasicBlo
let stmt = self.statement_as_expr(*stmt_id)?;
let span = self.thir[stmt].span;
let statement = self.parse_statement(stmt)?;
data.statements.push(Statement {
source_info: SourceInfo { span, scope: self.source_scope },
kind: statement,
});
data.statements
.push(Statement::new(SourceInfo { span, scope: self.source_scope }, statement));
}
let Some(trailing) = block.expr else { return Err(self.expr_error(expr_id, "terminator")) };
@@ -489,16 +489,16 @@ fn expr_as_place(
let place = place_builder.to_place(this);
this.cfg.push(
block,
Statement {
source_info: ty_source_info,
kind: StatementKind::AscribeUserType(
Statement::new(
ty_source_info,
StatementKind::AscribeUserType(
Box::new((
place,
UserTypeProjection { base: annotation_index, projs: vec![] },
)),
Variance::Invariant,
),
},
),
);
}
block.and(place_builder)
@@ -518,16 +518,16 @@ fn expr_as_place(
});
this.cfg.push(
block,
Statement {
source_info: ty_source_info,
kind: StatementKind::AscribeUserType(
Statement::new(
ty_source_info,
StatementKind::AscribeUserType(
Box::new((
Place::from(temp),
UserTypeProjection { base: annotation_index, projs: vec![] },
)),
Variance::Invariant,
),
},
),
);
}
block.and(PlaceBuilder::from(temp))
@@ -175,10 +175,8 @@ pub(crate) fn as_rvalue(
// and therefore is not considered during coroutine auto-trait
// determination. See the comment about `box` at `yield_in_scope`.
let result = this.local_decls.push(LocalDecl::new(expr.ty, expr_span));
this.cfg.push(
block,
Statement { source_info, kind: StatementKind::StorageLive(result) },
);
this.cfg
.push(block, Statement::new(source_info, StatementKind::StorageLive(result)));
if let Some(scope) = scope.temp_lifetime {
// schedule a shallow free of that memory, lest we unwind:
this.schedule_drop_storage_and_value(expr_span, scope, result);
@@ -278,12 +276,12 @@ pub(crate) fn as_rvalue(
};
this.cfg.push(
block,
Statement {
Statement::new(
source_info,
kind: StatementKind::Intrinsic(Box::new(
NonDivergingIntrinsic::Assume(Operand::Move(assert_place)),
)),
},
StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
Operand::Move(assert_place),
))),
),
);
}
@@ -789,7 +787,7 @@ fn limit_capture_mutability(
let source_info = this.source_info(upvar_span);
let temp = this.local_decls.push(LocalDecl::new(upvar_ty, upvar_span));
this.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
this.cfg.push(block, Statement::new(source_info, StatementKind::StorageLive(temp)));
let arg_place_builder = unpack!(block = this.as_place_builder(block, arg));
@@ -102,8 +102,7 @@ fn as_temp_inner(
if let Block { expr: None, targeted_by_break: false, .. } = this.thir[block]
&& expr_ty.is_never() => {}
_ => {
this.cfg
.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });
this.cfg.push(block, Statement::new(source_info, StatementKind::StorageLive(temp)));
// In constants, `temp_lifetime` is `None` for temporaries that
// live for the `'static` lifetime. Thus we do not drop these
@@ -646,9 +646,9 @@ pub(super) fn expr_into_pattern(
let base = self.canonical_user_type_annotations.push(annotation.clone());
self.cfg.push(
block,
Statement {
source_info: ty_source_info,
kind: StatementKind::AscribeUserType(
Statement::new(
ty_source_info,
StatementKind::AscribeUserType(
Box::new((place, UserTypeProjection { base, projs: Vec::new() })),
// We always use invariant as the variance here. This is because the
// variance field from the ascription refers to the variance to use
@@ -666,7 +666,7 @@ pub(super) fn expr_into_pattern(
// `<expr>`.
ty::Invariant,
),
},
),
);
self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
@@ -828,7 +828,7 @@ pub(crate) fn storage_live_binding(
) -> Place<'tcx> {
let local_id = self.var_local_id(var, for_guard);
let source_info = self.source_info(span);
self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
self.cfg.push(block, Statement::new(source_info, StatementKind::StorageLive(local_id)));
// Although there is almost always scope for given variable in corner cases
// like #92893 we might get variable with no scope.
if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id)
@@ -2578,16 +2578,16 @@ fn ascribe_types(
let base = self.canonical_user_type_annotations.push(ascription.annotation);
self.cfg.push(
block,
Statement {
Statement::new(
source_info,
kind: StatementKind::AscribeUserType(
StatementKind::AscribeUserType(
Box::new((
ascription.source,
UserTypeProjection { base, projs: Vec::new() },
)),
ascription.variance,
),
},
),
);
}
}
+16 -16
View File
@@ -431,13 +431,13 @@ fn link_blocks<'tcx>(
cfg.terminate(block, drop_node.data.source_info, terminator);
}
DropKind::ForLint => {
let stmt = Statement {
source_info: drop_node.data.source_info,
kind: StatementKind::BackwardIncompatibleDropHint {
let stmt = Statement::new(
drop_node.data.source_info,
StatementKind::BackwardIncompatibleDropHint {
place: Box::new(drop_node.data.local.into()),
reason: BackwardIncompatibleDropReason::Edition2024,
},
};
);
cfg.push(block, stmt);
let target = blocks[drop_node.next].unwrap();
if target != block {
@@ -454,10 +454,10 @@ fn link_blocks<'tcx>(
// Root nodes don't correspond to a drop.
DropKind::Storage if drop_idx == ROOT_NODE => {}
DropKind::Storage => {
let stmt = Statement {
source_info: drop_node.data.source_info,
kind: StatementKind::StorageDead(drop_node.data.local),
};
let stmt = Statement::new(
drop_node.data.source_info,
StatementKind::StorageDead(drop_node.data.local),
);
cfg.push(block, stmt);
let target = blocks[drop_node.next].unwrap();
if target != block {
@@ -1124,13 +1124,13 @@ pub(crate) fn break_for_tail_call(
DropKind::ForLint => {
self.cfg.push(
block,
Statement {
Statement::new(
source_info,
kind: StatementKind::BackwardIncompatibleDropHint {
StatementKind::BackwardIncompatibleDropHint {
place: Box::new(local.into()),
reason: BackwardIncompatibleDropReason::Edition2024,
},
},
),
);
}
DropKind::Storage => {
@@ -1138,7 +1138,7 @@ pub(crate) fn break_for_tail_call(
assert!(local.index() > self.arg_count);
self.cfg.push(
block,
Statement { source_info, kind: StatementKind::StorageDead(local) },
Statement::new(source_info, StatementKind::StorageDead(local)),
);
}
}
@@ -1880,13 +1880,13 @@ fn build_scope_drops<'tcx, F>(
cfg.push(
block,
Statement {
Statement::new(
source_info,
kind: StatementKind::BackwardIncompatibleDropHint {
StatementKind::BackwardIncompatibleDropHint {
place: Box::new(local.into()),
reason: BackwardIncompatibleDropReason::Edition2024,
},
},
),
);
}
DropKind::Storage => {
@@ -1910,7 +1910,7 @@ fn build_scope_drops<'tcx, F>(
}
// Only temps and vars need their storage dead.
assert!(local.index() > arg_count);
cfg.push(block, Statement { source_info, kind: StatementKind::StorageDead(local) });
cfg.push(block, Statement::new(source_info, StatementKind::StorageDead(local)));
}
}
}
@@ -17,13 +17,13 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
let mut blocks = IndexVec::new();
let mut block = |n, kind| {
let nop = mir::Statement { source_info, kind: mir::StatementKind::Nop };
let nop = mir::Statement::new(source_info, mir::StatementKind::Nop);
blocks.push(mir::BasicBlockData {
statements: std::iter::repeat(&nop).cloned().take(n).collect(),
terminator: Some(mir::Terminator { source_info, kind }),
is_cleanup: false,
})
blocks.push(mir::BasicBlockData::new_stmts(
std::iter::repeat(&nop).cloned().take(n).collect(),
Some(mir::Terminator { source_info, kind }),
false,
))
};
let dummy_place = mir::Place { local: mir::RETURN_PLACE, projection: ty::List::empty() };
@@ -44,11 +44,10 @@ fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let cur_len = body.basic_blocks.len();
let mut new_block = |source_info: SourceInfo, is_cleanup: bool, target: BasicBlock| {
let block = BasicBlockData {
statements: vec![],
let block = BasicBlockData::new(
Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }),
is_cleanup,
terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }),
};
);
let idx = cur_len + new_blocks.len();
new_blocks.push(block);
BasicBlock::new(idx)
@@ -93,11 +93,11 @@ fn add_move_for_packed_drop<'tcx>(
let ty = place.ty(body, tcx).ty;
let temp = patch.new_temp(ty, source_info.span);
let storage_dead_block = patch.new_block(BasicBlockData {
statements: vec![Statement { source_info, kind: StatementKind::StorageDead(temp) }],
terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }),
let storage_dead_block = patch.new_block(BasicBlockData::new_stmts(
vec![Statement::new(source_info, StatementKind::StorageDead(temp))],
Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }),
is_cleanup,
});
));
patch.add_statement(loc, StatementKind::StorageLive(temp));
patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place)));
+9 -10
View File
@@ -81,9 +81,11 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// Emit their retags.
basic_blocks[START_BLOCK].statements.splice(
0..0,
places.map(|(place, source_info)| Statement {
source_info,
kind: StatementKind::Retag(RetagKind::FnEntry, Box::new(place)),
places.map(|(place, source_info)| {
Statement::new(
source_info,
StatementKind::Retag(RetagKind::FnEntry, Box::new(place)),
)
}),
);
}
@@ -113,10 +115,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
for (source_info, dest_place, dest_block) in returns {
basic_blocks[dest_block].statements.insert(
0,
Statement {
Statement::new(
source_info,
kind: StatementKind::Retag(RetagKind::Default, Box::new(dest_place)),
},
StatementKind::Retag(RetagKind::Default, Box::new(dest_place)),
),
);
}
@@ -174,10 +176,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let source_info = block_data.statements[i].source_info;
block_data.statements.insert(
i + 1,
Statement {
source_info,
kind: StatementKind::Retag(retag_kind, Box::new(place)),
},
Statement::new(source_info, StatementKind::Retag(retag_kind, Box::new(place))),
);
}
}
@@ -51,22 +51,18 @@ fn insert_alignment_check<'tcx>(
let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr);
let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into();
stmts
.push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) });
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((thin_ptr, rvalue)))));
// Transmute the pointer to a usize (equivalent to `ptr.addr()`).
let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize);
let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) });
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((addr, rvalue)))));
// Get the alignment of the pointee
let alignment =
local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
let rvalue = Rvalue::NullaryOp(NullOp::AlignOf, pointee_ty);
stmts.push(Statement {
source_info,
kind: StatementKind::Assign(Box::new((alignment, rvalue))),
});
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((alignment, rvalue)))));
// Subtract 1 from the alignment to get the alignment mask
let alignment_mask =
@@ -76,13 +72,13 @@ fn insert_alignment_check<'tcx>(
user_ty: None,
const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize),
}));
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
alignment_mask,
Rvalue::BinaryOp(BinOp::Sub, Box::new((Operand::Copy(alignment), one))),
))),
});
));
// If this target does not have reliable alignment, further limit the mask by anding it with
// the mask for the highest reliable alignment.
@@ -99,31 +95,31 @@ fn insert_alignment_check<'tcx>(
tcx.types.usize,
),
}));
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
alignment_mask,
Rvalue::BinaryOp(
BinOp::BitAnd,
Box::new((Operand::Copy(alignment_mask), max_mask)),
),
))),
});
));
}
// BitAnd the alignment mask with the pointer
let alignment_bits =
local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
alignment_bits,
Rvalue::BinaryOp(
BinOp::BitAnd,
Box::new((Operand::Copy(addr), Operand::Copy(alignment_mask))),
),
))),
});
));
// Check if the alignment bits are all zero
let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
@@ -132,13 +128,13 @@ fn insert_alignment_check<'tcx>(
user_ty: None,
const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize),
}));
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
is_ok,
Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(alignment_bits), zero.clone()))),
))),
});
));
// Emit a check that asserts on the alignment and otherwise triggers a
// AssertKind::MisalignedPointerDereference.
+17 -18
View File
@@ -41,13 +41,12 @@ fn insert_null_check<'tcx>(
let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr);
let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into();
stmts
.push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) });
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((thin_ptr, rvalue)))));
// Transmute the pointer to a usize (equivalent to `ptr.addr()`).
let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize);
let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) });
stmts.push(Statement::new(source_info, StatementKind::Assign(Box::new((addr, rvalue)))));
let zero = Operand::Constant(Box::new(ConstOperand {
span: source_info.span,
@@ -71,24 +70,24 @@ fn insert_null_check<'tcx>(
let rvalue = Rvalue::NullaryOp(NullOp::SizeOf, pointee_ty);
let sizeof_pointee =
local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((sizeof_pointee, rvalue))),
});
StatementKind::Assign(Box::new((sizeof_pointee, rvalue))),
));
// Check that the pointee is not a ZST.
let is_pointee_not_zst =
local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
is_pointee_not_zst,
Rvalue::BinaryOp(
BinOp::Ne,
Box::new((Operand::Copy(sizeof_pointee), zero.clone())),
),
))),
});
));
// Pointer needs to be checked only if pointee is not a ZST.
Operand::Copy(is_pointee_not_zst)
@@ -97,38 +96,38 @@ fn insert_null_check<'tcx>(
// Check whether the pointer is null.
let is_null = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
is_null,
Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(addr), zero))),
))),
});
));
// We want to throw an exception if the pointer is null and the pointee is not unconditionally
// allowed (which for all non-borrow place uses, is when the pointee is ZST).
let should_throw_exception =
local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
should_throw_exception,
Rvalue::BinaryOp(
BinOp::BitAnd,
Box::new((Operand::Copy(is_null), pointee_should_be_checked)),
),
))),
});
));
// The final condition whether this pointer usage is ok or not.
let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
stmts.push(Statement {
stmts.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
is_ok,
Rvalue::UnaryOp(UnOp::Not, Operand::Copy(should_throw_exception)),
))),
});
));
// Emit a PointerCheck that asserts on the condition and otherwise triggers
// a AssertKind::NullPointerDereference.
@@ -235,11 +235,11 @@ fn split_block(
let block_data = &mut basic_blocks[location.block];
// Drain every statement after this one and move the current terminator to a new basic block.
let new_block = BasicBlockData {
statements: block_data.statements.split_off(location.statement_index),
terminator: block_data.terminator.take(),
is_cleanup: block_data.is_cleanup,
};
let new_block = BasicBlockData::new_stmts(
block_data.statements.split_off(location.statement_index),
block_data.terminator.take(),
block_data.is_cleanup,
);
basic_blocks.push(new_block)
}
+48 -63
View File
@@ -252,16 +252,16 @@ fn insert_none_ret_block(&self, body: &mut Body<'tcx>) -> BasicBlock {
}
};
let statements = vec![Statement {
kind: StatementKind::Assign(Box::new((Place::return_place(), none_value))),
let statements = vec![Statement::new(
source_info,
}];
StatementKind::Assign(Box::new((Place::return_place(), none_value))),
)];
body.basic_blocks_mut().push(BasicBlockData {
body.basic_blocks_mut().push(BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
});
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
));
block
}
@@ -342,10 +342,10 @@ fn make_state(
}
};
statements.push(Statement {
kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
statements.push(Statement::new(
source_info,
});
StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
));
}
// Create a Place referencing a coroutine struct field
@@ -361,13 +361,13 @@ fn make_field(&self, variant_index: VariantIdx, idx: FieldIdx, ty: Ty<'tcx>) ->
// Create a statement which changes the discriminant
fn set_discr(&self, state_disc: VariantIdx, source_info: SourceInfo) -> Statement<'tcx> {
let self_place = Place::from(SELF_ARG);
Statement {
Statement::new(
source_info,
kind: StatementKind::SetDiscriminant {
StatementKind::SetDiscriminant {
place: Box::new(self_place),
variant_index: state_disc,
},
}
)
}
// Create a statement which reads the discriminant into a temporary
@@ -377,10 +377,10 @@ fn get_discr(&self, body: &mut Body<'tcx>) -> (Statement<'tcx>, Place<'tcx>) {
let temp = Place::from(local_decls_len);
let self_place = Place::from(SELF_ARG);
let assign = Statement {
source_info: SourceInfo::outermost(body.span),
kind: StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))),
};
let assign = Statement::new(
SourceInfo::outermost(body.span),
StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))),
);
(assign, temp)
}
}
@@ -450,7 +450,7 @@ fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockDat
&& !self.always_live_locals.contains(l);
if needs_storage_dead {
data.statements
.push(Statement { source_info, kind: StatementKind::StorageDead(l) });
.push(Statement::new(source_info, StatementKind::StorageDead(l)));
}
}
@@ -596,10 +596,8 @@ fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local
let local = arg.node.place().unwrap().local;
let arg = Rvalue::Use(arg.node);
let assign = Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((destination, arg))),
};
let assign =
Statement::new(terminator.source_info, StatementKind::Assign(Box::new((destination, arg))));
bb_data.statements.push(assign);
bb_data.terminator = Some(Terminator {
source_info: terminator.source_info,
@@ -1075,11 +1073,11 @@ fn insert_switch<'tcx>(
let source_info = SourceInfo::outermost(body.span);
body.basic_blocks_mut().raw.insert(
0,
BasicBlockData {
statements: vec![assign],
terminator: Some(Terminator { source_info, kind: switch }),
is_cleanup: false,
},
BasicBlockData::new_stmts(
vec![assign],
Some(Terminator { source_info, kind: switch }),
false,
),
);
for b in body.basic_blocks_mut().iter_mut() {
@@ -1089,11 +1087,7 @@ fn insert_switch<'tcx>(
fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock {
let source_info = SourceInfo::outermost(body.span);
body.basic_blocks_mut().push(BasicBlockData {
statements: Vec::new(),
terminator: Some(Terminator { source_info, kind }),
is_cleanup: false,
})
body.basic_blocks_mut().push(BasicBlockData::new(Some(Terminator { source_info, kind }), false))
}
fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) -> Statement<'tcx> {
@@ -1109,19 +1103,16 @@ fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) ->
Box::new(AggregateKind::Adt(poll_def_id, VariantIdx::from_usize(0), args, None, None)),
IndexVec::from_raw(vec![val]),
);
Statement {
kind: StatementKind::Assign(Box::new((Place::return_place(), ready_val))),
source_info,
}
Statement::new(source_info, StatementKind::Assign(Box::new((Place::return_place(), ready_val))))
}
fn insert_poll_ready_block<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> BasicBlock {
let source_info = SourceInfo::outermost(body.span);
body.basic_blocks_mut().push(BasicBlockData {
statements: [return_poll_ready_assign(tcx, source_info)].to_vec(),
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
})
body.basic_blocks_mut().push(BasicBlockData::new_stmts(
[return_poll_ready_assign(tcx, source_info)].to_vec(),
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
))
}
fn insert_panic_block<'tcx>(
@@ -1205,13 +1196,11 @@ fn generate_poison_block_and_redirect_unwinds_there<'tcx>(
body: &mut Body<'tcx>,
) {
let source_info = SourceInfo::outermost(body.span);
let poison_block = body.basic_blocks_mut().push(BasicBlockData {
statements: vec![
transform.set_discr(VariantIdx::new(CoroutineArgs::POISONED), source_info),
],
terminator: Some(Terminator { source_info, kind: TerminatorKind::UnwindResume }),
is_cleanup: true,
});
let poison_block = body.basic_blocks_mut().push(BasicBlockData::new_stmts(
vec![transform.set_discr(VariantIdx::new(CoroutineArgs::POISONED), source_info)],
Some(Terminator { source_info, kind: TerminatorKind::UnwindResume }),
true,
));
for (idx, block) in body.basic_blocks_mut().iter_enumerated_mut() {
let source_info = block.terminator().source_info;
@@ -1345,32 +1334,28 @@ fn create_cases<'tcx>(
&& !transform.remap.contains(l)
&& !transform.always_live_locals.contains(l);
if needs_storage_live {
statements
.push(Statement { source_info, kind: StatementKind::StorageLive(l) });
statements.push(Statement::new(source_info, StatementKind::StorageLive(l)));
}
}
if operation == Operation::Resume {
// Move the resume argument to the destination place of the `Yield` terminator
let resume_arg = CTX_ARG;
statements.push(Statement {
statements.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
point.resume_arg,
Rvalue::Use(Operand::Move(resume_arg.into())),
))),
});
));
}
// Then jump to the real target
let block = body.basic_blocks_mut().push(BasicBlockData {
let block = body.basic_blocks_mut().push(BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator {
source_info,
kind: TerminatorKind::Goto { target },
}),
is_cleanup: false,
});
Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }),
false,
));
(point.state, block)
})
@@ -1540,13 +1525,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let stmts = &mut body.basic_blocks_mut()[START_BLOCK].statements;
stmts.insert(
0,
Statement {
Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
old_resume_local.into(),
Rvalue::Use(Operand::Move(resume_local.into())),
))),
},
),
);
let always_live_locals = always_storage_live_locals(body);
@@ -87,12 +87,11 @@ fn build_pin_fut<'tcx>(
const_: Const::zero_sized(pin_fut_new_unchecked_fn),
}));
let storage_live =
Statement { source_info, kind: StatementKind::StorageLive(fut_pin_place.local) };
let storage_live = Statement::new(source_info, StatementKind::StorageLive(fut_pin_place.local));
let fut_ref_assign = Statement {
let fut_ref_assign = Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
fut_ref_place,
Rvalue::Ref(
tcx.lifetimes.re_erased,
@@ -100,12 +99,12 @@ fn build_pin_fut<'tcx>(
fut_place,
),
))),
};
);
// call Pin<FutTy>::new_unchecked(&mut fut)
let pin_fut_bb = body.basic_blocks_mut().push(BasicBlockData {
statements: [storage_live, fut_ref_assign].to_vec(),
terminator: Some(Terminator {
let pin_fut_bb = body.basic_blocks_mut().push(BasicBlockData::new_stmts(
[storage_live, fut_ref_assign].to_vec(),
Some(Terminator {
source_info,
kind: TerminatorKind::Call {
func: pin_fut_new_unchecked_fn,
@@ -117,8 +116,8 @@ fn build_pin_fut<'tcx>(
fn_span: span,
},
}),
is_cleanup: false,
});
false,
));
(pin_fut_bb, fut_pin_place)
}
@@ -156,19 +155,15 @@ fn build_poll_switch<'tcx>(
let source_info = SourceInfo::outermost(body.span);
let poll_discr_place =
Place::from(body.local_decls.push(LocalDecl::new(poll_discr_ty, source_info.span)));
let discr_assign = Statement {
let discr_assign = Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
poll_discr_place,
Rvalue::Discriminant(*poll_unit_place),
))),
};
let storage_dead =
Statement { source_info, kind: StatementKind::StorageDead(fut_pin_place.local) };
StatementKind::Assign(Box::new((poll_discr_place, Rvalue::Discriminant(*poll_unit_place)))),
);
let storage_dead = Statement::new(source_info, StatementKind::StorageDead(fut_pin_place.local));
let unreachable_block = insert_term_block(body, TerminatorKind::Unreachable);
body.basic_blocks_mut().push(BasicBlockData {
statements: [storage_dead, discr_assign].to_vec(),
terminator: Some(Terminator {
body.basic_blocks_mut().push(BasicBlockData::new_stmts(
[storage_dead, discr_assign].to_vec(),
Some(Terminator {
source_info,
kind: TerminatorKind::SwitchInt {
discr: Operand::Move(poll_discr_place),
@@ -179,8 +174,8 @@ fn build_poll_switch<'tcx>(
),
},
}),
is_cleanup: false,
})
false,
))
}
// Gather blocks, reachable through 'drop' targets of Yield and Drop terminators (chained)
@@ -330,10 +325,10 @@ pub(super) fn expand_async_drops<'tcx>(
let context_ref_place =
Place::from(body.local_decls.push(LocalDecl::new(context_mut_ref, source_info.span)));
let arg = Rvalue::Use(Operand::Move(Place::from(CTX_ARG)));
body[bb].statements.push(Statement {
body[bb].statements.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((context_ref_place, arg))),
});
StatementKind::Assign(Box::new((context_ref_place, arg))),
));
let yield_block = insert_term_block(body, TerminatorKind::Unreachable); // `kind` replaced later to yield
let (pin_bb, fut_pin_place) =
build_pin_fut(tcx, body, fut_place.clone(), UnwindAction::Continue);
@@ -551,11 +546,8 @@ pub(super) fn insert_clean_drop<'tcx>(
};
// Create a block to destroy an unresumed coroutines. This can only destroy upvars.
body.basic_blocks_mut().push(BasicBlockData {
statements: Vec::new(),
terminator: Some(Terminator { source_info, kind: term }),
is_cleanup: false,
})
body.basic_blocks_mut()
.push(BasicBlockData::new(Some(Terminator { source_info, kind: term }), false))
}
pub(super) fn create_coroutine_drop_shim<'tcx>(
@@ -734,11 +726,7 @@ pub(super) fn create_coroutine_drop_shim_proxy_async<'tcx>(
body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(poll_enum, source_info);
// call coroutine_drop()
let call_bb = body.basic_blocks_mut().push(BasicBlockData {
statements: Vec::new(),
terminator: None,
is_cleanup: false,
});
let call_bb = body.basic_blocks_mut().push(BasicBlockData::new(None, false));
// return Poll::Ready()
let ret_bb = insert_poll_ready_block(tcx, &mut body);
@@ -259,7 +259,7 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
debug!(" injecting statement {counter_kind:?} for {bb:?}");
let data = &mut mir_body[bb];
let source_info = data.terminator().source_info;
let statement = Statement { source_info, kind: StatementKind::Coverage(counter_kind) };
let statement = Statement::new(source_info, StatementKind::Coverage(counter_kind));
data.statements.insert(0, statement);
}
@@ -68,14 +68,13 @@ fn push(&mut self, kind: TerminatorKind<'tcx>) -> BasicBlock {
BytePos(1)
};
let next_hi = next_lo + BytePos(1);
self.blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
self.blocks.push(BasicBlockData::new(
Some(Terminator {
source_info: SourceInfo::outermost(Span::with_root_ctxt(next_lo, next_hi)),
kind,
}),
is_cleanup: false,
})
false,
))
}
fn link(&mut self, from_block: BasicBlock, to_block: BasicBlock) {
@@ -55,8 +55,8 @@ fn has_back_edge(
}
fn insert_counter(basic_block_data: &mut BasicBlockData<'_>) {
basic_block_data.statements.push(Statement {
source_info: basic_block_data.terminator().source_info,
kind: StatementKind::ConstEvalCounter,
});
basic_block_data.statements.push(Statement::new(
basic_block_data.terminator().source_info,
StatementKind::ConstEvalCounter,
));
}
@@ -222,15 +222,14 @@ fn build_async_drop(
let span = self.source_info.span;
let pin_obj_bb = bb.unwrap_or_else(|| {
self.elaborator.patch().new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
self.elaborator.patch().new_block(BasicBlockData::new(
Some(Terminator {
// Temporary terminator, will be replaced by patch
source_info: self.source_info,
kind: TerminatorKind::Return,
}),
is_cleanup: false,
})
false,
))
});
let (fut_ty, drop_fn_def_id, trait_args) = if call_destructor_only {
@@ -366,10 +365,8 @@ fn build_async_drop(
call_statements.push(self.assign(obj_ptr_place, addr));
obj_ptr_place
};
call_statements.push(Statement {
source_info: self.source_info,
kind: StatementKind::StorageLive(fut.local),
});
call_statements
.push(Statement::new(self.source_info, StatementKind::StorageLive(fut.local)));
let call_drop_bb = self.new_block_with_statements(
unwind,
@@ -732,17 +729,17 @@ fn open_drop_for_box_contents(
let do_drop_bb = self.drop_subpath(interior, interior_path, succ, unwind, dropline);
let setup_bbd = BasicBlockData {
statements: vec![self.assign(
let setup_bbd = BasicBlockData::new_stmts(
vec![self.assign(
Place::from(ptr_local),
Rvalue::Cast(CastKind::Transmute, Operand::Copy(nonnull_place), ptr_ty),
)],
terminator: Some(Terminator {
Some(Terminator {
kind: TerminatorKind::Goto { target: do_drop_bb },
source_info: self.source_info,
}),
is_cleanup: unwind.is_cleanup(),
};
unwind.is_cleanup(),
);
self.elaborator.patch().new_block(setup_bbd)
}
@@ -753,14 +750,13 @@ fn open_drop_for_adt(
args: GenericArgsRef<'tcx>,
) -> BasicBlock {
if adt.variants().is_empty() {
return self.elaborator.patch().new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
return self.elaborator.patch().new_block(BasicBlockData::new(
Some(Terminator {
source_info: self.source_info,
kind: TerminatorKind::Unreachable,
}),
is_cleanup: self.unwind.is_cleanup(),
});
self.unwind.is_cleanup(),
));
}
let skip_contents = adt.is_union() || adt.is_manually_drop();
@@ -927,9 +923,9 @@ fn adt_switch_block(
let discr_ty = adt.repr().discr_type().to_ty(self.tcx());
let discr = Place::from(self.new_temp(discr_ty));
let discr_rv = Rvalue::Discriminant(self.place);
let switch_block = BasicBlockData {
statements: vec![self.assign(discr, discr_rv)],
terminator: Some(Terminator {
let switch_block = BasicBlockData::new_stmts(
vec![self.assign(discr, discr_rv)],
Some(Terminator {
source_info: self.source_info,
kind: TerminatorKind::SwitchInt {
discr: Operand::Move(discr),
@@ -939,8 +935,8 @@ fn adt_switch_block(
),
},
}),
is_cleanup: unwind.is_cleanup(),
};
unwind.is_cleanup(),
);
let switch_block = self.elaborator.patch().new_block(switch_block);
self.drop_flag_test_block(switch_block, succ, unwind)
}
@@ -956,8 +952,8 @@ fn destructor_call_block_sync(&mut self, (succ, unwind): (BasicBlock, Unwind)) -
let ref_place = self.new_temp(ref_ty);
let unit_temp = Place::from(self.new_temp(tcx.types.unit));
let result = BasicBlockData {
statements: vec![self.assign(
let result = BasicBlockData::new_stmts(
vec![self.assign(
Place::from(ref_place),
Rvalue::Ref(
tcx.lifetimes.re_erased,
@@ -965,7 +961,7 @@ fn destructor_call_block_sync(&mut self, (succ, unwind): (BasicBlock, Unwind)) -
self.place,
),
)],
terminator: Some(Terminator {
Some(Terminator {
kind: TerminatorKind::Call {
func: Operand::function_handle(
tcx,
@@ -983,8 +979,8 @@ fn destructor_call_block_sync(&mut self, (succ, unwind): (BasicBlock, Unwind)) -
},
source_info: self.source_info,
}),
is_cleanup: unwind.is_cleanup(),
};
unwind.is_cleanup(),
);
let destructor_block = self.elaborator.patch().new_block(result);
@@ -1047,8 +1043,8 @@ fn drop_loop(
let can_go = Place::from(self.new_temp(tcx.types.bool));
let one = self.constant_usize(1);
let drop_block = BasicBlockData {
statements: vec![
let drop_block = BasicBlockData::new_stmts(
vec![
self.assign(
ptr,
Rvalue::RawPtr(RawPtrKind::Mut, tcx.mk_place_index(self.place, cur)),
@@ -1058,26 +1054,26 @@ fn drop_loop(
Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))),
),
],
is_cleanup: unwind.is_cleanup(),
terminator: Some(Terminator {
Some(Terminator {
source_info: self.source_info,
// this gets overwritten by drop elaboration.
kind: TerminatorKind::Unreachable,
}),
};
unwind.is_cleanup(),
);
let drop_block = self.elaborator.patch().new_block(drop_block);
let loop_block = BasicBlockData {
statements: vec![self.assign(
let loop_block = BasicBlockData::new_stmts(
vec![self.assign(
can_go,
Rvalue::BinaryOp(BinOp::Eq, Box::new((copy(Place::from(cur)), copy(len.into())))),
)],
is_cleanup: unwind.is_cleanup(),
terminator: Some(Terminator {
Some(Terminator {
source_info: self.source_info,
kind: TerminatorKind::if_(move_(can_go), succ, drop_block),
}),
};
unwind.is_cleanup(),
);
let loop_block = self.elaborator.patch().new_block(loop_block);
let place = tcx.mk_place_deref(ptr);
@@ -1187,8 +1183,8 @@ enum ProjectionKind<Path> {
let slice_ptr_ty = Ty::new_mut_ptr(tcx, slice_ty);
let slice_ptr = self.new_temp(slice_ptr_ty);
let mut delegate_block = BasicBlockData {
statements: vec![
let mut delegate_block = BasicBlockData::new_stmts(
vec![
self.assign(Place::from(array_ptr), Rvalue::RawPtr(RawPtrKind::Mut, self.place)),
self.assign(
Place::from(slice_ptr),
@@ -1202,9 +1198,9 @@ enum ProjectionKind<Path> {
),
),
],
is_cleanup: self.unwind.is_cleanup(),
terminator: None,
};
None,
self.unwind.is_cleanup(),
);
let array_place = mem::replace(
&mut self.place,
@@ -1246,8 +1242,8 @@ fn drop_loop_trio_for_slice(&mut self, ety: Ty<'tcx>) -> BasicBlock {
};
let zero = self.constant_usize(0);
let block = BasicBlockData {
statements: vec![
let block = BasicBlockData::new_stmts(
vec![
self.assign(
len.into(),
Rvalue::UnaryOp(
@@ -1257,12 +1253,12 @@ fn drop_loop_trio_for_slice(&mut self, ety: Ty<'tcx>) -> BasicBlock {
),
self.assign(cur.into(), Rvalue::Use(zero)),
],
is_cleanup: unwind.is_cleanup(),
terminator: Some(Terminator {
Some(Terminator {
source_info: self.source_info,
kind: TerminatorKind::Goto { target: loop_block },
}),
};
unwind.is_cleanup(),
);
let drop_block = self.elaborator.patch().new_block(block);
// FIXME(#34708): handle partially-dropped array/slice elements.
@@ -1308,14 +1304,13 @@ fn open_drop(&mut self) -> BasicBlock {
self.source_info.span,
"open drop for unsafe binder shouldn't be encountered",
);
self.elaborator.patch().new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
self.elaborator.patch().new_block(BasicBlockData::new(
Some(Terminator {
source_info: self.source_info,
kind: TerminatorKind::Unreachable,
}),
is_cleanup: self.unwind.is_cleanup(),
})
self.unwind.is_cleanup(),
))
}
_ => span_bug!(self.source_info.span, "open drop from non-ADT `{:?}`", ty),
@@ -1434,11 +1429,10 @@ fn drop_flag_test_block(
}
fn new_block(&mut self, unwind: Unwind, k: TerminatorKind<'tcx>) -> BasicBlock {
self.elaborator.patch().new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator { source_info: self.source_info, kind: k }),
is_cleanup: unwind.is_cleanup(),
})
self.elaborator.patch().new_block(BasicBlockData::new(
Some(Terminator { source_info: self.source_info, kind: k }),
unwind.is_cleanup(),
))
}
fn new_block_with_statements(
@@ -1447,11 +1441,11 @@ fn new_block_with_statements(
statements: Vec<Statement<'tcx>>,
k: TerminatorKind<'tcx>,
) -> BasicBlock {
self.elaborator.patch().new_block(BasicBlockData {
self.elaborator.patch().new_block(BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator { source_info: self.source_info, kind: k }),
is_cleanup: unwind.is_cleanup(),
})
Some(Terminator { source_info: self.source_info, kind: k }),
unwind.is_cleanup(),
))
}
fn new_temp(&mut self, ty: Ty<'tcx>) -> Local {
@@ -1467,9 +1461,6 @@ fn constant_usize(&self, val: u16) -> Operand<'tcx> {
}
fn assign(&self, lhs: Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> {
Statement {
source_info: self.source_info,
kind: StatementKind::Assign(Box::new((lhs, rhs))),
}
Statement::new(self.source_info, StatementKind::Assign(Box::new((lhs, rhs))))
}
}
+25 -31
View File
@@ -900,10 +900,10 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
);
let dest_ty = dest.ty(caller_body, tcx);
let temp = Place::from(new_call_temp(caller_body, callsite, dest_ty, return_block));
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::Assign(Box::new((temp, dest))),
});
caller_body[callsite.block].statements.push(Statement::new(
callsite.source_info,
StatementKind::Assign(Box::new((temp, dest))),
));
tcx.mk_place_deref(temp)
} else {
destination
@@ -947,10 +947,9 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
for local in callee_body.vars_and_temps_iter() {
if integrator.always_live_locals.contains(local) {
let new_local = integrator.map_local(local);
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::StorageLive(new_local),
});
caller_body[callsite.block]
.statements
.push(Statement::new(callsite.source_info, StatementKind::StorageLive(new_local)));
}
}
if let Some(block) = return_block {
@@ -958,22 +957,22 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
// the slice once.
let mut n = 0;
if remap_destination {
caller_body[block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::Assign(Box::new((
caller_body[block].statements.push(Statement::new(
callsite.source_info,
StatementKind::Assign(Box::new((
dest,
Rvalue::Use(Operand::Move(destination_local.into())),
))),
});
));
n += 1;
}
for local in callee_body.vars_and_temps_iter().rev() {
if integrator.always_live_locals.contains(local) {
let new_local = integrator.map_local(local);
caller_body[block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::StorageDead(new_local),
});
caller_body[block].statements.push(Statement::new(
callsite.source_info,
StatementKind::StorageDead(new_local),
));
n += 1;
}
}
@@ -1126,10 +1125,10 @@ fn create_temp_if_necessary<'tcx, I: Inliner<'tcx>>(
trace!("creating temp for argument {:?}", arg);
let arg_ty = arg.ty(caller_body, inliner.tcx());
let local = new_call_temp(caller_body, callsite, arg_ty, return_block);
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))),
});
caller_body[callsite.block].statements.push(Statement::new(
callsite.source_info,
StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))),
));
local
}
@@ -1142,19 +1141,14 @@ fn new_call_temp<'tcx>(
) -> Local {
let local = caller_body.local_decls.push(LocalDecl::new(ty, callsite.source_info.span));
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
kind: StatementKind::StorageLive(local),
});
caller_body[callsite.block]
.statements
.push(Statement::new(callsite.source_info, StatementKind::StorageLive(local)));
if let Some(block) = return_block {
caller_body[block].statements.insert(
0,
Statement {
source_info: callsite.source_info,
kind: StatementKind::StorageDead(local),
},
);
caller_body[block]
.statements
.insert(0, Statement::new(callsite.source_info, StatementKind::StorageDead(local)));
}
local
@@ -240,15 +240,15 @@ fn simplify_primitive_clone(
let Some(arg_place) = arg.node.place() else { return };
statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::Use(Operand::Copy(
arg_place.project_deeper(&[ProjectionElem::Deref], self.tcx),
)),
))),
});
));
terminator.kind = TerminatorKind::Goto { target: *destination_block };
}
+4 -4
View File
@@ -259,13 +259,13 @@ fn remap_mir_for_const_eval_select<'tcx>(
// (const generic stuff) so we just create a temporary and deconstruct
// that.
let local = body.local_decls.push(LocalDecl::new(ty, fn_span));
bb.statements.push(Statement {
source_info: SourceInfo::outermost(fn_span),
kind: StatementKind::Assign(Box::new((
bb.statements.push(Statement::new(
SourceInfo::outermost(fn_span),
StatementKind::Assign(Box::new((
local.into(),
Rvalue::Use(tupled_args.node.clone()),
))),
});
));
(Operand::Move, local.into())
}
Operand::Move(place) => (Operand::Move, place),
@@ -25,31 +25,31 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
}
sym::ub_checks => {
let target = target.unwrap();
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::NullaryOp(NullOp::UbChecks, tcx.types.bool),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::contract_checks => {
let target = target.unwrap();
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::NullaryOp(NullOp::ContractChecks, tcx.types.bool),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::forget => {
let target = target.unwrap();
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
span: terminator.source_info.span,
@@ -57,7 +57,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
const_: Const::zero_sized(tcx.types.unit),
}))),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::copy_nonoverlapping => {
@@ -65,9 +65,9 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let Ok([src, dst, count]) = take_array(args) else {
bug!("Wrong arguments for copy_non_overlapping intrinsic");
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Intrinsic(Box::new(
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Intrinsic(Box::new(
NonDivergingIntrinsic::CopyNonOverlapping(
rustc_middle::mir::CopyNonOverlapping {
src: src.node,
@@ -76,7 +76,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
},
),
)),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::assume => {
@@ -84,12 +84,12 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let Ok([arg]) = take_array(args) else {
bug!("Wrong arguments for assume intrinsic");
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Intrinsic(Box::new(
NonDivergingIntrinsic::Assume(arg.node),
)),
});
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
arg.node,
))),
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::wrapping_add
@@ -121,13 +121,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
sym::unchecked_shr => BinOp::ShrUnchecked,
_ => bug!("unexpected intrinsic"),
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
@@ -141,13 +141,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
sym::mul_with_overflow => BinOp::MulWithOverflow,
_ => bug!("unexpected intrinsic"),
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::size_of | sym::align_of => {
@@ -158,13 +158,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
sym::align_of => NullOp::AlignOf,
_ => bug!("unexpected intrinsic"),
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::NullaryOp(null_op, tp_ty),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::read_via_copy => {
@@ -183,13 +183,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
};
// Add new statement at the end of the block that does the read, and patch
// up the terminator.
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::Use(Operand::Copy(derefed_place)),
))),
});
));
terminator.kind = match *target {
None => {
// No target means this read something uninhabited,
@@ -217,13 +217,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
"Only passing a local is supported"
);
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
derefed_place,
Rvalue::Use(val.node),
))),
});
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((derefed_place, Rvalue::Use(val.node)))),
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::discriminant_value => {
@@ -236,13 +233,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
};
let arg = arg.node.place().unwrap();
let arg = tcx.mk_place_deref(arg);
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::Discriminant(arg),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::offset => {
@@ -253,13 +250,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
"Wrong number of arguments for offset intrinsic",
);
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr.node, delta.node))),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::slice_get_unchecked => {
@@ -302,10 +299,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
_ => bug!("Unknown return type {ret_ty:?}"),
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((*destination, rvalue))),
});
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((*destination, rvalue))),
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::transmute | sym::transmute_unchecked => {
@@ -320,13 +317,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// Always emit the cast, even if we transmute to an uninhabited type,
// because that lets CTFE and codegen generate better error messages
// when such a transmute actually ends up reachable.
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::Cast(CastKind::Transmute, arg.node, dst_ty),
))),
});
));
if let Some(target) = *target {
terminator.kind = TerminatorKind::Goto { target };
} else {
@@ -351,13 +348,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
);
};
let fields = [data.node, meta.node];
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::Aggregate(Box::new(kind), fields.into()),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
sym::ptr_metadata => {
@@ -368,13 +365,13 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
);
};
let target = target.unwrap();
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
block.statements.push(Statement::new(
terminator.source_info,
StatementKind::Assign(Box::new((
*destination,
Rvalue::UnaryOp(UnOp::PtrMetadata, ptr.node),
))),
});
));
terminator.kind = TerminatorKind::Goto { target };
}
_ => {}
@@ -56,8 +56,7 @@ fn lower_slice_len_call<'tcx>(block: &mut BasicBlockData<'tcx>, slice_len_fn_ite
// make new RValue for Len
let r_value = Rvalue::UnaryOp(UnOp::PtrMetadata, arg.node.clone());
let len_statement_kind = StatementKind::Assign(Box::new((*destination, r_value)));
let add_statement =
Statement { kind: len_statement_kind, source_info: terminator.source_info };
let add_statement = Statement::new(terminator.source_info, len_statement_kind);
// modify terminator into simple Goto
let new_terminator_kind = TerminatorKind::Goto { target: *bb };
+17 -21
View File
@@ -78,14 +78,13 @@ pub(crate) fn resume_block(&mut self) -> BasicBlock {
return bb;
}
let bb = self.new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
let bb = self.new_block(BasicBlockData::new(
Some(Terminator {
source_info: SourceInfo::outermost(self.body_span),
kind: TerminatorKind::UnwindResume,
}),
is_cleanup: true,
});
true,
));
self.resume_block = Some(bb);
bb
}
@@ -95,14 +94,13 @@ pub(crate) fn unreachable_cleanup_block(&mut self) -> BasicBlock {
return bb;
}
let bb = self.new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
let bb = self.new_block(BasicBlockData::new(
Some(Terminator {
source_info: SourceInfo::outermost(self.body_span),
kind: TerminatorKind::Unreachable,
}),
is_cleanup: true,
});
true,
));
self.unreachable_cleanup_block = Some(bb);
bb
}
@@ -112,14 +110,13 @@ pub(crate) fn unreachable_no_cleanup_block(&mut self) -> BasicBlock {
return bb;
}
let bb = self.new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
let bb = self.new_block(BasicBlockData::new(
Some(Terminator {
source_info: SourceInfo::outermost(self.body_span),
kind: TerminatorKind::Unreachable,
}),
is_cleanup: false,
});
false,
));
self.unreachable_no_cleanup_block = Some(bb);
bb
}
@@ -131,14 +128,13 @@ pub(crate) fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Basic
return cached_bb;
}
let bb = self.new_block(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
let bb = self.new_block(BasicBlockData::new(
Some(Terminator {
source_info: SourceInfo::outermost(self.body_span),
kind: TerminatorKind::UnwindTerminate(reason),
}),
is_cleanup: true,
});
true,
));
self.terminate_block = Some((bb, reason));
bb
}
@@ -280,7 +276,7 @@ pub(crate) fn apply(self, body: &mut Body<'tcx>) {
let source_info = Self::source_info_for_index(&body[loc.block], loc);
body[loc.block]
.statements
.insert(loc.statement_index, Statement { source_info, kind: stmt });
.insert(loc.statement_index, Statement::new(source_info, stmt));
delta += 1;
}
}
@@ -731,23 +731,22 @@ struct Promoter<'a, 'tcx> {
impl<'a, 'tcx> Promoter<'a, 'tcx> {
fn new_block(&mut self) -> BasicBlock {
let span = self.promoted.span;
self.promoted.basic_blocks_mut().push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
self.promoted.basic_blocks_mut().push(BasicBlockData::new(
Some(Terminator {
source_info: SourceInfo::outermost(span),
kind: TerminatorKind::Return,
}),
is_cleanup: false,
})
false,
))
}
fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) {
let last = self.promoted.basic_blocks.last_index().unwrap();
let data = &mut self.promoted[last];
data.statements.push(Statement {
source_info: SourceInfo::outermost(span),
kind: StatementKind::Assign(Box::new((Place::from(dest), rvalue))),
});
data.statements.push(Statement::new(
SourceInfo::outermost(span),
StatementKind::Assign(Box::new((Place::from(dest), rvalue))),
));
}
fn is_temp_kind(&self, local: Local) -> bool {
@@ -914,13 +913,13 @@ fn promote_candidate(
assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
let promoted_operand = promoted_operand(ref_ty, span);
let promoted_ref_statement = Statement {
source_info: statement.source_info,
kind: StatementKind::Assign(Box::new((
let promoted_ref_statement = Statement::new(
statement.source_info,
StatementKind::Assign(Box::new((
Place::from(promoted_ref),
Rvalue::Use(Operand::Constant(Box::new(promoted_operand))),
))),
};
);
self.extra_statements.push((loc, promoted_ref_statement));
(
+42 -48
View File
@@ -323,9 +323,7 @@ fn dropee_emit_retag<'tcx>(
StatementKind::Retag(RetagKind::FnEntry, Box::new(dropee_ptr)),
];
for s in new_statements {
body.basic_blocks_mut()[START_BLOCK]
.statements
.push(Statement { source_info, kind: s });
body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info, s));
}
}
dropee_ptr
@@ -350,11 +348,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
let return_block = BasicBlock::new(1);
let mut blocks = IndexVec::with_capacity(2);
let block = |blocks: &mut IndexVec<_, _>, kind| {
blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator { source_info, kind }),
is_cleanup: false,
})
blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false))
};
block(&mut blocks, TerminatorKind::Goto { target: return_block });
block(&mut blocks, TerminatorKind::Return);
@@ -515,17 +509,17 @@ fn build_thread_local_shim<'tcx>(
let span = tcx.def_span(def_id);
let source_info = SourceInfo::outermost(span);
let blocks = IndexVec::from_raw(vec![BasicBlockData {
statements: vec![Statement {
let blocks = IndexVec::from_raw(vec![BasicBlockData::new_stmts(
vec![Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
Place::return_place(),
Rvalue::ThreadLocalRef(def_id),
))),
}],
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
}]);
)],
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
)]);
new_body(
MirSource::from_instance(instance),
@@ -609,11 +603,11 @@ fn block(
is_cleanup: bool,
) -> BasicBlock {
let source_info = self.source_info();
self.blocks.push(BasicBlockData {
self.blocks.push(BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator { source_info, kind }),
Some(Terminator { source_info, kind }),
is_cleanup,
})
))
}
/// Gives the index of an upcoming BasicBlock, with an offset.
@@ -625,7 +619,7 @@ fn block_index_offset(&self, offset: usize) -> BasicBlock {
}
fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> {
Statement { source_info: self.source_info(), kind }
Statement::new(self.source_info(), kind)
}
fn copy_shim(&mut self) {
@@ -901,13 +895,13 @@ fn build_call_shim<'tcx>(
.immutable(),
);
let borrow_kind = BorrowKind::Mut { kind: MutBorrowKind::Default };
statements.push(Statement {
statements.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
Place::from(ref_rcvr),
Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()),
))),
});
));
Operand::Move(Place::from(ref_rcvr))
}
});
@@ -956,11 +950,11 @@ fn build_call_shim<'tcx>(
let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 };
let mut blocks = IndexVec::with_capacity(n_blocks);
let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
blocks.push(BasicBlockData {
blocks.push(BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator { source_info, kind }),
Some(Terminator { source_info, kind }),
is_cleanup,
})
))
};
// BB #0
@@ -1071,8 +1065,9 @@ pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
let kind = AggregateKind::Adt(adt_def.did(), variant_index, args, None, None);
let variant = adt_def.variant(variant_index);
let statement = Statement {
kind: StatementKind::Assign(Box::new((
let statement = Statement::new(
source_info,
StatementKind::Assign(Box::new((
Place::return_place(),
Rvalue::Aggregate(
Box::new(kind),
@@ -1081,14 +1076,13 @@ pub(super) fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
.collect(),
),
))),
source_info,
};
);
let start_block = BasicBlockData {
statements: vec![statement],
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
};
let start_block = BasicBlockData::new_stmts(
vec![statement],
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
);
let source = MirSource::item(ctor_id);
let mut body = new_body(
@@ -1130,16 +1124,16 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t
Operand::Move(Place::from(Local::new(1))),
Ty::new_imm_ptr(tcx, tcx.types.unit),
);
let stmt = Statement {
let stmt = Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
};
StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
);
let statements = vec![stmt];
let start_block = BasicBlockData {
let start_block = BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
};
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
);
let source = MirSource::from_instance(ty::InstanceKind::FnPtrAddrShim(def_id, self_ty));
new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span)
}
@@ -1230,16 +1224,16 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
Box::new(AggregateKind::Coroutine(coroutine_def_id, coroutine_args)),
IndexVec::from_raw(fields),
);
let stmt = Statement {
let stmt = Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
};
StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
);
let statements = vec![stmt];
let start_block = BasicBlockData {
let start_block = BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
};
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
);
let source = MirSource::from_instance(ty::InstanceKind::ConstructCoroutineInClosureShim {
coroutine_closure_def_id,
@@ -88,11 +88,7 @@ pub(super) fn build_async_drop_shim<'tcx>(
let return_block = BasicBlock::new(1);
let mut blocks = IndexVec::with_capacity(2);
let block = |blocks: &mut IndexVec<_, _>, kind| {
blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator { source_info, kind }),
is_cleanup: false,
})
blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false))
};
block(
&mut blocks,
@@ -133,7 +129,7 @@ pub(super) fn build_async_drop_shim<'tcx>(
dropee_ptr,
Rvalue::Use(Operand::Move(coroutine_layout_dropee)),
)));
body.basic_blocks_mut()[START_BLOCK].statements.push(Statement { source_info, kind: st_kind });
body.basic_blocks_mut()[START_BLOCK].statements.push(Statement::new(source_info, st_kind));
dropee_ptr = dropee_emit_retag(tcx, &mut body, dropee_ptr, span);
let dropline = body.basic_blocks.last_index();
@@ -240,13 +236,13 @@ fn build_adrop_for_coroutine_shim<'tcx>(
.project_deeper(&[PlaceElem::Field(FieldIdx::ZERO, proxy_ref)], tcx);
body.basic_blocks_mut()[START_BLOCK].statements.insert(
idx,
Statement {
Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
Place::from(proxy_ref_local),
Rvalue::CopyForDeref(proxy_ref_place),
))),
},
),
);
idx += 1;
let mut cor_ptr_local = proxy_ref_local;
@@ -261,13 +257,13 @@ fn build_adrop_for_coroutine_shim<'tcx>(
// _cor_ptr = _proxy.0.0 (... .0)
body.basic_blocks_mut()[START_BLOCK].statements.insert(
idx,
Statement {
Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
Place::from(cor_ptr_local),
Rvalue::CopyForDeref(impl_ptr_place),
))),
},
),
);
idx += 1;
}
@@ -281,10 +277,10 @@ fn build_adrop_for_coroutine_shim<'tcx>(
);
body.basic_blocks_mut()[START_BLOCK].statements.insert(
idx,
Statement {
Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((Place::from(cor_ref_local), reborrow))),
},
StatementKind::Assign(Box::new((Place::from(cor_ref_local), reborrow))),
),
);
}
body
@@ -334,13 +330,13 @@ fn build_adrop_for_adrop_shim<'tcx>(
let mut statements = Vec::new();
statements.push(Statement {
statements.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
Place::from(proxy_ref_local),
Rvalue::CopyForDeref(proxy_ref_place),
))),
});
));
let mut cor_ptr_local = proxy_ref_local;
proxy_ty.find_async_drop_impl_coroutine(tcx, |ty| {
@@ -350,13 +346,13 @@ fn build_adrop_for_adrop_shim<'tcx>(
.project_deeper(&[PlaceElem::Deref, PlaceElem::Field(FieldIdx::ZERO, ty_ptr)], tcx);
cor_ptr_local = locals.push(LocalDecl::new(ty_ptr, span));
// _cor_ptr = _proxy.0.0 (... .0)
statements.push(Statement {
statements.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((
StatementKind::Assign(Box::new((
Place::from(cor_ptr_local),
Rvalue::CopyForDeref(impl_ptr_place),
))),
});
));
}
});
@@ -367,10 +363,10 @@ fn build_adrop_for_adrop_shim<'tcx>(
tcx.mk_place_deref(Place::from(cor_ptr_local)),
);
let cor_ref_place = Place::from(locals.push(LocalDecl::new(cor_ref, span)));
statements.push(Statement {
statements.push(Statement::new(
source_info,
kind: StatementKind::Assign(Box::new((cor_ref_place, reborrow))),
});
StatementKind::Assign(Box::new((cor_ref_place, reborrow))),
));
// cor_pin_ty = `Pin<&mut cor_ref>`
let cor_pin_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[cor_ref.into()]));
@@ -378,9 +374,9 @@ fn build_adrop_for_adrop_shim<'tcx>(
let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, span);
// call Pin<FutTy>::new_unchecked(&mut impl_cor)
blocks.push(BasicBlockData {
blocks.push(BasicBlockData::new_stmts(
statements,
terminator: Some(Terminator {
Some(Terminator {
source_info,
kind: TerminatorKind::Call {
func: Operand::function_handle(tcx, pin_fn, [cor_ref.into()], span),
@@ -392,15 +388,14 @@ fn build_adrop_for_adrop_shim<'tcx>(
fn_span: span,
},
}),
is_cleanup: false,
});
false,
));
// When dropping async drop coroutine, we continue its execution:
// we call impl::poll (impl_layout, ctx)
let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, span);
let resume_ctx = Place::from(Local::new(2));
blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator {
blocks.push(BasicBlockData::new(
Some(Terminator {
source_info,
kind: TerminatorKind::Call {
func: Operand::function_handle(tcx, poll_fn, [impl_ty.into()], span),
@@ -416,13 +411,12 @@ fn build_adrop_for_adrop_shim<'tcx>(
fn_span: span,
},
}),
is_cleanup: false,
});
blocks.push(BasicBlockData {
statements: vec![],
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
});
false,
));
blocks.push(BasicBlockData::new(
Some(Terminator { source_info, kind: TerminatorKind::Return }),
false,
));
let source = MirSource::from_instance(instance);
let mut body = new_body(source, blocks, locals, sig.inputs().len(), span);
@@ -115,10 +115,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
for bb_idx in new_targets.all_targets() {
storage_deads_to_insert.push((
*bb_idx,
Statement {
source_info: terminator.source_info,
kind: StatementKind::StorageDead(opt.to_switch_on.local),
},
Statement::new(
terminator.source_info,
StatementKind::StorageDead(opt.to_switch_on.local),
),
));
}
}
@@ -383,10 +383,10 @@ pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
let mut candidates = vec![];
if let TypingMode::Coherence = self.typing_mode() {
if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) {
return vec![candidate];
}
if let TypingMode::Coherence = self.typing_mode()
&& let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal)
{
return vec![candidate];
}
self.assemble_alias_bound_candidates(goal, &mut candidates);
@@ -997,12 +997,12 @@ fn cx(&self) -> I {
}
fn try_fold_ty(&mut self, ty: I::Ty) -> Result<I::Ty, Ambiguous> {
if let ty::Alias(ty::Projection, alias_ty) = ty.kind() {
if let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())? {
return Ok(term.expect_ty());
}
if let ty::Alias(ty::Projection, alias_ty) = ty.kind()
&& let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())?
{
Ok(term.expect_ty())
} else {
ty.try_super_fold_with(self)
}
ty.try_super_fold_with(self)
}
}
@@ -42,20 +42,18 @@ fn fast_reject_assumption(
goal: Goal<I, Self>,
assumption: I::Clause,
) -> Result<(), NoSolution> {
if let Some(host_clause) = assumption.as_host_effect_clause() {
if host_clause.def_id() == goal.predicate.def_id()
&& host_clause.constness().satisfies(goal.predicate.constness)
{
if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
goal.predicate.trait_ref.args,
host_clause.skip_binder().trait_ref.args,
) {
return Ok(());
}
}
if let Some(host_clause) = assumption.as_host_effect_clause()
&& host_clause.def_id() == goal.predicate.def_id()
&& host_clause.constness().satisfies(goal.predicate.constness)
&& DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
goal.predicate.trait_ref.args,
host_clause.skip_binder().trait_ref.args,
)
{
Ok(())
} else {
Err(NoSolution)
}
Err(NoSolution)
}
fn match_assumption(
@@ -429,22 +429,21 @@ pub(super) fn evaluate_goal_raw(
// If we have run this goal before, and it was stalled, check that any of the goal's
// args have changed. Otherwise, we don't need to re-run the goal because it'll remain
// stalled, since it'll canonicalize the same way and evaluation is pure.
if let Some(stalled_on) = stalled_on {
if !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value))
&& !self
.delegate
.opaque_types_storage_num_entries()
.needs_reevaluation(stalled_on.num_opaques)
{
return Ok((
NestedNormalizationGoals::empty(),
GoalEvaluation {
certainty: Certainty::Maybe(stalled_on.stalled_cause),
has_changed: HasChanged::No,
stalled_on: Some(stalled_on),
},
));
}
if let Some(stalled_on) = stalled_on
&& !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value))
&& !self
.delegate
.opaque_types_storage_num_entries()
.needs_reevaluation(stalled_on.num_opaques)
{
return Ok((
NestedNormalizationGoals::empty(),
GoalEvaluation {
certainty: Certainty::Maybe(stalled_on.stalled_cause),
has_changed: HasChanged::No,
stalled_on: Some(stalled_on),
},
));
}
let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
@@ -833,14 +832,11 @@ fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
match t.kind() {
ty::Infer(ty::TyVar(vid)) => {
if let ty::TermKind::Ty(term) = self.term.kind() {
if let ty::Infer(ty::TyVar(term_vid)) = term.kind() {
if self.delegate.root_ty_var(vid)
== self.delegate.root_ty_var(term_vid)
{
return ControlFlow::Break(());
}
}
if let ty::TermKind::Ty(term) = self.term.kind()
&& let ty::Infer(ty::TyVar(term_vid)) = term.kind()
&& self.delegate.root_ty_var(vid) == self.delegate.root_ty_var(term_vid)
{
return ControlFlow::Break(());
}
self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?;
@@ -860,15 +856,12 @@ fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
fn visit_const(&mut self, c: I::Const) -> Self::Result {
match c.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
if let ty::TermKind::Const(term) = self.term.kind() {
if let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind()
{
if self.delegate.root_const_var(vid)
== self.delegate.root_const_var(term_vid)
{
return ControlFlow::Break(());
}
}
if let ty::TermKind::Const(term) = self.term.kind()
&& let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind()
&& self.delegate.root_const_var(vid)
== self.delegate.root_const_var(term_vid)
{
return ControlFlow::Break(());
}
self.check_nameable(self.delegate.universe_of_ct(vid).unwrap())
@@ -112,18 +112,17 @@ fn fast_reject_assumption(
goal: Goal<I, Self>,
assumption: I::Clause,
) -> Result<(), NoSolution> {
if let Some(projection_pred) = assumption.as_projection_clause() {
if projection_pred.item_def_id() == goal.predicate.def_id() {
if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
goal.predicate.alias.args,
projection_pred.skip_binder().projection_term.args,
) {
return Ok(());
}
}
if let Some(projection_pred) = assumption.as_projection_clause()
&& projection_pred.item_def_id() == goal.predicate.def_id()
&& DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
goal.predicate.alias.args,
projection_pred.skip_binder().projection_term.args,
)
{
Ok(())
} else {
Err(NoSolution)
}
Err(NoSolution)
}
fn match_assumption(
@@ -127,33 +127,32 @@ fn fast_reject_assumption(
goal: Goal<I, Self>,
assumption: I::Clause,
) -> Result<(), NoSolution> {
if let Some(trait_clause) = assumption.as_trait_clause() {
if trait_clause.polarity() != goal.predicate.polarity {
return Err(NoSolution);
}
if trait_clause.def_id() == goal.predicate.def_id() {
if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
goal.predicate.trait_ref.args,
trait_clause.skip_binder().trait_ref.args,
) {
return Ok(());
}
}
fn trait_def_id_matches<I: Interner>(
cx: I,
clause_def_id: I::DefId,
goal_def_id: I::DefId,
) -> bool {
clause_def_id == goal_def_id
// PERF(sized-hierarchy): Sizedness supertraits aren't elaborated to improve perf, so
// check for a `Sized` subtrait when looking for `MetaSized`. `PointeeSized` bounds
// are syntactic sugar for a lack of bounds so don't need this.
if ecx.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::MetaSized)
&& ecx.cx().is_lang_item(trait_clause.def_id(), TraitSolverLangItem::Sized)
{
let meta_sized_clause =
trait_predicate_with_def_id(ecx.cx(), trait_clause, goal.predicate.def_id());
return Self::fast_reject_assumption(ecx, goal, meta_sized_clause);
}
// check for a `MetaSized` supertrait being matched against a `Sized` assumption.
//
// `PointeeSized` bounds are syntactic sugar for a lack of bounds so don't need this.
|| (cx.is_lang_item(clause_def_id, TraitSolverLangItem::Sized)
&& cx.is_lang_item(goal_def_id, TraitSolverLangItem::MetaSized))
}
Err(NoSolution)
if let Some(trait_clause) = assumption.as_trait_clause()
&& trait_clause.polarity() == goal.predicate.polarity
&& trait_def_id_matches(ecx.cx(), trait_clause.def_id(), goal.predicate.def_id())
&& DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
goal.predicate.trait_ref.args,
trait_clause.skip_binder().trait_ref.args,
)
{
return Ok(());
} else {
Err(NoSolution)
}
}
fn match_assumption(
+6 -4
View File
@@ -177,6 +177,9 @@ fn check_attributes(
Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => {
self.check_align(span, target, *align, *repr_span)
}
Attribute::Parsed(AttributeKind::LinkSection { span: attr_span, .. }) => {
self.check_link_section(hir_id, *attr_span, span, target)
}
Attribute::Parsed(AttributeKind::Naked(attr_span)) => {
self.check_naked(hir_id, *attr_span, span, target)
}
@@ -286,7 +289,6 @@ fn check_attributes(
[sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target),
[sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target),
[sym::link, ..] => self.check_link(hir_id, attr, span, target),
[sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target),
[sym::macro_use, ..] | [sym::macro_escape, ..] => {
self.check_macro_use(hir_id, attr, target)
}
@@ -1831,7 +1833,7 @@ fn check_must_be_applied_to_trait(&self, attr_span: Span, defn_span: Span, targe
}
/// Checks if `#[link_section]` is applied to a function or static.
fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
fn check_link_section(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
match target {
Target::Static | Target::Fn | Target::Method(..) => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
@@ -1839,7 +1841,7 @@ fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target
// erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => {
self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_section");
self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "link_section");
}
_ => {
// FIXME: #[link_section] was previously allowed on non-functions/statics and some
@@ -1847,7 +1849,7 @@ fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target
self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span(),
attr_span,
errors::LinkSection { span },
);
}
+4 -4
View File
@@ -320,10 +320,10 @@ pub fn supertrait_def_ids<I: Interner>(
let trait_def_id = stack.pop()?;
for (predicate, _) in cx.explicit_super_predicates_of(trait_def_id).iter_identity() {
if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() {
if set.insert(data.def_id()) {
stack.push(data.def_id());
}
if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder()
&& set.insert(data.def_id())
{
stack.push(data.def_id());
}
}
@@ -284,12 +284,12 @@ fn binders<T>(
}
// If they have no bound vars, relate normally.
if let Some(a_inner) = a.no_bound_vars() {
if let Some(b_inner) = b.no_bound_vars() {
self.relate(a_inner, b_inner)?;
return Ok(a);
}
};
if let Some(a_inner) = a.no_bound_vars()
&& let Some(b_inner) = b.no_bound_vars()
{
self.relate(a_inner, b_inner)?;
return Ok(a);
}
match self.ambient_variance {
// Checks whether `for<..> sub <: for<..> sup` holds.
@@ -80,31 +80,29 @@ pub(super) fn get<'a>(
mut candidate_is_applicable: impl FnMut(&NestedGoals<X>) -> bool,
) -> Option<CacheData<'a, X>> {
let entry = self.map.get(&input)?;
if let Some(Success { required_depth, ref nested_goals, ref result }) = entry.success {
if available_depth.cache_entry_is_applicable(required_depth)
&& candidate_is_applicable(nested_goals)
{
return Some(CacheData {
result: cx.get_tracked(&result),
required_depth,
encountered_overflow: false,
nested_goals,
});
}
if let Some(Success { required_depth, ref nested_goals, ref result }) = entry.success
&& available_depth.cache_entry_is_applicable(required_depth)
&& candidate_is_applicable(nested_goals)
{
return Some(CacheData {
result: cx.get_tracked(&result),
required_depth,
encountered_overflow: false,
nested_goals,
});
}
let additional_depth = available_depth.0;
if let Some(WithOverflow { nested_goals, result }) =
entry.with_overflow.get(&additional_depth)
&& candidate_is_applicable(nested_goals)
{
if candidate_is_applicable(nested_goals) {
return Some(CacheData {
result: cx.get_tracked(result),
required_depth: additional_depth,
encountered_overflow: true,
nested_goals,
});
}
return Some(CacheData {
result: cx.get_tracked(result),
required_depth: additional_depth,
encountered_overflow: true,
nested_goals,
});
}
None
+5
View File
@@ -316,6 +316,11 @@ mod prim_bool {}
#[unstable(feature = "never_type", issue = "35121")]
mod prim_never {}
// Required to make auto trait impls render.
// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
#[doc(hidden)]
impl ! {}
#[rustc_doc_primitive = "char"]
#[allow(rustdoc::invalid_rust_codeblocks)]
/// A character type.
@@ -33,7 +33,7 @@
use super::{AsRawHandle, DirBuff, File, FromRawHandle};
use crate::sys::c;
use crate::sys::pal::api::WinError;
use crate::sys::pal::api::{UnicodeStrRef, WinError, unicode_str};
use crate::thread;
// The maximum number of times to spin when waiting for deletes to complete.
@@ -74,7 +74,7 @@ unsafe fn nt_open_file(
/// `options` will be OR'd with `FILE_OPEN_REPARSE_POINT`.
fn open_link_no_reparse(
parent: &File,
path: &[u16],
path: UnicodeStrRef<'_>,
access: u32,
options: u32,
) -> Result<Option<File>, WinError> {
@@ -90,9 +90,8 @@ fn open_link_no_reparse(
static ATTRIBUTES: Atomic<u32> = AtomicU32::new(c::OBJ_DONT_REPARSE);
let result = unsafe {
let mut path_str = c::UNICODE_STRING::from_ref(path);
let mut object = c::OBJECT_ATTRIBUTES {
ObjectName: &mut path_str,
ObjectName: path.as_ptr(),
RootDirectory: parent.as_raw_handle(),
Attributes: ATTRIBUTES.load(Ordering::Relaxed),
..c::OBJECT_ATTRIBUTES::with_length()
@@ -129,7 +128,7 @@ fn open_link_no_reparse(
}
}
fn open_dir(parent: &File, name: &[u16]) -> Result<Option<File>, WinError> {
fn open_dir(parent: &File, name: UnicodeStrRef<'_>) -> Result<Option<File>, WinError> {
// Open the directory for synchronous directory listing.
open_link_no_reparse(
parent,
@@ -140,7 +139,7 @@ fn open_dir(parent: &File, name: &[u16]) -> Result<Option<File>, WinError> {
)
}
fn delete(parent: &File, name: &[u16]) -> Result<(), WinError> {
fn delete(parent: &File, name: UnicodeStrRef<'_>) -> Result<(), WinError> {
// Note that the `delete` function consumes the opened file to ensure it's
// dropped immediately. See module comments for why this is important.
match open_link_no_reparse(parent, name, c::DELETE, 0) {
@@ -179,8 +178,9 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> {
'outer: while let Some(dir) = dirlist.pop() {
let more_data = dir.fill_dir_buff(&mut buffer, restart)?;
for (name, is_directory) in buffer.iter() {
let name = unicode_str!(&name);
if is_directory {
let Some(subdir) = open_dir(&dir, &name)? else { continue };
let Some(subdir) = open_dir(&dir, name)? else { continue };
dirlist.push(dir);
dirlist.push(subdir);
continue 'outer;
@@ -188,7 +188,7 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> {
// Attempt to delete, retrying on sharing violation errors as these
// can often be very temporary. E.g. if something takes just a
// bit longer than expected to release a file handle.
retry(|| delete(&dir, &name), WinError::SHARING_VIOLATION)?;
retry(|| delete(&dir, name), WinError::SHARING_VIOLATION)?;
}
}
if more_data {
@@ -197,7 +197,8 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> {
} else {
// Attempt to delete, retrying on not empty errors because we may
// need to wait some time for files to be removed from the filesystem.
retry(|| delete(&dir, &[]), WinError::DIR_NOT_EMPTY)?;
let name = unicode_str!("");
retry(|| delete(&dir, name), WinError::DIR_NOT_EMPTY)?;
restart = true;
}
}
+73
View File
@@ -30,6 +30,7 @@
//! should go in sys/pal/windows/mod.rs rather than here. See `IoResult` as an example.
use core::ffi::c_void;
use core::marker::PhantomData;
use super::c;
@@ -291,3 +292,75 @@ impl WinError {
pub const TIMEOUT: Self = Self::new(c::ERROR_TIMEOUT);
// tidy-alphabetical-end
}
/// A wrapper around a UNICODE_STRING that is equivalent to `&[u16]`.
///
/// It is preferable to use the `unicode_str!` macro as that contains mitigations for #143078.
///
/// If the MaximumLength field of the underlying UNICODE_STRING is greater than
/// the Length field then you can test if the string is null terminated by inspecting
/// the u16 directly after the string. You cannot otherwise depend on nul termination.
#[derive(Copy, Clone)]
pub struct UnicodeStrRef<'a> {
s: c::UNICODE_STRING,
lifetime: PhantomData<&'a [u16]>,
}
static EMPTY_STRING_NULL_TERMINATED: &[u16] = &[0];
impl UnicodeStrRef<'_> {
const fn new(slice: &[u16], is_null_terminated: bool) -> Self {
let (len, max_len, ptr) = if slice.is_empty() {
(0, 2, EMPTY_STRING_NULL_TERMINATED.as_ptr().cast_mut())
} else {
let len = slice.len() - (is_null_terminated as usize);
(len * 2, size_of_val(slice), slice.as_ptr().cast_mut())
};
Self {
s: c::UNICODE_STRING { Length: len as _, MaximumLength: max_len as _, Buffer: ptr },
lifetime: PhantomData,
}
}
pub const fn from_slice_with_nul(slice: &[u16]) -> Self {
if !slice.is_empty() {
debug_assert!(slice[slice.len() - 1] == 0);
}
Self::new(slice, true)
}
pub const fn from_slice(slice: &[u16]) -> Self {
Self::new(slice, false)
}
/// Returns a pointer to the underlying UNICODE_STRING
pub const fn as_ptr(&self) -> *const c::UNICODE_STRING {
&self.s
}
}
/// Create a UnicodeStringRef from a literal str or a u16 array.
///
/// To mitigate #143078, when using a literal str the created UNICODE_STRING
/// will be nul terminated. The MaximumLength field of the UNICODE_STRING will
/// be set greater than the Length field to indicate that a nul may be present.
///
/// If using a u16 array, the array is used exactly as provided and you cannot
/// count on the string being nul terminated.
/// This should generally be used for strings that come from the OS.
///
/// **NOTE:** we lack a UNICODE_STRING builder type as we don't currently have
/// a use for it. If needing to dynamically build a UNICODE_STRING, the builder
/// should try to ensure there's a nul one past the end of the string.
pub macro unicode_str {
($str:literal) => {const {
crate::sys::pal::windows::api::UnicodeStrRef::from_slice_with_nul(
crate::sys::pal::windows::api::wide_str!($str),
)
}},
($array:expr) => {
crate::sys::pal::windows::api::UnicodeStrRef::from_slice(
$array,
)
}
}
-7
View File
@@ -37,13 +37,6 @@ pub fn nt_success(status: NTSTATUS) -> bool {
status >= 0
}
impl UNICODE_STRING {
pub fn from_ref(slice: &[u16]) -> Self {
let len = size_of_val(slice);
Self { Length: len as _, MaximumLength: len as _, Buffer: slice.as_ptr() as _ }
}
}
impl OBJECT_ATTRIBUTES {
pub fn with_length() -> Self {
Self {
+8 -5
View File
@@ -1,9 +1,8 @@
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::ops::Neg;
use crate::os::windows::prelude::*;
use crate::sys::api::utf16;
use crate::sys::c;
use crate::sys::handle::Handle;
use crate::sys::{api, c};
use crate::sys_common::{FromInner, IntoInner};
use crate::{mem, ptr};
@@ -73,8 +72,8 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
// Open a handle to the pipe filesystem (`\??\PIPE\`).
// This will be used when creating a new annon pipe.
let pipe_fs = {
let path = c::UNICODE_STRING::from_ref(utf16!(r"\??\PIPE\"));
object_attributes.ObjectName = &path;
let path = api::unicode_str!(r"\??\PIPE\");
object_attributes.ObjectName = path.as_ptr();
let mut pipe_fs = ptr::null_mut();
let status = c::NtOpenFile(
&mut pipe_fs,
@@ -93,8 +92,12 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
// From now on we're using handles instead of paths to create and open pipes.
// So set the `ObjectName` to a zero length string.
// As a (perhaps overzealous) mitigation for #143078, we use the null pointer
// for empty.Buffer instead of unicode_str!("").
// There's no difference to the OS itself but it's possible that third party
// DLLs which hook in to processes could be relying on the exact form of this string.
let empty = c::UNICODE_STRING::default();
object_attributes.ObjectName = &empty;
object_attributes.ObjectName = &raw const empty;
// Create our side of the pipe for async access.
let ours = {
@@ -7,7 +7,7 @@ USAGE:
intrinsic-test [FLAGS] [OPTIONS] <INPUT>
FLAGS:
--a32 Run tests for A32 instrinsics instead of A64
--a32 Run tests for A32 intrinsics instead of A64
--generate-only Regenerate test programs, but don't build or run them
-h, --help Prints help information
-V, --version Prints version information
+1 -1
View File
@@ -499,7 +499,7 @@ This directive takes comma-separated issue numbers as arguments, or `"unknown"`:
- `//@ known-bug: rust-lang/chalk#123456`
(allows arbitrary text before the `#`, which is useful when the issue is on another repo)
- `//@ known-bug: unknown`
(when there is no known issue yet; preferrably open one if it does not already exist)
(when there is no known issue yet; preferably open one if it does not already exist)
Do not include [error annotations](#error-annotations) in a test with
`known-bug`. The test should still include other normal directives and
@@ -64,7 +64,7 @@ struct HaveAlias {
In this example, the concrete type referred to by `Alias` is guaranteed to be the same wherever `Alias` occurs.
> Orginally this feature included type aliases as an associated type of a trait. In [#110237] this was split off to [`impl_trait_in_assoc_type`].
> Originally this feature included type aliases as an associated type of a trait. In [#110237] this was split off to [`impl_trait_in_assoc_type`].
### `type_alias_impl_trait` in argument position.
+4 -1
View File
@@ -753,9 +753,12 @@ fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec<String>
.other_attrs
.iter()
.filter_map(|attr| {
if let hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) = attr {
Some(format!("#[link_section = \"{name}\"]"))
}
// NoMangle is special cased, as it appears in HTML output, and we want to show it in source form, not HIR printing.
// It is also used by cargo-semver-checks.
if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr {
else if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr {
Some("#[no_mangle]".to_string())
} else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr
{
+68 -32
View File
@@ -191,7 +191,7 @@ fn emulate_intrinsic_by_name(
let [f] = check_intrinsic_arg_count(args)?;
let f = this.read_scalar(f)?.to_f32()?;
let res = fixed_float_value(intrinsic_name, &[f]).unwrap_or_else(||{
let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
// Using host floats (but it's fine, these operations do not have
// guaranteed precision).
let host = f.to_host();
@@ -235,7 +235,7 @@ fn emulate_intrinsic_by_name(
let [f] = check_intrinsic_arg_count(args)?;
let f = this.read_scalar(f)?.to_f64()?;
let res = fixed_float_value(intrinsic_name, &[f]).unwrap_or_else(||{
let res = fixed_float_value(this, intrinsic_name, &[f]).unwrap_or_else(|| {
// Using host floats (but it's fine, these operations do not have
// guaranteed precision).
let host = f.to_host();
@@ -312,7 +312,7 @@ fn emulate_intrinsic_by_name(
let f1 = this.read_scalar(f1)?.to_f32()?;
let f2 = this.read_scalar(f2)?.to_f32()?;
let res = fixed_float_value(intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
// Using host floats (but it's fine, this operation does not have guaranteed precision).
let res = f1.to_host().powf(f2.to_host()).to_soft();
@@ -330,7 +330,7 @@ fn emulate_intrinsic_by_name(
let f1 = this.read_scalar(f1)?.to_f64()?;
let f2 = this.read_scalar(f2)?.to_f64()?;
let res = fixed_float_value(intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
let res = fixed_float_value(this, intrinsic_name, &[f1, f2]).unwrap_or_else(|| {
// Using host floats (but it's fine, this operation does not have guaranteed precision).
let res = f1.to_host().powf(f2.to_host()).to_soft();
@@ -349,7 +349,7 @@ fn emulate_intrinsic_by_name(
let f = this.read_scalar(f)?.to_f32()?;
let i = this.read_scalar(i)?.to_i32()?;
let res = fixed_powi_float_value(f, i).unwrap_or_else(|| {
let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| {
// Using host floats (but it's fine, this operation does not have guaranteed precision).
let res = f.to_host().powi(i).to_soft();
@@ -367,7 +367,7 @@ fn emulate_intrinsic_by_name(
let f = this.read_scalar(f)?.to_f64()?;
let i = this.read_scalar(i)?.to_i32()?;
let res = fixed_powi_float_value(f, i).unwrap_or_else(|| {
let res = fixed_powi_float_value(this, f, i).unwrap_or_else(|| {
// Using host floats (but it's fine, this operation does not have guaranteed precision).
let res = f.to_host().powi(i).to_soft();
@@ -496,52 +496,88 @@ fn apply_random_float_error_to_imm<'tcx>(
/// - logf32, logf64, log2f32, log2f64, log10f32, log10f64
/// - powf32, powf64
///
/// # Return
///
/// Returns `Some(output)` if the `intrinsic` results in a defined fixed `output` specified in the C standard
/// (specifically, C23 annex F.10) when given `args` as arguments. Outputs that are unaffected by a relative error
/// (such as INF and zero) are not handled here, they are assumed to be handled by the underlying
/// implementation. Returns `None` if no specific value is guaranteed.
///
/// # Note
///
/// For `powf*` operations of the form:
///
/// - `(SNaN)^(±0)`
/// - `1^(SNaN)`
///
/// The result is implementation-defined:
/// - musl returns for both `1.0`
/// - glibc returns for both `NaN`
///
/// This discrepancy exists because SNaN handling is not consistently defined across platforms,
/// and the C standard leaves behavior for SNaNs unspecified.
///
/// Miri chooses to adhere to both implementations and returns either one of them non-deterministically.
fn fixed_float_value<S: Semantics>(
ecx: &mut MiriInterpCx<'_>,
intrinsic_name: &str,
args: &[IeeeFloat<S>],
) -> Option<IeeeFloat<S>> {
let one = IeeeFloat::<S>::one();
match (intrinsic_name, args) {
Some(match (intrinsic_name, args) {
// cos(+- 0) = 1
("cosf32" | "cosf64", [input]) if input.is_zero() => Some(one),
("cosf32" | "cosf64", [input]) if input.is_zero() => one,
// e^0 = 1
("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => Some(one),
// 1^y = 1 for any y, even a NaN.
("powf32" | "powf64", [base, _]) if *base == one => Some(one),
("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => one,
// (-1)^(±INF) = 1
("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => Some(one),
("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => one,
// 1^y = 1 for any y, even a NaN
("powf32" | "powf64", [base, exp]) if *base == one => {
let rng = ecx.machine.rng.get_mut();
// SNaN exponents get special treatment: they might return 1, or a NaN.
let return_nan = exp.is_signaling() && ecx.machine.float_nondet && rng.random();
// Handle both the musl and glibc cases non-deterministically.
if return_nan { ecx.generate_nan(args) } else { one }
}
// FIXME(#4286): The C ecosystem is inconsistent with handling sNaN's, some return 1 others propogate
// the NaN. We should return either 1 or the NaN non-deterministically here.
// But for now, just handle them all the same.
// x^(±0) = 1 for any x, even a NaN
("powf32" | "powf64", [_, exp]) if exp.is_zero() => Some(one),
("powf32" | "powf64", [base, exp]) if exp.is_zero() => {
let rng = ecx.machine.rng.get_mut();
// SNaN bases get special treatment: they might return 1, or a NaN.
let return_nan = base.is_signaling() && ecx.machine.float_nondet && rng.random();
// Handle both the musl and glibc cases non-deterministically.
if return_nan { ecx.generate_nan(args) } else { one }
}
// There are a lot of cases for fixed outputs according to the C Standard, but these are mainly INF or zero
// which are not affected by the applied error.
_ => None,
}
// There are a lot of cases for fixed outputs according to the C Standard, but these are
// mainly INF or zero which are not affected by the applied error.
_ => return None,
})
}
/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the C standard
/// (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
fn fixed_powi_float_value<S: Semantics>(base: IeeeFloat<S>, exp: i32) -> Option<IeeeFloat<S>> {
match (base.category(), exp) {
// x^0 = 1, if x is not a Signaling NaN
// FIXME(#4286): The C ecosystem is inconsistent with handling sNaN's, some return 1 others propogate
// the NaN. We should return either 1 or the NaN non-deterministically here.
// But for now, just handle them all the same.
(_, 0) => Some(IeeeFloat::<S>::one()),
/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the
/// C standard (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
fn fixed_powi_float_value<S: Semantics>(
ecx: &mut MiriInterpCx<'_>,
base: IeeeFloat<S>,
exp: i32,
) -> Option<IeeeFloat<S>> {
Some(match exp {
0 => {
let one = IeeeFloat::<S>::one();
let rng = ecx.machine.rng.get_mut();
let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling();
// For SNaN treatment, we are consistent with `powf`above.
// (We wouldn't have two, unlike powf all implementations seem to agree for powi,
// but for now we are maximally conservative.)
if return_nan { ecx.generate_nan(&[base]) } else { one }
}
_ => None,
}
_ => return None,
})
}
/// Given an floating-point operation and a floating-point value, clamps the result to the output
+14 -11
View File
@@ -1066,17 +1066,6 @@ fn ldexp(a: f64, b: i32) -> f64 {
assert_eq!((-1f32).powf(f32::NEG_INFINITY), 1.0);
assert_eq!((-1f64).powf(f64::NEG_INFINITY), 1.0);
// For pow (powf in rust) the C standard says:
// x^0 = 1 for all x even a sNaN
// FIXME(#4286): this does not match the behavior of all implementations.
assert_eq!(SNAN_F32.powf(0.0), 1.0);
assert_eq!(SNAN_F64.powf(0.0), 1.0);
// For pown (powi in rust) the C standard says:
// x^0 = 1 for all x even a sNaN
// FIXME(#4286): this does not match the behavior of all implementations.
assert_eq!(SNAN_F32.powi(0), 1.0);
assert_eq!(SNAN_F64.powi(0), 1.0);
assert_eq!(0f32.powi(10), 0.0);
assert_eq!(0f64.powi(100), 0.0);
@@ -1500,4 +1489,18 @@ pub fn test_operations_f128(a: f128, b: f128) {
test_operations_f32(12., 5.);
test_operations_f64(19., 11.);
test_operations_f128(25., 18.);
// SNaN^0 = (1 | NaN)
ensure_nondet(|| f32::powf(SNAN_F32, 0.0).is_nan());
ensure_nondet(|| f64::powf(SNAN_F64, 0.0).is_nan());
// 1^SNaN = (1 | NaN)
ensure_nondet(|| f32::powf(1.0, SNAN_F32).is_nan());
ensure_nondet(|| f64::powf(1.0, SNAN_F64).is_nan());
// same as powf (keep it consistent):
// x^SNaN = (1 | NaN)
ensure_nondet(|| f32::powi(SNAN_F32, 0).is_nan());
ensure_nondet(|| f64::powi(SNAN_F64, 0).is_nan());
}
+26
View File
@@ -260,6 +260,7 @@ fn test_f32() {
// Intrinsics
let nan = F32::nan(Neg, Quiet, 0).as_f32();
let snan = F32::nan(Neg, Signaling, 1).as_f32();
check_all_outcomes(
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(f32::min(nan, nan)),
@@ -313,6 +314,18 @@ fn test_f32() {
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
|| F32::from(nan.ln_gamma().0),
);
check_all_outcomes(
HashSet::from_iter([
F32::from(1.0),
F32::nan(Pos, Quiet, 0),
F32::nan(Neg, Quiet, 0),
F32::nan(Pos, Quiet, 1),
F32::nan(Neg, Quiet, 1),
F32::nan(Pos, Signaling, 1),
F32::nan(Neg, Signaling, 1),
]),
|| F32::from(snan.powf(0.0)),
);
}
fn test_f64() {
@@ -376,6 +389,7 @@ fn test_f64() {
// Intrinsics
let nan = F64::nan(Neg, Quiet, 0).as_f64();
let snan = F64::nan(Neg, Signaling, 1).as_f64();
check_all_outcomes(
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
|| F64::from(f64::min(nan, nan)),
@@ -433,6 +447,18 @@ fn test_f64() {
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
|| F64::from(nan.ln_gamma().0),
);
check_all_outcomes(
HashSet::from_iter([
F64::from(1.0),
F64::nan(Pos, Quiet, 0),
F64::nan(Neg, Quiet, 0),
F64::nan(Pos, Quiet, 1),
F64::nan(Neg, Quiet, 1),
F64::nan(Pos, Signaling, 1),
F64::nan(Neg, Signaling, 1),
]),
|| F64::from(snan.powf(0.0)),
);
}
fn test_casts() {
+1 -1
View File
@@ -51,7 +51,7 @@ To combine installers.
* Make install.sh not have to be customized, pull it's data from a
config file.
* Be more resiliant to installation failures, particularly if the disk
* Be more resilient to installation failures, particularly if the disk
is full.
* Pre-install and post-uninstall scripts.
* Allow components to depend on or contradict other components.
-1
View File
@@ -1368,7 +1368,6 @@ ui/infinite/issue-41731-infinite-macro-println.rs
ui/intrinsics/issue-28575.rs
ui/intrinsics/issue-84297-reifying-copy.rs
ui/invalid/issue-114435-layout-type-err.rs
ui/issue-11881.rs
ui/issue-15924.rs
ui/issue-16822.rs
ui/issues-71798.rs
-13
View File
@@ -1,13 +0,0 @@
//@ known-bug: #132882
use std::ops::Add;
pub trait Numoid
where
for<N: Numoid> &'a Self: Add<Self>,
{
}
pub fn compute<N: Numoid>(a: N) -> N {
&a + a
}
+6 -3
View File
@@ -5,9 +5,12 @@
// See https://github.com/rust-lang/rust/issues/107910
//@ needs-target-std
//@ ignore-i686-pc-windows-msvc
// Reason: the assert_eq! on line 37 fails, almost seems like it missing debug info?
// Haven't been able to reproduce locally, but it happens on CI.
//@ ignore-windows-msvc
//
// - FIXME(#143198): On `i686-pc-windows-msvc`: the assert_eq! on line 37 fails, almost seems like
// it missing debug info? Haven't been able to reproduce locally, but it happens on CI.
// - FIXME(#143198): On `x86_64-pc-windows-msvc`: full backtrace sometimes do not contain matching
// count of short backtrace markers (e.g. 5x end marker, but 3x start marker).
use run_make_support::rustc;
@@ -0,0 +1,6 @@
//@ edition: 2021
#![no_std]
//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]'
#[link_section = ".text"]
pub extern "C" fn example() {}
@@ -0,0 +1,9 @@
//@ edition: 2024
#![no_std]
// Since the 2024 edition the link_section attribute must use the unsafe qualification.
// However, the unsafe qualification is not shown by rustdoc.
//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]'
#[unsafe(link_section = ".text")]
pub extern "C" fn example() {}
@@ -0,0 +1,36 @@
//! Test inner attributes (#![...]) behavior in impl blocks with cfg conditions.
//!
//! This test verifies that:
//! - Inner attributes can conditionally exclude entire impl blocks
//! - Regular attributes within impl blocks work independently
//! - Attribute parsing doesn't consume too eagerly
//@ run-pass
struct Foo;
impl Foo {
#![cfg(false)]
fn method(&self) -> bool {
false
}
}
impl Foo {
#![cfg(not(FALSE))]
// Check that we don't eat attributes too eagerly.
#[cfg(false)]
fn method(&self) -> bool {
false
}
fn method(&self) -> bool {
true
}
}
pub fn main() {
assert!(Foo.method());
}
@@ -0,0 +1,12 @@
//! Test that -Z maximal-hir-to-mir-coverage flag is accepted.
//!
//! Original PR: https://github.com/rust-lang/rust/pull/105286
//@ compile-flags: -Zmaximal-hir-to-mir-coverage
//@ run-pass
fn main() {
let x = 1;
let y = x + 1;
println!("{y}");
}
@@ -0,0 +1,37 @@
//! Test that monomorphization correctly distinguishes types with different ABI alignment.
//!
//! On x86_64-linux-gnu and similar platforms, structs get 8-byte "preferred"
//! alignment, but their "ABI" alignment (what actually matters for data layout)
//! is the largest alignment of any field. If monomorphization incorrectly uses
//! "preferred" alignment instead of "ABI" alignment, it might unify types `A`
//! and `B` even though `S<A>` and `S<B>` have field `t` at different offsets,
//! leading to incorrect method dispatch for `unwrap()`.
//@ run-pass
#[derive(Copy, Clone)]
struct S<T> {
#[allow(dead_code)]
i: u8,
t: T,
}
impl<T> S<T> {
fn unwrap(self) -> T {
self.t
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
struct A((u32, u32)); // Different ABI alignment than B
#[derive(Copy, Clone, PartialEq, Debug)]
struct B(u64); // Different ABI alignment than A
pub fn main() {
static CA: S<A> = S { i: 0, t: A((13, 104)) };
static CB: S<B> = S { i: 0, t: B(31337) };
assert_eq!(CA.unwrap(), A((13, 104)));
assert_eq!(CB.unwrap(), B(31337));
}
@@ -0,0 +1,37 @@
//! Test that opt-level=z produces correct code on Windows MSVC targets.
//!
//! A previously outdated version of LLVM caused compilation failures and
//! generated invalid code on Windows specifically with optimization level `z`.
//! The bug manifested as corrupted base pointers due to incorrect register
//! usage in the generated assembly (e.g., `popl %esi` corrupting local variables).
//! After updating to a more recent LLVM version, this test ensures that
//! compilation and execution both succeed with opt-level=z.
//!
//! Regression test for <https://github.com/rust-lang/rust/issues/45034>.
//@ ignore-cross-compile
// Reason: the compiled binary is executed
//@ only-windows
// Reason: the observed bug only occurred on Windows MSVC targets
//@ run-pass
//@ compile-flags: -C opt-level=z
#![feature(test)]
extern crate test;
fn foo(x: i32, y: i32) -> i64 {
(x + y) as i64
}
#[inline(never)]
fn bar() {
let _f = Box::new(0);
// This call used to trigger an LLVM bug in opt-level=z where the base
// pointer gets corrupted due to incorrect register allocation
let y: fn(i32, i32) -> i64 = test::black_box(foo);
test::black_box(y(1, 2));
}
fn main() {
bar();
}
@@ -0,0 +1,9 @@
//! Regression test checks UI tests without error annotations are detected as failing.
//!
//! This tests that when we forget to use any `//~ ERROR` comments whatsoever,
//! the test doesn't succeed
//! Originally created in https://github.com/rust-lang/rust/pull/56244
//@ should-fail
fn main() {}
@@ -0,0 +1,30 @@
//! Test that `#[derive(Debug)]` for enums correctly formats variant names.
//@ run-pass
#[derive(Debug)]
enum Foo {
A(usize),
C,
}
#[derive(Debug)]
enum Bar {
D,
}
pub fn main() {
// Test variant with data
let foo_a = Foo::A(22);
assert_eq!("A(22)".to_string(), format!("{:?}", foo_a));
if let Foo::A(value) = foo_a {
println!("Value: {}", value); // This needs to remove #[allow(dead_code)]
}
// Test unit variant
assert_eq!("C".to_string(), format!("{:?}", Foo::C));
// Test unit variant from different enum
assert_eq!("D".to_string(), format!("{:?}", Bar::D));
}
@@ -387,14 +387,6 @@ LL | #![link()]
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
warning: attribute should be applied to a function or static
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1
|
LL | #![link_section = "1800"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not a function or static
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
warning: attribute should be applied to a function definition
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1
|
@@ -411,6 +403,14 @@ LL | #![link_name = "1900"]
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
warning: attribute should be applied to a function or static
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1
|
LL | #![link_section = "1800"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not a function or static
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
warning: `#[must_use]` has no effect when applied to a module
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1
|
@@ -1,9 +1,12 @@
//! Test that Debug::fmt is called exactly once during formatting.
//!
//! This is a regression test for PR https://github.com/rust-lang/rust/pull/10715
//@ run-pass
//@ needs-threads
use std::cell::Cell;
use std::fmt;
use std::thread;
use std::{fmt, thread};
struct Foo(Cell<isize>);
@@ -1,16 +1,20 @@
//! Test that only usize can be used for indexing arrays and slices.
pub fn main() {
let v: Vec<isize> = vec![0, 1, 2, 3, 4, 5];
let s: String = "abcdef".to_string();
// Valid indexing with usize
v[3_usize];
v[3];
v[3u8]; //~ ERROR the type `[isize]` cannot be indexed by `u8`
v[3i8]; //~ ERROR the type `[isize]` cannot be indexed by `i8`
v[3u8]; //~ ERROR the type `[isize]` cannot be indexed by `u8`
v[3i8]; //~ ERROR the type `[isize]` cannot be indexed by `i8`
v[3u32]; //~ ERROR the type `[isize]` cannot be indexed by `u32`
v[3i32]; //~ ERROR the type `[isize]` cannot be indexed by `i32`
s.as_bytes()[3_usize];
s.as_bytes()[3];
s.as_bytes()[3u8]; //~ ERROR the type `[u8]` cannot be indexed by `u8`
s.as_bytes()[3i8]; //~ ERROR the type `[u8]` cannot be indexed by `i8`
s.as_bytes()[3u8]; //~ ERROR the type `[u8]` cannot be indexed by `u8`
s.as_bytes()[3i8]; //~ ERROR the type `[u8]` cannot be indexed by `i8`
s.as_bytes()[3u32]; //~ ERROR the type `[u8]` cannot be indexed by `u32`
s.as_bytes()[3i32]; //~ ERROR the type `[u8]` cannot be indexed by `i32`
}
@@ -1,5 +1,5 @@
error[E0277]: the type `[isize]` cannot be indexed by `u8`
--> $DIR/integral-indexing.rs:6:7
--> $DIR/indexing-integral-types.rs:10:7
|
LL | v[3u8];
| ^^^ slice indices are of type `usize` or ranges of `usize`
@@ -11,7 +11,7 @@ LL | v[3u8];
= note: required for `Vec<isize>` to implement `Index<u8>`
error[E0277]: the type `[isize]` cannot be indexed by `i8`
--> $DIR/integral-indexing.rs:7:7
--> $DIR/indexing-integral-types.rs:11:7
|
LL | v[3i8];
| ^^^ slice indices are of type `usize` or ranges of `usize`
@@ -23,7 +23,7 @@ LL | v[3i8];
= note: required for `Vec<isize>` to implement `Index<i8>`
error[E0277]: the type `[isize]` cannot be indexed by `u32`
--> $DIR/integral-indexing.rs:8:7
--> $DIR/indexing-integral-types.rs:12:7
|
LL | v[3u32];
| ^^^^ slice indices are of type `usize` or ranges of `usize`
@@ -35,7 +35,7 @@ LL | v[3u32];
= note: required for `Vec<isize>` to implement `Index<u32>`
error[E0277]: the type `[isize]` cannot be indexed by `i32`
--> $DIR/integral-indexing.rs:9:7
--> $DIR/indexing-integral-types.rs:13:7
|
LL | v[3i32];
| ^^^^ slice indices are of type `usize` or ranges of `usize`
@@ -47,7 +47,7 @@ LL | v[3i32];
= note: required for `Vec<isize>` to implement `Index<i32>`
error[E0277]: the type `[u8]` cannot be indexed by `u8`
--> $DIR/integral-indexing.rs:12:18
--> $DIR/indexing-integral-types.rs:16:18
|
LL | s.as_bytes()[3u8];
| ^^^ slice indices are of type `usize` or ranges of `usize`
@@ -59,7 +59,7 @@ LL | s.as_bytes()[3u8];
= note: required for `[u8]` to implement `Index<u8>`
error[E0277]: the type `[u8]` cannot be indexed by `i8`
--> $DIR/integral-indexing.rs:13:18
--> $DIR/indexing-integral-types.rs:17:18
|
LL | s.as_bytes()[3i8];
| ^^^ slice indices are of type `usize` or ranges of `usize`
@@ -71,7 +71,7 @@ LL | s.as_bytes()[3i8];
= note: required for `[u8]` to implement `Index<i8>`
error[E0277]: the type `[u8]` cannot be indexed by `u32`
--> $DIR/integral-indexing.rs:14:18
--> $DIR/indexing-integral-types.rs:18:18
|
LL | s.as_bytes()[3u32];
| ^^^^ slice indices are of type `usize` or ranges of `usize`
@@ -83,7 +83,7 @@ LL | s.as_bytes()[3u32];
= note: required for `[u8]` to implement `Index<u32>`
error[E0277]: the type `[u8]` cannot be indexed by `i32`
--> $DIR/integral-indexing.rs:15:18
--> $DIR/indexing-integral-types.rs:19:18
|
LL | s.as_bytes()[3i32];
| ^^^^ slice indices are of type `usize` or ranges of `usize`
-24
View File
@@ -1,24 +0,0 @@
//@ run-pass
struct Foo;
impl Foo {
#![cfg(false)]
fn method(&self) -> bool { false }
}
impl Foo {
#![cfg(not(FALSE))]
// check that we don't eat attributes too eagerly.
#[cfg(false)]
fn method(&self) -> bool { false }
fn method(&self) -> bool { true }
}
pub fn main() {
assert!(Foo.method());
}
-10
View File
@@ -1,10 +0,0 @@
//@ run-pass
mod inner {
pub mod inner2 {
pub fn hello() { println!("hello, modular world"); }
}
pub fn hello() { inner2::hello(); }
}
pub fn main() { inner::hello(); inner::inner2::hello(); }
-11
View File
@@ -1,11 +0,0 @@
// see #9186
enum Bar<T> { What } //~ ERROR parameter `T` is never used
fn foo<T>() {
static a: Bar<T> = Bar::What;
//~^ ERROR can't use generic parameters from outer item
}
fn main() {
}
@@ -1,8 +1,9 @@
//! Test placement of functions and statics in custom link sections
//@ run-pass
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]
#![allow(non_upper_case_globals)]
#[cfg(not(target_vendor = "apple"))]
#[link_section = ".moretext"]
@@ -0,0 +1,18 @@
//! Test that static data from external crates can be imported on MSVC targets.
//!
//! On Windows MSVC targets, static data from external rlibs must be imported
//! through `__imp_<symbol>` stubs to ensure proper linking. Without this,
//! the linker would fail with "unresolved external symbol" errors when trying
//! to reference static data from another crate.
//!
//! Regression test for <https://github.com/rust-lang/rust/issues/26591>.
//! Fixed in <https://github.com/rust-lang/rust/pull/28646>.
//@ run-pass
//@ aux-build:msvc-static-data-import-lib.rs
extern crate msvc_static_data_import_lib;
fn main() {
println!("The answer is {}!", msvc_static_data_import_lib::FOO);
}
@@ -1,3 +1,7 @@
//! Test the `missing_debug_implementations` lint that warns about public types without Debug.
//!
//! See https://github.com/rust-lang/rust/issues/20855
//@ compile-flags: --crate-type lib
#![deny(missing_debug_implementations)]
#![allow(unused)]
@@ -10,7 +14,6 @@ pub enum A {} //~ ERROR type does not implement `Debug`
pub enum B {}
pub enum C {}
impl fmt::Debug for C {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
Ok(())
@@ -23,15 +26,14 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
pub struct Bar;
pub struct Baz;
impl fmt::Debug for Baz {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
// Private types should not trigger the lint
struct PrivateStruct;
enum PrivateEnum {}
#[derive(Debug)]
@@ -1,17 +1,17 @@
error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation
--> $DIR/missing_debug_impls.rs:7:1
--> $DIR/missing-debug-implementations-lint.rs:11:1
|
LL | pub enum A {}
| ^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/missing_debug_impls.rs:2:9
--> $DIR/missing-debug-implementations-lint.rs:6:9
|
LL | #![deny(missing_debug_implementations)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation
--> $DIR/missing_debug_impls.rs:20:1
--> $DIR/missing-debug-implementations-lint.rs:23:1
|
LL | pub struct Foo;
| ^^^^^^^^^^^^^^^
@@ -102,4 +102,10 @@ pub fn no_mangle_test() {}
#[used] //~ ERROR unused attribute
static FOO: u32 = 0;
#[link_section = ".text"]
//~^ ERROR unused attribute
//~| WARN this was previously accepted
#[link_section = ".bss"]
pub extern "C" fn example() {}
fn main() {}
@@ -289,5 +289,18 @@ note: attribute also specified here
LL | #[used]
| ^^^^^^^
error: aborting due to 23 previous errors
error: unused attribute
--> $DIR/unused-attr-duplicate.rs:105:1
|
LL | #[link_section = ".text"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:108:1
|
LL | #[link_section = ".bss"]
| ^^^^^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
error: aborting due to 24 previous errors
-7
View File
@@ -1,7 +0,0 @@
//@ run-pass
pub fn main() {
if false {
println!("{}", "foobar");
}
}
@@ -1,21 +0,0 @@
//@ run-pass
#![allow(non_camel_case_types)]
#![allow(dead_code)]
#[derive(Debug)]
enum foo {
a(usize),
b(String),
c,
}
#[derive(Debug)]
enum bar {
d, e, f
}
pub fn main() {
assert_eq!("a(22)".to_string(), format!("{:?}", foo::a(22)));
assert_eq!("c".to_string(), format!("{:?}", foo::c));
assert_eq!("d".to_string(), format!("{:?}", bar::d));
}
-6
View File
@@ -1,6 +0,0 @@
//@ should-fail
// this test ensures that when we forget to use
// any `//~ ERROR` comments whatsoever, that the test doesn't succeed
fn main() {}
-10
View File
@@ -1,10 +0,0 @@
//@ compile-flags: -Zmaximal-hir-to-mir-coverage
//@ run-pass
// Just making sure this flag is accepted and doesn't crash the compiler
fn main() {
let x = 1;
let y = x + 1;
println!("{y}");
}
-9
View File
@@ -1,9 +0,0 @@
trait Tr: ?Sized {}
//~^ ERROR `?Trait` is not permitted in supertraits
type A1 = dyn Tr + (?Sized);
//~^ ERROR `?Trait` is not permitted in trait object types
type A2 = dyn for<'a> Tr + (?Sized);
//~^ ERROR `?Trait` is not permitted in trait object types
fn main() {}
@@ -1,8 +0,0 @@
fn bar() {}
fn foo(x: i32) -> u32 {
0
}
fn main() {
let b: fn() -> u32 = bar; //~ ERROR mismatched types [E0308]
let f: fn(i32) = foo; //~ ERROR mismatched types [E0308]
}
@@ -0,0 +1,16 @@
//! This test checks that when there's a type mismatch between a function item and
//! a function pointer, the error message focuses on the actual type difference
//! (return types, argument types) rather than the confusing "pointer vs item" distinction.
//!
//! See https://github.com/rust-lang/rust/issues/127263
fn bar() {}
fn foo(x: i32) -> u32 {
0
}
fn main() {
let b: fn() -> u32 = bar; //~ ERROR mismatched types [E0308]
let f: fn(i32) = foo; //~ ERROR mismatched types [E0308]
}

Some files were not shown because too many files have changed in this diff Show More