diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 14181e440e96a..9599d7848c74a 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -228,6 +228,15 @@ pub enum AngleBracketedArg { Constraint(AssocTyConstraint), } +impl AngleBracketedArg { + pub fn span(&self) -> Span { + match self { + AngleBracketedArg::Arg(arg) => arg.span(), + AngleBracketedArg::Constraint(constraint) => constraint.span, + } + } +} + impl Into>> for AngleBracketedArgs { fn into(self) -> Option> { Some(P(GenericArgs::AngleBracketed(self))) diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index be5d322ba1677..5e09f4930084f 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -313,6 +313,13 @@ impl TokenKind { _ => None, } } + + pub fn should_end_const_arg(&self) -> bool { + match self { + Gt | Ge | BinOp(Shr) | BinOpEq(Shr) => true, + _ => false, + } + } } impl Token { diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 47dd757823be2..18582d8012c1b 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -49,7 +49,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; -use rustc_errors::struct_span_err; +use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX}; @@ -1136,6 +1136,71 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } } + // Possible `a + b` expression that should be surrounded in braces but was parsed + // as trait bounds in a trait object. Suggest surrounding with braces. + if let TyKind::TraitObject(ref bounds, TraitObjectSyntax::None) = ty.kind { + // We cannot disambiguate multi-segment paths right now as that requires type + // checking. + let const_expr_without_braces = bounds.iter().all(|bound| match bound { + GenericBound::Trait( + PolyTraitRef { + bound_generic_params, + trait_ref: TraitRef { path, .. }, + .. + }, + TraitBoundModifier::None, + ) if bound_generic_params.is_empty() + && path.segments.len() == 1 + && path.segments[0].args.is_none() => + { + let part_res = self.resolver.get_partial_res(path.segments[0].id); + match part_res.map(|r| r.base_res()) { + Some(res) => { + !res.matches_ns(Namespace::TypeNS) + && res.matches_ns(Namespace::ValueNS) + } + None => true, + } + } + _ => false, + }); + if const_expr_without_braces { + self.sess.struct_span_err(ty.span, "likely `const` expression parsed as trait bounds") + .span_label(ty.span, "parsed as trait bounds but traits weren't found") + .multipart_suggestion( + "if you meant to write a `const` expression, surround the expression with braces", + vec![ + (ty.span.shrink_to_lo(), "{ ".to_string()), + (ty.span.shrink_to_hi(), " }".to_string()), + ], + Applicability::MachineApplicable, + ) + .emit(); + + let parent_def_id = self.current_hir_id_owner.last().unwrap().0; + let node_id = self.resolver.next_node_id(); + // Add a definition for the in-band const def. + self.resolver.definitions().create_def_with_parent( + parent_def_id, + node_id, + DefPathData::AnonConst, + ExpnId::root(), + ty.span, + ); + + let path_expr = Expr { + id: ty.id, + kind: ExprKind::Err, + span: ty.span, + attrs: AttrVec::new(), + }; + let value = self.with_new_scopes(|this| hir::AnonConst { + hir_id: this.lower_node_id(node_id), + body: this.lower_const_body(path_expr.span, Some(&path_expr)), + }); + return GenericArg::Const(ConstArg { value, span: ty.span }); + } + } GenericArg::Type(self.lower_ty_direct(&ty, itctx)) } ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg { diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index ac5477edcc3c0..84c1f9acc8395 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -2275,6 +2275,7 @@ impl<'tcx> Const<'tcx> { let name = tcx.hir().name(hir_id); ty::ConstKind::Param(ty::ParamConst::new(index, name)) } + ExprKind::Err => ty::ConstKind::Error, _ => ty::ConstKind::Unevaluated( def_id.to_def_id(), InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 3f08fb79790fb..4ab1481ad183e 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -329,8 +329,20 @@ impl<'a> Parser<'a> { /// The method does not advance the current token. /// /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively. - fn check_assoc_op(&self) -> Option> { + crate fn check_assoc_op(&self) -> Option> { let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) { + // When parsing const expressions, stop parsing when encountering `>`. + ( + Some( + AssocOp::ShiftRight + | AssocOp::Greater + | AssocOp::GreaterEqual + | AssocOp::AssignOp(token::BinOpToken::Shr), + ), + _, + ) if self.restrictions.contains(Restrictions::CONST_EXPR) => { + return None; + } (Some(op), _) => (op, self.token.span), (None, Some((Ident { name: sym::and, span }, false))) => { self.error_bad_logical_op("and", "&&", "conjunction"); @@ -1585,7 +1597,9 @@ impl<'a> Parser<'a> { let lo = self.prev_token.span; let pat = self.parse_top_pat(GateOr::No)?; self.expect(&token::Eq)?; - let expr = self.with_res(Restrictions::NO_STRUCT_LITERAL, |this| { + // `self.restrictions |` below is to account for `CONST_EXPR` so that we can correctly + // parse `let` expressions in `const` arguments. + let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| { this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into()) })?; let span = lo.to(expr.span); diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 9264fc8a73518..9dc1159b681ea 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -34,6 +34,7 @@ bitflags::bitflags! { struct Restrictions: u8 { const STMT_EXPR = 1 << 0; const NO_STRUCT_LITERAL = 1 << 1; + const CONST_EXPR = 1 << 2; } } diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 9fa7bc027b878..52bbf13c8aa43 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -1,12 +1,13 @@ use super::ty::{AllowPlus, RecoverQPath}; -use super::{Parser, TokenType}; +use super::{Parser, Restrictions, TokenType}; use crate::maybe_whole; use rustc_ast::ast::{self, AngleBracketedArg, AngleBracketedArgs, GenericArg, ParenthesizedArgs}; use rustc_ast::ast::{AnonConst, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode}; use rustc_ast::ast::{Ident, Path, PathSegment, QSelf}; use rustc_ast::ptr::P; use rustc_ast::token::{self, Token}; -use rustc_errors::{pluralize, Applicability, PResult}; +use rustc_ast::util::parser::AssocOp; +use rustc_errors::{pluralize, Applicability, DiagnosticBuilder, PResult}; use rustc_span::source_map::{BytePos, Span}; use rustc_span::symbol::{kw, sym}; @@ -392,12 +393,112 @@ impl<'a> Parser<'a> { while let Some(arg) = self.parse_angle_arg()? { args.push(arg); if !self.eat(&token::Comma) { + if self.token.kind.should_end_const_arg() { + // We will correctly parse a closing `>`, exit. + } else { + // Try to recover from possible `const` arg without braces. + let arg = args.pop().unwrap(); + // FIXME: for some reason using `unexpected` or `expected_one_of_not_found` has + // adverse side-effects to subsequent errors and seems to advance the parser. + // We are causing this error here exclusively in case that a `const` expression + // could be recovered from the current parser state, even if followed by more + // arguments after a comma. + let mut err = self.struct_span_err( + self.token.span, + &format!( + "expected one of `,` or `>`, found {}", + super::token_descr(&self.token) + ), + ); + err.span_label(self.token.span, "expected one of `,` or `>`"); + match self.recover_const_arg(arg.span(), err) { + Ok(arg) => { + args.push(AngleBracketedArg::Arg(arg)); + if self.eat(&token::Comma) { + continue; + } + } + Err(mut err) => { + args.push(arg); + // We will emit a more generic error later. + err.delay_as_bug(); + } + } + } break; } } Ok(args) } + /// Try to recover from possible `const` arg without braces. + /// + /// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest + /// `foo::<{ bar + 3 }>` and `foo::<{ bar - baz }>` respectively. We only provide a suggestion + /// when we have a high degree of certainty that the resulting expression would be well formed. + pub fn recover_const_arg( + &mut self, + start: Span, + mut err: DiagnosticBuilder<'a>, + ) -> PResult<'a, GenericArg> { + let is_op = AssocOp::from_token(&self.token) + .and_then(|op| { + if let AssocOp::Greater + | AssocOp::Less + | AssocOp::ShiftRight + | AssocOp::GreaterEqual + | AssocOp::Assign // Don't recover from `foo::` + | AssocOp::AssignOp(_) = op + { + None + } else { + Some(op) + } + }) + .is_some(); + // This will be true when a trait object type `Foo +` or a path which was a `const fn` with + // type params has been parsed. + let was_op = + matches!(self.prev_token.kind, token::BinOp(token::Plus | token::Shr) | token::Gt); + if !is_op && !was_op { + // We perform these checks and early return to avoid taking a snapshot unnecessarily. + return Err(err); + } + let snapshot = self.clone(); + if is_op { + self.bump(); + } + match self.parse_expr_res(Restrictions::CONST_EXPR, None) { + Ok(expr) => { + if token::Comma == self.token.kind || self.token.kind.should_end_const_arg() { + // Avoid the following output by checking that we consumed a full const arg: + // help: to write a `const` expression, surround it with braces for it to + // be unambiguous + // | + // LL | let sr: Vec<{ (u32, _, _) = vec![] }; + // | ^ ^ + err.multipart_suggestion( + "to write a `const` expression, surround it with braces for it to be \ + unambiguous", + vec![ + (start.shrink_to_lo(), "{ ".to_string()), + (expr.span.shrink_to_hi(), " }".to_string()), + ], + Applicability::MaybeIncorrect, + ); + let value = self.mk_expr_err(start.to(expr.span)); + err.emit(); + return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })); + } + } + Err(mut err) => { + err.cancel(); + } + } + *self = snapshot; + Err(err) + } + /// Parses a single argument in the angle arguments `<...>` of a path segment. fn parse_angle_arg(&mut self) -> PResult<'a, Option> { if self.check_ident() && self.look_ahead(1, |t| matches!(t.kind, token::Eq | token::Colon)) @@ -474,41 +575,72 @@ impl<'a> Parser<'a> { /// Parse a generic argument in a path segment. /// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`. fn parse_generic_arg(&mut self) -> PResult<'a, Option> { + let start = self.token.span; let arg = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { // Parse lifetime argument. GenericArg::Lifetime(self.expect_lifetime()) } else if self.check_const_arg() { // Parse const argument. - let expr = if let token::OpenDelim(token::Brace) = self.token.kind { + let value = if let token::OpenDelim(token::Brace) = self.token.kind { self.parse_block_expr( None, self.token.span, BlockCheckMode::Default, ast::AttrVec::new(), )? - } else if self.token.is_ident() { + } else { // FIXME(const_generics): to distinguish between idents for types and consts, // we should introduce a GenericArg::Ident in the AST and distinguish when // lowering to the HIR. For now, idents for const args are not permitted. - if self.token.is_bool_lit() { - self.parse_literal_maybe_minus()? - } else { - let span = self.token.span; - let msg = "identifiers may currently not be used for const generics"; - self.struct_span_err(span, msg).emit(); - let block = self.mk_block_err(span); - self.mk_expr(span, ast::ExprKind::Block(block, None), ast::AttrVec::new()) + let start = self.token.span; + let expr = + self.parse_expr_res(Restrictions::CONST_EXPR, None).map_err(|mut err| { + err.span_label( + start.shrink_to_lo(), + "while parsing a `const` argument starting here", + ); + err + })?; + let valid_const = match &expr.kind { + ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true, + ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind { + ast::ExprKind::Lit(_) => true, + _ => false, + }, + _ => false, + }; + if !valid_const { + self.struct_span_err( + expr.span, + "`const` generic expressions without braces are not supported", + ) + .note("only literals are supported as `const` generic without braces") + .multipart_suggestion( + "surround `const` expressions with braces", + vec![ + (expr.span.shrink_to_lo(), "{ ".to_string()), + (expr.span.shrink_to_hi(), " }".to_string()), + ], + Applicability::MachineApplicable, + ) + .emit(); } - } else { - self.parse_literal_maybe_minus()? + expr }; - GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: expr }) + GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }) } else if self.check_type() { // Parse type argument. - GenericArg::Type(self.parse_ty()?) + match self.parse_ty() { + Ok(ty) => GenericArg::Type(ty), + Err(err) => { + // Try to recover from possible `const` arg without braces. + return self.recover_const_arg(start, err).map(Some); + } + } } else { return Ok(None); }; + // FIXME: recover from const expressions without braces that require them. Ok(Some(arg)) } } diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index f369e827a402b..32b4b873cbd9f 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -558,25 +558,22 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { let prev = replace(&mut self.diagnostic_metadata.currently_processing_generics, true); match arg { GenericArg::Type(ref ty) => { - // We parse const arguments as path types as we cannot distinguish them during - // parsing. We try to resolve that ambiguity by attempting resolution the type - // namespace first, and if that fails we try again in the value namespace. If - // resolution in the value namespace succeeds, we have an generic const argument on - // our hands. - if let TyKind::Path(ref qself, ref path) = ty.kind { - // We cannot disambiguate multi-segment paths right now as that requires type - // checking. - if path.segments.len() == 1 && path.segments[0].args.is_none() { - let mut check_ns = |ns| { - self.resolve_ident_in_lexical_scope( - path.segments[0].ident, - ns, - None, - path.span, - ) - .is_some() - }; - if !check_ns(TypeNS) && check_ns(ValueNS) { + let mut check_ns = |path: &Path, ns| { + self.resolve_ident_in_lexical_scope(path.segments[0].ident, ns, None, path.span) + .is_some() + && path.segments.len() == 1 + && path.segments[0].args.is_none() + }; + match ty.kind { + // We parse const arguments as path types as we cannot distinguish them during + // parsing. We try to resolve that ambiguity by attempting resolution the type + // namespace first, and if that fails we try again in the value namespace. If + // resolution in the value namespace succeeds, we have an generic const argument + // on our hands. + TyKind::Path(ref qself, ref path) => { + // We cannot disambiguate multi-segment paths right now as that requires type + // checking. + if !check_ns(path, TypeNS) && check_ns(path, ValueNS) { // This must be equivalent to `visit_anon_const`, but we cannot call it // directly due to visitor lifetimes so we have to copy-paste some code. self.with_constant_rib(|this| { @@ -597,6 +594,38 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { return; } } + + // Possible `a + b` expression that should be surrounded in braces but was + // parsed as trait bounds in a trait object. Suggest surrounding with braces. + TyKind::TraitObject(ref bounds, TraitObjectSyntax::None) => { + // We cannot disambiguate multi-segment paths right now as that requires + // type checking. + let const_expr_without_braces = bounds.iter().all(|bound| match bound { + GenericBound::Trait( + PolyTraitRef { + bound_generic_params, + trait_ref: TraitRef { path, .. }, + .. + }, + TraitBoundModifier::None, + ) if bound_generic_params.is_empty() => { + !check_ns(path, TypeNS) && check_ns(path, ValueNS) + } + _ => false, + }); + if const_expr_without_braces { + // This will be handled and emit an appropriate error in + // `rustc_ast_lowering::LoweringContext::lower_generic_arg`. We do not + // `visit_ty` in this case to avoid extra unnecessary output. + self.r.session.delay_span_bug( + ty.span, + "`const` expression parsed as trait bounds", + ); + self.diagnostic_metadata.currently_processing_generics = prev; + return; + } + } + _ => {} } self.visit_ty(ty); diff --git a/src/test/ui/const-generics/const-expression-missing-braces.rs b/src/test/ui/const-generics/const-expression-missing-braces.rs new file mode 100644 index 0000000000000..2e79182c67f0b --- /dev/null +++ b/src/test/ui/const-generics/const-expression-missing-braces.rs @@ -0,0 +1,49 @@ +#![allow(incomplete_features)] +#![feature(const_generics)] + +fn foo() {} + +const BAR: usize = 42; + +fn a() { + foo::(); //~ ERROR expected one of +} +fn b() { + foo::(); //~ ERROR likely `const` expression parsed as trait bounds +} +fn c() { + foo::<3 + 3>(); //~ ERROR `const` generic expressions without braces are not supported +} +fn d() { + foo::(); //~ ERROR expected one of +} +fn e() { + foo::(); //~ ERROR expected one of +} +fn f() { + foo::<100 - BAR>(); //~ ERROR `const` generic expressions without braces are not supported +} +fn g() { + foo::()>(); //~ ERROR expected one of +} +fn h() { + foo::()>(); //~ ERROR expected one of +} +fn i() { + foo::() + BAR>(); //~ ERROR expected one of +} +fn j() { + foo::() - BAR>(); //~ ERROR expected one of +} +fn k() { + foo::()>(); //~ ERROR expected one of +} +fn l() { + foo::()>(); //~ ERROR expected one of +} + +const fn bar() -> usize { + C +} + +fn main() {} diff --git a/src/test/ui/const-generics/const-expression-missing-braces.stderr b/src/test/ui/const-generics/const-expression-missing-braces.stderr new file mode 100644 index 0000000000000..89539b3f1be6f --- /dev/null +++ b/src/test/ui/const-generics/const-expression-missing-braces.stderr @@ -0,0 +1,136 @@ +error: expected one of `,` or `>`, found `3` + --> $DIR/const-expression-missing-braces.rs:9:17 + | +LL | foo::(); + | ^ expected one of `,` or `>` + | +help: to write a `const` expression, surround it with braces for it to be unambiguous + | +LL | foo::<{ BAR + 3 }>(); + | ^ ^ + +error: `const` generic expressions without braces are not supported + --> $DIR/const-expression-missing-braces.rs:15:11 + | +LL | foo::<3 + 3>(); + | ^^^^^ + | + = note: only literals are supported as `const` generic without braces +help: surround `const` expressions with braces + | +LL | foo::<{ 3 + 3 }>(); + | ^ ^ + +error: expected one of `,` or `>`, found `-` + --> $DIR/const-expression-missing-braces.rs:18:15 + | +LL | foo::(); + | ^ expected one of `,` or `>` + | +help: to write a `const` expression, surround it with braces for it to be unambiguous + | +LL | foo::<{ BAR - 3 }>(); + | ^ ^ + +error: expected one of `,` or `>`, found `-` + --> $DIR/const-expression-missing-braces.rs:21:15 + | +LL | foo::(); + | ^ expected one of `,` or `>` + | +help: to write a `const` expression, surround it with braces for it to be unambiguous + | +LL | foo::<{ BAR - BAR }>(); + | ^ ^ + +error: `const` generic expressions without braces are not supported + --> $DIR/const-expression-missing-braces.rs:24:11 + | +LL | foo::<100 - BAR>(); + | ^^^^^^^^^ + | + = note: only literals are supported as `const` generic without braces +help: surround `const` expressions with braces + | +LL | foo::<{ 100 - BAR }>(); + | ^ ^ + +error: expected one of `,` or `>`, found `(` + --> $DIR/const-expression-missing-braces.rs:27:19 + | +LL | foo::()>(); + | ^ expected one of `,` or `>` + | +help: to write a `const` expression, surround it with braces for it to be unambiguous + | +LL | foo::<{ bar() }>(); + | ^ ^ + +error: expected one of `,` or `>`, found `(` + --> $DIR/const-expression-missing-braces.rs:30:21 + | +LL | foo::()>(); + | ^ expected one of `,` or `>` + | +help: to write a `const` expression, surround it with braces for it to be unambiguous + | +LL | foo::<{ bar::() }>(); + | ^ ^ + +error: expected one of `,` or `>`, found `(` + --> $DIR/const-expression-missing-braces.rs:33:21 + | +LL | foo::() + BAR>(); + | ^ expected one of `,` or `>` + | +help: to write a `const` expression, surround it with braces for it to be unambiguous + | +LL | foo::<{ bar::() + BAR }>(); + | ^ ^ + +error: expected one of `,` or `>`, found `(` + --> $DIR/const-expression-missing-braces.rs:36:21 + | +LL | foo::() - BAR>(); + | ^ expected one of `,` or `>` + | +help: to write a `const` expression, surround it with braces for it to be unambiguous + | +LL | foo::<{ bar::() - BAR }>(); + | ^ ^ + +error: expected one of `,` or `>`, found `-` + --> $DIR/const-expression-missing-braces.rs:39:15 + | +LL | foo::()>(); + | ^ expected one of `,` or `>` + | +help: to write a `const` expression, surround it with braces for it to be unambiguous + | +LL | foo::<{ BAR - bar::() }>(); + | ^ ^ + +error: expected one of `,` or `>`, found `-` + --> $DIR/const-expression-missing-braces.rs:42:15 + | +LL | foo::()>(); + | ^ expected one of `,` or `>` + | +help: to write a `const` expression, surround it with braces for it to be unambiguous + | +LL | foo::<{ BAR - bar::() }>(); + | ^ ^ + +error: likely `const` expression parsed as trait bounds + --> $DIR/const-expression-missing-braces.rs:12:11 + | +LL | foo::(); + | ^^^^^^^^^ parsed as trait bounds but traits weren't found + | +help: if you meant to write a `const` expression, surround the expression with braces + | +LL | foo::<{ BAR + BAR }>(); + | ^ ^ + +error: aborting due to 12 previous errors + diff --git a/src/test/ui/const-generics/const-expression-parameter.rs b/src/test/ui/const-generics/const-expression-parameter.rs index 22c6c35162281..6999d8266169b 100644 --- a/src/test/ui/const-generics/const-expression-parameter.rs +++ b/src/test/ui/const-generics/const-expression-parameter.rs @@ -1,5 +1,5 @@ +#![allow(incomplete_features)] #![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash fn i32_identity() -> i32 { 5 @@ -10,7 +10,7 @@ fn foo_a() { } fn foo_b() { - i32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+` + i32_identity::<1 + 2>(); //~ ERROR `const` generic expressions without braces are not supported } fn foo_c() { diff --git a/src/test/ui/const-generics/const-expression-parameter.stderr b/src/test/ui/const-generics/const-expression-parameter.stderr index 6784aeebf0fec..4685b67d75a98 100644 --- a/src/test/ui/const-generics/const-expression-parameter.stderr +++ b/src/test/ui/const-generics/const-expression-parameter.stderr @@ -1,16 +1,14 @@ -error: expected one of `,` or `>`, found `+` - --> $DIR/const-expression-parameter.rs:13:22 +error: `const` generic expressions without braces are not supported + --> $DIR/const-expression-parameter.rs:13:20 | LL | i32_identity::<1 + 2>(); - | ^ expected one of `,` or `>` - -warning: the feature `const_generics` is incomplete and may cause the compiler to crash - --> $DIR/const-expression-parameter.rs:1:12 + | ^^^^^ | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ + = note: only literals are supported as `const` generic without braces +help: surround `const` expressions with braces | - = note: `#[warn(incomplete_features)]` on by default +LL | i32_identity::<{ 1 + 2 }>(); + | ^ ^ -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-closure-lifetime.rs b/src/test/ui/parser/removed-syntax-closure-lifetime.rs index ceac94080062d..969c49feb8905 100644 --- a/src/test/ui/parser/removed-syntax-closure-lifetime.rs +++ b/src/test/ui/parser/removed-syntax-closure-lifetime.rs @@ -1,2 +1,2 @@ type closure = Box; -//~^ ERROR expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `/` +//~^ ERROR expected one of diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs index d5756737f1791..70c7fa74098a6 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs @@ -232,10 +232,11 @@ fn inside_const_generic_arguments() { // In the cases above we have `ExprKind::Block` to help us out. // Below however, we would not have a block and so an implementation might go // from visiting expressions to types without banning `let` expressions down the tree. - // This tests ensures that we are not caught by surprise should the parser - // admit non-IDENT expressions in const generic arguments. - + // The parser admits non-IDENT expressions in const generic arguments and is caught by the + // test below. if A::< - true && let 1 = 1 //~ ERROR expected one of `,` or `>`, found `&&` + true && let 1 = 1 //~ ERROR `let` expressions are not supported here + //~^ ERROR `match` is not allowed in a `const` + //~| ERROR `const` generic expressions without braces are not supported >::O == 5 {} } diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index 4f11c306f5036..25f9db0819bcb 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -1,8 +1,14 @@ -error: expected one of `,` or `>`, found `&&` - --> $DIR/disallowed-positions.rs:239:14 +error: `const` generic expressions without braces are not supported + --> $DIR/disallowed-positions.rs:238:9 | LL | true && let 1 = 1 - | ^^ expected one of `,` or `>` + | ^^^^^^^^^^^^^^^^^ + | + = note: only literals are supported as `const` generic without braces +help: surround `const` expressions with braces + | +LL | { true && let 1 = 1 } + | ^ ^ error: `let` expressions are not supported here --> $DIR/disallowed-positions.rs:32:9 @@ -499,6 +505,15 @@ LL | true && let 1 = 1 = note: only supported directly in conditions of `if`- and `while`-expressions = note: as well as when nested within `&&` and parenthesis in those conditions +error: `let` expressions are not supported here + --> $DIR/disallowed-positions.rs:238:17 + | +LL | true && let 1 = 1 + | ^^^^^^^^^ + | + = note: only supported directly in conditions of `if`- and `while`-expressions + = note: as well as when nested within `&&` and parenthesis in those conditions + warning: the feature `const_generics` is incomplete and may cause the compiler to crash --> $DIR/disallowed-positions.rs:20:12 | @@ -540,6 +555,15 @@ LL | true && let 1 = 1 = note: see issue #49146 for more information = help: add `#![feature(const_if_match)]` to the crate attributes to enable +error[E0658]: `match` is not allowed in a `const` + --> $DIR/disallowed-positions.rs:238:17 + | +LL | true && let 1 = 1 + | ^^^^^^^^^ + | + = note: see issue #49146 for more information + = help: add `#![feature(const_if_match)]` to the crate attributes to enable + error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:32:8 | @@ -980,7 +1004,7 @@ LL | let 0 = 0?; = help: the trait `std::ops::Try` is not implemented for `{integer}` = note: required by `std::ops::Try::into_result` -error: aborting due to 106 previous errors; 2 warnings emitted +error: aborting due to 108 previous errors; 2 warnings emitted Some errors have detailed explanations: E0277, E0308, E0600, E0614, E0658. For more information about an error, try `rustc --explain E0277`.