Auto merge of #95215 - Dylan-DPC:rollup-l9f9t7l, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #95188 ([`macro-metavar-expr`] Fix generated tokens hygiene) - #95196 (rename LocalState::Uninitialized to Unallocated) - #95197 (Suggest constraining param for unary ops when missing trait impl) - #95200 (Cancel a not emitted error after parsing const generic args) - #95207 (update Termination trait docs) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
5f37001055
10 changed files with 107 additions and 26 deletions
|
@ -177,11 +177,10 @@ pub struct LocalState<'tcx, Tag: Provenance = AllocId> {
|
||||||
pub enum LocalValue<Tag: Provenance = AllocId> {
|
pub enum LocalValue<Tag: Provenance = AllocId> {
|
||||||
/// This local is not currently alive, and cannot be used at all.
|
/// This local is not currently alive, and cannot be used at all.
|
||||||
Dead,
|
Dead,
|
||||||
/// This local is alive but not yet initialized. It can be written to
|
/// This local is alive but not yet allocated. It cannot be read from or have its address taken,
|
||||||
/// but not read from or its address taken. Locals get initialized on
|
/// and will be allocated on the first write. This is to support unsized locals, where we cannot
|
||||||
/// first write because for unsized locals, we do not know their size
|
/// know their size in advance.
|
||||||
/// before that.
|
Unallocated,
|
||||||
Uninitialized,
|
|
||||||
/// A normal, live local.
|
/// A normal, live local.
|
||||||
/// Mostly for convenience, we re-use the `Operand` type here.
|
/// Mostly for convenience, we re-use the `Operand` type here.
|
||||||
/// This is an optimization over just always having a pointer here;
|
/// This is an optimization over just always having a pointer here;
|
||||||
|
@ -198,7 +197,7 @@ impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> {
|
||||||
pub fn access(&self) -> InterpResult<'tcx, Operand<Tag>> {
|
pub fn access(&self) -> InterpResult<'tcx, Operand<Tag>> {
|
||||||
match self.value {
|
match self.value {
|
||||||
LocalValue::Dead => throw_ub!(DeadLocal),
|
LocalValue::Dead => throw_ub!(DeadLocal),
|
||||||
LocalValue::Uninitialized => {
|
LocalValue::Unallocated => {
|
||||||
bug!("The type checker should prevent reading from a never-written local")
|
bug!("The type checker should prevent reading from a never-written local")
|
||||||
}
|
}
|
||||||
LocalValue::Live(val) => Ok(val),
|
LocalValue::Live(val) => Ok(val),
|
||||||
|
@ -216,8 +215,7 @@ impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> {
|
||||||
match self.value {
|
match self.value {
|
||||||
LocalValue::Dead => throw_ub!(DeadLocal),
|
LocalValue::Dead => throw_ub!(DeadLocal),
|
||||||
LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)),
|
LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)),
|
||||||
ref mut
|
ref mut local @ (LocalValue::Live(Operand::Immediate(_)) | LocalValue::Unallocated) => {
|
||||||
local @ (LocalValue::Live(Operand::Immediate(_)) | LocalValue::Uninitialized) => {
|
|
||||||
Ok(Ok(local))
|
Ok(Ok(local))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -752,8 +750,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locals are initially uninitialized.
|
// Locals are initially unallocated.
|
||||||
let dummy = LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) };
|
let dummy = LocalState { value: LocalValue::Unallocated, layout: Cell::new(None) };
|
||||||
let mut locals = IndexVec::from_elem(dummy, &body.local_decls);
|
let mut locals = IndexVec::from_elem(dummy, &body.local_decls);
|
||||||
|
|
||||||
// Now mark those locals as dead that we do not want to initialize
|
// Now mark those locals as dead that we do not want to initialize
|
||||||
|
@ -921,7 +919,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
|
assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
|
||||||
trace!("{:?} is now live", local);
|
trace!("{:?} is now live", local);
|
||||||
|
|
||||||
let local_val = LocalValue::Uninitialized;
|
let local_val = LocalValue::Unallocated;
|
||||||
// StorageLive expects the local to be dead, and marks it live.
|
// StorageLive expects the local to be dead, and marks it live.
|
||||||
let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
|
let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
|
||||||
if !matches!(old, LocalValue::Dead) {
|
if !matches!(old, LocalValue::Dead) {
|
||||||
|
@ -1025,7 +1023,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug
|
||||||
|
|
||||||
match self.ecx.stack()[frame].locals[local].value {
|
match self.ecx.stack()[frame].locals[local].value {
|
||||||
LocalValue::Dead => write!(fmt, " is dead")?,
|
LocalValue::Dead => write!(fmt, " is dead")?,
|
||||||
LocalValue::Uninitialized => write!(fmt, " is uninitialized")?,
|
LocalValue::Unallocated => write!(fmt, " is unallocated")?,
|
||||||
LocalValue::Live(Operand::Indirect(mplace)) => {
|
LocalValue::Live(Operand::Indirect(mplace)) => {
|
||||||
write!(
|
write!(
|
||||||
fmt,
|
fmt,
|
||||||
|
|
|
@ -257,7 +257,7 @@ pub(super) fn transcribe<'a>(
|
||||||
|
|
||||||
// Replace meta-variable expressions with the result of their expansion.
|
// Replace meta-variable expressions with the result of their expansion.
|
||||||
mbe::TokenTree::MetaVarExpr(sp, expr) => {
|
mbe::TokenTree::MetaVarExpr(sp, expr) => {
|
||||||
transcribe_metavar_expr(cx, expr, interp, &repeats, &mut result, &sp)?;
|
transcribe_metavar_expr(cx, expr, interp, &mut marker, &repeats, &mut result, &sp)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are entering a new delimiter, we push its contents to the `stack` to be
|
// If we are entering a new delimiter, we push its contents to the `stack` to be
|
||||||
|
@ -513,17 +513,23 @@ fn transcribe_metavar_expr<'a>(
|
||||||
cx: &ExtCtxt<'a>,
|
cx: &ExtCtxt<'a>,
|
||||||
expr: MetaVarExpr,
|
expr: MetaVarExpr,
|
||||||
interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
|
interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
|
||||||
|
marker: &mut Marker,
|
||||||
repeats: &[(usize, usize)],
|
repeats: &[(usize, usize)],
|
||||||
result: &mut Vec<TreeAndSpacing>,
|
result: &mut Vec<TreeAndSpacing>,
|
||||||
sp: &DelimSpan,
|
sp: &DelimSpan,
|
||||||
) -> PResult<'a, ()> {
|
) -> PResult<'a, ()> {
|
||||||
|
let mut visited_span = || {
|
||||||
|
let mut span = sp.entire();
|
||||||
|
marker.visit_span(&mut span);
|
||||||
|
span
|
||||||
|
};
|
||||||
match expr {
|
match expr {
|
||||||
MetaVarExpr::Count(original_ident, depth_opt) => {
|
MetaVarExpr::Count(original_ident, depth_opt) => {
|
||||||
let matched = matched_from_ident(cx, original_ident, interp)?;
|
let matched = matched_from_ident(cx, original_ident, interp)?;
|
||||||
let count = count_repetitions(cx, depth_opt, matched, &repeats, sp)?;
|
let count = count_repetitions(cx, depth_opt, matched, &repeats, sp)?;
|
||||||
let tt = TokenTree::token(
|
let tt = TokenTree::token(
|
||||||
TokenKind::lit(token::Integer, sym::integer(count), None),
|
TokenKind::lit(token::Integer, sym::integer(count), None),
|
||||||
sp.entire(),
|
visited_span(),
|
||||||
);
|
);
|
||||||
result.push(tt.into());
|
result.push(tt.into());
|
||||||
}
|
}
|
||||||
|
@ -536,7 +542,7 @@ fn transcribe_metavar_expr<'a>(
|
||||||
result.push(
|
result.push(
|
||||||
TokenTree::token(
|
TokenTree::token(
|
||||||
TokenKind::lit(token::Integer, sym::integer(*index), None),
|
TokenKind::lit(token::Integer, sym::integer(*index), None),
|
||||||
sp.entire(),
|
visited_span(),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
@ -548,7 +554,7 @@ fn transcribe_metavar_expr<'a>(
|
||||||
result.push(
|
result.push(
|
||||||
TokenTree::token(
|
TokenTree::token(
|
||||||
TokenKind::lit(token::Integer, sym::integer(*length), None),
|
TokenKind::lit(token::Integer, sym::integer(*length), None),
|
||||||
sp.entire(),
|
visited_span(),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -244,8 +244,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
|
||||||
) -> InterpResult<'tcx, InterpOperand<Self::PointerTag>> {
|
) -> InterpResult<'tcx, InterpOperand<Self::PointerTag>> {
|
||||||
let l = &frame.locals[local];
|
let l = &frame.locals[local];
|
||||||
|
|
||||||
if l.value == LocalValue::Uninitialized {
|
if l.value == LocalValue::Unallocated {
|
||||||
throw_machine_stop_str!("tried to access an uninitialized local")
|
throw_machine_stop_str!("tried to access an unallocated local")
|
||||||
}
|
}
|
||||||
|
|
||||||
l.access()
|
l.access()
|
||||||
|
@ -442,7 +442,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
/// but not reading from them anymore.
|
/// but not reading from them anymore.
|
||||||
fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) {
|
fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) {
|
||||||
ecx.frame_mut().locals[local] =
|
ecx.frame_mut().locals[local] =
|
||||||
LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) };
|
LocalState { value: LocalValue::Unallocated, layout: Cell::new(None) };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> {
|
fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> {
|
||||||
|
@ -1147,7 +1147,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
||||||
let frame = self.ecx.frame_mut();
|
let frame = self.ecx.frame_mut();
|
||||||
frame.locals[local].value =
|
frame.locals[local].value =
|
||||||
if let StatementKind::StorageLive(_) = statement.kind {
|
if let StatementKind::StorageLive(_) = statement.kind {
|
||||||
LocalValue::Uninitialized
|
LocalValue::Unallocated
|
||||||
} else {
|
} else {
|
||||||
LocalValue::Dead
|
LocalValue::Dead
|
||||||
};
|
};
|
||||||
|
|
|
@ -630,11 +630,15 @@ impl<'a> Parser<'a> {
|
||||||
Ok(ty) => GenericArg::Type(ty),
|
Ok(ty) => GenericArg::Type(ty),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if is_const_fn {
|
if is_const_fn {
|
||||||
if let Ok(expr) = (*snapshot).parse_expr_res(Restrictions::CONST_EXPR, None)
|
match (*snapshot).parse_expr_res(Restrictions::CONST_EXPR, None) {
|
||||||
{
|
Ok(expr) => {
|
||||||
self.restore_snapshot(snapshot);
|
self.restore_snapshot(snapshot);
|
||||||
return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span)));
|
return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span)));
|
||||||
}
|
}
|
||||||
|
Err(err) => {
|
||||||
|
err.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Try to recover from possible `const` arg without braces.
|
// Try to recover from possible `const` arg without braces.
|
||||||
return self.recover_const_arg(start, err).map(Some);
|
return self.recover_const_arg(start, err).map(Some);
|
||||||
|
|
|
@ -672,6 +672,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
ex.span,
|
ex.span,
|
||||||
format!("cannot apply unary operator `{}`", op.as_str()),
|
format!("cannot apply unary operator `{}`", op.as_str()),
|
||||||
);
|
);
|
||||||
|
let missing_trait = match op {
|
||||||
|
hir::UnOp::Deref => unreachable!("check unary op `-` or `!` only"),
|
||||||
|
hir::UnOp::Not => "std::ops::Not",
|
||||||
|
hir::UnOp::Neg => "std::ops::Neg",
|
||||||
|
};
|
||||||
|
let mut visitor = TypeParamVisitor(vec![]);
|
||||||
|
visitor.visit_ty(operand_ty);
|
||||||
|
if let [ty] = &visitor.0[..] {
|
||||||
|
if let ty::Param(p) = *operand_ty.kind() {
|
||||||
|
suggest_constraining_param(
|
||||||
|
self.tcx,
|
||||||
|
self.body_id,
|
||||||
|
&mut err,
|
||||||
|
*ty,
|
||||||
|
operand_ty,
|
||||||
|
missing_trait,
|
||||||
|
p,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let sp = self.tcx.sess.source_map().start_point(ex.span);
|
let sp = self.tcx.sess.source_map().start_point(ex.span);
|
||||||
if let Some(sp) =
|
if let Some(sp) =
|
||||||
|
|
|
@ -2030,6 +2030,11 @@ pub fn id() -> u32 {
|
||||||
///
|
///
|
||||||
/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate
|
/// The default implementations are returning `libc::EXIT_SUCCESS` to indicate
|
||||||
/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned.
|
/// a successful execution. In case of a failure, `libc::EXIT_FAILURE` is returned.
|
||||||
|
///
|
||||||
|
/// Because different runtimes have different specifications on the return value
|
||||||
|
/// of the `main` function, this trait is likely to be available only on
|
||||||
|
/// standard library's runtime for convenience. Other runtimes are not required
|
||||||
|
/// to provide similar functionality.
|
||||||
#[cfg_attr(not(test), lang = "termination")]
|
#[cfg_attr(not(test), lang = "termination")]
|
||||||
#[unstable(feature = "termination_trait_lib", issue = "43301")]
|
#[unstable(feature = "termination_trait_lib", issue = "43301")]
|
||||||
#[rustc_on_unimplemented(
|
#[rustc_on_unimplemented(
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
// #95163
|
||||||
|
fn return_ty() -> impl Into<<() as Reexported;
|
||||||
|
//~^ ERROR expected one of `(`, `::`, `<`, or `>`, found `;`
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,8 @@
|
||||||
|
error: expected one of `(`, `::`, `<`, or `>`, found `;`
|
||||||
|
--> $DIR/ice-const-generic-function-return-ty.rs:2:46
|
||||||
|
|
|
||||||
|
LL | fn return_ty() -> impl Into<<() as Reexported;
|
||||||
|
| ^ expected one of `(`, `::`, `<`, or `>`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -8,3 +8,9 @@ fn foo<T>(x: T, y: T) {
|
||||||
fn bar<T>(x: T) {
|
fn bar<T>(x: T) {
|
||||||
x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T`
|
x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn baz<T>(x: T) {
|
||||||
|
let y = -x; //~ ERROR cannot apply unary operator `-` to type `T`
|
||||||
|
let y = !x; //~ ERROR cannot apply unary operator `!` to type `T`
|
||||||
|
let y = *x; //~ ERROR type `T` cannot be dereferenced
|
||||||
|
}
|
||||||
|
|
|
@ -24,7 +24,35 @@ help: consider restricting type parameter `T`
|
||||||
LL | fn bar<T: std::ops::AddAssign>(x: T) {
|
LL | fn bar<T: std::ops::AddAssign>(x: T) {
|
||||||
| +++++++++++++++++++++
|
| +++++++++++++++++++++
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error[E0600]: cannot apply unary operator `-` to type `T`
|
||||||
|
--> $DIR/missing_trait_impl.rs:13:13
|
||||||
|
|
|
||||||
|
LL | let y = -x;
|
||||||
|
| ^^ cannot apply unary operator `-`
|
||||||
|
|
|
||||||
|
help: consider restricting type parameter `T`
|
||||||
|
|
|
||||||
|
LL | fn baz<T: std::ops::Neg<Output = T>>(x: T) {
|
||||||
|
| +++++++++++++++++++++++++++
|
||||||
|
|
||||||
Some errors have detailed explanations: E0368, E0369.
|
error[E0600]: cannot apply unary operator `!` to type `T`
|
||||||
|
--> $DIR/missing_trait_impl.rs:14:13
|
||||||
|
|
|
||||||
|
LL | let y = !x;
|
||||||
|
| ^^ cannot apply unary operator `!`
|
||||||
|
|
|
||||||
|
help: consider restricting type parameter `T`
|
||||||
|
|
|
||||||
|
LL | fn baz<T: std::ops::Not<Output = T>>(x: T) {
|
||||||
|
| +++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
error[E0614]: type `T` cannot be dereferenced
|
||||||
|
--> $DIR/missing_trait_impl.rs:15:13
|
||||||
|
|
|
||||||
|
LL | let y = *x;
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0368, E0369, E0600, E0614.
|
||||||
For more information about an error, try `rustc --explain E0368`.
|
For more information about an error, try `rustc --explain E0368`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue