diff --git a/compiler/rustc_parse/src/diagnostics.rs b/compiler/rustc_parse/src/diagnostics.rs index 7897239d248ea..b8ed0e9a4e359 100644 --- a/compiler/rustc_parse/src/diagnostics.rs +++ b/compiler/rustc_parse/src/diagnostics.rs @@ -4700,3 +4700,88 @@ pub(crate) struct SuggestIntroduceTypeParameter { pub span: Span, pub parameters: String, } + +#[derive(Diagnostic)] +pub(crate) enum CStyleReferenceMut { + #[diag("`mut` must be written after the lifetime")] + WithLifetime { + #[primary_span] + span: Span, + #[subdiagnostic] + sugg: CStyleReferenceMutLifetimeSugg, + }, + #[diag("reference types must be written as `&mut T`")] + Plain { + #[primary_span] + span: Span, + #[subdiagnostic] + sugg: CStyleReferenceMutPlainSugg, + }, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("put `mut` after the lifetime", applicability = "machine-applicable")] +pub(crate) struct CStyleReferenceMutLifetimeSugg { + #[suggestion_part(code = "")] + pub remove: Span, + #[suggestion_part(code = " mut")] + pub insert: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("put the `&` before `mut`", applicability = "machine-applicable")] +pub(crate) struct CStyleReferenceMutPlainSugg { + #[suggestion_part(code = "")] + pub remove: Span, + #[suggestion_part(code = "&")] + pub insert: Span, +} + +#[derive(Diagnostic)] +#[diag("reference types must be written as `&T`")] +pub(crate) struct CStyleReference { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sugg: CStyleReferenceSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("put the `&` before the type", applicability = "machine-applicable")] +pub(crate) struct CStyleReferenceSugg { + #[suggestion_part(code = "")] + pub remove: Span, + #[suggestion_part(code = "&")] + pub insert: Span, +} + +#[derive(Diagnostic)] +#[diag("reference types must be written as `&{$mutbl}expr`")] +pub(crate) struct CStyleReferenceExpr { + #[primary_span] + pub span: Span, + pub mutbl: String, + #[subdiagnostic] + pub sugg: Option, +} + +#[derive(Subdiagnostic)] +pub(crate) enum CStyleReferenceExprSugg { + #[multipart_suggestion("put the `&` before the `expr`", applicability = "machine-applicable")] + Shared { + #[suggestion_part(code = "")] + removal: Span, + #[suggestion_part(code = "&")] + insert: Span, + }, + #[multipart_suggestion( + "put the `&mut` before the `expr`", + applicability = "machine-applicable" + )] + Mut { + #[suggestion_part(code = "")] + removal: Span, + #[suggestion_part(code = "&mut ")] + insert: Span, + }, +} diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 0b91828639d36..ecb5054f00f46 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -6,8 +6,9 @@ use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, - Block, BlockCheckMode, Expr, ExprKind, GenericArg, GenericArgs, Generics, Item, ItemKind, - Param, Pat, PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, + Block, BlockCheckMode, BorrowKind, Expr, ExprKind, GenericArg, GenericArgs, Generics, Item, + ItemKind, MutTy, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Recovered, Ty, + TyKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -27,7 +28,8 @@ use super::{ }; use crate::diagnostics::{ AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType, - AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, + AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, CStyleReference, + CStyleReferenceExpr, CStyleReferenceExprSugg, CStyleReferenceSugg, ColonAsSemi, ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, ExprParenthesesNeeded, FoundPathInGenerics, @@ -1593,6 +1595,31 @@ impl<'a> Parser<'a> { } } + /// If a user writes `T&` instead of `&T`, this method + /// attempts to recover and provide a helpful error message. + pub(super) fn maybe_recover_from_c_style_reference(&mut self, ty: Box) -> Box { + if self.token == token::And + && self.may_recover() + && !self.look_ahead(1, |t| t.can_begin_type() || t.is_keyword(kw::Mut)) + { + self.bump(); + + let ref_span = self.prev_token.span; + + self.dcx().emit_err(CStyleReference { + span: ref_span, + sugg: CStyleReferenceSugg { remove: ref_span, insert: ty.span.shrink_to_lo() }, + }); + + self.mk_ty( + ty.span.to(ref_span), + TyKind::Ref(None, MutTy { ty, mutbl: Mutability::Not }), + ) + } else { + ty + } + } + /// Rust has no ternary operator (`cond ? then : else`). Parse it and try /// to recover from it if `then` and `else` are valid expressions. Returns /// an err if this appears to be a ternary expression. @@ -3187,4 +3214,36 @@ impl<'a> Parser<'a> { new_error }) } + + pub(super) fn recover_from_c_style_reference(&mut self, lhs: Box) -> Box { + let ref_span = self.prev_token.span; + + let mutbl = self.parse_mutability(); + let prefix = mutbl.prefix_str(); + + let op_span = ref_span.to(self.prev_token.span); + let span = lhs.span.to(op_span); + + if matches!(lhs.kind, ExprKind::Binary(..) | ExprKind::Cast(..)) { + self.dcx().emit_err(CStyleReferenceExpr { + span, + mutbl: prefix.to_string(), + sugg: None, + }); + return lhs; + } + + let insert = lhs.span.shrink_to_lo(); + let sugg = match mutbl { + Mutability::Mut => CStyleReferenceExprSugg::Mut { removal: op_span, insert }, + Mutability::Not => CStyleReferenceExprSugg::Shared { removal: op_span, insert }, + }; + self.dcx().emit_err(CStyleReferenceExpr { + span, + mutbl: prefix.to_string(), + sugg: Some(sugg), + }); + + self.mk_expr(span, ExprKind::AddrOf(BorrowKind::Ref, mutbl, lhs)) + } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 3e03730ab632b..d623dc67ae676 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -278,6 +278,13 @@ impl<'a> Parser<'a> { continue; } + // Look for C-style reference expressions like + // `x&`, `x &mut` and recover + if self.prev_token == token::And && self.may_recover() && !self.token.can_begin_expr() { + lhs = self.recover_from_c_style_reference(lhs); + continue; + } + let op_span = op.span; let op = op.node; // Special cases: diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index c67f220e84bd9..f06cf91a916fe 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1810,6 +1810,12 @@ impl<'a> Parser<'a> { } None } + + fn is_c_style_reference_start(&self) -> bool { + self.token.is_keyword(kw::Mut) + && self.may_recover() + && self.look_ahead(1, |t| *t == token::And) + } } // Metavar captures of various kinds. The more complex node kinds (e.g. `Item`, `Expr`) store diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 664c089e3f153..b8b39f3628293 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -927,7 +927,7 @@ impl<'a> Parser<'a> { } else if self.check_const_arg() { // Parse const argument. GenericArg::Const(self.parse_const_arg()?) - } else if self.check_type() { + } else if self.check_type() || self.is_c_style_reference_start() { // Parse type argument. // Proactively create a parser snapshot enabling us to rewind and try to reparse the diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 1d2021cfe50ae..8f2c7d12a2208 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -12,10 +12,12 @@ use thin_vec::{ThinVec, thin_vec}; use super::{Parser, PathStyle, SeqSep, TokenType, Trailing}; use crate::diagnostics::{ - self, AttributeOnEmptyType, AttributeOnType, DynAfterMut, ExpectedFnPathFoundFnKeyword, - ExpectedMutOrConstInRawPointerType, FnPtrWithGenerics, FnPtrWithGenericsSugg, - HelpUseLatestEdition, InvalidCVariadicType, InvalidDynKeyword, LifetimeAfterMut, - NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow, + self, AttributeOnEmptyType, AttributeOnType, CStyleReferenceMut, + CStyleReferenceMutLifetimeSugg, CStyleReferenceMutPlainSugg, DynAfterMut, + ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, FnPtrWithGenerics, + FnPtrWithGenericsSugg, HelpUseLatestEdition, InvalidCVariadicType, InvalidDynKeyword, + LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, + ReturnTypesUseThinArrow, }; use crate::parser::{FnContext, FnParseMode, FrontMatterParsingMode}; use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; @@ -408,6 +410,8 @@ impl<'a> Parser<'a> { && self.look_ahead(1, |t| *t == token::Star) { self.parse_ty_c_style_pointer()? + } else if self.is_c_style_reference_start() { + self.parse_ty_c_style_reference()? } else if self.check_path() { self.parse_path_start_ty(lo, allow_plus, ty_generics)? } else if self.can_begin_bound() { @@ -439,7 +443,11 @@ impl<'a> Parser<'a> { // Try to recover from use of `+` with incorrect priority. match allow_plus { - AllowPlus::Yes => self.maybe_recover_from_bad_type_plus(&ty)?, + AllowPlus::Yes => { + self.maybe_recover_from_bad_type_plus(&ty)?; + // Try to recover from `T&`. + ty = self.maybe_recover_from_c_style_reference(ty); + } AllowPlus::No => self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty), } if let RecoverQuestionMark::Yes = recover_question_mark { @@ -624,6 +632,47 @@ impl<'a> Parser<'a> { unreachable!("this could never happen") } + /// Parses a reference with a C-style typo + /// Only for `mut` + fn parse_ty_c_style_reference(&mut self) -> PResult<'a, TyKind> { + let kw_span = self.token.span; + let mutbl = self.parse_mutability(); + let ref_span = self.token.span; + + self.bump(); // `&` + + let (lifetime, err) = if self.token.is_lifetime() { + let lifetime = self.expect_lifetime(); + ( + Some(lifetime), + CStyleReferenceMut::WithLifetime { + span: kw_span, + sugg: CStyleReferenceMutLifetimeSugg { + remove: kw_span.until(ref_span), + insert: lifetime.ident.span.shrink_to_hi(), + }, + }, + ) + } else { + ( + None, + CStyleReferenceMut::Plain { + span: kw_span, + sugg: CStyleReferenceMutPlainSugg { + remove: ref_span, + insert: kw_span.shrink_to_lo(), + }, + }, + ) + }; + + let ty = self.parse_ty_no_question_mark_recover()?; + + self.dcx().emit_err(err); + + return Ok(TyKind::Ref(lifetime, MutTy { ty, mutbl })); + } + /// Parses a raw pointer type: `*[const | mut] $type`. fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> { let mutbl = self.parse_mut_or_const().unwrap_or_else(|| { diff --git a/tests/ui/did_you_mean/c-style-reference-exprs-issue-101487.fixed b/tests/ui/did_you_mean/c-style-reference-exprs-issue-101487.fixed new file mode 100644 index 0000000000000..691697fe50627 --- /dev/null +++ b/tests/ui/did_you_mean/c-style-reference-exprs-issue-101487.fixed @@ -0,0 +1,47 @@ +// Tests for https://github.com/rust-lang/rust/issues/101487 +// `&` should go before the expression in C-style references +//@ run-rustfix + +#![allow(unused)] + +static N: i32 = 0; +fn func2() -> &'static i32 { + &N + //~^ ERROR reference types must be written as `&expr` + //~| HELP put the `&` before the `expr` +} + +macro_rules! m { + ($e:expr) => { $e }; + ($($t:tt)*) => { 0 }; +} +fn func1(num: &mut i32) {} + +fn main() { + let x = 12; + let _ptr = &x; + //~^ ERROR reference types must be written as `&expr` + //~| HELP put the `&` before the `expr` + + let mut y = 34; + func1(&mut y ); + //~^ ERROR reference types must be written as `&mut expr` + //~| HELP put the `&mut` before the `expr` + + let arr = [&x, &y]; + //~^ ERROR reference types must be written as `&expr` + //~| HELP put the `&` before the `expr` + //~| ERROR reference types must be written as `&expr` + //~| HELP put the `&` before the `expr` + + // Normal bitwise operations, should not have any errors + let b = x & y; + + m!(x & y); + + let _ptr2 = &x; + let c = x & *_ptr2; + let d = x & !y; + let e = x & (y); + let f = x & &y; +} diff --git a/tests/ui/did_you_mean/c-style-reference-exprs-issue-101487.rs b/tests/ui/did_you_mean/c-style-reference-exprs-issue-101487.rs new file mode 100644 index 0000000000000..51ee475202b93 --- /dev/null +++ b/tests/ui/did_you_mean/c-style-reference-exprs-issue-101487.rs @@ -0,0 +1,47 @@ +// Tests for https://github.com/rust-lang/rust/issues/101487 +// `&` should go before the expression in C-style references +//@ run-rustfix + +#![allow(unused)] + +static N: i32 = 0; +fn func2() -> &'static i32 { + N& + //~^ ERROR reference types must be written as `&expr` + //~| HELP put the `&` before the `expr` +} + +macro_rules! m { + ($e:expr) => { $e }; + ($($t:tt)*) => { 0 }; +} +fn func1(num: &mut i32) {} + +fn main() { + let x = 12; + let _ptr = x&; + //~^ ERROR reference types must be written as `&expr` + //~| HELP put the `&` before the `expr` + + let mut y = 34; + func1(y &mut); + //~^ ERROR reference types must be written as `&mut expr` + //~| HELP put the `&mut` before the `expr` + + let arr = [x&, y&]; + //~^ ERROR reference types must be written as `&expr` + //~| HELP put the `&` before the `expr` + //~| ERROR reference types must be written as `&expr` + //~| HELP put the `&` before the `expr` + + // Normal bitwise operations, should not have any errors + let b = x & y; + + m!(x & y); + + let _ptr2 = &x; + let c = x & *_ptr2; + let d = x & !y; + let e = x & (y); + let f = x & &y; +} diff --git a/tests/ui/did_you_mean/c-style-reference-exprs-issue-101487.stderr b/tests/ui/did_you_mean/c-style-reference-exprs-issue-101487.stderr new file mode 100644 index 0000000000000..5a152ab03bd2a --- /dev/null +++ b/tests/ui/did_you_mean/c-style-reference-exprs-issue-101487.stderr @@ -0,0 +1,62 @@ +error: reference types must be written as `&expr` + --> $DIR/c-style-reference-exprs-issue-101487.rs:9:5 + | +LL | N& + | ^^ + | +help: put the `&` before the `expr` + | +LL - N& +LL + &N + | + +error: reference types must be written as `&expr` + --> $DIR/c-style-reference-exprs-issue-101487.rs:22:16 + | +LL | let _ptr = x&; + | ^^ + | +help: put the `&` before the `expr` + | +LL - let _ptr = x&; +LL + let _ptr = &x; + | + +error: reference types must be written as `&mut expr` + --> $DIR/c-style-reference-exprs-issue-101487.rs:27:11 + | +LL | func1(y &mut); + | ^^^^^^ + | +help: put the `&mut` before the `expr` + | +LL - func1(y &mut); +LL + func1(&mut y ); + | + +error: reference types must be written as `&expr` + --> $DIR/c-style-reference-exprs-issue-101487.rs:31:16 + | +LL | let arr = [x&, y&]; + | ^^ + | +help: put the `&` before the `expr` + | +LL - let arr = [x&, y&]; +LL + let arr = [&x, y&]; + | + +error: reference types must be written as `&expr` + --> $DIR/c-style-reference-exprs-issue-101487.rs:31:20 + | +LL | let arr = [x&, y&]; + | ^^ + | +help: put the `&` before the `expr` + | +LL - let arr = [x&, y&]; +LL + let arr = [x&, &y]; + | + +error: aborting due to 5 previous errors + diff --git a/tests/ui/did_you_mean/c-style-reference-no-sugg-issue-101487.rs b/tests/ui/did_you_mean/c-style-reference-no-sugg-issue-101487.rs new file mode 100644 index 0000000000000..f404ad929821f --- /dev/null +++ b/tests/ui/did_you_mean/c-style-reference-no-sugg-issue-101487.rs @@ -0,0 +1,32 @@ +// Tests for https://github.com/rust-lang/rust/issues/101487 +// These C-style reference cases should not +// provide machine-applicable suggestions + +macro_rules! m { + ($e:expr) => { $e }; + ($($t:tt)*) => { 0 }; +} + +fn a() { + let _c: u8 & u8; + //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `&` +} + +fn b() { + let _c: u8 &mut; + //~^ ERROR expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `&` +} + +fn main() { + let x = 12; + let y = 34; + + let a = x + y&; + //~^ ERROR reference types must be written as `&expr` + + let _d = x as u8&; + //~^ ERROR reference types must be written as `&expr` + + m!(x &); + //~^ ERROR expected expression, found end of macro arguments +} diff --git a/tests/ui/did_you_mean/c-style-reference-no-sugg-issue-101487.stderr b/tests/ui/did_you_mean/c-style-reference-no-sugg-issue-101487.stderr new file mode 100644 index 0000000000000..72dbb2c1c1d35 --- /dev/null +++ b/tests/ui/did_you_mean/c-style-reference-no-sugg-issue-101487.stderr @@ -0,0 +1,39 @@ +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `&` + --> $DIR/c-style-reference-no-sugg-issue-101487.rs:11:16 + | +LL | let _c: u8 & u8; + | - ^ expected one of 7 possible tokens + | | + | while parsing the type for `_c` + +error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `&` + --> $DIR/c-style-reference-no-sugg-issue-101487.rs:16:16 + | +LL | let _c: u8 &mut; + | - ^ expected one of 7 possible tokens + | | + | while parsing the type for `_c` + +error: reference types must be written as `&expr` + --> $DIR/c-style-reference-no-sugg-issue-101487.rs:24:13 + | +LL | let a = x + y&; + | ^^^^^^ + +error: reference types must be written as `&expr` + --> $DIR/c-style-reference-no-sugg-issue-101487.rs:27:14 + | +LL | let _d = x as u8&; + | ^^^^^^^^ + +error: expected expression, found end of macro arguments + --> $DIR/c-style-reference-no-sugg-issue-101487.rs:30:11 + | +LL | ($e:expr) => { $e }; + | ------- while parsing argument for this `expr` macro fragment +... +LL | m!(x &); + | ^ expected expression + +error: aborting due to 5 previous errors + diff --git a/tests/ui/did_you_mean/c-style-reference-types-issue-101487.fixed b/tests/ui/did_you_mean/c-style-reference-types-issue-101487.fixed new file mode 100644 index 0000000000000..57d53139e461d --- /dev/null +++ b/tests/ui/did_you_mean/c-style-reference-types-issue-101487.fixed @@ -0,0 +1,118 @@ +// Tests for https://github.com/rust-lang/rust/issues/101487 +// `&` should go before the type and `mut` in C-style references +//@ run-rustfix + +#![allow(unused)] + +macro_rules! m { + ($t:ty) => { 0u8 }; + ($($t:tt)*) => { 0u8 }; +} + +fn func1(_num: &mut i32) {} +//~^ ERROR reference types must be written as `&mut T` +//~| HELP put the `&` before `mut` + +fn func2(_num: &i32) {} +//~^ ERROR reference types must be written as `&T` +//~| HELP put the `&` before the type + +fn func3<'a>(_num: &'a mut i32) {} +//~^ ERROR `mut` must be written after the lifetime +//~| HELP put `mut` after the lifetime + +struct S1; +impl S1 { + fn method(self, _size: &mut u32) {} + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + fn method2(self, _size: &i32) {} + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type +} + +trait Trait1 { + fn method(_p: &mut u8); + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + fn method3(_p: &i32); + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type +} + +fn generic_func(_t: &mut T) {} +//~^ ERROR reference types must be written as `&mut T` +//~| HELP put the `&` before `mut` + +fn generic_func2(_t: &T) {} +//~^ ERROR reference types must be written as `&T` +//~| HELP put the `&` before the type + + +fn main() { + let _ptr: &mut u8; + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _tuple: (&mut u8, i32); + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _array: [&mut u8; 2]; + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _generic: Vec<&mut u8>; + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _nested: Option<&mut u8>; + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _ptr2: &mut u8; + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _ptr3: &mut u8; + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _ptr4: &'static mut u8; + //~^ ERROR `mut` must be written after the lifetime + //~| HELP put `mut` after the lifetime + + let _tuple2: (&u8, i32); + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type + + let _array2: [&u8; 2]; + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type + + let _generic2: Vec<&u8>; + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type + + let _nested2: Option<&u8>; + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type + + let _a: &u8; + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type + + let _b: &u8 ; + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type + + // The following lines are examples of bitwise AND operations + // They should not trigger any errors related to reference types. + let x = 5i32; + let y = 3u8; + let t = 4u8; + let _z = x as u8 & y; + let _m = m!(t & y); +} diff --git a/tests/ui/did_you_mean/c-style-reference-types-issue-101487.rs b/tests/ui/did_you_mean/c-style-reference-types-issue-101487.rs new file mode 100644 index 0000000000000..00d49c2080088 --- /dev/null +++ b/tests/ui/did_you_mean/c-style-reference-types-issue-101487.rs @@ -0,0 +1,118 @@ +// Tests for https://github.com/rust-lang/rust/issues/101487 +// `&` should go before the type and `mut` in C-style references +//@ run-rustfix + +#![allow(unused)] + +macro_rules! m { + ($t:ty) => { 0u8 }; + ($($t:tt)*) => { 0u8 }; +} + +fn func1(_num: mut& i32) {} +//~^ ERROR reference types must be written as `&mut T` +//~| HELP put the `&` before `mut` + +fn func2(_num: i32&) {} +//~^ ERROR reference types must be written as `&T` +//~| HELP put the `&` before the type + +fn func3<'a>(_num: mut &'a i32) {} +//~^ ERROR `mut` must be written after the lifetime +//~| HELP put `mut` after the lifetime + +struct S1; +impl S1 { + fn method(self, _size: mut& u32) {} + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + fn method2(self, _size: i32&) {} + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type +} + +trait Trait1 { + fn method(_p: mut& u8); + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + fn method3(_p: i32&); + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type +} + +fn generic_func(_t: mut& T) {} +//~^ ERROR reference types must be written as `&mut T` +//~| HELP put the `&` before `mut` + +fn generic_func2(_t: T&) {} +//~^ ERROR reference types must be written as `&T` +//~| HELP put the `&` before the type + + +fn main() { + let _ptr: mut& u8; + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _tuple: (mut& u8, i32); + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _array: [mut& u8; 2]; + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _generic: Vec; + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _nested: Option; + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _ptr2: mut &u8; + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _ptr3: mut & u8; + //~^ ERROR reference types must be written as `&mut T` + //~| HELP put the `&` before `mut` + + let _ptr4: mut &'static u8; + //~^ ERROR `mut` must be written after the lifetime + //~| HELP put `mut` after the lifetime + + let _tuple2: (u8&, i32); + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type + + let _array2: [u8&; 2]; + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type + + let _generic2: Vec; + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type + + let _nested2: Option; + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type + + let _a: u8&; + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type + + let _b: u8 &; + //~^ ERROR reference types must be written as `&T` + //~| HELP put the `&` before the type + + // The following lines are examples of bitwise AND operations + // They should not trigger any errors related to reference types. + let x = 5i32; + let y = 3u8; + let t = 4u8; + let _z = x as u8 & y; + let _m = m!(t & y); +} diff --git a/tests/ui/did_you_mean/c-style-reference-types-issue-101487.stderr b/tests/ui/did_you_mean/c-style-reference-types-issue-101487.stderr new file mode 100644 index 0000000000000..122b5dcfb70a3 --- /dev/null +++ b/tests/ui/did_you_mean/c-style-reference-types-issue-101487.stderr @@ -0,0 +1,278 @@ +error: reference types must be written as `&mut T` + --> $DIR/c-style-reference-types-issue-101487.rs:12:16 + | +LL | fn func1(_num: mut& i32) {} + | ^^^ + | +help: put the `&` before `mut` + | +LL - fn func1(_num: mut& i32) {} +LL + fn func1(_num: &mut i32) {} + | + +error: reference types must be written as `&T` + --> $DIR/c-style-reference-types-issue-101487.rs:16:19 + | +LL | fn func2(_num: i32&) {} + | ^ + | +help: put the `&` before the type + | +LL - fn func2(_num: i32&) {} +LL + fn func2(_num: &i32) {} + | + +error: `mut` must be written after the lifetime + --> $DIR/c-style-reference-types-issue-101487.rs:20:20 + | +LL | fn func3<'a>(_num: mut &'a i32) {} + | ^^^ + | +help: put `mut` after the lifetime + | +LL - fn func3<'a>(_num: mut &'a i32) {} +LL + fn func3<'a>(_num: &'a mut i32) {} + | + +error: reference types must be written as `&mut T` + --> $DIR/c-style-reference-types-issue-101487.rs:26:28 + | +LL | fn method(self, _size: mut& u32) {} + | ^^^ + | +help: put the `&` before `mut` + | +LL - fn method(self, _size: mut& u32) {} +LL + fn method(self, _size: &mut u32) {} + | + +error: reference types must be written as `&T` + --> $DIR/c-style-reference-types-issue-101487.rs:30:32 + | +LL | fn method2(self, _size: i32&) {} + | ^ + | +help: put the `&` before the type + | +LL - fn method2(self, _size: i32&) {} +LL + fn method2(self, _size: &i32) {} + | + +error: reference types must be written as `&mut T` + --> $DIR/c-style-reference-types-issue-101487.rs:36:19 + | +LL | fn method(_p: mut& u8); + | ^^^ + | +help: put the `&` before `mut` + | +LL - fn method(_p: mut& u8); +LL + fn method(_p: &mut u8); + | + +error: reference types must be written as `&T` + --> $DIR/c-style-reference-types-issue-101487.rs:40:23 + | +LL | fn method3(_p: i32&); + | ^ + | +help: put the `&` before the type + | +LL - fn method3(_p: i32&); +LL + fn method3(_p: &i32); + | + +error: reference types must be written as `&mut T` + --> $DIR/c-style-reference-types-issue-101487.rs:45:24 + | +LL | fn generic_func(_t: mut& T) {} + | ^^^ + | +help: put the `&` before `mut` + | +LL - fn generic_func(_t: mut& T) {} +LL + fn generic_func(_t: &mut T) {} + | + +error: reference types must be written as `&T` + --> $DIR/c-style-reference-types-issue-101487.rs:49:26 + | +LL | fn generic_func2(_t: T&) {} + | ^ + | +help: put the `&` before the type + | +LL - fn generic_func2(_t: T&) {} +LL + fn generic_func2(_t: &T) {} + | + +error: reference types must be written as `&mut T` + --> $DIR/c-style-reference-types-issue-101487.rs:55:15 + | +LL | let _ptr: mut& u8; + | ^^^ + | +help: put the `&` before `mut` + | +LL - let _ptr: mut& u8; +LL + let _ptr: &mut u8; + | + +error: reference types must be written as `&mut T` + --> $DIR/c-style-reference-types-issue-101487.rs:59:18 + | +LL | let _tuple: (mut& u8, i32); + | ^^^ + | +help: put the `&` before `mut` + | +LL - let _tuple: (mut& u8, i32); +LL + let _tuple: (&mut u8, i32); + | + +error: reference types must be written as `&mut T` + --> $DIR/c-style-reference-types-issue-101487.rs:63:18 + | +LL | let _array: [mut& u8; 2]; + | ^^^ + | +help: put the `&` before `mut` + | +LL - let _array: [mut& u8; 2]; +LL + let _array: [&mut u8; 2]; + | + +error: reference types must be written as `&mut T` + --> $DIR/c-style-reference-types-issue-101487.rs:67:23 + | +LL | let _generic: Vec; + | ^^^ + | +help: put the `&` before `mut` + | +LL - let _generic: Vec; +LL + let _generic: Vec<&mut u8>; + | + +error: reference types must be written as `&mut T` + --> $DIR/c-style-reference-types-issue-101487.rs:71:25 + | +LL | let _nested: Option; + | ^^^ + | +help: put the `&` before `mut` + | +LL - let _nested: Option; +LL + let _nested: Option<&mut u8>; + | + +error: reference types must be written as `&mut T` + --> $DIR/c-style-reference-types-issue-101487.rs:75:16 + | +LL | let _ptr2: mut &u8; + | ^^^ + | +help: put the `&` before `mut` + | +LL - let _ptr2: mut &u8; +LL + let _ptr2: &mut u8; + | + +error: reference types must be written as `&mut T` + --> $DIR/c-style-reference-types-issue-101487.rs:79:16 + | +LL | let _ptr3: mut & u8; + | ^^^ + | +help: put the `&` before `mut` + | +LL - let _ptr3: mut & u8; +LL + let _ptr3: &mut u8; + | + +error: `mut` must be written after the lifetime + --> $DIR/c-style-reference-types-issue-101487.rs:83:16 + | +LL | let _ptr4: mut &'static u8; + | ^^^ + | +help: put `mut` after the lifetime + | +LL - let _ptr4: mut &'static u8; +LL + let _ptr4: &'static mut u8; + | + +error: reference types must be written as `&T` + --> $DIR/c-style-reference-types-issue-101487.rs:87:21 + | +LL | let _tuple2: (u8&, i32); + | ^ + | +help: put the `&` before the type + | +LL - let _tuple2: (u8&, i32); +LL + let _tuple2: (&u8, i32); + | + +error: reference types must be written as `&T` + --> $DIR/c-style-reference-types-issue-101487.rs:91:21 + | +LL | let _array2: [u8&; 2]; + | ^ + | +help: put the `&` before the type + | +LL - let _array2: [u8&; 2]; +LL + let _array2: [&u8; 2]; + | + +error: reference types must be written as `&T` + --> $DIR/c-style-reference-types-issue-101487.rs:95:26 + | +LL | let _generic2: Vec; + | ^ + | +help: put the `&` before the type + | +LL - let _generic2: Vec; +LL + let _generic2: Vec<&u8>; + | + +error: reference types must be written as `&T` + --> $DIR/c-style-reference-types-issue-101487.rs:99:28 + | +LL | let _nested2: Option; + | ^ + | +help: put the `&` before the type + | +LL - let _nested2: Option; +LL + let _nested2: Option<&u8>; + | + +error: reference types must be written as `&T` + --> $DIR/c-style-reference-types-issue-101487.rs:103:15 + | +LL | let _a: u8&; + | ^ + | +help: put the `&` before the type + | +LL - let _a: u8&; +LL + let _a: &u8; + | + +error: reference types must be written as `&T` + --> $DIR/c-style-reference-types-issue-101487.rs:107:16 + | +LL | let _b: u8 &; + | ^ + | +help: put the `&` before the type + | +LL - let _b: u8 &; +LL + let _b: &u8 ; + | + +error: aborting due to 23 previous errors +