mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #97860 - Dylan-DPC:rollup-t3vxos8, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #97595 (Remove unwrap from get_vtable) - #97597 (Preserve unused pointer to address casts) - #97819 (Recover `import` instead of `use` in item) - #97823 (Recover missing comma after match arm) - #97851 (Use repr(C) when depending on struct layout in ptr tests) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e45d9973b2
@ -2605,9 +2605,34 @@ pub enum Rvalue<'tcx> {
|
|||||||
static_assert_size!(Rvalue<'_>, 40);
|
static_assert_size!(Rvalue<'_>, 40);
|
||||||
|
|
||||||
impl<'tcx> Rvalue<'tcx> {
|
impl<'tcx> Rvalue<'tcx> {
|
||||||
|
/// Returns true if rvalue can be safely removed when the result is unused.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_pointer_int_cast(&self) -> bool {
|
pub fn is_safe_to_remove(&self) -> bool {
|
||||||
matches!(self, Rvalue::Cast(CastKind::PointerExposeAddress, _, _))
|
match self {
|
||||||
|
// Pointer to int casts may be side-effects due to exposing the provenance.
|
||||||
|
// While the model is undecided, we should be conservative. See
|
||||||
|
// <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
|
||||||
|
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
|
||||||
|
|
||||||
|
Rvalue::Use(_)
|
||||||
|
| Rvalue::Repeat(_, _)
|
||||||
|
| Rvalue::Ref(_, _, _)
|
||||||
|
| Rvalue::ThreadLocalRef(_)
|
||||||
|
| Rvalue::AddressOf(_, _)
|
||||||
|
| Rvalue::Len(_)
|
||||||
|
| Rvalue::Cast(
|
||||||
|
CastKind::Misc | CastKind::Pointer(_) | CastKind::PointerFromExposedAddress,
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
)
|
||||||
|
| Rvalue::BinaryOp(_, _)
|
||||||
|
| Rvalue::CheckedBinaryOp(_, _)
|
||||||
|
| Rvalue::NullaryOp(_, _)
|
||||||
|
| Rvalue::UnaryOp(_, _)
|
||||||
|
| Rvalue::Discriminant(_)
|
||||||
|
| Rvalue::Aggregate(_, _)
|
||||||
|
| Rvalue::ShallowInitBox(_, _) => true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,13 +244,10 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
|
|||||||
// Compute the place that we are storing to, if any
|
// Compute the place that we are storing to, if any
|
||||||
let destination = match &statement.kind {
|
let destination = match &statement.kind {
|
||||||
StatementKind::Assign(assign) => {
|
StatementKind::Assign(assign) => {
|
||||||
if assign.1.is_pointer_int_cast() {
|
if assign.1.is_safe_to_remove() {
|
||||||
// Pointer to int casts may be side-effects due to exposing the provenance.
|
|
||||||
// While the model is undecided, we should be conservative. See
|
|
||||||
// <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(assign.0)
|
Some(assign.0)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
|
StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
|
||||||
|
@ -34,7 +34,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
|
|||||||
for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() {
|
for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() {
|
||||||
let loc = Location { block: bb, statement_index };
|
let loc = Location { block: bb, statement_index };
|
||||||
if let StatementKind::Assign(assign) = &statement.kind {
|
if let StatementKind::Assign(assign) = &statement.kind {
|
||||||
if assign.1.is_pointer_int_cast() {
|
if !assign.1.is_safe_to_remove() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -494,8 +494,12 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
|
|||||||
StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {}
|
StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {}
|
||||||
|
|
||||||
StatementKind::Assign(box (ref place, ref rvalue)) => {
|
StatementKind::Assign(box (ref place, ref rvalue)) => {
|
||||||
|
if rvalue.is_safe_to_remove() {
|
||||||
self.visit_lhs(place, location);
|
self.visit_lhs(place, location);
|
||||||
self.visit_rvalue(rvalue, location);
|
self.visit_rvalue(rvalue, location);
|
||||||
|
} else {
|
||||||
|
self.super_statement(statement, location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StatementKind::SetDiscriminant { ref place, variant_index: _ }
|
StatementKind::SetDiscriminant { ref place, variant_index: _ }
|
||||||
|
@ -2718,13 +2718,12 @@ impl<'a> Parser<'a> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)])
|
this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)])
|
||||||
.map_err(|mut err| {
|
.or_else(|mut err| {
|
||||||
match (sm.span_to_lines(expr.span), sm.span_to_lines(arm_start_span)) {
|
if this.token == token::FatArrow {
|
||||||
(Ok(ref expr_lines), Ok(ref arm_start_lines))
|
if let Ok(expr_lines) = sm.span_to_lines(expr.span)
|
||||||
if arm_start_lines.lines[0].end_col
|
&& let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span)
|
||||||
== expr_lines.lines[0].end_col
|
&& arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col
|
||||||
&& expr_lines.lines.len() == 2
|
&& expr_lines.lines.len() == 2
|
||||||
&& this.token == token::FatArrow =>
|
|
||||||
{
|
{
|
||||||
// We check whether there's any trailing code in the parse span,
|
// We check whether there's any trailing code in the parse span,
|
||||||
// if there isn't, we very likely have the following:
|
// if there isn't, we very likely have the following:
|
||||||
@ -2743,15 +2742,41 @@ impl<'a> Parser<'a> {
|
|||||||
",".to_owned(),
|
",".to_owned(),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
|
return Err(err);
|
||||||
}
|
}
|
||||||
_ => {
|
} else {
|
||||||
err.span_label(
|
// FIXME(compiler-errors): We could also recover `; PAT =>` here
|
||||||
arrow_span,
|
|
||||||
"while parsing the `match` arm starting here",
|
// Try to parse a following `PAT =>`, if successful
|
||||||
);
|
// then we should recover.
|
||||||
|
let mut snapshot = this.create_snapshot_for_diagnostic();
|
||||||
|
let pattern_follows = snapshot
|
||||||
|
.parse_pat_allow_top_alt(
|
||||||
|
None,
|
||||||
|
RecoverComma::Yes,
|
||||||
|
RecoverColon::Yes,
|
||||||
|
CommaRecoveryMode::EitherTupleOrPipe,
|
||||||
|
)
|
||||||
|
.map_err(|err| err.cancel())
|
||||||
|
.is_ok();
|
||||||
|
if pattern_follows && snapshot.check(&TokenKind::FatArrow) {
|
||||||
|
err.cancel();
|
||||||
|
this.struct_span_err(
|
||||||
|
hi.shrink_to_hi(),
|
||||||
|
"expected `,` following `match` arm",
|
||||||
|
)
|
||||||
|
.span_suggestion(
|
||||||
|
hi.shrink_to_hi(),
|
||||||
|
"missing a comma here to end this `match` arm",
|
||||||
|
",".to_owned(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
return Ok(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err
|
err.span_label(arrow_span, "while parsing the `match` arm starting here");
|
||||||
|
Err(err)
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
this.eat(&token::Comma);
|
this.eat(&token::Comma);
|
||||||
|
@ -204,25 +204,7 @@ impl<'a> Parser<'a> {
|
|||||||
let mut def = || mem::replace(def, Defaultness::Final);
|
let mut def = || mem::replace(def, Defaultness::Final);
|
||||||
|
|
||||||
let info = if self.eat_keyword(kw::Use) {
|
let info = if self.eat_keyword(kw::Use) {
|
||||||
// USE ITEM
|
self.parse_use_item()?
|
||||||
let tree = self.parse_use_tree()?;
|
|
||||||
|
|
||||||
// If wildcard or glob-like brace syntax doesn't have `;`,
|
|
||||||
// the user may not know `*` or `{}` should be the last.
|
|
||||||
if let Err(mut e) = self.expect_semi() {
|
|
||||||
match tree.kind {
|
|
||||||
UseTreeKind::Glob => {
|
|
||||||
e.note("the wildcard token must be last on the path");
|
|
||||||
}
|
|
||||||
UseTreeKind::Nested(..) => {
|
|
||||||
e.note("glob-like brace syntax must be last on the path");
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
(Ident::empty(), ItemKind::Use(tree))
|
|
||||||
} else if self.check_fn_front_matter(def_final) {
|
} else if self.check_fn_front_matter(def_final) {
|
||||||
// FUNCTION ITEM
|
// FUNCTION ITEM
|
||||||
let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis)?;
|
let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis)?;
|
||||||
@ -288,7 +270,12 @@ impl<'a> Parser<'a> {
|
|||||||
} else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {
|
} else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {
|
||||||
// MACRO_RULES ITEM
|
// MACRO_RULES ITEM
|
||||||
self.parse_item_macro_rules(vis, has_bang)?
|
self.parse_item_macro_rules(vis, has_bang)?
|
||||||
} else if vis.kind.is_pub() && self.isnt_macro_invocation() {
|
} else if self.isnt_macro_invocation()
|
||||||
|
&& (self.token.is_ident_named(Symbol::intern("import"))
|
||||||
|
|| self.token.is_ident_named(Symbol::intern("using")))
|
||||||
|
{
|
||||||
|
return self.recover_import_as_use();
|
||||||
|
} else if self.isnt_macro_invocation() && vis.kind.is_pub() {
|
||||||
self.recover_missing_kw_before_item()?;
|
self.recover_missing_kw_before_item()?;
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
} else if macros_allowed && self.check_path() {
|
} else if macros_allowed && self.check_path() {
|
||||||
@ -300,6 +287,48 @@ impl<'a> Parser<'a> {
|
|||||||
Ok(Some(info))
|
Ok(Some(info))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn recover_import_as_use(&mut self) -> PResult<'a, Option<(Ident, ItemKind)>> {
|
||||||
|
let span = self.token.span;
|
||||||
|
let token_name = super::token_descr(&self.token);
|
||||||
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
|
self.bump();
|
||||||
|
match self.parse_use_item() {
|
||||||
|
Ok(u) => {
|
||||||
|
self.struct_span_err(span, format!("expected item, found {token_name}"))
|
||||||
|
.span_suggestion_short(
|
||||||
|
span,
|
||||||
|
"items are imported using the `use` keyword",
|
||||||
|
"use".to_owned(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
Ok(Some(u))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
e.cancel();
|
||||||
|
self.restore_snapshot(snapshot);
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_use_item(&mut self) -> PResult<'a, (Ident, ItemKind)> {
|
||||||
|
let tree = self.parse_use_tree()?;
|
||||||
|
if let Err(mut e) = self.expect_semi() {
|
||||||
|
match tree.kind {
|
||||||
|
UseTreeKind::Glob => {
|
||||||
|
e.note("the wildcard token must be last on the path");
|
||||||
|
}
|
||||||
|
UseTreeKind::Nested(..) => {
|
||||||
|
e.note("glob-like brace syntax must be last on the path");
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
Ok((Ident::empty(), ItemKind::Use(tree)))
|
||||||
|
}
|
||||||
|
|
||||||
/// When parsing a statement, would the start of a path be an item?
|
/// When parsing a statement, would the start of a path be an item?
|
||||||
pub(super) fn is_path_start_item(&mut self) -> bool {
|
pub(super) fn is_path_start_item(&mut self) -> bool {
|
||||||
self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
|
self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
|
||||||
|
@ -304,22 +304,24 @@ pub fn get_vtable_index_of_object_method<'tcx, N>(
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
object: &super::ImplSourceObjectData<'tcx, N>,
|
object: &super::ImplSourceObjectData<'tcx, N>,
|
||||||
method_def_id: DefId,
|
method_def_id: DefId,
|
||||||
) -> usize {
|
) -> Option<usize> {
|
||||||
let existential_trait_ref = object
|
let existential_trait_ref = object
|
||||||
.upcast_trait_ref
|
.upcast_trait_ref
|
||||||
.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
|
.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
|
||||||
let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
|
let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
|
||||||
|
|
||||||
// Count number of methods preceding the one we are selecting and
|
// Count number of methods preceding the one we are selecting and
|
||||||
// add them to the total offset.
|
// add them to the total offset.
|
||||||
let index = tcx
|
if let Some(index) = tcx
|
||||||
.own_existential_vtable_entries(existential_trait_ref)
|
.own_existential_vtable_entries(existential_trait_ref)
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
.position(|def_id| def_id == method_def_id)
|
.position(|def_id| def_id == method_def_id)
|
||||||
.unwrap_or_else(|| {
|
{
|
||||||
bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id);
|
Some(object.vtable_base + index)
|
||||||
});
|
} else {
|
||||||
object.vtable_base + index
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn closure_trait_ref_and_return_type<'tcx>(
|
pub fn closure_trait_ref_and_return_type<'tcx>(
|
||||||
|
@ -349,11 +349,15 @@ fn resolve_associated_item<'tcx>(
|
|||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
traits::ImplSource::Object(ref data) => {
|
traits::ImplSource::Object(ref data) => {
|
||||||
let index = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id);
|
if let Some(index) = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id)
|
||||||
|
{
|
||||||
Some(Instance {
|
Some(Instance {
|
||||||
def: ty::InstanceDef::Virtual(trait_item_id, index),
|
def: ty::InstanceDef::Virtual(trait_item_id, index),
|
||||||
substs: rcvr_substs,
|
substs: rcvr_substs,
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
traits::ImplSource::Builtin(..) => {
|
traits::ImplSource::Builtin(..) => {
|
||||||
if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
|
if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
|
||||||
|
@ -19,6 +19,7 @@ fn test_const_from_raw_parts() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
#[repr(C)]
|
||||||
struct Pair {
|
struct Pair {
|
||||||
fst: isize,
|
fst: isize,
|
||||||
snd: isize,
|
snd: isize,
|
||||||
|
@ -62,6 +62,12 @@ fn t4() -> u32 {
|
|||||||
unsafe { X + 1 }
|
unsafe { X + 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EMIT_MIR simplify_locals.expose_addr.SimplifyLocals.diff
|
||||||
|
fn expose_addr(p: *const usize) {
|
||||||
|
// Used pointer to address cast. Has a side effect of exposing the provenance.
|
||||||
|
p as usize;
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
c();
|
c();
|
||||||
d1();
|
d1();
|
||||||
@ -71,4 +77,5 @@ fn main() {
|
|||||||
t2();
|
t2();
|
||||||
t3();
|
t3();
|
||||||
t4();
|
t4();
|
||||||
|
expose_addr(&0);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
- // MIR for `expose_addr` before SimplifyLocals
|
||||||
|
+ // MIR for `expose_addr` after SimplifyLocals
|
||||||
|
|
||||||
|
fn expose_addr(_1: *const usize) -> () {
|
||||||
|
debug p => _1; // in scope 0 at $DIR/simplify-locals.rs:66:16: 66:17
|
||||||
|
let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:66:33: 66:33
|
||||||
|
let _2: usize; // in scope 0 at $DIR/simplify-locals.rs:68:5: 68:15
|
||||||
|
let mut _3: *const usize; // in scope 0 at $DIR/simplify-locals.rs:68:5: 68:6
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
StorageLive(_2); // scope 0 at $DIR/simplify-locals.rs:68:5: 68:15
|
||||||
|
StorageLive(_3); // scope 0 at $DIR/simplify-locals.rs:68:5: 68:6
|
||||||
|
_3 = _1; // scope 0 at $DIR/simplify-locals.rs:68:5: 68:6
|
||||||
|
_2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/simplify-locals.rs:68:5: 68:15
|
||||||
|
StorageDead(_3); // scope 0 at $DIR/simplify-locals.rs:68:14: 68:15
|
||||||
|
StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:68:15: 68:16
|
||||||
|
_0 = const (); // scope 0 at $DIR/simplify-locals.rs:66:33: 69:2
|
||||||
|
return; // scope 0 at $DIR/simplify-locals.rs:69:2: 69:2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
15
src/test/ui/did_you_mean/use_instead_of_import.fixed
Normal file
15
src/test/ui/did_you_mean/use_instead_of_import.fixed
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
//~^ ERROR expected item, found `import`
|
||||||
|
io::Write,
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use std::io;
|
||||||
|
//~^ ERROR expected item, found `using`
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = Rc::new(1);
|
||||||
|
let _ = write!(io::stdout(), "{:?}", x);
|
||||||
|
}
|
15
src/test/ui/did_you_mean/use_instead_of_import.rs
Normal file
15
src/test/ui/did_you_mean/use_instead_of_import.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
import std::{
|
||||||
|
//~^ ERROR expected item, found `import`
|
||||||
|
io::Write,
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub using std::io;
|
||||||
|
//~^ ERROR expected item, found `using`
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = Rc::new(1);
|
||||||
|
let _ = write!(io::stdout(), "{:?}", x);
|
||||||
|
}
|
14
src/test/ui/did_you_mean/use_instead_of_import.stderr
Normal file
14
src/test/ui/did_you_mean/use_instead_of_import.stderr
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
error: expected item, found `import`
|
||||||
|
--> $DIR/use_instead_of_import.rs:3:1
|
||||||
|
|
|
||||||
|
LL | import std::{
|
||||||
|
| ^^^^^^ help: items are imported using the `use` keyword
|
||||||
|
|
||||||
|
error: expected item, found `using`
|
||||||
|
--> $DIR/use_instead_of_import.rs:9:5
|
||||||
|
|
|
||||||
|
LL | pub using std::io;
|
||||||
|
| ^^^^^ help: items are imported using the `use` keyword
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
@ -45,9 +45,9 @@ fn main() {
|
|||||||
15;
|
15;
|
||||||
}
|
}
|
||||||
match S::get(16) {
|
match S::get(16) {
|
||||||
Some(Val::Foo) => 17
|
Some(Val::Foo) => 17 //~ ERROR expected `,` following `match` arm
|
||||||
_ => 18, //~ ERROR expected one of
|
_ => 18,
|
||||||
}
|
};
|
||||||
match S::get(19) {
|
match S::get(19) {
|
||||||
Some(Val::Foo) =>
|
Some(Val::Foo) =>
|
||||||
20; //~ ERROR `match` arm body without braces
|
20; //~ ERROR `match` arm body without braces
|
||||||
|
@ -52,15 +52,11 @@ LL ~ { 14;
|
|||||||
LL ~ 15; }
|
LL ~ 15; }
|
||||||
|
|
|
|
||||||
|
|
||||||
error: expected one of `,`, `.`, `?`, `}`, or an operator, found reserved identifier `_`
|
error: expected `,` following `match` arm
|
||||||
--> $DIR/match-arm-without-braces.rs:49:9
|
--> $DIR/match-arm-without-braces.rs:48:29
|
||||||
|
|
|
|
||||||
LL | Some(Val::Foo) => 17
|
LL | Some(Val::Foo) => 17
|
||||||
| -- - expected one of `,`, `.`, `?`, `}`, or an operator
|
| ^ help: missing a comma here to end this `match` arm: `,`
|
||||||
| |
|
|
||||||
| while parsing the `match` arm starting here
|
|
||||||
LL | _ => 18,
|
|
||||||
| ^ unexpected token
|
|
||||||
|
|
||||||
error: `match` arm body without braces
|
error: `match` arm body without braces
|
||||||
--> $DIR/match-arm-without-braces.rs:53:11
|
--> $DIR/match-arm-without-braces.rs:53:11
|
||||||
|
30
src/test/ui/traits/vtable/issue-97381.rs
Normal file
30
src/test/ui/traits/vtable/issue-97381.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use std::ops::Deref;
|
||||||
|
trait MyTrait: Deref<Target = u32> {}
|
||||||
|
struct MyStruct(u32);
|
||||||
|
impl MyTrait for MyStruct {}
|
||||||
|
impl Deref for MyStruct {
|
||||||
|
type Target = u32;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_concrete_value(i: u32) -> MyStruct {
|
||||||
|
MyStruct(i)
|
||||||
|
}
|
||||||
|
fn get_boxed_value(i: u32) -> Box<dyn MyTrait> {
|
||||||
|
Box::new(get_concrete_value(i))
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let v = [1, 2, 3]
|
||||||
|
.iter()
|
||||||
|
.map(|i| get_boxed_value(*i))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let el = &v[0];
|
||||||
|
|
||||||
|
for _ in v {
|
||||||
|
//~^ ERROR cannot move out of `v` because it is borrowed
|
||||||
|
println!("{}", ***el > 0);
|
||||||
|
}
|
||||||
|
}
|
15
src/test/ui/traits/vtable/issue-97381.stderr
Normal file
15
src/test/ui/traits/vtable/issue-97381.stderr
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
error[E0505]: cannot move out of `v` because it is borrowed
|
||||||
|
--> $DIR/issue-97381.rs:26:14
|
||||||
|
|
|
||||||
|
LL | let el = &v[0];
|
||||||
|
| - borrow of `v` occurs here
|
||||||
|
LL |
|
||||||
|
LL | for _ in v {
|
||||||
|
| ^ move out of `v` occurs here
|
||||||
|
LL |
|
||||||
|
LL | println!("{}", ***el > 0);
|
||||||
|
| ---- borrow later used here
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0505`.
|
59
src/test/ui/type/type-unsatisfiable.rs
Normal file
59
src/test/ui/type/type-unsatisfiable.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// revisions: lib usage
|
||||||
|
//[lib] compile-flags: --crate-type=lib
|
||||||
|
//[lib] build-pass
|
||||||
|
|
||||||
|
use std::ops::Sub;
|
||||||
|
trait Vector2 {
|
||||||
|
type ScalarType;
|
||||||
|
|
||||||
|
fn from_values(x: Self::ScalarType, y: Self::ScalarType) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
|
fn x(&self) -> Self::ScalarType;
|
||||||
|
fn y(&self) -> Self::ScalarType;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Sub for dyn Vector2<ScalarType = T>
|
||||||
|
where
|
||||||
|
T: Sub<Output = T>,
|
||||||
|
(dyn Vector2<ScalarType = T>): Sized,
|
||||||
|
{
|
||||||
|
type Output = dyn Vector2<ScalarType = T>;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self::from_values(self.x() - rhs.x(), self.y() - rhs.y())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Vec2 {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vector2 for Vec2 {
|
||||||
|
type ScalarType = i32;
|
||||||
|
|
||||||
|
fn from_values(x: Self::ScalarType, y: Self::ScalarType) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn x(&self) -> Self::ScalarType {
|
||||||
|
self.x
|
||||||
|
}
|
||||||
|
fn y(&self) -> Self::ScalarType {
|
||||||
|
self.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(usage)]
|
||||||
|
fn main() {
|
||||||
|
let hey: Box<dyn Vector2<ScalarType = i32>> = Box::new(Vec2 { x: 1, y: 2 });
|
||||||
|
let word: Box<dyn Vector2<ScalarType = i32>> = Box::new(Vec2 { x: 1, y: 2 });
|
||||||
|
|
||||||
|
let bar = *hey - *word;
|
||||||
|
//[usage]~^ ERROR cannot subtract
|
||||||
|
}
|
11
src/test/ui/type/type-unsatisfiable.usage.stderr
Normal file
11
src/test/ui/type/type-unsatisfiable.usage.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
error[E0369]: cannot subtract `(dyn Vector2<ScalarType = i32> + 'static)` from `dyn Vector2<ScalarType = i32>`
|
||||||
|
--> $DIR/type-unsatisfiable.rs:57:20
|
||||||
|
|
|
||||||
|
LL | let bar = *hey - *word;
|
||||||
|
| ---- ^ ----- (dyn Vector2<ScalarType = i32> + 'static)
|
||||||
|
| |
|
||||||
|
| dyn Vector2<ScalarType = i32>
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0369`.
|
Loading…
Reference in New Issue
Block a user