diff options
Diffstat (limited to 'tests/incremental/issue-85197-invalid-span')
4 files changed, 68 insertions, 0 deletions
diff --git a/tests/incremental/issue-85197-invalid-span/auxiliary/invalid-span-helper-lib.rs b/tests/incremental/issue-85197-invalid-span/auxiliary/invalid-span-helper-lib.rs new file mode 100644 index 000000000..2453af5b6 --- /dev/null +++ b/tests/incremental/issue-85197-invalid-span/auxiliary/invalid-span-helper-lib.rs @@ -0,0 +1,11 @@ +// revisions: rpass1 rpass2 + +extern crate respan; + +#[macro_use] +#[path = "invalid-span-helper-mod.rs"] +mod invalid_span_helper_mod; + +// Invoke a macro from a different file - this +// allows us to get tokens with spans from different files +helper!(1); diff --git a/tests/incremental/issue-85197-invalid-span/auxiliary/invalid-span-helper-mod.rs b/tests/incremental/issue-85197-invalid-span/auxiliary/invalid-span-helper-mod.rs new file mode 100644 index 000000000..747174b1e --- /dev/null +++ b/tests/incremental/issue-85197-invalid-span/auxiliary/invalid-span-helper-mod.rs @@ -0,0 +1,14 @@ +#[macro_export] +macro_rules! helper { + // Use `:tt` instead of `:ident` so that we don't get a `None`-delimited group + ($first:tt) => { + pub fn foo<T>() { + // The span of `$first` comes from another file, + // so the expression `1 + $first` ends up with an + // 'invalid' span that starts and ends in different files. + // We use the `respan!` macro to give all tokens the same + // `SyntaxContext`, so that the parser will try to merge the spans. + respan::respan!(let a = 1 + $first;); + } + } +} diff --git a/tests/incremental/issue-85197-invalid-span/auxiliary/respan.rs b/tests/incremental/issue-85197-invalid-span/auxiliary/respan.rs new file mode 100644 index 000000000..5088eab62 --- /dev/null +++ b/tests/incremental/issue-85197-invalid-span/auxiliary/respan.rs @@ -0,0 +1,19 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + + +/// Copies the resolution information (the `SyntaxContext`) of the first +/// token to all other tokens in the stream. Does not recurse into groups. +#[proc_macro] +pub fn respan(input: TokenStream) -> TokenStream { + let first_span = input.clone().into_iter().next().unwrap().span(); + input.into_iter().map(|mut tree| { + tree.set_span(tree.span().resolved_at(first_span)); + tree + }).collect() +} diff --git a/tests/incremental/issue-85197-invalid-span/invalid_span_main.rs b/tests/incremental/issue-85197-invalid-span/invalid_span_main.rs new file mode 100644 index 000000000..f358460b3 --- /dev/null +++ b/tests/incremental/issue-85197-invalid-span/invalid_span_main.rs @@ -0,0 +1,24 @@ +// revisions: rpass1 rpass2 +// aux-build:respan.rs +// aux-build:invalid-span-helper-lib.rs + +// This issue has several different parts. The high level idea is: +// 1. We create an 'invalid' span with the help of the `respan` proc-macro, +// The compiler attempts to prevent the creation of invalid spans by +// refusing to join spans with different `SyntaxContext`s. We work around +// this by applying the same `SyntaxContext` to the span of every token, +// using `Span::resolved_at` +// 2. We using this invalid span in the body of a function, causing it to get +// encoded into the `optimized_mir` +// 3. We call the function from a different crate - since the function is generic, +// monomorphization runs, causing `optimized_mir` to get called. +// 4. We re-run compilation using our populated incremental cache, but without +// making any changes. When we recompile the crate containing our generic function +// (`invalid_span_helper_lib`), we load the span from the incremental cache, and +// write it into the crate metadata. + +extern crate invalid_span_helper_lib; + +fn main() { + invalid_span_helper_lib::foo::<u8>(); +} |