Auto merge of #119053 - matthiaskrgr:rollup-hky3ld3, r=matthiaskrgr
Rollup of 4 pull requests Successful merges: - #118880 (More expressions correctly are marked to end with curly braces) - #118928 (fix: Overlapping spans in delimited meta-vars) - #119022 (Remove unnecessary constness from ProjectionCandidate) - #119052 (Avoid overflow in GVN constant indexing.) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
6a62871320
@ -40,15 +40,44 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
|
||||
| Range(_, Some(e), _)
|
||||
| Ret(Some(e))
|
||||
| Unary(_, e)
|
||||
| Yield(Some(e)) => {
|
||||
| Yield(Some(e))
|
||||
| Yeet(Some(e))
|
||||
| Become(e) => {
|
||||
expr = e;
|
||||
}
|
||||
Closure(closure) => {
|
||||
expr = &closure.body;
|
||||
}
|
||||
Gen(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..)
|
||||
| TryBlock(..) | While(..) => break Some(expr),
|
||||
_ => break None,
|
||||
| TryBlock(..) | While(..) | ConstBlock(_) => break Some(expr),
|
||||
|
||||
// FIXME: These can end in `}`, but changing these would break stable code.
|
||||
InlineAsm(_) | OffsetOf(_, _) | MacCall(_) | IncludedBytes(_) | FormatArgs(_) => {
|
||||
break None;
|
||||
}
|
||||
|
||||
Break(_, None)
|
||||
| Range(_, None, _)
|
||||
| Ret(None)
|
||||
| Yield(None)
|
||||
| Array(_)
|
||||
| Call(_, _)
|
||||
| MethodCall(_)
|
||||
| Tup(_)
|
||||
| Lit(_)
|
||||
| Cast(_, _)
|
||||
| Type(_, _)
|
||||
| Await(_, _)
|
||||
| Field(_, _)
|
||||
| Index(_, _, _)
|
||||
| Underscore
|
||||
| Path(_, _)
|
||||
| Continue(_)
|
||||
| Repeat(_, _)
|
||||
| Paren(_)
|
||||
| Try(_)
|
||||
| Yeet(None)
|
||||
| Err => break None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -236,6 +236,13 @@ fn expand_macro<'cx>(
|
||||
target_sp.open = source_sp.open.with_ctxt(ctxt);
|
||||
target_sp.close = source_sp.close.with_ctxt(ctxt);
|
||||
}
|
||||
(
|
||||
TokenTree::Delimited(target_sp, ..),
|
||||
mbe::TokenTree::MetaVar(source_sp, ..),
|
||||
) => {
|
||||
target_sp.open = source_sp.with_ctxt(ctxt);
|
||||
target_sp.close = source_sp.with_ctxt(ctxt).shrink_to_hi();
|
||||
}
|
||||
_ => {
|
||||
let sp = rhs_tt.span().with_ctxt(ctxt);
|
||||
tt.set_span(sp);
|
||||
|
@ -125,10 +125,8 @@ pub enum SelectionCandidate<'tcx> {
|
||||
|
||||
/// This is a trait matching with a projected type as `Self`, and we found
|
||||
/// an applicable bound in the trait definition. The `usize` is an index
|
||||
/// into the list returned by `tcx.item_bounds`. The constness is the
|
||||
/// constness of the bound in the trait.
|
||||
// FIXME(effects) do we need this constness
|
||||
ProjectionCandidate(usize, ty::BoundConstness),
|
||||
/// into the list returned by `tcx.item_bounds`.
|
||||
ProjectionCandidate(usize),
|
||||
|
||||
/// Implementation of a `Fn`-family trait by one of the anonymous types
|
||||
/// generated for an `||` expression.
|
||||
|
@ -644,12 +644,10 @@ fn simplify_place_projection(&mut self, place: &mut Place<'tcx>, location: Locat
|
||||
{
|
||||
if let Some(offset) = self.evaluated[idx].as_ref()
|
||||
&& let Ok(offset) = self.ecx.read_target_usize(offset)
|
||||
&& let Some(min_length) = offset.checked_add(1)
|
||||
{
|
||||
projection.to_mut()[i] = ProjectionElem::ConstantIndex {
|
||||
offset,
|
||||
min_length: offset + 1,
|
||||
from_end: false,
|
||||
};
|
||||
projection.to_mut()[i] =
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end: false };
|
||||
} else if let Some(new_idx) = self.try_as_local(idx, location) {
|
||||
projection.to_mut()[i] = ProjectionElem::Index(new_idx);
|
||||
self.reused_locals.insert(new_idx);
|
||||
|
@ -154,10 +154,7 @@ fn assemble_candidates_from_projected_tys(
|
||||
.infcx
|
||||
.probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
|
||||
|
||||
// FIXME(effects) proper constness needed?
|
||||
candidates.vec.extend(
|
||||
result.into_iter().map(|idx| ProjectionCandidate(idx, ty::BoundConstness::NotConst)),
|
||||
);
|
||||
candidates.vec.extend(result.into_iter().map(|idx| ProjectionCandidate(idx)));
|
||||
}
|
||||
|
||||
/// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller
|
||||
@ -585,7 +582,7 @@ fn assemble_candidates_from_auto_impls(
|
||||
}
|
||||
|
||||
ty::Alias(ty::Opaque, _) => {
|
||||
if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) {
|
||||
if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(_))) {
|
||||
// We do not generate an auto impl candidate for `impl Trait`s which already
|
||||
// reference our auto trait.
|
||||
//
|
||||
|
@ -71,7 +71,7 @@ pub(super) fn confirm_candidate(
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||
}
|
||||
|
||||
ProjectionCandidate(idx, _) => {
|
||||
ProjectionCandidate(idx) => {
|
||||
let obligations = self.confirm_projection_candidate(obligation, idx)?;
|
||||
ImplSource::Param(obligations)
|
||||
}
|
||||
@ -1313,7 +1313,6 @@ fn confirm_const_destruct_candidate(
|
||||
// If we have a projection type, make sure to normalize it so we replace it
|
||||
// with a fresh infer variable
|
||||
ty::Alias(ty::Projection | ty::Inherent, ..) => {
|
||||
// FIXME(effects) this needs constness
|
||||
let predicate = normalize_with_depth_to(
|
||||
self,
|
||||
obligation.param_env,
|
||||
@ -1344,7 +1343,6 @@ fn confirm_const_destruct_candidate(
|
||||
// since it's either not `const Drop` (and we raise an error during selection),
|
||||
// or it's an ADT (and we need to check for a custom impl during selection)
|
||||
_ => {
|
||||
// FIXME(effects) this needs constness
|
||||
let predicate = self_ty.rebind(ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef::from_lang_item(
|
||||
self.tcx(),
|
||||
|
@ -1883,7 +1883,7 @@ fn candidate_should_be_dropped_in_favor_of(
|
||||
| BuiltinCandidate { .. }
|
||||
| TraitAliasCandidate
|
||||
| ObjectCandidate(_)
|
||||
| ProjectionCandidate(..),
|
||||
| ProjectionCandidate(_),
|
||||
) => {
|
||||
// We have a where clause so don't go around looking
|
||||
// for impls. Arbitrarily give param candidates priority
|
||||
@ -1893,7 +1893,7 @@ fn candidate_should_be_dropped_in_favor_of(
|
||||
// here (see issue #50825).
|
||||
DropVictim::drop_if(!is_global(other_cand))
|
||||
}
|
||||
(ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => {
|
||||
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref victim_cand)) => {
|
||||
// Prefer these to a global where-clause bound
|
||||
// (see issue #50825).
|
||||
if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No }
|
||||
@ -1921,20 +1921,20 @@ fn candidate_should_be_dropped_in_favor_of(
|
||||
)
|
||||
}
|
||||
|
||||
(ProjectionCandidate(i, _), ProjectionCandidate(j, _))
|
||||
(ProjectionCandidate(i), ProjectionCandidate(j))
|
||||
| (ObjectCandidate(i), ObjectCandidate(j)) => {
|
||||
// Arbitrarily pick the lower numbered candidate for backwards
|
||||
// compatibility reasons. Don't let this affect inference.
|
||||
DropVictim::drop_if(i < j && !has_non_region_infer)
|
||||
}
|
||||
(ObjectCandidate(_), ProjectionCandidate(..))
|
||||
| (ProjectionCandidate(..), ObjectCandidate(_)) => {
|
||||
(ObjectCandidate(_), ProjectionCandidate(_))
|
||||
| (ProjectionCandidate(_), ObjectCandidate(_)) => {
|
||||
bug!("Have both object and projection candidate")
|
||||
}
|
||||
|
||||
// Arbitrarily give projection and object candidates priority.
|
||||
(
|
||||
ObjectCandidate(_) | ProjectionCandidate(..),
|
||||
ObjectCandidate(_) | ProjectionCandidate(_),
|
||||
ImplCandidate(..)
|
||||
| AutoImplCandidate
|
||||
| ClosureCandidate { .. }
|
||||
@ -1964,7 +1964,7 @@ fn candidate_should_be_dropped_in_favor_of(
|
||||
| TraitUpcastingUnsizeCandidate(_)
|
||||
| BuiltinCandidate { .. }
|
||||
| TraitAliasCandidate,
|
||||
ObjectCandidate(_) | ProjectionCandidate(..),
|
||||
ObjectCandidate(_) | ProjectionCandidate(_),
|
||||
) => DropVictim::No,
|
||||
|
||||
(&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
|
||||
|
104
tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff
Normal file
104
tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff
Normal file
@ -0,0 +1,104 @@
|
||||
- // MIR for `constant_index_overflow` before GVN
|
||||
+ // MIR for `constant_index_overflow` after GVN
|
||||
|
||||
fn constant_index_overflow(_1: &[T]) -> () {
|
||||
debug x => _1;
|
||||
let mut _0: ();
|
||||
let _2: usize;
|
||||
let mut _4: bool;
|
||||
let mut _5: usize;
|
||||
let mut _6: usize;
|
||||
let mut _7: &[T];
|
||||
let _8: usize;
|
||||
let mut _9: usize;
|
||||
let mut _10: bool;
|
||||
let _11: usize;
|
||||
let mut _12: usize;
|
||||
let mut _13: bool;
|
||||
let mut _14: T;
|
||||
scope 1 {
|
||||
debug a => _2;
|
||||
let _3: T;
|
||||
scope 2 {
|
||||
debug b => _3;
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- StorageLive(_2);
|
||||
- _2 = const _ as usize (IntToInt);
|
||||
+ nop;
|
||||
+ _2 = const usize::MAX;
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
StorageLive(_5);
|
||||
- _5 = _2;
|
||||
+ _5 = const usize::MAX;
|
||||
StorageLive(_6);
|
||||
StorageLive(_7);
|
||||
_7 = &(*_1);
|
||||
_6 = core::slice::<impl [T]>::len(move _7) -> [return: bb1, unwind unreachable];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageDead(_7);
|
||||
- _4 = Lt(move _5, move _6);
|
||||
+ _4 = Lt(const usize::MAX, move _6);
|
||||
switchInt(move _4) -> [0: bb4, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
StorageLive(_8);
|
||||
- _8 = _2;
|
||||
+ _8 = const usize::MAX;
|
||||
_9 = Len((*_1));
|
||||
- _10 = Lt(_8, _9);
|
||||
- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind unreachable];
|
||||
+ _10 = Lt(const usize::MAX, _9);
|
||||
+ assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, const usize::MAX) -> [success: bb3, unwind unreachable];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
- _3 = (*_1)[_8];
|
||||
+ _3 = (*_1)[_2];
|
||||
StorageDead(_8);
|
||||
goto -> bb6;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
StorageLive(_11);
|
||||
_11 = const 0_usize;
|
||||
_12 = Len((*_1));
|
||||
- _13 = Lt(_11, _12);
|
||||
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb5, unwind unreachable];
|
||||
+ _13 = Lt(const 0_usize, _12);
|
||||
+ assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 0_usize) -> [success: bb5, unwind unreachable];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
- _3 = (*_1)[_11];
|
||||
+ _3 = (*_1)[0 of 1];
|
||||
StorageDead(_11);
|
||||
goto -> bb6;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_4);
|
||||
StorageLive(_14);
|
||||
_14 = _3;
|
||||
_0 = opaque::<T>(move _14) -> [return: bb7, unwind unreachable];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageDead(_14);
|
||||
StorageDead(_3);
|
||||
- StorageDead(_2);
|
||||
+ nop;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
104
tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff
Normal file
104
tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff
Normal file
@ -0,0 +1,104 @@
|
||||
- // MIR for `constant_index_overflow` before GVN
|
||||
+ // MIR for `constant_index_overflow` after GVN
|
||||
|
||||
fn constant_index_overflow(_1: &[T]) -> () {
|
||||
debug x => _1;
|
||||
let mut _0: ();
|
||||
let _2: usize;
|
||||
let mut _4: bool;
|
||||
let mut _5: usize;
|
||||
let mut _6: usize;
|
||||
let mut _7: &[T];
|
||||
let _8: usize;
|
||||
let mut _9: usize;
|
||||
let mut _10: bool;
|
||||
let _11: usize;
|
||||
let mut _12: usize;
|
||||
let mut _13: bool;
|
||||
let mut _14: T;
|
||||
scope 1 {
|
||||
debug a => _2;
|
||||
let _3: T;
|
||||
scope 2 {
|
||||
debug b => _3;
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
- StorageLive(_2);
|
||||
- _2 = const _ as usize (IntToInt);
|
||||
+ nop;
|
||||
+ _2 = const usize::MAX;
|
||||
StorageLive(_3);
|
||||
StorageLive(_4);
|
||||
StorageLive(_5);
|
||||
- _5 = _2;
|
||||
+ _5 = const usize::MAX;
|
||||
StorageLive(_6);
|
||||
StorageLive(_7);
|
||||
_7 = &(*_1);
|
||||
_6 = core::slice::<impl [T]>::len(move _7) -> [return: bb1, unwind continue];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
StorageDead(_7);
|
||||
- _4 = Lt(move _5, move _6);
|
||||
+ _4 = Lt(const usize::MAX, move _6);
|
||||
switchInt(move _4) -> [0: bb4, otherwise: bb2];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
StorageLive(_8);
|
||||
- _8 = _2;
|
||||
+ _8 = const usize::MAX;
|
||||
_9 = Len((*_1));
|
||||
- _10 = Lt(_8, _9);
|
||||
- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind continue];
|
||||
+ _10 = Lt(const usize::MAX, _9);
|
||||
+ assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, const usize::MAX) -> [success: bb3, unwind continue];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
- _3 = (*_1)[_8];
|
||||
+ _3 = (*_1)[_2];
|
||||
StorageDead(_8);
|
||||
goto -> bb6;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_6);
|
||||
StorageDead(_5);
|
||||
StorageLive(_11);
|
||||
_11 = const 0_usize;
|
||||
_12 = Len((*_1));
|
||||
- _13 = Lt(_11, _12);
|
||||
- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb5, unwind continue];
|
||||
+ _13 = Lt(const 0_usize, _12);
|
||||
+ assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 0_usize) -> [success: bb5, unwind continue];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
- _3 = (*_1)[_11];
|
||||
+ _3 = (*_1)[0 of 1];
|
||||
StorageDead(_11);
|
||||
goto -> bb6;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_4);
|
||||
StorageLive(_14);
|
||||
_14 = _3;
|
||||
_0 = opaque::<T>(move _14) -> [return: bb7, unwind continue];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
StorageDead(_14);
|
||||
StorageDead(_3);
|
||||
- StorageDead(_2);
|
||||
+ nop;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -609,6 +609,22 @@ fn indirect_static() {
|
||||
})
|
||||
}
|
||||
|
||||
/// Verify that having constant index `u64::MAX` does not yield to an overflow in rustc.
|
||||
fn constant_index_overflow<T: Copy>(x: &[T]) {
|
||||
// CHECK-LABEL: fn constant_index_overflow(
|
||||
// CHECK: debug a => [[a:_.*]];
|
||||
// CHECK: debug b => [[b:_.*]];
|
||||
// CHECK: [[a]] = const usize::MAX;
|
||||
// CHECK-NOT: = (*_1)[{{.*}} of 0];
|
||||
// CHECK: [[b]] = (*_1)[[[a]]];
|
||||
// CHECK-NOT: = (*_1)[{{.*}} of 0];
|
||||
// CHECK: [[b]] = (*_1)[0 of 1];
|
||||
// CHECK-NOT: = (*_1)[{{.*}} of 0];
|
||||
let a = u64::MAX as usize;
|
||||
let b = if a < x.len() { x[a] } else { x[0] };
|
||||
opaque(b)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
subexpression_elimination(2, 4, 5);
|
||||
wrap_unwrap(5);
|
||||
@ -627,6 +643,7 @@ fn main() {
|
||||
repeat();
|
||||
fn_pointers();
|
||||
indirect_static();
|
||||
constant_index_overflow(&[5, 3]);
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
@ -653,3 +670,4 @@ fn identity<T>(x: T) -> T {
|
||||
// EMIT_MIR gvn.repeat.GVN.diff
|
||||
// EMIT_MIR gvn.fn_pointers.GVN.diff
|
||||
// EMIT_MIR gvn.indirect_static.GVN.diff
|
||||
// EMIT_MIR gvn.constant_index_overflow.GVN.diff
|
||||
|
16
tests/ui/macros/issue-118786.rs
Normal file
16
tests/ui/macros/issue-118786.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// compile-flags: --crate-type lib -O -C debug-assertions=yes
|
||||
|
||||
// Regression test for issue 118786
|
||||
|
||||
macro_rules! make_macro {
|
||||
($macro_name:tt) => {
|
||||
macro_rules! $macro_name {
|
||||
//~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon
|
||||
//~| ERROR macro expansion ignores token `{` and any following
|
||||
//~| ERROR cannot find macro `macro_rules` in this scope
|
||||
() => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
make_macro!((meow));
|
47
tests/ui/macros/issue-118786.stderr
Normal file
47
tests/ui/macros/issue-118786.stderr
Normal file
@ -0,0 +1,47 @@
|
||||
error: macros that expand to items must be delimited with braces or followed by a semicolon
|
||||
--> $DIR/issue-118786.rs:7:22
|
||||
|
|
||||
LL | macro_rules! $macro_name {
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
help: change the delimiters to curly braces
|
||||
|
|
||||
LL | macro_rules! {} {
|
||||
| ~ +
|
||||
help: add a semicolon
|
||||
|
|
||||
LL | macro_rules! $macro_name; {
|
||||
| +
|
||||
|
||||
error: macro expansion ignores token `{` and any following
|
||||
--> $DIR/issue-118786.rs:7:34
|
||||
|
|
||||
LL | macro_rules! $macro_name {
|
||||
| ^
|
||||
...
|
||||
LL | make_macro!((meow));
|
||||
| ------------------- caused by the macro expansion here
|
||||
|
|
||||
= note: the usage of `make_macro!` is likely invalid in item context
|
||||
|
||||
error: cannot find macro `macro_rules` in this scope
|
||||
--> $DIR/issue-118786.rs:7:9
|
||||
|
|
||||
LL | macro_rules! $macro_name {
|
||||
| ^^^^^^^^^^^
|
||||
...
|
||||
LL | make_macro!((meow));
|
||||
| ------------------- in this macro invocation
|
||||
|
|
||||
note: maybe you have forgotten to define a name for this `macro_rules!`
|
||||
--> $DIR/issue-118786.rs:7:9
|
||||
|
|
||||
LL | macro_rules! $macro_name {
|
||||
| ^^^^^^^^^^^
|
||||
...
|
||||
LL | make_macro!((meow));
|
||||
| ------------------- in this macro invocation
|
||||
= note: this error originates in the macro `make_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
164
tests/ui/parser/bad-let-else-statement.rs
Normal file
164
tests/ui/parser/bad-let-else-statement.rs
Normal file
@ -0,0 +1,164 @@
|
||||
#![feature(inline_const)]
|
||||
#![feature(yeet_expr)]
|
||||
#![allow(incomplete_features)] // Necessary for now, while explicit_tail_calls is incomplete
|
||||
#![feature(explicit_tail_calls)]
|
||||
|
||||
fn a() {
|
||||
let foo = {
|
||||
1
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn b() {
|
||||
let foo = for i in 1..2 {
|
||||
break;
|
||||
} else {
|
||||
//~^ ERROR `for...else` loops are not supported
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn c() {
|
||||
let foo = if true {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn d() {
|
||||
let foo = loop {
|
||||
break;
|
||||
} else {
|
||||
//~^ ERROR loop...else` loops are not supported
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn e() {
|
||||
let foo = match true {
|
||||
true => 1,
|
||||
false => 0
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
struct X {a: i32}
|
||||
fn f() {
|
||||
let foo = X {
|
||||
a: 1
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn g() {
|
||||
let foo = while false {
|
||||
break;
|
||||
} else {
|
||||
//~^ ERROR `while...else` loops are not supported
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn h() {
|
||||
let foo = const {
|
||||
1
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn i() {
|
||||
let foo = &{
|
||||
1
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn j() {
|
||||
let bar = 0;
|
||||
let foo = bar = {
|
||||
1
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn k() {
|
||||
let foo = 1 + {
|
||||
1
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn l() {
|
||||
let foo = 1..{
|
||||
1
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn m() {
|
||||
let foo = return {
|
||||
()
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn n() {
|
||||
let foo = -{
|
||||
1
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn o() -> Result<(), ()> {
|
||||
let foo = do yeet {
|
||||
()
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return Ok(());
|
||||
};
|
||||
}
|
||||
|
||||
fn p() {
|
||||
let foo = become {
|
||||
()
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn q() {
|
||||
let foo = |x: i32| {
|
||||
x
|
||||
} else {
|
||||
//~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
232
tests/ui/parser/bad-let-else-statement.stderr
Normal file
232
tests/ui/parser/bad-let-else-statement.stderr
Normal file
@ -0,0 +1,232 @@
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:9:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = ({
|
||||
LL | 1
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: `for...else` loops are not supported
|
||||
--> $DIR/bad-let-else-statement.rs:18:7
|
||||
|
|
||||
LL | let foo = for i in 1..2 {
|
||||
| --- `else` is attached to this loop
|
||||
LL | break;
|
||||
LL | } else {
|
||||
| _______^
|
||||
LL | |
|
||||
LL | | return;
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
= note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
|
||||
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:29:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = (if true {
|
||||
LL | 1
|
||||
LL | } else {
|
||||
LL | 0
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: `loop...else` loops are not supported
|
||||
--> $DIR/bad-let-else-statement.rs:38:7
|
||||
|
|
||||
LL | let foo = loop {
|
||||
| ---- `else` is attached to this loop
|
||||
LL | break;
|
||||
LL | } else {
|
||||
| _______^
|
||||
LL | |
|
||||
LL | | return;
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
= note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
|
||||
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:48:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = (match true {
|
||||
LL | true => 1,
|
||||
LL | false => 0
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:58:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = (X {
|
||||
LL | a: 1
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: `while...else` loops are not supported
|
||||
--> $DIR/bad-let-else-statement.rs:67:7
|
||||
|
|
||||
LL | let foo = while false {
|
||||
| ----- `else` is attached to this loop
|
||||
LL | break;
|
||||
LL | } else {
|
||||
| _______^
|
||||
LL | |
|
||||
LL | | return;
|
||||
LL | | };
|
||||
| |_____^
|
||||
|
|
||||
= note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
|
||||
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:76:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = (const {
|
||||
LL | 1
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:85:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = &({
|
||||
LL | 1
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:95:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = bar = ({
|
||||
LL | 1
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:104:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = 1 + ({
|
||||
LL | 1
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:113:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = 1..({
|
||||
LL | 1
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:122:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = return ({
|
||||
LL | ()
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:131:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = -({
|
||||
LL | 1
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:140:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = do yeet ({
|
||||
LL | ()
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:149:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = become ({
|
||||
LL | ()
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: right curly brace `}` before `else` in a `let...else` statement not allowed
|
||||
--> $DIR/bad-let-else-statement.rs:158:5
|
||||
|
|
||||
LL | } else {
|
||||
| ^
|
||||
|
|
||||
help: wrap the expression in parentheses
|
||||
|
|
||||
LL ~ let foo = |x: i32| ({
|
||||
LL | x
|
||||
LL ~ }) else {
|
||||
|
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user