pre-RFC: Enable setting of source file, line & column

I'd say the attributes fit fairly well into the new #[diagnostic::] namespace, since this part of the span info is for diagnostics (it wouldn't impact the resolution part of the span). Except that since proc macros can (unstably) read that span info, it wouldn't be "ignorable" the way #[diagnostic::] is intended to be (as are the other "tool attributes"). (Which is what allows an unrecognized/uninterpreted tool attribute to be not an error, since they're never permitted to impact semantics.)

So honestly I think we'd end up with spans containing three bits of span information — the "real" span location for what source it comes from, the "assigned diagnostic" span location, and the resolution location.

If the attributes have the semantic of setting span info for the decorated syntax only and then resetting afterwards, then attributes absolutely make sense. The way that #file style works, though, is that it's set and impacts any following lines until it's set again. That's the behavior that functionlike macros would have.

The only generically useful functionality I can really see existing is an attribute to set the textual span of some syntax to be a section of a file, e.g. #[diagnostic::span("file", line:col..line:col)], and every token covered by the annotation gets the same span pointing to that whole region. Basically, the way any tokens generated by a macro (call_site() or mixed_site() hygiene) point to the entire macro invocation. Assigning spans at a finer scope seems impractical to stuff declaratively into the Rust grammar.

C preprocessor directives have the "advantage" that they can be placed arbitrarily between any whichever tokens in the actual language grammar. Rust macros deliberately don't have that level of syntactic freedom; functionlike macros can only show up in expression, item, pattern, statement, or type position, and attribute macros can only decorate items, statements, or (unstably) expressions.

Also keep in mind that C and C++ have historically just shown the file:line:col reference and maybe a snippet of the blamed line, whereas Rust tries a lot harder to show specific source regions in errors. Arbitrary span manipulation makes this significantly more difficult; even macros can easily make errors look weird when combining nontrivial error span assignment with nontrivial span provenance. (E.g. how can you point at an expression a + b when the three tokens' spans come from three different files?)