Question: let attrs = self.parse_outer_attributes()?; let lo = self.token.span; <del> Ok(Some(if self.eat_keyword(kw::Let) { Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Local(self.parse_local(attrs.into())?), span: lo.to(self.prev_span), } } else if let Some(macro_def) = self.eat_macro_def( &attrs, &respan(lo, VisibilityKind::Inherited), lo, )? { Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Item(macro_def), span: lo.to(self.prev_span), } </del> <ins> if self.eat_keyword(kw::Let) { let local = self.parse_local(attrs.into())?; return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Local(local)))); } let mac_vis = respan(lo, VisibilityKind::Inherited); if let Some(macro_def) = self.eat_macro_def(&attrs, &mac_vis, lo)? { return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Item(macro_def)))); } </ins> // Starts like a simple path, being careful to avoid contextual keywords // such as a union items, item with `crate` visibility or auto trait items. // Our goal here is to parse an arbitrary path `a::b::c` but not something that starts // like a path (1 token), but it fact not a path. <del> // `union::b::c` - path, `union U { ... }` - not a path. // `crate::b::c` - path, `crate struct S;` - not a path. } else if self.token.is_path_start() && !self.token.is_qpath_start() && !self.is_union_item() && !self.is_crate_vis() && !self.is_auto_trait_item() && !self.is_async_fn() { </del> <ins> if self.token.is_path_start() && !self.token.is_qpath_start() && !self.is_union_item() // `union::b::c` - path, `union U { ... }` - not a path. && !self.is_crate_vis() // `crate::b::c` - path, `crate struct S;` - not a path. && !self.is_auto_trait_item() && !self.is_async_fn() { </ins> let path = self.parse_path(PathStyle::Expr)?; <del> if !self.eat(&token::Not) { let expr = if self.check(&token::OpenDelim(token::Brace)) { self.parse_struct_expr(lo, path, ThinVec::new())? } else { let hi = self.prev_span; self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new()) }; let expr = self.with_res(Restrictions::STMT_EXPR, |this| { let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) })?; return Ok(Some(Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Expr(expr), span: lo.to(self.prev_span), })); </del> <ins> if self.eat(&token::Not) { return self.parse_stmt_mac(lo, attrs.into(), path, macro_legacy_warnings); </ins> } <del> let args = self.parse_mac_args()?; let delim = args.delim(); let hi = self.prev_span; let style = if delim == token::Brace { MacStmtStyle::Braces </del> <ins> let expr = if self.check(&token::OpenDelim(token::Brace)) { self.parse_struct_expr(lo, path, ThinVec::new())? </ins> } else { <del> MacStmtStyle::NoBraces </del> <ins> let hi = self.prev_span; self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new()) </ins> }; <del> let mac = Mac { path, args, prior_type_ascription: self.last_type_ascription, }; let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { StmtKind::Mac(P((mac, style, attrs.into()))) } // We used to incorrectly stop parsing macro-expanded statements here. // If the next token will be an error anyway but could have parsed with the // earlier behavior, stop parsing here and emit a warning to avoid breakage. else if macro_legacy_warnings && self.token.can_begin_expr() && match self.token.kind { // These can continue an expression, so we can't stop parsing and warn. token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) | token::BinOp(token::Minus) | token::BinOp(token::Star) | token::BinOp(token::And) | token::BinOp(token::Or) | token::AndAnd | token::OrOr | token::DotDot | token::DotDotDot | token::DotDotEq => false, _ => true, } { self.warn_missing_semicolon(); StmtKind::Mac(P((mac, style, attrs.into()))) } else { let e = self.mk_expr(lo.to(hi), ExprKind::Mac(mac), ThinVec::new()); let e = self.maybe_recover_from_bad_qpath(e, true)?; let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; StmtKind::Expr(e) }; Stmt { id: DUMMY_NODE_ID, span: lo.to(hi), kind, </del> <ins> let expr = self.with_res(Restrictions::STMT_EXPR, |this| { let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) })?; return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Expr(expr)))); } // FIXME: Bad copy of attrs let old_directory_ownership = mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); let item = self.parse_item_(attrs.clone(), false, true)?; self.directory.ownership = old_directory_ownership; if let Some(item) = item { return Ok(Some(self.mk_stmt(lo.to(item.span), StmtKind::Item(item)))); } // Do not attempt to parse an expression if we're done here. if self.token == token::Semi { self.error_outer_attrs(&attrs); self.bump(); let mut last_semi = lo; while self.token == token::Semi { last_semi = self.token.span; self.bump(); </ins> } <ins> // We are encoding a string of semicolons as an an empty tuple that spans // the excess semicolons to preserve this info until the lint stage. let kind = StmtKind::Semi(self.mk_expr( lo.to(last_semi), ExprKind::Tup(Vec::new()), ThinVec::new() )); return Ok(Some(self.mk_stmt(lo.to(last_semi), kind))); } if self.token == token::CloseDelim(token::Brace) { self.error_outer_attrs(&attrs); return Ok(None); } // Remainder are line-expr stmts. let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?; Ok(Some(self.mk_stmt(lo.to(e.span), StmtKind::Expr(e)))) } /// Parses a statement macro `mac!(args)` provided a `path` representing `mac`. /// At this point, the `!` token after the path has already been eaten. fn parse_stmt_mac( &mut self, lo: Span, attrs: ThinVec<Attribute>, path: ast::Path, legacy_warnings: bool, ) -> PResult<'a, Option<Stmt>> { let args = self.parse_mac_args()?; let delim = args.delim(); let hi = self.prev_span; let style = if delim == token::Brace { MacStmtStyle::Braces </ins> } else { <del> // FIXME: Bad copy of attrs let old_directory_ownership = mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); let item = self.parse_item_(attrs.clone(), false, true)?; self.directory.ownership = old_directory_ownership; match item { Some(i) => Stmt { id: DUMMY_NODE_ID, span: lo.to(i.span), kind: StmtKind::Item(i), }, None => { let unused_attrs = |attrs: &[Attribute], s: &mut Self| { if !attrs.is_empty() { if s.prev_token_kind == PrevTokenKind::DocComment { s.span_fatal_err(s.prev_span, Error::UselessDocComment).emit(); } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) { s.span_err( s.token.span, "expected statement after outer attribute" ); } } }; // Do not attempt to parse an expression if we're done here. if self.token == token::Semi { unused_attrs(&attrs, self); self.bump(); let mut last_semi = lo; while self.token == token::Semi { last_semi = self.token.span; self.bump(); } // We are encoding a string of semicolons as an // an empty tuple that spans the excess semicolons // to preserve this info until the lint stage return Ok(Some(Stmt { id: DUMMY_NODE_ID, span: lo.to(last_semi), kind: StmtKind::Semi(self.mk_expr(lo.to(last_semi), ExprKind::Tup(Vec::new()), ThinVec::new() )), })); } </del> <ins> MacStmtStyle::NoBraces }; </ins> <del> if self.token == token::CloseDelim(token::Brace) { unused_attrs(&attrs, self); return Ok(None); } </del> <ins> let mac = Mac { path, args, prior_type_ascription: self.last_type_ascription, }; </ins> <del> // Remainder are line-expr stmts. let e = self.parse_expr_res( Restrictions::STMT_EXPR, Some(attrs.into()))?; Stmt { id: DUMMY_NODE_ID, span: lo.to(e.span), kind: StmtKind::Expr(e), } } </del> <ins> let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { StmtKind::Mac(P((mac, style, attrs.into()))) } // We used to incorrectly stop parsing macro-expanded statements here. // If the next token will be an error anyway but could have parsed with the // earlier behavior, stop parsing here and emit a warning to avoid breakage. else if legacy_warnings && self.token.can_begin_expr() && match self.token.kind { // These can continue an expression, so we can't stop parsing and warn. token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) | token::BinOp(token::Minus) | token::BinOp(token::Star) | token::BinOp(token::And) | token::BinOp(token::Or) | token::AndAnd | token::OrOr | token::DotDot | token::DotDotDot | token::DotDotEq => false, _ => true, </ins> } <del> })) </del> <ins> { self.warn_missing_semicolon(); StmtKind::Mac(P((mac, style, attrs))) } else { // Since none of the above applied, this is an expression statement macro. let e = self.mk_expr(lo.to(hi), ExprKind::Mac(mac), ThinVec::new()); let e = self.maybe_recover_from_bad_qpath(e, true)?; let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?; let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; StmtKind::Expr(e) }; Ok(Some(self.mk_stmt(lo.to(hi), kind))) } /// Error on outer attributes in this context. /// Also error if the previous token was a doc comment. fn error_outer_attrs(&self, attrs: &[Attribute]) { if !attrs.is_empty() { if self.prev_token_kind == PrevTokenKind::DocComment { self.span_fatal_err(self.prev_span, Error::UselessDocComment).emit(); } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) { self.span_err(self.token.span, "expected statement after outer attribute"); } } </ins> } /// Parses a local variable declaration.

Although I would also guess that the initial idea is very unlikely to end up accepted, it feels premature to unilaterally hijack the thread in your very first comment and make it have a different (and in a way opposite) purpose. Teams of the Rust project are designed to make decisions collectively. Improving diagnostics sounds good, but issue numbers are cheap.
Implementing something as a diagnostic actually brings you closer to a working implementation -- I think more proposals should start out as diagnostics. I will not bother the other language team members with not-fully-formed proposals that we will not accept in either case. I converted the issue into the most actionable and productive thing it could be. The place for ephemeral discussions is either on Discord or on internals. If you want to discuss this further, I'm available at Discord (but will not respond to it further here). wasting everyone's time with things that will go nowhere (because it won't be accepted and because it is not important enough to be raised at the team) is not.
IMHO, the original thing this issue was opened for should be an RFC, not an issue. I'd have closed this, pointed the OP to the RFCs repo, and opened a new issue for the diagnostic issue.
This issue was literally in the RFCs repo initially, transferred it from there.
Language bashing is not welcome here
Wait, so should I unassign here, and assign to the new issue?
Nah, just use this one.
Yeah, thats fine. You can just change this issue to be for diagnostics instead.
I'm sorry, I've been pretty busy with coursework, and I'm still fighting my Python installation to even build the compiler, let alone make progress on this. Sorry :(
I'll assign this to myself to work on when I have time. If you want to work on it however, feel free to work-steal it from me!
I would like to help with this
Sorry; should have updated this issue...! There's a PR at the moment. Feel free to leave suggestions on it if you like. :)


Question: let attrs = self.parse_outer_attributes()?; let lo = self.token.span; <del> Ok(Some(if self.eat_keyword(kw::Let) { Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Local(self.parse_local(attrs.into())?), span: lo.to(self.prev_span), } } else if let Some(macro_def) = self.eat_macro_def( &attrs, &respan(lo, VisibilityKind::Inherited), lo, )? { Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Item(macro_def), span: lo.to(self.prev_span), } </del> <ins> if self.eat_keyword(kw::Let) { let local = self.parse_local(attrs.into())?; return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Local(local)))); } let mac_vis = respan(lo, VisibilityKind::Inherited); if let Some(macro_def) = self.eat_macro_def(&attrs, &mac_vis, lo)? { return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Item(macro_def)))); } </ins> // Starts like a simple path, being careful to avoid contextual keywords // such as a union items, item with `crate` visibility or auto trait items. // Our goal here is to parse an arbitrary path `a::b::c` but not something that starts // like a path (1 token), but it fact not a path. <del> // `union::b::c` - path, `union U { ... }` - not a path. // `crate::b::c` - path, `crate struct S;` - not a path. } else if self.token.is_path_start() && !self.token.is_qpath_start() && !self.is_union_item() && !self.is_crate_vis() && !self.is_auto_trait_item() && !self.is_async_fn() { </del> <ins> if self.token.is_path_start() && !self.token.is_qpath_start() && !self.is_union_item() // `union::b::c` - path, `union U { ... }` - not a path. && !self.is_crate_vis() // `crate::b::c` - path, `crate struct S;` - not a path. && !self.is_auto_trait_item() && !self.is_async_fn() { </ins> let path = self.parse_path(PathStyle::Expr)?; <del> if !self.eat(&token::Not) { let expr = if self.check(&token::OpenDelim(token::Brace)) { self.parse_struct_expr(lo, path, ThinVec::new())? } else { let hi = self.prev_span; self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new()) }; let expr = self.with_res(Restrictions::STMT_EXPR, |this| { let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) })?; return Ok(Some(Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Expr(expr), span: lo.to(self.prev_span), })); </del> <ins> if self.eat(&token::Not) { return self.parse_stmt_mac(lo, attrs.into(), path, macro_legacy_warnings); </ins> } <del> let args = self.parse_mac_args()?; let delim = args.delim(); let hi = self.prev_span; let style = if delim == token::Brace { MacStmtStyle::Braces </del> <ins> let expr = if self.check(&token::OpenDelim(token::Brace)) { self.parse_struct_expr(lo, path, ThinVec::new())? </ins> } else { <del> MacStmtStyle::NoBraces </del> <ins> let hi = self.prev_span; self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new()) </ins> }; <del> let mac = Mac { path, args, prior_type_ascription: self.last_type_ascription, }; let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { StmtKind::Mac(P((mac, style, attrs.into()))) } // We used to incorrectly stop parsing macro-expanded statements here. // If the next token will be an error anyway but could have parsed with the // earlier behavior, stop parsing here and emit a warning to avoid breakage. else if macro_legacy_warnings && self.token.can_begin_expr() && match self.token.kind { // These can continue an expression, so we can't stop parsing and warn. token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) | token::BinOp(token::Minus) | token::BinOp(token::Star) | token::BinOp(token::And) | token::BinOp(token::Or) | token::AndAnd | token::OrOr | token::DotDot | token::DotDotDot | token::DotDotEq => false, _ => true, } { self.warn_missing_semicolon(); StmtKind::Mac(P((mac, style, attrs.into()))) } else { let e = self.mk_expr(lo.to(hi), ExprKind::Mac(mac), ThinVec::new()); let e = self.maybe_recover_from_bad_qpath(e, true)?; let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; StmtKind::Expr(e) }; Stmt { id: DUMMY_NODE_ID, span: lo.to(hi), kind, </del> <ins> let expr = self.with_res(Restrictions::STMT_EXPR, |this| { let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?; this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr)) })?; return Ok(Some(self.mk_stmt(lo.to(self.prev_span), StmtKind::Expr(expr)))); } // FIXME: Bad copy of attrs let old_directory_ownership = mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); let item = self.parse_item_(attrs.clone(), false, true)?; self.directory.ownership = old_directory_ownership; if let Some(item) = item { return Ok(Some(self.mk_stmt(lo.to(item.span), StmtKind::Item(item)))); } // Do not attempt to parse an expression if we're done here. if self.token == token::Semi { self.error_outer_attrs(&attrs); self.bump(); let mut last_semi = lo; while self.token == token::Semi { last_semi = self.token.span; self.bump(); </ins> } <ins> // We are encoding a string of semicolons as an an empty tuple that spans // the excess semicolons to preserve this info until the lint stage. let kind = StmtKind::Semi(self.mk_expr( lo.to(last_semi), ExprKind::Tup(Vec::new()), ThinVec::new() )); return Ok(Some(self.mk_stmt(lo.to(last_semi), kind))); } if self.token == token::CloseDelim(token::Brace) { self.error_outer_attrs(&attrs); return Ok(None); } // Remainder are line-expr stmts. let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?; Ok(Some(self.mk_stmt(lo.to(e.span), StmtKind::Expr(e)))) } /// Parses a statement macro `mac!(args)` provided a `path` representing `mac`. /// At this point, the `!` token after the path has already been eaten. fn parse_stmt_mac( &mut self, lo: Span, attrs: ThinVec<Attribute>, path: ast::Path, legacy_warnings: bool, ) -> PResult<'a, Option<Stmt>> { let args = self.parse_mac_args()?; let delim = args.delim(); let hi = self.prev_span; let style = if delim == token::Brace { MacStmtStyle::Braces </ins> } else { <del> // FIXME: Bad copy of attrs let old_directory_ownership = mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock); let item = self.parse_item_(attrs.clone(), false, true)?; self.directory.ownership = old_directory_ownership; match item { Some(i) => Stmt { id: DUMMY_NODE_ID, span: lo.to(i.span), kind: StmtKind::Item(i), }, None => { let unused_attrs = |attrs: &[Attribute], s: &mut Self| { if !attrs.is_empty() { if s.prev_token_kind == PrevTokenKind::DocComment { s.span_fatal_err(s.prev_span, Error::UselessDocComment).emit(); } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) { s.span_err( s.token.span, "expected statement after outer attribute" ); } } }; // Do not attempt to parse an expression if we're done here. if self.token == token::Semi { unused_attrs(&attrs, self); self.bump(); let mut last_semi = lo; while self.token == token::Semi { last_semi = self.token.span; self.bump(); } // We are encoding a string of semicolons as an // an empty tuple that spans the excess semicolons // to preserve this info until the lint stage return Ok(Some(Stmt { id: DUMMY_NODE_ID, span: lo.to(last_semi), kind: StmtKind::Semi(self.mk_expr(lo.to(last_semi), ExprKind::Tup(Vec::new()), ThinVec::new() )), })); } </del> <ins> MacStmtStyle::NoBraces }; </ins> <del> if self.token == token::CloseDelim(token::Brace) { unused_attrs(&attrs, self); return Ok(None); } </del> <ins> let mac = Mac { path, args, prior_type_ascription: self.last_type_ascription, }; </ins> <del> // Remainder are line-expr stmts. let e = self.parse_expr_res( Restrictions::STMT_EXPR, Some(attrs.into()))?; Stmt { id: DUMMY_NODE_ID, span: lo.to(e.span), kind: StmtKind::Expr(e), } } </del> <ins> let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { StmtKind::Mac(P((mac, style, attrs.into()))) } // We used to incorrectly stop parsing macro-expanded statements here. // If the next token will be an error anyway but could have parsed with the // earlier behavior, stop parsing here and emit a warning to avoid breakage. else if legacy_warnings && self.token.can_begin_expr() && match self.token.kind { // These can continue an expression, so we can't stop parsing and warn. token::OpenDelim(token::Paren) | token::OpenDelim(token::Bracket) | token::BinOp(token::Minus) | token::BinOp(token::Star) | token::BinOp(token::And) | token::BinOp(token::Or) | token::AndAnd | token::OrOr | token::DotDot | token::DotDotDot | token::DotDotEq => false, _ => true, </ins> } <del> })) </del> <ins> { self.warn_missing_semicolon(); StmtKind::Mac(P((mac, style, attrs))) } else { // Since none of the above applied, this is an expression statement macro. let e = self.mk_expr(lo.to(hi), ExprKind::Mac(mac), ThinVec::new()); let e = self.maybe_recover_from_bad_qpath(e, true)?; let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?; let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; StmtKind::Expr(e) }; Ok(Some(self.mk_stmt(lo.to(hi), kind))) } /// Error on outer attributes in this context. /// Also error if the previous token was a doc comment. fn error_outer_attrs(&self, attrs: &[Attribute]) { if !attrs.is_empty() { if self.prev_token_kind == PrevTokenKind::DocComment { self.span_fatal_err(self.prev_span, Error::UselessDocComment).emit(); } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) { self.span_err(self.token.span, "expected statement after outer attribute"); } } </ins> } /// Parses a local variable declaration.

From The following code should be using the common list parsing utilities: CC
What/where are the common list parsing utilties? Edit: never mind, I've got it. , , etc. for anyone who's wondering.


Question: <ins> use std::convert::TryInto; trait A<T> { fn foo() {} } trait B<T, U> { fn bar() {} } struct S; impl<T> A<T> for S {} impl<T, U> B<T, U> for S {} fn main() { let _ = A::foo::<S>(); //~^ ERROR //~| HELP remove these generics //~| HELP consider moving this generic argument let _ = B::bar::<S, S>(); //~^ ERROR //~| HELP remove these generics //~| HELP consider moving these generic arguments let _ = A::<S>::foo::<S>(); //~^ ERROR //~| HELP remove these generics let _ = 42.into::<Option<_>>(); //~^ ERROR //~| HELP remove these generics //~| HELP consider moving this generic argument } </ins>

<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. If you cannot produce a minimal reproduction case (something that would work in isolation), please provide the steps or even link to a repository that causes the problematic output to occur. --Given the following code: The current output is: <!-- The following is not always necessary. --Ideally the output should look like: When a user called with an annotation, it's helpful to suggest too. <!-- If the problem is not self-explanatory, please provide a rationale for the change. --<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
If it's ok, I would like to give a shot. If you plan to work on it, please go ahead.
It's yours :)
claim
Hi, I would like to ask a question... I'm reading the code now and am thinking of extending the error messages by adding to . My plan is that start adding some fields (like ty::TraitRef) to and dbg! the output to get the value of trait information like for a new error message. Is my approach out of line or is there a better approach for that.
You don't have to hold information of in because we can get the info on-demand by the combination of and . Say you'd add a method of , the code will be something like this: For getting the name of the trait in question, or will be handy for you.
I appreciate your answer.
are you still working on this? :)


Question: } .example-wrap.ignore .tooltip { <del> color:  var(--codeblock-ignore-color); </del> <ins> color: var(--codeblock-ignore-color); </ins> } .example-wrap.compile_fail:hover .tooltip,

Following , we realized that rustdoc users would prefer to have a syntax extension rather than using plain HTML to have warning blocks. suggested the following: suggested: What do you think? cc
Personal Opinions: The first style will look fine for short forms, but I'm not sure for longer text. A possible syntax: Which to me pushes the text too far right. Not having any spacing, but just separating with newlines, seems hard to parse at a glance what is part of the WARNING, and prevents multiple line breaks inside the warning. Also, it's not as extensible. INFO can be , but if we ever want more extensions, they would increasingly possibly conflict with other things. The second style makes it immediately clear what is part of the block, and is unlikely to accidentally conflict if we ever want to add more block styles. It also supports multiple lines or inner blocks trivially. A final advantage is that it may support nested blocks, in case those ever come to be useful. Overall: I prefer the second form, both aesthetically and for future-proofing
I think I agree with in preferring the second form. I like the first form's simplicity, but it also seems surprising that is treated as a 'keyword' and will change the formatting of the docs.
That's why we have this debate. :stuckouttongue:
I personally actually prefer stabilizing a CSS class, I think we should do more of that, just because parsing can get annoying. But this is not that hard to parse anyway. The problem with is precisely that you can't scope it easily: what if you want to add code blocks? bullet points?
The problem with this is it ties rustdoc to the HTML backend; like I said nothing rustdoc currently does guarentees that it will generate HTML from the markdown. Changing that means that to make the JSON backend have the same info, we'd have to add a full HTML parser to rustdoc just to read the HTML in the markdown, because pulldown does not parse HTML for us. I really think we should avoid making the JSON backend a second-class citizen.
Also there's not much point to this if it's just a little CSS IMO, you can add that yourself with and it will look just as good and be more flexible since you can control the styles yourself.


Question: } .example-wrap.ignore .tooltip { <del> color:  var(--codeblock-ignore-color); </del> <ins> color: var(--codeblock-ignore-color); </ins> } .example-wrap.compile_fail:hover .tooltip,

I'm not a giant fan of the syntax because it looks odd when rendered by anything other than rustdoc, which I'd rather avoid, one of the major design concerns for intra-doc links was compatibility with other markdown parsers:
So, I agree, but I'm not convinced that the warning class is something that needs to be surfaced in the JSON backend as anything special. Also, bear in mind, HTML is a part of markdown: valid HTML (well a subset of HTML) is valid markdown. Users already can , and they do that in many cases. Markdown parsers already need to be able to handle HTML. There's nothing new there. Whatever consumes the JSON backend will need to be able to handle that too. I mean, yes, in theory, in practice people don't do this because of the barrier to entry (you have to get your tools to use that, including )
Also, this is incorrect, pulldown absolutely parses HTML. It has to, like I said valid HTML is valid Markdown. It doesn't parse it thoroughly, I believe you can mess it up with sufficiently complex HTML, but it parses HTML. What this changes is subtler: up till now you did not need any particular stylesheet to acceptably render rustdoc markdown from the JSON backend on your own (just use your favorite markdown renderer's stylesheet), but now you will need other css classes to handle rendering warnings as warnings.
I do not agree that this is a problem. I've used Phabricator's implementation of this approach happily and it is by design that warning banners are one paragraph. It is not the intention that you would put entire sections of documentation into a warning banner. They are for a brief callout. It's fine to refer to a subsequent section of the documentation from the callout if needed. I suppose this is a matter of taste but it's one where I believe the opinionatedness of the syntax is a positive thing.
So I discussed this a bit with on the side, we agree that the effect on the JSON backend isn't major since HTML is already a subset of markdown and docs use HTML already (especially for images and tables). My position is as follows: I strictly prefer HTML over some other scoped syntax with nuances people have to learn. I don't think there's as much value in unscoped syntax which makes my position "HTML or nothing", basically.


Question: } .example-wrap.ignore .tooltip { <del> color:  var(--codeblock-ignore-color); </del> <ins> color: var(--codeblock-ignore-color); </ins> } .example-wrap.compile_fail:hover .tooltip,

I'm not wholly against unscoped single-line syntax. We and syntax in W3C specs and you invariably need to add more stuff to it (there's an HTML class in these specs for this reason). Furthermore, Rust has a strong culture of wrapping text, so this means we need to work well while wrapped, and that means we're again introducing some form of scoping mechanism (e.g. indenting the text), which editors will have to learn, as well.
I don't know about admonitions specifically but there seems to be something of a community habit to use "magic tags" on fenced code blocks for this sort of features (e.g. github has a tag), maybe that could be an option? I don't know if pulldown_cmark has a hook for manipulating code blocks but… So a warning would be or maybe the tag would be to leave room for things like note/todo/danger/… Alternatively, take a gander at how other markdown implementations extend the language for this sort of features? e.g. seems to be using for admonitions.
Hmm, but is still for code, even if it has some extra behavior. Aside from the design concerns, this would be feasible to implement: we just extract the language string from the code block with pulldown.
Could you use something that's already built into markdown? For example, rustdoc could take and render it as an admonition.
That's what suggested: to use markdown and make some changes on rustdoc side. I think the codeblock approach is the best personally.
My bad, I didn't see that.
I wonder if it makes more sense to add this as a proc-macro. Rustdoc can still provide the CSS classes and things, and you could use them with HTML directly, but you could use or something and it would expand to the correct HTML tags and classes.
Might be better to have a then, no?
Is that going to be a special header similar to the "unsafe"/"experimental"/etc ones, or is that going to also be used within docs in an order-sensitive way? If the latter we should probably just use a CSS class; mixing and is ugly
Agreed.


Question: } .example-wrap.ignore .tooltip { <del> color:  var(--codeblock-ignore-color); </del> <ins> color: var(--codeblock-ignore-color); </ins> } .example-wrap.compile_fail:hover .tooltip,

Among the suggested ideas, my favourite one remains the code block with "warning" as tag:
Yeah, but triple backticks is also for preformatted text without further markup, so you won't be able to e.g. use text formatting (or other code) in there
True... Finding the right syntax is much more complicated than expected...
That's the issue of using markdown, for all that it has a pretty nice baseline syntax it really was not designed for extensibility.
We can always use : it'd allow to have text formatting inside it.
I would use , it's not quite kosher to invent arbitrary HTML tags (though you can use Custom Elements, which is more heavyweight)
Sounds good to me. It's funny because we kinda came back to the . :rofl:
I just thought: we could use tag in the markdown and then transform it into in the generated HTML?
My main objection to all of these is that rustdoc shouldn't be adding custom markdown syntax that no one else supports. Any new syntax we use should look reasonable even if rendered with the default renderer.
Well, it remains valid markdown since it's HTML (even though it's custom tag). I'm completely fine with , but it might be simpler/better for users to simply write .
Coming back to this (because of ), it seems like the conversation kinda agreed on adding a CSS class directly and then it would look like this in the docs: . I'll send a PR in the next days and then we can open an FCP to see if everyone is ok with it (and if not, we'll have code to help the debate).
This indeed seems like a better solution than the HTML block. It also plays better with something said about not linking it too much too HTML. This will look like a proper warning or note, mostly independent of the HTML generation.
They also seemed to not be too favourable to anything that needs some extra parsing from rustdoc iuc. I'm fine with bot the github solution and the CSS class.
Maybe one more comment to make here. The note-taking app, which uses Markdown also has a similar syntax to create these blocks. It is called . It uses a syntax similar to the syntax that is used for doc intra-links currently, and it is fully compatible with them.


Question: } .example-wrap.ignore .tooltip { <del> color:  var(--codeblock-ignore-color); </del> <ins> color: var(--codeblock-ignore-color); </ins> } .example-wrap.compile_fail:hover .tooltip,

I am uncertain if this is any better than what suggested from the GitHub syntax, but because of the similarity to the doc intra-link syntax. I do feel like this might be interesting because it should go well with backwards compatibility. However, this may look worse than the GitHub syntax solution when not going through cargo doc.
I thought I'd already left this comment, but I'd really like to avoid adding more markdown syntax where possible. This feature works fine without special syntax, I don't think we need it. edit: copying over the reasoning from the :
Although, I might not agree fully, I can fully appreciate and understand the reasoning you left in the corresponding PR. Still, I do think it might be worth to standardize some kind of syntax for some kind of warning block. This does not actually require customized markdown. Alternatively, I can suggest adding the GitHub flavor with emojis to the . This may help in standardizing short form warnings and notes within documentation. We could for example propose to standardize: which should look like the following I do value people's opinion on this. Is this a possible compromise?
That's a valid alternative, I think the yellow color is pretty important though, and it's useful for themes to be able to make styling decisions about warnings so I do think that having some way of marking it is important. I just don't think the way of marking it should be some magic invocation as opposed to CSS classes. (And I think that the bar for a feature that is adding new semantics to the Rustdoc markdown parser is much, much higher than that of one stabilizing a CSS class)
100% agree. I will look at the Rust API guidelines issue and possibly an RFC to rust to track the adoption in GitHub and possibly eventually merge. Thank you :smile:
Beyond all this discussion of third-party tools, I'd really like to make sure that whatever new syntax and presentation we add to rustdoc can also be to [mdBook]. That way, when the standard library starts using callouts, we can make sure the same style also gets used in The Book. Mostly, The Book seems to just use blockquotes, often with headings like [this one about ownership]. mdBook doesn't do anything special with it: it's [just a block quote with a header].


Question: } .example-wrap.ignore .tooltip { <del> color:  var(--codeblock-ignore-color); </del> <ins> color: var(--codeblock-ignore-color); </ins> } .example-wrap.compile_fail:hover .tooltip,

[mdBook]: [this one about ownership]: [just a block quote with a header]:
This is a good point. Once we have something merged here, I'll send a PR there to have an equivalent.
CC
I'd be happy to add some CSS rules to mdbook if that is what you are proposing.
Yeah, it is.
FYI, using a is not semantic and Microsoft GitHub is setting a bad precedence. — CommonMark Spec v0.30, denotes a in Markdown and is rendered as such. — W3C HTML spec, Unless you are quoting a source, this is not the correct element to use. While I disagree with even using altogether, at least some tools out there are at least translating the blockquote in admonition context into a (div has no semantic meaning which is unfortunately the best HTML option for admonitions). It would be ill-advised to follow Microsoft GitHub’s Markdown syntax fork—especially with their disregard for semantics. Similarly using a block would also be breaking semantics as an admonition is not preformatted text. CommonMark does have that could be used if the solution was preferred. There’s also other reasonable options noted here that don’t break semantics.
I agree that block quotes for callouts are bad, and would like to work with mdBook to roll out a common syntax (probably ) that will replace the ad-hoc, unsemantic markup that they use right now.
Using is what we agreed upon in The debate now is on the look itself.
Unfortunately isn't great because markdown has a "boundary" when HTML tags are used. I wanted to add a warning indicating that users probably wanted another trait, but intra-doc links don't work (which is the correct behavior per markdown spec).
Works perfectly fine though (well, minus the UI bug I just discovered haha): ! I used this code: I'll send a PR to improve documentation.
Ah. Well I suppose the issue wasn't with intra-doc links, but with inline code blocks. What I tried was that but with bar`, and it failed.
Works too: !
I opened which adds extra explanation on how to use markdown inside html tags. That should solve your issue.
That note is exactly what I was just looking in to. I had it inline, given my familiarity with HTML. TIL that matters.


Question: } .example-wrap.ignore .tooltip { <del> color:  var(--codeblock-ignore-color); </del> <ins> color: var(--codeblock-ignore-color); </ins> } .example-wrap.compile_fail:hover .tooltip,

It doesn't hurt to have it and if it can helps users, well, why not doing it. :)


Question: Ok(pat) } <ins> /// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`. /// /// Allowed binding patterns generated by `binding ::= ref? mut? $ident @ $pat_rhs` /// should already have been parsed by now  at this point, /// if the next token is `@` then we can try to parse the more general form. /// /// Consult `parse_pat_ident` for the `binding` grammar. /// /// The notion of intersection patterns are found in /// e.g. [F#][and] where they are called AND-patterns. /// /// [and]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> { if self.token.kind != token::At { // Next token is not `@` so it's not going to be an intersection pattern. return Ok(lhs); } // At this point we attempt to parse `@ $pat_rhs` and emit an error. self.bump(); // `@` let mut rhs = self.parse_pat(None)?; let sp = lhs.span.to(rhs.span); if let PatKind::Ident(_, _, ref mut sub @ None) = rhs.kind { // The user inverted the order, so help them fix that. let mut applicability = Applicability::MachineApplicable; lhs.walk(&mut |p| match p.kind { // `check_match` is unhappy if the subpattern has a binding anywhere. PatKind::Ident(..) => { applicability = Applicability::MaybeIncorrect; false // Short-circuit. }, _ => true, }); let lhs_span = lhs.span; // Move the LHS into the RHS as a subpattern. // The RHS is now the full pattern. *sub = Some(lhs); self.struct_span_err(sp, "pattern on wrong side of `@`") .span_label(lhs_span, "pattern on the left, should be on the right") .span_label(rhs.span, "binding on the right, should be on the left") .span_suggestion(sp, "switch the order", pprust::pat_to_string(&rhs), applicability) .emit(); } else { // The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`. rhs.kind = PatKind::Wild; self.struct_span_err(sp, "left-hand side of `@` must be a binding") .span_label(lhs.span, "interpreted as a pattern, not a binding") .span_label(rhs.span, "also a pattern") .note("bindings are `x`, `mut x`, `ref x`, and `ref mut x`") .emit(); } rhs.span = sp; Ok(rhs) } </ins> /// Ban a range pattern if it has an ambiguous interpretation. fn ban_pat_range_if_ambiguous(&self, pat: &Pat) -> PResult<'a, ()> { match pat.kind {

The compiler could suggest that identifier must precede the pattern in the following code: playpen link: Current error message: It could be improved as:
modify labels: A-diagnostics C-feature-request T-compiler
So what happens after is that we've parsed a and then follows which is not a valid token after a parsed . To fix this we can, after having parsed in , check if follows and then emit appropriate suggestions. We will need to use some heuristics to figure out what the user wants based on the structure of . Some of the suggestions would be and some not. cc


Question: (removed, test_removed_feature, "1.0.0", None), (removed, visible_private_types, "1.0.0", None), (removed, unsafe_no_drop_flag, "1.0.0", None), <ins> // Allows using items which are missing stability attributes // rustc internal (removed, unmarked_api, "1.0.0", None), </ins> ); declare_features! (

According to and in , this feature-gate should not be used. It appears that earlier error checking in the compiler prevents it from ever mattering anyway.


Question: } fn unindent_fragments(docs: &mut Vec<DocFragment>) { <del> for fragment in docs { fragment.doc = unindent(&fragment.doc); } } fn unindent(s: &str) -> String { let lines = s.lines().collect::<Vec<&str>>(); let mut saw_first_line = false; let mut saw_second_line = false; let min_indent = lines.iter().fold(usize::MAX, |min_indent, line| { // After we see the first non-whitespace line, look at // the line we have. If it is not whitespace, and therefore // part of the first paragraph, then ignore the indentation // level of the first line let ignore_previous_indents = saw_first_line && !saw_second_line && !line.chars().all(|c| c.is_whitespace()); </del> <ins> // `add` is used in case the most common sugared doc syntax is used ("/// "). The other // fragments kind's lines are never starting with a whitespace unless they are using some // markdown formatting requiring it. Therefore, if the doc block have a mix between the two, // we need to take into account the fact that the minimum indent minus one (to take this // whitespace into account). // // For example: // // /// hello! // #[doc = "another"] // // In this case, you want "hello! another" and not "hello!  another". let add = if docs.windows(2).any(|arr| arr[0].kind != arr[1].kind) && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc) { // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to // "decide" how much the minimum indent will be. 1 } else { 0 }; </ins> <del> let min_indent = if ignore_previous_indents { usize::MAX } else { min_indent }; </del> <ins> // `min_indent` is used to know how much whitespaces from the start of each lines must be // removed. Example: // // ///     hello! // #[doc = "another"] // // In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum // 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4 // (5 - 1) whitespaces. let min_indent = match docs .iter() .map(|fragment| { fragment.doc.lines().fold(usize::MAX, |min_indent, line| { if line.chars().all(|c| c.is_whitespace()) { min_indent } else { // Compare against either space or tab, ignoring whether they are // mixed or not. let whitespace = line.chars().take_while(|c| *c == ' ' || *c == 't').count(); cmp::min(min_indent, whitespace) + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add } } }) }) .min() { Some(x) => x, None => return, }; </ins> <del> if saw_first_line { saw_second_line = true; </del> <ins> for fragment in docs { if fragment.doc.lines().count() == 0 { continue; </ins> } <del> if line.chars().all(|c| c.is_whitespace()) { min_indent </del> <ins> let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 { min_indent - add </ins> } else { <del> saw_first_line = true; let mut whitespace = 0; line.chars().all(|char| { // Compare against either space or tab, ignoring whether they // are mixed or not if char == ' ' || char == 't' { whitespace += 1; true </del> <ins> min_indent }; fragment.doc = fragment .doc .lines() .map(|line| { if line.chars().all(|c| c.is_whitespace()) { line.to_string() </ins> } else { <del> false </del> <ins> assert!(line.len() >= min_indent); line[min_indent..].to_string() </ins> } <del> }); cmp::min(min_indent, whitespace) } }); if !lines.is_empty() { let mut unindented = vec![lines[0].trim_start().to_string()]; unindented.extend_from_slice( &lines[1..] .iter() .map(|&line| { if line.chars().all(|c| c.is_whitespace()) { line.to_string() } else { assert!(line.len() >= min_indent); line[min_indent..].to_string() } }) .collect::<Vec<_>>(), ); unindented.join("n") } else { s.to_string() </del> <ins> }) .collect::<Vec<_>>() .join("n"); </ins> } }

<!-- Thank you for filing a bug report! Please provide a short summary of the bug, along with any information you feel relevant to replicating the bug. --I tried this code: /// let example = Example::new() /// .first("hello") #[cfgattr(not(feature = "one"), doc = " .second("hello")n")] /// .third("hello") /// .build(); /// with I expected to see this: ! Instead, this happened: ! <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: running over the code gives me /// let example = Example::new() /// .first("hello") /// .second("hello") /// .third("hello") /// .build(); ///
As explained on discord, <strikethe attributes aren't applied to doc comments</strike(EDIT: they are applied, the problem seems to be that it results in two doc comments for rustdoc). However, your doc comment is split in two so the second half isn't considered as being inside a code block, explaining why you have this display. Even if shows it as one doc comment, rustdoc sees two of them. <strikeMaybe we should add a warning or something that attributes aren't applied to doc comments... What do you think ?</strike
How can an attribute get applied to a doc comment? Both are, under the hood, attributes, no? I would expect that to be equivalent to expecting to only derive Debug if is passed, which is not how that works. I'm guessing what is true is that attributes directly written don't actually merge with -style comments. Potentially relevant: , ,
Simplified reproducer rust //! foo(); #![doc = " bar();"] //! Checking with 1.31.0 it still ignores it (so likely not related), but checking with 1.21.0 (and 1.0.0) it worked as expected, so somewhere within that range (but I don't have any other versions installed at the moment to check).
Compilation broke somewhere between 1.23.0 (works) 1.24.0 (does not work) I tested it with rust //! let x = r#" #![doc = " bar();"] //! "#; //! assert_eq!


Question: } fn unindent_fragments(docs: &mut Vec<DocFragment>) { <del> for fragment in docs { fragment.doc = unindent(&fragment.doc); } } fn unindent(s: &str) -> String { let lines = s.lines().collect::<Vec<&str>>(); let mut saw_first_line = false; let mut saw_second_line = false; let min_indent = lines.iter().fold(usize::MAX, |min_indent, line| { // After we see the first non-whitespace line, look at // the line we have. If it is not whitespace, and therefore // part of the first paragraph, then ignore the indentation // level of the first line let ignore_previous_indents = saw_first_line && !saw_second_line && !line.chars().all(|c| c.is_whitespace()); </del> <ins> // `add` is used in case the most common sugared doc syntax is used ("/// "). The other // fragments kind's lines are never starting with a whitespace unless they are using some // markdown formatting requiring it. Therefore, if the doc block have a mix between the two, // we need to take into account the fact that the minimum indent minus one (to take this // whitespace into account). // // For example: // // /// hello! // #[doc = "another"] // // In this case, you want "hello! another" and not "hello!  another". let add = if docs.windows(2).any(|arr| arr[0].kind != arr[1].kind) && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc) { // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to // "decide" how much the minimum indent will be. 1 } else { 0 }; </ins> <del> let min_indent = if ignore_previous_indents { usize::MAX } else { min_indent }; </del> <ins> // `min_indent` is used to know how much whitespaces from the start of each lines must be // removed. Example: // // ///     hello! // #[doc = "another"] // // In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum // 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4 // (5 - 1) whitespaces. let min_indent = match docs .iter() .map(|fragment| { fragment.doc.lines().fold(usize::MAX, |min_indent, line| { if line.chars().all(|c| c.is_whitespace()) { min_indent } else { // Compare against either space or tab, ignoring whether they are // mixed or not. let whitespace = line.chars().take_while(|c| *c == ' ' || *c == 't').count(); cmp::min(min_indent, whitespace) + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add } } }) }) .min() { Some(x) => x, None => return, }; </ins> <del> if saw_first_line { saw_second_line = true; </del> <ins> for fragment in docs { if fragment.doc.lines().count() == 0 { continue; </ins> } <del> if line.chars().all(|c| c.is_whitespace()) { min_indent </del> <ins> let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 { min_indent - add </ins> } else { <del> saw_first_line = true; let mut whitespace = 0; line.chars().all(|char| { // Compare against either space or tab, ignoring whether they // are mixed or not if char == ' ' || char == 't' { whitespace += 1; true </del> <ins> min_indent }; fragment.doc = fragment .doc .lines() .map(|line| { if line.chars().all(|c| c.is_whitespace()) { line.to_string() </ins> } else { <del> false </del> <ins> assert!(line.len() >= min_indent); line[min_indent..].to_string() </ins> } <del> }); cmp::min(min_indent, whitespace) } }); if !lines.is_empty() { let mut unindented = vec![lines[0].trim_start().to_string()]; unindented.extend_from_slice( &lines[1..] .iter() .map(|&line| { if line.chars().all(|c| c.is_whitespace()) { line.to_string() } else { assert!(line.len() >= min_indent); line[min_indent..].to_string() } }) .collect::<Vec<_>>(), ); unindented.join("n") } else { s.to_string() </del> <ins> }) .collect::<Vec<_>>() .join("n"); </ins> } }

(x, "n bar();n"); //!
They are not supposed to be applied to a doc comment I do not think that. Your example would make sense for which I also consider to be wrong, but I am talking about which should insert the attribute conditionally but that is not the point. It might help to illustrate my thought process; We have some kind of documented item: rust /// let example = Example::new() /// .first() /// .build(); /// and each of those is turned into a doc attribute rust"] #[doc = "let example = Example::new()"] #[doc = " .first()"] #[doc = " .build();"] #[doc = " In a later step those attributes would then be concatenated and parsed as markdown or whatever. I want to use this behavior to document items conditionally, depending on which features the crate user has enabled. One way to do this would be to do rust let example = Example::new() .first() .build(); rust let example = Example::new() .first() .second() .build(); but that would blow up the source code with many duplicate lines, where only some minor things were changed. So I thought that it might make more sense to conditionally include a doc comment like this: rust /// let example = Example::new() /// .first() #[cfgattr(feature = "one", doc = " .second()")] /// .build(); /// which would turn into rust"] #[doc = "let example = Example::new()"] #[doc = " .first()"] #[doc = " .second()"] #[doc = " .build();"] #[doc = " or rust"] #[doc = "let example = Example::new()"] #[doc = " .first()"] #[doc = " .build();"] #[doc = " depending on whether the feature is enabled. So the attribute should not be inserted and not applied to the following doc comment. The weird thing is that the manually expanded version is working as expected. rust"] #[doc = "let example = Example::new()"] #[doc = " .first()"] #[cfg_attr(feature = "one", doc = " .second()")] #[doc = " .build();"] #[doc = " but this is very unhandy to work with :/
I was randomly looking at passes for another reason and noticed what is likely the source of this issue.


Question: } fn unindent_fragments(docs: &mut Vec<DocFragment>) { <del> for fragment in docs { fragment.doc = unindent(&fragment.doc); } } fn unindent(s: &str) -> String { let lines = s.lines().collect::<Vec<&str>>(); let mut saw_first_line = false; let mut saw_second_line = false; let min_indent = lines.iter().fold(usize::MAX, |min_indent, line| { // After we see the first non-whitespace line, look at // the line we have. If it is not whitespace, and therefore // part of the first paragraph, then ignore the indentation // level of the first line let ignore_previous_indents = saw_first_line && !saw_second_line && !line.chars().all(|c| c.is_whitespace()); </del> <ins> // `add` is used in case the most common sugared doc syntax is used ("/// "). The other // fragments kind's lines are never starting with a whitespace unless they are using some // markdown formatting requiring it. Therefore, if the doc block have a mix between the two, // we need to take into account the fact that the minimum indent minus one (to take this // whitespace into account). // // For example: // // /// hello! // #[doc = "another"] // // In this case, you want "hello! another" and not "hello!  another". let add = if docs.windows(2).any(|arr| arr[0].kind != arr[1].kind) && docs.iter().any(|d| d.kind == DocFragmentKind::SugaredDoc) { // In case we have a mix of sugared doc comments and "raw" ones, we want the sugared one to // "decide" how much the minimum indent will be. 1 } else { 0 }; </ins> <del> let min_indent = if ignore_previous_indents { usize::MAX } else { min_indent }; </del> <ins> // `min_indent` is used to know how much whitespaces from the start of each lines must be // removed. Example: // // ///     hello! // #[doc = "another"] // // In here, the `min_indent` is 1 (because non-sugared fragment are always counted with minimum // 1 whitespace), meaning that "hello!" will be considered a codeblock because it starts with 4 // (5 - 1) whitespaces. let min_indent = match docs .iter() .map(|fragment| { fragment.doc.lines().fold(usize::MAX, |min_indent, line| { if line.chars().all(|c| c.is_whitespace()) { min_indent } else { // Compare against either space or tab, ignoring whether they are // mixed or not. let whitespace = line.chars().take_while(|c| *c == ' ' || *c == 't').count(); cmp::min(min_indent, whitespace) + if fragment.kind == DocFragmentKind::SugaredDoc { 0 } else { add } } }) }) .min() { Some(x) => x, None => return, }; </ins> <del> if saw_first_line { saw_second_line = true; </del> <ins> for fragment in docs { if fragment.doc.lines().count() == 0 { continue; </ins> } <del> if line.chars().all(|c| c.is_whitespace()) { min_indent </del> <ins> let min_indent = if fragment.kind != DocFragmentKind::SugaredDoc && min_indent > 0 { min_indent - add </ins> } else { <del> saw_first_line = true; let mut whitespace = 0; line.chars().all(|char| { // Compare against either space or tab, ignoring whether they // are mixed or not if char == ' ' || char == 't' { whitespace += 1; true </del> <ins> min_indent }; fragment.doc = fragment .doc .lines() .map(|line| { if line.chars().all(|c| c.is_whitespace()) { line.to_string() </ins> } else { <del> false </del> <ins> assert!(line.len() >= min_indent); line[min_indent..].to_string() </ins> } <del> }); cmp::min(min_indent, whitespace) } }); if !lines.is_empty() { let mut unindented = vec![lines[0].trim_start().to_string()]; unindented.extend_from_slice( &lines[1..] .iter() .map(|&line| { if line.chars().all(|c| c.is_whitespace()) { line.to_string() } else { assert!(line.len() >= min_indent); line[min_indent..].to_string() } }) .collect::<Vec<_>>(), ); unindented.join("n") } else { s.to_string() </del> <ins> }) .collect::<Vec<_>>() .join("n"); </ins> } }

There are two relevant passes: runs second and removes leading columns of whitespace from the docs. This runs on a single "doc fragment" at a time, because of merging that normally means the entire documentation string, but since sugared and raw docs aren't merged they remain as separate fragments and use their own widths of leading whitespace to strip.
That also matches up with first released in 1.24 which introduced this distinction between doc kinds in order to fix , which IMO was user error in not matching the indent depth.


Question: } None => { check_expr_has_type(fcx, &idx, fcx.tcx().types.err); <del> fcx.type_error_message( </del> <ins> let mut err = fcx.type_error_struct( </ins> expr.span, |actual| { format!("cannot index a value of type `{}`",

When trying to (erroneously) access members of a tuple using square brackets, rather than a period, the compiler gives the message " error: cannot index a value of type .... ". Particularly as a new user, it would be nice if the compiler could suggest something like "try using the syntax rather than <tuple[idx]." This isn't by any means a big issue, but it would help eliminate yet another search through the documentation.


Question: version = "0.6.0" dependencies = [ "clippy_lints", <del> "env_logger 0.7.1", </del> <ins> "env_logger 0.9.0", </ins> "futures 0.3.12", "log", <del> "rand 0.7.3", </del> <ins> "rand 0.8.4", </ins> "rls-data", "rls-ipc", "serde",

Hello, this is your friendly neighborhood mergebot. After merging PR rust-lang/rust, I observed that the tool rls no longer builds. A follow-up PR to the repository is needed to fix the fallout. cc do you think you would have time to do the follow-up work? If so, that would be great!
This might be due to no longer builds: ` We need a new version I think. The last published version of is 5 months old already :thinking: Can you please check why there are no new versions being published?
TIL scheduled GitHub Action Workflows apparently require regular activity in the repository to keep going :eyes:
I didn't realize anyone was still using those crates so I disabled the action, I believe it was broken anyway. Does rustfmt and/or other crates still use those packages? If so I can try to find time to restart the action.
Racer those crates. And RLS . So without those crates compiling racer with the latest nightly isn't possible, which makes compiling RLS impossible and therefore blocks the sync of RLS back to rust-lang/rust.
Would it maybe be an option to make racer depend on to compile instead of publishing AP crates?
We stopped using them in rustfmt a while ago and I can't imagine a scenario where we'd switch back. Agreed on racer, which AIUI is the last true direct consumer of those crates. However, it's also in and those crates only get bumped in racer when a racer consumer needs them to be bumped.
Ah ok. In that case if this is purely for something in maintenance mode I think my own personal tenure in maintaining these crates is over with, so I would prefer to hand over the reins to someone else. Would someone be willing to volunteer to take over these crates?
let's sync up on #t-infra on Zulip -- I think it makes sense to move these crates into infra control/publication.
Let's wait if Racer can move over to rustc-dev racer-rust/racer. If so, there shouldn't be a need to keep maintaining rustc-ap crates at all. Looking at the dependents on , there really is only , the crates themselves and (which by now uses ).
has some relevant considerations as well.


Question: version = "0.6.0" dependencies = [ "clippy_lints", <del> "env_logger 0.7.1", </del> <ins> "env_logger 0.9.0", </ins> "futures 0.3.12", "log", <del> "rand 0.7.3", </del> <ins> "rand 0.8.4", </ins> "rls-data", "rls-ipc", "serde",

One way or another I think the AP crates need to be accounted for as per the accepted RFC, though it certainly would be a simpler story if they no longer need to be updated/published
Happy to coordinate as necessary, just let me know!
Over a month now. Is this gonna be fixed?
it's blocked on


Question: <del> use crate::infer::outlives::components::{compute_components_recursive, Component}; </del> <ins> use crate::infer::outlives::components::{compute_alias_components_recursive, Component}; </ins> use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::region_constraints::VerifyIfEq; use crate::infer::VerifyBound;

Another regresssion of with a different failure path: It should be fixed by ignoring non-captured lifetimes in: cc label regression-from-stable-to-stable C-bug T-compiler T-types A-impl-trait
Note that fixing this issue is necessary for , but might not be sufficient. I'll investigate more...
WG-prioritization assigning priority (). label -I-prioritize +P-high


Question: <del> use crate::infer::outlives::components::{compute_components_recursive, Component}; </del> <ins> use crate::infer::outlives::components::{compute_alias_components_recursive, Component}; </ins> use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::region_constraints::VerifyIfEq; use crate::infer::VerifyBound;

Some regressions of that I previously reported in , but they were missed: I guess the way to fix this is to ignore non-captured lifetimes of opaque types here cc label C-bug regression-from-stable-to-stable T-types T-compiler A-impl-trait
WG-prioritization assigning priority (). label -I-prioritize +P-high


Question: <ins> // Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. // no-prefer-dynamic #[crate_id = "collections#0.10-pre"]; #[crate_type = "rlib"]; </ins>

Built glfw-rs using rust 0.10-pre. When referencing this crate in another source file and building, I get error: internal compiler error: unexpected failure This message reflects a bug in the Rust compiler. We would appreciate a bug report: note: the compiler hit an unexpected failure path. this is a bug Ok(task 'rustc' failed at 'assertion failed: ()', ) This is on OSX 10.9: rustc 0.10-pre ( 2014-02-18 10:16:48 -0800) host: x8664-apple-darwin
This means that you've got two versions of the same lying around, and doesn't like having two versions. This will be fixed by , I just need to land it :(
I have just build the library for the first time, and I can only find one dylib for it on my system (next to the rlib, but I gues that shouldn't cause any problems). Is there another possibility for this error? Gesendet: Mittwoch, 19. Februar 2014 um 01:09 UhrVon: "Alex Crichton" : mozilla/rust hhildebr : Re: [rust] Compiler error when referencing crate "glfw-rs" () This means that you've got two versions of the same libglfw- lying around, and rustc doesn't like having two versions. This will be fixed by , I just need to land it :( — Reply to this email directly or view it on GitHub.
my reading of is that having a dylib and an rlib simultaneously is a problem.
Having a dylib and an rlib simultaneously should not be a problem, it is in fact quite common. Having 2 dylibs and 1 rlib or 2 rlibs and 1 dylib however is a problem.
sorry, my mistake in parsing the title of .
Yes, indeed, I had several identical dylibs, but it wasn't the glfw-rs.. there were rust libs in /usr/local/lib and /usr/local/lib/rustlib/... Thanks! Gesendet: Mittwoch, 19.


Question: <ins> // Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. // no-prefer-dynamic #[crate_id = "collections#0.10-pre"]; #[crate_type = "rlib"]; </ins>

Februar 2014 um 17:15 UhrVon: "Alex Crichton" : mozilla/rust hhildebr : Re: [rust] Compiler error when referencing crate "glfw-rs" () Having a dylib and an rlib simultaneously should not be a problem, it is in fact quite common. Having 2 dylibs and 1 rlib or 2 rlibs and 1 dylib however is a problem. — Reply to this email directly or view it on GitHub.
so can we close this ticket now, in that case? Or do you want to wait for alexcrichton's patches to land, and see what things look like for you then?
Nono, the ticket can be closed for now. Thanks for your help! Gesendet: Mittwoch, 19. Februar 2014 um 21:30 UhrVon: "Felix S Klock II" : mozilla/rust hhildebr : Re: [rust] Compiler error when referencing crate "glfw-rs" () so can we close this ticket now, in that case? Or do you want to wait for alexcrichton's patches to land, and see what things look like for you then? — Reply to this email directly or view it on GitHub.


Question: } #[inline] <ins> fn fold<Acc, F>(self, init: Acc, f: F) -> Acc where F: FnMut(Acc, Self::Item) -> Acc, { ZipImpl::fold(self, init, f) } #[inline] </ins> unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where Self: TrustedRandomAccessNoCoerce,

<!-- Thank you for filing a regression report! A regression is something that changed between versions of Rust but was not supposed to. Please provide a short summary of the regression, along with any information you feel is relevant to replicate it. --I tried this code: I expected to see this happen: same codegen or similar in performance Instead, this happened: array has way worse codegen <details<summaryAssembly</summary<p</p</details<!-- Provide the most recent version this worked on, for example: It most recently worked on: Rust 1.47 --It most recently worked on: 1.64 <!-- Provide the version you are using that has the regression. --65 till now. Regressed in nightly-2022-08-13, maybe LLVM 15 ?: : <!-- Did the compiler crash? If so, please provide a backtrace. --<!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summaryBacktrace</summary<p</p</details<!-- If you know when this regression occurred, please add a line like below, replacing with one of stable, beta, or nightly. -- modify labels: +regression-from-stable-to-stable -regression-untriaged <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
WG-prioritization assigning priority (). cc since this regressed in the LLVM 15 update label -I-prioritize +P-medium +T-compiler
I've seen llvm doing these strange 1-byte-at-a-time "vectorizations" in other places too. This might be a more general problem. In this case we can probably paper over it by implementing TrustedRandomAccess for the array iter.
Unfortunately, the array iterator is fundamentally worse right now, because indexing into it -- a fundamental part of being a by-value array iterator -- keeps it from SRoAing and thus doesn't optimize well. This is why when I was making better I ended up making to not have to use . Sadly, for the foreseeable future you're better off using the "weaker" slice iterator when you can.
My guess is that the SROA is missing something in the opaque pointer mode.


Question: } #[inline] <ins> fn fold<Acc, F>(self, init: Acc, f: F) -> Acc where F: FnMut(Acc, Self::Item) -> Acc, { ZipImpl::fold(self, init, f) } #[inline] </ins> unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where Self: TrustedRandomAccessNoCoerce,

claim
It's not about vectorization. This optimization can be restored by using . But highly unrecommended. Upstream issue:
The upstream issue is closed. claim


Question: /// # Examples /// /// ``` <del> /// #![feature(osstring_ascii)] </del> /// use std::ffi::OsString; /// /// assert!(OsString::from("Ferris").eq_ignore_ascii_case("FERRIS")); /// assert!(OsString::from("Ferrös").eq_ignore_ascii_case("FERRöS")); /// assert!(!OsString::from("Ferrös").eq_ignore_ascii_case("FERRÖS")); /// ``` <del> #[unstable(feature = "osstring_ascii", issue = "70516")] </del> <ins> #[stable(feature = "osstring_ascii", since = "1.53.0")] </ins> pub fn eq_ignore_ascii_case<S: AsRef<OsStr>>(&self, other: S) -> bool { self.inner.eq_ignore_ascii_case(&other.as_ref().inner) }

<!-- Thank you for creating a tracking issue! Tracking issues are for tracking a feature from implementation to stabilization. Make sure to include the relevant RFC for the feature if it has one. If the new feature is small, it may be fine to skip the RFC process. In that case, you can use use in your initial implementation PR. The reviewer will ask you to open a tracking issue if they agree your feature can be without an RFC. --Feature gate: <!-- For most library features, it'd be useful to include a summarized version of the public API. (E.g. just the public function signatures without their doc comments or implementation.) --<!-- For larger features, more steps might be involved. If the feature is changed later, please add those PRs here as well. --- [x] - Stabilized traits necessary to obtain [x] - Added ASCII methods on [x] Final commenting period (FCP) [x] - Stabilization PR <!-- Once the feature has gone through a few release cycles and there are no unresolved questions left, the feature might be ready for stabilization. If this feature didn't go through the RFC process, a final commenting period (FCP) is always needed before stabilization. This works as follows: A library team member can kick off the stabilization process, at which point the rfcbot will ask all the team members to verify they agree with stabilization. Once enough members agree and there are no concerns, the final commenting period begins: this issue will be marked as such and will be listed in the next This Week in Rust newsletter. If no blocking concerns are raised in that period of 10 days, a stabilzation PR can be opened by anyone. --<!-- Include any open questions that need to be answered before the feature can be stabilised. If multiple (unrelated) big questions come up, it can be a good idea to open a separate issue for each, to make it easier to keep track of the discussions. It's useful to link any relevant discussions and conclusions (whether on GitHub, Zulip, or the internals forum) here. --- None yet.
Just needed to manipulate paths on windows -- I need to lower case driver letter, -.
Currently, SQLx contains The UTF-8 check that is included in there, while not a problem in practice, seems pointless. Changing to lands me here because of the .


Question: /// # Examples /// /// ``` <del> /// #![feature(osstring_ascii)] </del> /// use std::ffi::OsString; /// /// assert!(OsString::from("Ferris").eq_ignore_ascii_case("FERRIS")); /// assert!(OsString::from("Ferrös").eq_ignore_ascii_case("FERRöS")); /// assert!(!OsString::from("Ferrös").eq_ignore_ascii_case("FERRÖS")); /// ``` <del> #[unstable(feature = "osstring_ascii", issue = "70516")] </del> <ins> #[stable(feature = "osstring_ascii", since = "1.53.0")] </ins> pub fn eq_ignore_ascii_case<S: AsRef<OsStr>>(&self, other: S) -> bool { self.inner.eq_ignore_ascii_case(&other.as_ref().inner) }

Also, if somebody did a similar thing with instead of , the version could drop that and would then be a bit less noisy.
is a stabilization PR. Since lib team wants to do fcp in the tracking issue. could you start one ?
merge
Team member has proposed to merge this. The next step is review by the rest of the tagged team members: [x] [x] [x] [x] [x] [ ] Concerns: resolved by Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See for info about what commands tagged team members can give me.
Slight question about -- normally when dealing with AsRef args, they come in without an explicit reference in the signature (), except when necessary to support a lifetime in the return value (). Currently is declared as: Is this supposed to be instead? concern eqignoreasciicase &S
I think it should be. I'm not sure why I wrote it like I did originally, but this makes more sense to me. I can make that PR if needed. Or can it be done in the stabilization PR? Not sure what the process is from here.
resolve eqignoreascii_case &S reviewed Fixed in .
:bell: This is now entering its final comment period, as per the . :bell:
The final comment period, with a disposition to merge, as per the , is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. The RFC will be merged soon.
you can tick the FCP box, as the FCP is complete.


Question: let outdir = if let Some(mut path) = rustdoc_options.persist_doctests.clone() { path.push(&test_id); <del> std::fs::create_dir_all(&path) .expect("Couldn't create directory for doctest executables"); </del> <ins> if let Err(err) = std::fs::create_dir_all(&path) { eprintln!("Couldn't create directory for doctest executables: {}", err); panic::resume_unwind(box ()); } </ins> DirState::Perm(path) } else {

When setting the directory to persist doctests to if an UNC path is used on windows there's a segfault. The offending setting of persist-doctests: . cargo-tarpaulin sets this programatically using a path it gets for the target directory from cargo-metadata. The path from cargo-metadata is an UNC path and this then causes a segfault. I'm going to detect UNC paths in my code and remove the on windows, but I felt this warrants a bug report as someone else will hit it eventually. Also, I'm not sure if other parts of the compiler fall prey to this issue? Compiler version is: the latest nightly (1.64.0-nightly 2022-06-28) The stack trace: <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
This panic is also triggered in Linux if e.g. trying to write into a directory that the user has no permission to write. I PR'd fix to change the unwrap to more orderly panic and relaying the underlying error detail via eprintln! ~/gg/rust/build/x86_64-unknown-linux-gnu/stage2/bin/rustdoc --test -Z unstable-options --persist-doctests /tmp/foobar Couldn't create directory for doctest executables: Permission denied (os error 13) instead of:
The lack of ICE is definitely nicer, but this still won't handle UNC paths on windows will it? Which is the main issue I personally have with the code
That's a problem for std::fs::createdirall(&path) me thinks has to be fixed there
Makes sense looking at the code, should I raise another issue for the libs team?
Actually, yes it would be great to raise another issue targeting std::fs::createdirall - as it is wider issue. you are right. Thanks!
So isn't this an issue with the tool generating an incorrect argument?
So the paths are weirding me out (I normally only use linux), because they seem to sometimes print differently given different display methods. It shows up as printing the path in my rust code before making the env var, and if I print the rustdocflags I'm setting it's correct.


Question: let outdir = if let Some(mut path) = rustdoc_options.persist_doctests.clone() { path.push(&test_id); <del> std::fs::create_dir_all(&path) .expect("Couldn't create directory for doctest executables"); </del> <ins> if let Err(err) = std::fs::create_dir_all(&path) { eprintln!("Couldn't create directory for doctest executables: {}", err); panic::resume_unwind(box ()); } </ins> DirState::Perm(path) } else {

But if I do it returns false, I have to do for it to return true. I'll raise the other issue and after work look into it more properly try to make a better MRE for windows
do you mind changing title s/UNC/invalid/ to address the panic on this issue, thanks! :)
also please remove s/on windows// thanks a lot :+1:
Done, and I realised what was wrong with the path, it's correct in the code, it's just when it got set into the environment variable it seems it needed the first slash to be escaped and that caused the invalid path (so no issues in std::fs need fixing)
claim label +I-ICE +T-RUSTDOC


Question: for (hir, ty) in hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) { try_visit!(visitor.visit(hir.span, ty.map_bound(|x| *x))); } <del> for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { </del> <ins> for (pred, span) in tcx.explicit_predicates_of(item).instantiate_identity(tcx) { </ins> try_visit!(visitor.visit(span, pred)); } }

https://crater-
searched nightlies: from nightly-2024-02-01 to nightly-2024-03-20 regressed nightly: nightly-2024-02-10 searched commit range: regressed commit: <details<summarybisected with <a href=''cargo-bisect-rustc</av0.6.8</summaryHost triple: x86_64-unknown-linux-gnu Reproduce with: </detailsprobably
WG-prioritization assigning priority (). label -I-prioritize +P-high
MCVE


Question: let op = ecx.eval_const_to_op(val, None).unwrap(); ecx.read_discriminant(op).unwrap().1 } <del> /// Turn an interpreter error into something to report to the user. /// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace. /// Should be called only if the error is actually going to to be reported! pub fn error_to_const_error<'mir, 'tcx, M: Machine<'mir, 'tcx>>( ecx: &InterpCx<'mir, 'tcx, M>, mut error: InterpErrorInfo<'tcx>, ) -> ConstEvalErr<'tcx> { error.print_backtrace(); let stacktrace = ecx.generate_stacktrace(None); ConstEvalErr { error: error.kind, stacktrace, span: ecx.tcx.span } } pub fn note_on_undefined_behavior_error() -> &'static str { "The rules on what exactly is undefined behavior aren't clear,  so this check might be overzealous. Please open an issue on the rustc  repository if you believe it should not be considered undefined behavior." } fn validate_and_turn_into_const<'tcx>( tcx: TyCtxt<'tcx>, constant: RawConst<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { let cid = key.value; let def_id = cid.instance.def.def_id(); let is_static = tcx.is_static(def_id); let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static); let val = (|| { let mplace = ecx.raw_const_to_mplace(constant)?; let mut ref_tracking = RefTracking::new(mplace); while let Some((mplace, path)) = ref_tracking.todo.pop() { ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?; } // Now that we validated, turn this into a proper constant. // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides // whether they become immediates. if is_static || cid.promoted.is_some() { let ptr = mplace.ptr.to_ptr()?; Ok(tcx.mk_const(ty::Const { val: ty::ConstKind::Value(ConstValue::ByRef { alloc: ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), offset: ptr.offset, }), ty: mplace.layout.ty, })) } else { Ok(op_to_const(&ecx, mplace.into())) } })(); val.map_err(|error| { let err = error_to_const_error(&ecx, error); match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") { Ok(mut diag) => { diag.note(note_on_undefined_behavior_error()); diag.emit(); ErrorHandled::Reported } Err(err) => err, } }) } pub fn const_eval_validated_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { // see comment in const_eval_raw_provider for what we're doing here if key.param_env.reveal == Reveal::All { let mut key = key.clone(); key.param_env.reveal = Reveal::UserFacing; match tcx.const_eval_validated(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => { // Promoteds should never be "too generic" when getting evaluated. // They either don't get evaluated, or we are in a monomorphic context assert!(key.value.promoted.is_none()); } // dedupliate calls other => return other, } } // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. // Catch such calls and evaluate them instead of trying to load a constant's MIR. if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { let ty = key.value.instance.ty(tcx); let substs = match ty.kind { ty::FnDef(_, substs) => substs, _ => bug!("intrinsic with type {:?}", ty), }; return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| { let span = tcx.def_span(def_id); let error = ConstEvalErr { error: error.kind, stacktrace: vec![], span }; error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic") }); } tcx.const_eval_raw(key).and_then(|val| validate_and_turn_into_const(tcx, val, key)) } pub fn const_eval_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc::mir::interpret::ConstEvalRawResult<'tcx> { // Because the constant is computed twice (once per value of `Reveal`), we are at risk of // reporting the same error twice here. To resolve this, we check whether we can evaluate the // constant in the more restrictive `Reveal::UserFacing`, which most likely already was // computed. For a large percentage of constants that will already have succeeded. Only // associated constants of generic functions will fail due to not enough monomorphization // information being available. // In case we fail in the `UserFacing` variant, we just do the real computation. if key.param_env.reveal == Reveal::All { let mut key = key.clone(); key.param_env.reveal = Reveal::UserFacing; match tcx.const_eval_raw(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} // dedupliate calls other => return other, } } if cfg!(debug_assertions) { // Make sure we format the instance even if we do not print it. // This serves as a regression test against an ICE on printing. // The next two lines concatenated contain some discussion: // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/ // subject/anon_const_instance_printing/near/135980032 let instance = key.value.instance.to_string(); trace!("const eval: {:?} ({})", key, instance); } let cid = key.value; let def_id = cid.instance.def.def_id(); if def_id.is_local() && tcx.typeck_tables_of(def_id).tainted_by_errors { return Err(ErrorHandled::Reported); } let is_static = tcx.is_static(def_id); let span = tcx.def_span(cid.instance.def_id()); let mut ecx = InterpCx::new( tcx.at(span), key.param_env, CompileTimeInterpreter::new(), MemoryExtra { can_access_statics: is_static }, ); let res = ecx.load_mir(cid.instance.def, cid.promoted); res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, *body)) .and_then(|place| { Ok(RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty }) }) .map_err(|error| { let err = error_to_const_error(&ecx, error); // errors in statics are always emitted as fatal errors if is_static { // Ensure that if the above error was either `TooGeneric` or `Reported` // an error must be reported. let v = err.report_as_error(ecx.tcx, "could not evaluate static initializer"); tcx.sess.delay_span_bug( err.span, &format!("static eval failure did not emit an error: {:#?}", v), ); v } else if def_id.is_local() { // constant defined in this crate, we can figure out a lint level! match tcx.def_kind(def_id) { // constants never produce a hard error at the definition site. Anything else is // a backwards compatibility hazard (and will break old versions of winapi for sure) // // note that validation may still cause a hard error on this very same constant, // because any code that existed before validation could not have failed validation // thus preventing such a hard error from being a backwards compatibility hazard Some(DefKind::Const) | Some(DefKind::AssocConst) => { let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); err.report_as_lint( tcx.at(tcx.def_span(def_id)), "any use of this value will cause an error", hir_id, Some(err.span), ) } // promoting runtime code is only allowed to error if it references broken constants // any other kind of error will be reported to the user as a deny-by-default lint _ => { if let Some(p) = cid.promoted { let span = tcx.promoted_mir(def_id)[p].span; if let err_inval!(ReferencedConstant) = err.error { err.report_as_error( tcx.at(span), "evaluation of constant expression failed", ) } else { err.report_as_lint( tcx.at(span), "reaching this expression at runtime will panic or abort", tcx.hir().as_local_hir_id(def_id).unwrap(), Some(err.span), ) } // anything else (array lengths, enum initializers, constant patterns) are reported // as hard errors } else { err.report_as_error(ecx.tcx, "evaluation of constant value failed") } } } } else { // use of broken constant from other crate err.report_as_error(ecx.tcx, "could not evaluate constant") } }) } </del>

Follow-up to agreed to move to . Generally I propose that should not contain code that is only needed by CTFE. We have and in there are they need some very deep access to Miri engine internals, but at least those are separate modules. Also, has grown pretty messy, and it does not seem like the order of definitions in that file follows any principle. We could split the file into two similar to what I did with Miri: for implementing the machine trait and defining everything that is needed during CTFE execution, and for defining the setup functions and all the glue that connects CTFE with the rest of the compiler.


Question: use rustc_errors::Applicability; use rustc_hir as hir; use rustc_middle::ty::subst::InternalSubsts; <del> use rustc_middle::ty::{Ref, Ty}; </del> <ins> use rustc_middle::ty::{Adt, Ref, Ty}; </ins> use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS; use rustc_span::symbol::kw::Underscore; use rustc_span::symbol::{sym, Ident};

For generic types, the prelude collision lint can produce suggestions that do not compile: Code: Suggestion from the prelude collision lint: Error after applying the suggestion: <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
cc
My guess is this should be a simple fix, just copying the code the lint already uses for adding unspecified generics (). Will try implementing a fix soon.
assign
release-assignment
The code related to this lint lives in the . The relevant suggestion is generated here: The "self type" string comes from here: The code for traits is here: This is actually just a touch tricky, because currently we are getting the "self type" just by copying the text the user wrote. Probably the most correct thing for us to do would be to examine the 'self expression' HIR and, if it is a plain path, then to append the and otherwise skip it. Specifically, the other case that I am thinking about is code like this: Currently , meaning that it offers the suggestion "disambiguate the associated function: ".
claim
great! Let us know if you need anything or make progress. This issue is fairly time sensitive.
release-assignment
claim


Question: let out = cargo.output() .expect("We already ran `cargo miri setup` before and that worked"); assert!(out.status.success(), "`cargo miri setup` returned with non-0 exit code"); <del> // Output is "MIRI_SYSROOT=<str>n". </del> <ins> // Output is "<sysroot>n". </ins> let stdout = String::from_utf8(out.stdout) .expect("`cargo miri setup` stdout is not valid UTF-8"); <del> let stdout = stdout.trim(); builder.verbose(&format!("`cargo miri setup --env` returned: {:?}", stdout)); let sysroot = stdout.splitn(2, '=') .nth(1).expect("`cargo miri setup` stdout did not contain '='"); </del> <ins> let sysroot = stdout.trim_end(); builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {:?}", sysroot)); </ins> sysroot.to_owned() };

Hello, this is your friendly neighborhood mergebot. After merging PR rust-lang/rust, I observed that the tool miri no longer builds. A follow-up PR to the repository is needed to fix the fallout. cc do you think you would have time to do the follow-up work? If so, that would be great! cc the PR reviewer, and nominating for compiler team prioritization.


Question: set -ex source shared.sh <del> curl https://www.python.org/ftp/python/3.9.1/Python-3.9.1.tgz |  </del> <ins> curl https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz |  </ins> tar xzf - mkdir python-build

When I install the latest master toolchains via and try to build with them, linking fails: I did some bisection, and it looks like the problem started happening with Cc
The error is actually already mentioned in However, I am building Miri with cargo, so I don't know how I'd "use LLD instead".
Hm, we probably need to revert that PR. I did not realize we'd need lld downstream too, I thought that was only on our builder. cc
Yes, a revert seems appropriate. We're going to have to figure out where that's actually coming from. The only change I saw between 10 and 11 by grepping was the removal of llgo, but maybe there's some bad remnant.
Yeah, I thought this issue would be limited to the rustc build, but it makes sense that it can also affect project linking against rustc shared objects. I've looked a bit into what the root cause is, and what I have so far as that the symbol comes from and is present as a weak symbol both when compiling with clang-10 and clang-11. The only difference I see from is this: So apparently was treated as a symbol of the library, while now it's treated as a symbol of -- I'm not sure what that actually means, but presumably that refers to the compiler runtime libraries. My guess is that previously it just ended up being nulled out as a missing weak symbol, but now it's actually being found and linking fails because ... reasons. I'm not good at linkers :) Edit: shows these as:
can you prepare a revert PR?
Done in . If nobody has an idea on how to avoid the linker error, two more options would be to comment out the symbol in our llvm-project fork, or to avoid upgrading clang altogether and just build both Python 2 and Python 3 for that image.
The issue is probably going to be in how exactly the objects that comprise are compiled, not linked. I suspect just ends up ignoring the malformed object or otherwise not reporting the issue, but the object and the relevant symbols ultimately end up in the anyway. Alas, reasons these obscure failures can occur are many – I've seen them occur from things as trivial as forgetting to . The question is: is there perhaps a way to disable ExecutionEngine entirely? Intuitively nothing we do should depend on that code.


Question: set -ex source shared.sh <del> curl https://www.python.org/ftp/python/3.9.1/Python-3.9.1.tgz |  </del> <ins> curl https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz |  </ins> tar xzf - mkdir python-build

And if not, I'm comfortable patching out in our fork as we get closer to Feb 11 and continue having trouble pinpointing exact cause of this problem.
We normally don't link ExecutionEngine, but dist-x8664-linux in particular builds LLVM with ThinLTO, in which case we link as shared, instead of statically linking individual components into rustcllvm.
It seems to be possible to configure the components in using , but I'm not sure to what degree we can restrict those (not sure if this job also ships LLVM tools).
So, I think we could have used to exclude unnecessary parts from , as LLVM tools can still statically link the parts not in the dylib. But in the end, we can't use the option anyway due to
Looks like I'm getting this locally when trying to bootstrap rustc (while building ), might happen since the llvm upgrade but I'm not 100% sure. Are there some workarounds I can put into my for this? I'm using lld to link. <details<summaryBacktrace</summary<p</p</details
which commit are you trying to build?
latest git master
Probably best to open a new issue then; this one has been closed and the steps to reproduce it still work without error -- you might be having a different problem.
Opened
Did anyone file an upstream bug report about this? I'm observing it outside of Rust, but with a similar setup ( with lld+ThinLTO, then linking it into a binary with ). If not, I'd try to build a reproducer.
I've opened for this.
The bug has been fixed, the fix will be in LLVM 12.0.1.
Thanks! We can try updating clang again once the 12.0.1 tag is there.


Question: fn main() { let o = Obj { closure: || 42 }; o.closure(); //~ ERROR no method named `closure` found <del> //~^ NOTE use `(s.closure)(...)` if you meant to call the function stored in the `closure` field </del> <ins> //~^ NOTE use `(o.closure)(...)` if you meant to call the function stored in the `closure` field </ins> }

I forget if there's already a bug on this, but it would be nice if, when you wrote and doesn't have a field named , but does have a nullary method named , the compiler gave a hint like "did you mean to write ?" It could also do vice versa (if you write A.B()ABA.B?) I ran into this in trans, where I have frequently written instead of .
Test: The error message is better now than it was: in that it suggests there is a method named . But it could still be improved. (The intention may not have been to take the method's value; it seems more likely that the programmer thought it wasn't a method at all.)
My previous comment still holds. It would be great if you would see the "try writing an anonymous function" hint for something like and instead see a "did you mean to write ?" in situations like this one.
I'd also like to see one when trying to call a function-typed struct field: emits Foof. It'd be nice if it tried to see if it could auto-deref to a struct field, and if so, say (f.f)().
A nice idea. Assigning P-low.
Currently gives which is pretty close to the proposed behavior. Replacing the wih yields the same as before (i.e. does not suggest removing the ):
Updated the example gives: which now prints It's nice that the note is there, but the text is suboptimal: isn't a function.
I'm working on a fix for this, but I'm struggling with the final portion. With this code: I get the output: My current changes are . I'm not sure if it's possible to have the output say "" and "kitty.x" with the input to the function. Any ideas? Or should I just keep the message in the same format as it is now and output "s.func" and "did you mean to write ?"? Edit: Ideally, I would like to output: I'm wondering if that's at all possible, especially because instead of , there might be an expression.
I got around that error message. Now I'm making sure the previous message is displayed under the proper circumstances.


Question: # - thumbv7em-none-eabihf (Bare Cortex-M4F, M7F, FPU, hardfloat) # - thumbv7m-none-eabi (Bare Cortex-M3) <del> # only-thumbv6m-none-eabi # only-thumbv7em-none-eabi # only-thumbv7em-none-eabihf # only-thumbv7m-none-eabi </del> <ins> # only-thumb </ins> # For cargo setting RUSTC := $(RUSTC_ORIGINAL)

I was working on making a run-make test today for a particular thumb target. While looking over how we do this elsewhere, I found this bit of code: From my local testing, it seems like having multiple lines of this form has the net effect of making the test a no-op that does not test anything: since a target matching line 13 will not match line 14, and vice versa, there are no targets that can run on this test. We should either revert the portion of the commit that did this: or figure out some other way to express the desired property here (or change the semantics of when multiple targets are provided to make it gather all such targets up in a set before doing the check for membership... but I am wary of making such a change since doing it right would require differentiating e.g. processor target vs OS target, for example...)
Also, It looks like there may be other instances of the same mistake elsewhere in the test suite, such as in:
Oof, not good. It shouldn't be hard to make rustbuild outright reject this scenario though.
Further effort on has led me to conclude that these lines do not work at all, at least not for cross-compilation.


Question: <ins> error: invalid format string: tuple index access isn't supported --> $DIR/format-args-non-identifier-diagnostics.rs:8:16 | LL |     println!("{x.0}"); |                ^^^ not supported in format string | help: consider using a positional formatting argument instead | LL |     println!("{0}", x.0); |                ~  +++++ error: aborting due to 1 previous error </ins>

<!-- While learning rust from the book i tried printing the second(.1) value in a tuple, and it broke the format string and wouldn't compile --I tried this code: I expected to see this happen: printing of the value 1. Instead, this happened: it gave the following error: if you intended to print , you can escape it using rustc <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --:
Only printing an identifer is supported, arbitrary expressions are not: https://rust-
There's more discussion about this in or in many other places, it's a thing that keeps coming up.
The error message could be nicer, so I'll convert it into a diagnostics issue.


Question: } ``` <del> Any type parameter of an `impl` must meet at least one of the following criteria: </del> <ins> Any type or const parameter of an `impl` must meet at least one of the following criteria: </ins> - it appears in the _implementing type_ of the impl, e.g. `impl<T> Foo<T>` - for a trait impl, it appears in the _implemented trait_, e.g.

As it is currently written, E0207 talks entirely about type parameters. Now that const parameters also need to constrain implementations (under the same rules described for types), they also need to be mentioned in the error explanation. Since other items don't require const parameters to be used at all, we might also want to specifically call out this difference here. Furthermore, E0207 triggers if you use an unconstrained lifetime in an associated type, and this is completely unspecified by the error as well. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
claim