Skip to content

Commit 71ff9b4

Browse files
committed
Auto merge of #87712 - est31:line-column-1-based, r=petrochenkov
Proc macro spans: make columns 1 based This makes proc macro spans consistent with the `column!()` macro as well as `std::panic::Location`, as both are 1-based. #54725 (comment)
2 parents bb744e1 + 7d20789 commit 71ff9b4

File tree

4 files changed

+85
-4
lines changed

4 files changed

+85
-4
lines changed

library/proc_macro/src/lib.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -348,13 +348,13 @@ impl Span {
348348
/// Gets the starting line/column in the source file for this span.
349349
#[unstable(feature = "proc_macro_span", issue = "54725")]
350350
pub fn start(&self) -> LineColumn {
351-
self.0.start()
351+
self.0.start().add_1_to_column()
352352
}
353353

354354
/// Gets the ending line/column in the source file for this span.
355355
#[unstable(feature = "proc_macro_span", issue = "54725")]
356356
pub fn end(&self) -> LineColumn {
357-
self.0.end()
357+
self.0.end().add_1_to_column()
358358
}
359359

360360
/// Creates a new span encompassing `self` and `other`.
@@ -432,12 +432,18 @@ pub struct LineColumn {
432432
/// The 1-indexed line in the source file on which the span starts or ends (inclusive).
433433
#[unstable(feature = "proc_macro_span", issue = "54725")]
434434
pub line: usize,
435-
/// The 0-indexed column (in UTF-8 characters) in the source file on which
436-
/// the span starts or ends (inclusive).
435+
/// The 1-indexed column (number of bytes in UTF-8 encoding) in the source
436+
/// file on which the span starts or ends (inclusive).
437437
#[unstable(feature = "proc_macro_span", issue = "54725")]
438438
pub column: usize,
439439
}
440440

441+
impl LineColumn {
442+
fn add_1_to_column(self) -> Self {
443+
LineColumn { line: self.line, column: self.column + 1 }
444+
}
445+
}
446+
441447
#[unstable(feature = "proc_macro_span", issue = "54725")]
442448
impl !Send for LineColumn {}
443449
#[unstable(feature = "proc_macro_span", issue = "54725")]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// force-host
2+
// no-prefer-dynamic
3+
4+
#![feature(proc_macro_diagnostic, proc_macro_span)]
5+
#![crate_type = "proc-macro"]
6+
7+
extern crate proc_macro;
8+
9+
use proc_macro::{TokenStream, TokenTree, Span};
10+
11+
fn lit_span(tt: TokenTree) -> (Span, String) {
12+
match tt {
13+
TokenTree::Literal(..) |
14+
TokenTree::Group(..) => (tt.span(), tt.to_string().trim().into()),
15+
_ => panic!("expected a literal in token tree, got: {:?}", tt)
16+
}
17+
}
18+
19+
#[proc_macro]
20+
pub fn assert_span_pos(input: TokenStream) -> TokenStream {
21+
let mut tokens = input.into_iter();
22+
let (sp1, str1) = lit_span(tokens.next().expect("first argument"));
23+
let _ = tokens.next();
24+
let (_sp2, str2) = lit_span(tokens.next().expect("second argument"));
25+
26+
let line: usize = str1.parse().unwrap();
27+
let col: usize = str2.parse().unwrap();
28+
29+
let sp1s = sp1.start();
30+
if (line, col) != (sp1s.line, sp1s.column) {
31+
let msg = format!("line/column mismatch: ({}, {}) != ({}, {})", line, col,
32+
sp1s.line, sp1s.column);
33+
sp1.error(msg).emit();
34+
}
35+
36+
"".parse().unwrap()
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// aux-build:assert-span-pos.rs
2+
// ignore-tidy-tab
3+
extern crate assert_span_pos;
4+
5+
assert_span_pos::assert_span_pos!(5, 35);
6+
7+
// Test space indentation
8+
assert_span_pos::assert_span_pos!(8, 39);
9+
// Test tab indentation
10+
assert_span_pos::assert_span_pos!(10, 36);
11+
12+
// Two tests to ensure the promise of the docs that the column is the number
13+
// of UTF-8 bytes instead of some other number like number of code points.
14+
15+
// Test that multi byte UTF-8 characters indeed count as multiple bytes
16+
/*🌈*/assert_span_pos::assert_span_pos!(16, 40);
17+
// Test with a complete grapheme cluster
18+
/*🏳️‍🌈*/assert_span_pos::assert_span_pos!(18, 43);
19+
20+
// Test that the macro actually emits an error on a mismatch:
21+
assert_span_pos::assert_span_pos!(0, 35); //~ ERROR line/column mismatch: (0, 35) != (21, 35)
22+
assert_span_pos::assert_span_pos!(22, 0); //~ ERROR line/column mismatch: (22, 0) != (22, 35)
23+
24+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: line/column mismatch: (0, 35) != (21, 35)
2+
--> $DIR/span-absolute-posititions.rs:21:35
3+
|
4+
LL | assert_span_pos::assert_span_pos!(0, 35);
5+
| ^
6+
7+
error: line/column mismatch: (22, 0) != (22, 35)
8+
--> $DIR/span-absolute-posititions.rs:22:35
9+
|
10+
LL | assert_span_pos::assert_span_pos!(22, 0);
11+
| ^^
12+
13+
error: aborting due to 2 previous errors
14+

0 commit comments

Comments
 (0)