Change:
Given the following we currently emit We should emit at least the following We might also want to provide suggestions when it makes sense (like turning the attr into an outer attr).
Hey , I tried to solve this with a little help of on a rust meetup. I wasn't able to run because of the following message. But I started to add some code you can read here: is this going into the right direction?
thank you for taking a look at this! You should be able to run the tests with . Use to update the relevant files. The code you've written would generate the following output: Instead, we'd want this to be a single error. What you'd want to do is 1) get the span for the prior attribute from 2) expand to also hold an extra field and 3) change the following to be This lets you point at the prior span in the same error. The second part of this ticket is changing the linked code to no longer use , but rather synthesize a new span from the first 's span to the closing . You can use to do so. Finally, we change the above to be something like
Are you still working on this? I'm thinking of giving it a try.
Go on! I don’t have so much time atm so just go there step by step while learning rust. If you want so solve it - awesome

Discussion:
use crate::parse::token::{self, Nonterminal, DelimToken}; use crate::parse::parser::{Parser, TokenType, PathStyle}; use crate::tokenstream::{TokenStream, TokenTree}; <ins> use crate::source_map::Span; </ins> use log::debug; use smallvec::smallvec;

#[derive(Debug)] enum InnerAttributeParsePolicy<'a> { Permitted, <del> NotPermitted { reason: &'a str }, </del> <ins> NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> }, </ins> } const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not 

DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG }; let inner_parse_policy = <del> InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason }; </del> <ins> InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason, saw_doc_comment: just_parsed_doc_comment, prev_attr_sp: attrs.last().and_then(|a| Some(a.span)) }; </ins> let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; attrs.push(attr); just_parsed_doc_comment = false;

let inner_parse_policy = if permit_inner { InnerAttributeParsePolicy::Permitted } else { <del> InnerAttributeParsePolicy::NotPermitted { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG } </del> <ins> InnerAttributeParsePolicy::NotPermitted { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, saw_doc_comment: false, prev_attr_sp: None } </ins> }; self.parse_attribute_with_inner_parse_policy(inner_parse_policy) }

if let InnerAttributeParsePolicy::Permitted = inner_parse_policy { self.expected_tokens.push(TokenType::Token(token::Not)); } let style = if self.token == token::Not { self.bump(); <del> if let InnerAttributeParsePolicy::NotPermitted { reason } = inner_parse_policy { let span = self.token.span; self.diagnostic() .struct_span_err(span, reason) .note("inner attributes, like `#![no_std]`, annotate the item  enclosing them, and are usually found at the beginning of  source files. Outer attributes, like `#[test]`, annotate the  item following them.") .emit() } </del> ast::AttrStyle::Inner } else { ast::AttrStyle::Outer

self.expect(&token::CloseDelim(token::Bracket))?; let hi = self.prev_span; <del> (lo.to(hi), path, tokens, style) </del> <ins> let attr_sp = lo.to(hi); // Emit error if inner attribute is encountered and not permitted if style == ast::AttrStyle::Inner { if let InnerAttributeParsePolicy::NotPermitted { reason, saw_doc_comment, prev_attr_sp } = inner_parse_policy { let prev_attr_note = if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" }; let mut diagnostic = self .diagnostic() .struct_span_err(attr_sp, reason); if let Some(prev_attr_sp) = prev_attr_sp { diagnostic .span_label(attr_sp, "not permitted following an outer attibute") .span_label(prev_attr_sp, prev_attr_note); } diagnostic .note("inner attributes, like `#![no_std]`, annotate the item  enclosing them, and are usually found at the beginning of  source files. Outer attributes, like `#[test]`, annotate the  item following them.") .emit() } } (attr_sp, path, tokens, style) </ins> } _ => { let token_str = self.this_token_to_string();

error: an inner attribute is not permitted in this context <del> --> $DIR/issue-45296.rs:4:7 </del> <ins> --> $DIR/issue-45296.rs:4:5 </ins> | LL |     #![allow(unused_variables)] <del> |       ^ </del> <ins> |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ </ins> | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.

error: an inner attribute is not permitted in this context <del> --> $DIR/attr.rs:5:3 </del> <ins> --> $DIR/attr.rs:5:1 </ins> | LL | #![lang = "foo"] <del> |   ^ </del> <ins> | ^^^^^^^^^^^^^^^^ </ins> | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.

error: an inner attribute is not permitted following an outer doc comment <del> --> $DIR/inner-attr-after-doc-comment.rs:6:3 </del> <ins> --> $DIR/inner-attr-after-doc-comment.rs:6:1 </ins> | <del> LL | #![recursion_limit="100"] |   ^ </del> <ins> LL | / /** LL | |  * My module LL | |  */ | |___- previous doc comment LL | LL |   #![recursion_limit="100"] |   ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attibute </ins> | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.

error: an inner attribute is not permitted following an outer attribute <del> --> $DIR/inner-attr.rs:3:3 </del> <ins> --> $DIR/inner-attr.rs:3:1 </ins> | <ins> LL | #[feature(lang_items)] | ---------------------- previous outer attribute LL | </ins> LL | #![recursion_limit="100"] <del> |   ^ </del> <ins> | ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attibute </ins> | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.