aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2020-09-30 04:48:30 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-09-30 04:48:30 +0000
commit7c5e37eb1cbc03760ccece0e20ff4a28f2edfe34 (patch)
tree1e5c4afb87741351207fbb77e2e68f489670f8bc
parent4f775fbd2186e2cf157ee0cedf266c2189f85091 (diff)
parenteef7c23c35e10d408ff6ee75bfd990539883067f (diff)
downloadproc-macro-error-7c5e37eb1cbc03760ccece0e20ff4a28f2edfe34.tar.gz
Upgrade rust/crates/proc-macro-error to 1.0.4 am: eef7c23c35
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/proc-macro-error/+/1414396 Change-Id: I2dc949e737d3d2d9982ceda2d2d29d5310ce46aa
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp12
-rw-r--r--CHANGELOG.md11
-rw-r--r--Cargo.toml13
-rw-r--r--Cargo.toml.orig15
-rw-r--r--LICENSE-APACHE2
-rw-r--r--LICENSE-MIT2
-rw-r--r--METADATA8
-rw-r--r--README.md18
-rw-r--r--src/diagnostic.rs170
-rw-r--r--src/imp/delegate.rs19
-rw-r--r--src/lib.rs144
-rw-r--r--src/macros.rs60
-rw-r--r--src/sealed.rs3
-rw-r--r--tests/ui/abort.rs1
-rw-r--r--tests/ui/abort.stderr8
-rw-r--r--tests/ui/emit.rs2
-rw-r--r--tests/ui/emit.stderr16
-rw-r--r--tests/ui/explicit_span_range.rs6
-rw-r--r--tests/ui/explicit_span_range.stderr5
-rw-r--r--tests/ui/misuse.stderr17
-rw-r--r--tests/ui/not_proc_macro.stderr6
-rw-r--r--tests/ui/option_ext.stderr4
-rw-r--r--tests/ui/proc_macro_hack.stderr6
24 files changed, 409 insertions, 141 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 0b126fe..1561cb4 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "69743a4ceab6c8da1ddb473f54a6a01840de90d9"
+ "sha1": "e231741c47af1beda78d53aee29500cccb8266cd"
}
}
diff --git a/Android.bp b/Android.bp
index 583b93d..da13ffc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -5,6 +5,11 @@ rust_library_host {
crate_name: "proc_macro_error",
srcs: ["src/lib.rs"],
edition: "2018",
+ features: [
+ "default",
+ "syn",
+ "syn-error",
+ ],
flags: [
"--cfg skip_ui_tests",
],
@@ -20,10 +25,9 @@ rust_library_host {
}
// dependent_library ["feature_list"]
-// proc-macro-error-attr-1.0.2
-// proc-macro2-1.0.19 "default,proc-macro"
+// proc-macro-error-attr-1.0.4
+// proc-macro2-1.0.23 "default,proc-macro"
// quote-1.0.7 "default,proc-macro"
-// syn-1.0.36 "clone-impls,default,derive,parsing,printing,proc-macro,quote,visit"
-// syn-mid-0.5.0
+// syn-1.0.42 "clone-impls,default,derive,parsing,printing,proc-macro,quote,visit"
// unicode-xid-0.2.1 "default"
// version_check-0.9.2
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c1a2d3c..3c422f1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+# v1.0.4 (2020-7-31)
+
+* `SpanRange` facility is now public.
+* Docs have been improved.
+* Introduced the `syn-error` feature so you can opt-out from the `syn` dependency.
+
+# v1.0.3 (2020-6-26)
+
+* Corrected a few typos.
+* Fixed the `emit_call_site_warning` macro.
+
# v1.0.2 (2020-4-9)
* An obsolete note was removed from documentation.
diff --git a/Cargo.toml b/Cargo.toml
index fc90d7d..869585f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "proc-macro-error"
-version = "1.0.2"
+version = "1.0.4"
authors = ["CreepySkeleton <creepy-skeleton@yandex.ru>"]
build = "build.rs"
description = "Almost drop-in replacement to panics in proc-macros"
@@ -25,7 +25,7 @@ repository = "https://gitlab.com/CreepySkeleton/proc-macro-error"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies.proc-macro-error-attr]
-version = "=1.0.2"
+version = "=1.0.4"
[dependencies.proc-macro2]
version = "1"
@@ -35,8 +35,11 @@ version = "1"
[dependencies.syn]
version = "1"
-features = ["derive", "parsing", "proc-macro", "printing"]
+optional = true
default-features = false
+[dev-dependencies.serde_derive]
+version = "=1.0.107"
+
[dev-dependencies.toml]
version = "=0.5.2"
@@ -45,5 +48,9 @@ version = "1.0.19"
features = ["diff"]
[build-dependencies.version_check]
version = "0.9"
+
+[features]
+default = ["syn-error"]
+syn-error = ["syn"]
[badges.maintenance]
status = "passively-maintained"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 83f6781..5ad358d 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "proc-macro-error"
-version = "1.0.2"
+version = "1.0.4"
authors = ["CreepySkeleton <creepy-skeleton@yandex.ru>"]
description = "Almost drop-in replacement to panics in proc-macros"
@@ -22,14 +22,23 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
quote = "1"
proc-macro2 = "1"
-syn = { version = "1", default-features = false, features = ["derive", "parsing", "proc-macro", "printing"] }
-proc-macro-error-attr = { path = "./proc-macro-error-attr", version = "=1.0.2"}
+proc-macro-error-attr = { path = "./proc-macro-error-attr", version = "=1.0.4"}
+
+[dependencies.syn]
+version = "1"
+optional = true
+default-features = false
[dev-dependencies]
test-crate = { path = "./test-crate" }
proc-macro-hack-test = { path = "./test-crate/proc-macro-hack-test" }
trybuild = { version = "1.0.19", features = ["diff"] }
toml = "=0.5.2" # DO NOT BUMP
+serde_derive = "=1.0.107" # DO NOT BUMP
[build-dependencies]
version_check = "0.9"
+
+[features]
+default = ["syn-error"]
+syn-error = ["syn"]
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
index 52ba334..cc17374 100644
--- a/LICENSE-APACHE
+++ b/LICENSE-APACHE
@@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
same "printed page" as the copyright notice for easier
identification within third-party archives.
-Copyright 2019 CreepySkeleton <creepy-skeleton@yandex.ru>
+Copyright 2019-2020 CreepySkeleton <creepy-skeleton@yandex.ru>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/LICENSE-MIT b/LICENSE-MIT
index d01f775..fc73e59 100644
--- a/LICENSE-MIT
+++ b/LICENSE-MIT
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2019 CreepySkeleton
+Copyright (c) 2019-2020 CreepySkeleton
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/METADATA b/METADATA
index 07686e8..e10f8c2 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/proc-macro-error/proc-macro-error-1.0.2.crate"
+ value: "https://static.crates.io/crates/proc-macro-error/proc-macro-error-1.0.4.crate"
}
- version: "1.0.2"
+ version: "1.0.4"
license_type: NOTICE
last_upgrade_date {
year: 2020
- month: 5
- day: 6
+ month: 9
+ day: 29
}
}
diff --git a/README.md b/README.md
index fb1da50..7fbe07c 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,15 @@
This crate aims to make error reporting in proc-macros simple and easy to use.
Migrate from `panic!`-based errors for as little effort as possible!
-Also, there's ability to [append a dummy token stream][crate::dummy] to your errors.
+Also, you can explicitly [append a dummy token stream][crate::dummy] to your errors.
+
+To achieve his, this crate serves as a tiny shim around `proc_macro::Diagnostic` and
+`compile_error!`. It detects the most preferable way to emit errors based on compiler's version.
+When the underlying diagnostic type is finally stabilized, this crate will be simply
+delegating to it, requiring no changes in your code!
+
+So you can just use this crate and have *both* some of `proc_macro::Diagnostic` functionality
+available on stable ahead of time and your error-reporting code future-proof.
```toml
[dependencies]
@@ -242,9 +250,9 @@ be dual licensed as above, without any additional terms or conditions.
[compl_err]: https://doc.rust-lang.org/std/macro.compile_error.html
[`proc_macro::Diagnostic`]: https://doc.rust-lang.org/proc_macro/struct.Diagnostic.html
-[crate::dummy]: https://docs.rs/proc-macro-error/0.4/proc_macro_error/dummy/index.html
-[crate::multi]: https://docs.rs/proc-macro-error/0.4/proc_macro_error/multi/index.html
+[crate::dummy]: https://docs.rs/proc-macro-error/1/proc_macro_error/dummy/index.html
+[crate::multi]: https://docs.rs/proc-macro-error/1/proc_macro_error/multi/index.html
-[`abort_call_site!`]: https://docs.rs/proc-macro-error/0.4/proc_macro_error/macro.abort_call_site.html
-[`abort!`]: https://docs.rs/proc-macro-error/0.4/proc_macro_error/macro.abort.html
+[`abort_call_site!`]: https://docs.rs/proc-macro-error/1/proc_macro_error/macro.abort_call_site.html
+[`abort!`]: https://docs.rs/proc-macro-error/1/proc_macro_error/macro.abort.html
[guide]: https://docs.rs/proc-macro-error
diff --git a/src/diagnostic.rs b/src/diagnostic.rs
index 5ec8ce2..983e617 100644
--- a/src/diagnostic.rs
+++ b/src/diagnostic.rs
@@ -1,4 +1,4 @@
-use crate::{abort_now, check_correctness};
+use crate::{abort_now, check_correctness, sealed::Sealed, SpanRange};
use proc_macro2::Span;
use proc_macro2::TokenStream;
@@ -21,11 +21,78 @@ pub enum Level {
#[derive(Debug)]
pub struct Diagnostic {
pub(crate) level: Level,
- pub(crate) start: Span,
- pub(crate) end: Span,
+ pub(crate) span_range: SpanRange,
pub(crate) msg: String,
- pub(crate) suggestions: Vec<(SuggestionKind, String, Option<Span>)>,
- pub(crate) children: Vec<(Span, Span, String)>,
+ pub(crate) suggestions: Vec<(SuggestionKind, String, Option<SpanRange>)>,
+ pub(crate) children: Vec<(SpanRange, String)>,
+}
+
+/// A collection of methods that do not exist in `proc_macro::Diagnostic`
+/// but still useful to have around.
+///
+/// This trait is sealed and cannot be implemented outside of `proc_macro_error`.
+pub trait DiagnosticExt: Sealed {
+ /// Create a new diagnostic message that points to the `span_range`.
+ ///
+ /// This function is the same as `Diagnostic::spanned` but produces considerably
+ /// better error messages for multi-token spans on stable.
+ fn spanned_range(span_range: SpanRange, level: Level, message: String) -> Self;
+
+ /// Add another error message to self such that it will be emitted right after
+ /// the main message.
+ ///
+ /// This function is the same as `Diagnostic::span_error` but produces considerably
+ /// better error messages for multi-token spans on stable.
+ fn span_range_error(self, span_range: SpanRange, msg: String) -> Self;
+
+ /// Attach a "help" note to your main message, the note will have it's own span on nightly.
+ ///
+ /// This function is the same as `Diagnostic::span_help` but produces considerably
+ /// better error messages for multi-token spans on stable.
+ ///
+ /// # Span
+ ///
+ /// The span is ignored on stable, the note effectively inherits its parent's (main message) span
+ fn span_range_help(self, span_range: SpanRange, msg: String) -> Self;
+
+ /// Attach a note to your main message, the note will have it's own span on nightly.
+ ///
+ /// This function is the same as `Diagnostic::span_note` but produces considerably
+ /// better error messages for multi-token spans on stable.
+ ///
+ /// # Span
+ ///
+ /// The span is ignored on stable, the note effectively inherits its parent's (main message) span
+ fn span_range_note(self, span_range: SpanRange, msg: String) -> Self;
+}
+
+impl DiagnosticExt for Diagnostic {
+ fn spanned_range(span_range: SpanRange, level: Level, message: String) -> Self {
+ Diagnostic {
+ level,
+ span_range,
+ msg: message,
+ suggestions: vec![],
+ children: vec![],
+ }
+ }
+
+ fn span_range_error(mut self, span_range: SpanRange, msg: String) -> Self {
+ self.children.push((span_range, msg));
+ self
+ }
+
+ fn span_range_help(mut self, span_range: SpanRange, msg: String) -> Self {
+ self.suggestions
+ .push((SuggestionKind::Help, msg, Some(span_range)));
+ self
+ }
+
+ fn span_range_note(mut self, span_range: SpanRange, msg: String) -> Self {
+ self.suggestions
+ .push((SuggestionKind::Note, msg, Some(span_range)));
+ self
+ }
}
impl Diagnostic {
@@ -36,13 +103,26 @@ impl Diagnostic {
/// Create a new diagnostic message that points to the `span`
pub fn spanned(span: Span, level: Level, message: String) -> Self {
- Diagnostic::double_spanned(span, span, level, message)
+ Diagnostic::spanned_range(
+ SpanRange {
+ first: span,
+ last: span,
+ },
+ level,
+ message,
+ )
}
/// Add another error message to self such that it will be emitted right after
/// the main message.
pub fn span_error(self, span: Span, msg: String) -> Self {
- self.double_span_error(span, span, msg)
+ self.span_range_error(
+ SpanRange {
+ first: span,
+ last: span,
+ },
+ msg,
+ )
}
/// Attach a "help" note to your main message, the note will have it's own span on nightly.
@@ -50,10 +130,14 @@ impl Diagnostic {
/// # Span
///
/// The span is ignored on stable, the note effectively inherits its parent's (main message) span
- pub fn span_help(mut self, span: Span, msg: String) -> Self {
- self.suggestions
- .push((SuggestionKind::Help, msg, Some(span)));
- self
+ pub fn span_help(self, span: Span, msg: String) -> Self {
+ self.span_range_help(
+ SpanRange {
+ first: span,
+ last: span,
+ },
+ msg,
+ )
}
/// Attach a "help" note to your main message.
@@ -67,10 +151,14 @@ impl Diagnostic {
/// # Span
///
/// The span is ignored on stable, the note effectively inherits its parent's (main message) span
- pub fn span_note(mut self, span: Span, msg: String) -> Self {
- self.suggestions
- .push((SuggestionKind::Note, msg, Some(span)));
- self
+ pub fn span_note(self, span: Span, msg: String) -> Self {
+ self.span_range_note(
+ SpanRange {
+ first: span,
+ last: span,
+ },
+ msg,
+ )
}
/// Attach a note to your main message
@@ -88,7 +176,7 @@ impl Diagnostic {
///
/// # Warnings
///
- /// Warnings do not get emitted on stable/beta but this function will abort anyway.
+ /// Warnings are not emitted on stable and beta, but this function will abort anyway.
pub fn abort(self) -> ! {
self.emit();
abort_now()
@@ -108,22 +196,6 @@ impl Diagnostic {
/// **NOT PUBLIC API! NOTHING TO SEE HERE!!!**
#[doc(hidden)]
impl Diagnostic {
- pub fn double_spanned(start: Span, end: Span, level: Level, message: String) -> Self {
- Diagnostic {
- level,
- start,
- end,
- msg: message,
- suggestions: vec![],
- children: vec![],
- }
- }
-
- pub fn double_span_error(mut self, start: Span, end: Span, msg: String) -> Self {
- self.children.push((start, end, msg));
- self
- }
-
pub fn span_suggestion(self, span: Span, suggestion: &str, msg: String) -> Self {
match suggestion {
"help" | "hint" => self.span_help(span, msg),
@@ -153,11 +225,10 @@ impl ToTokens for Diagnostic {
}
fn diag_to_tokens(
- start: Span,
- end: Span,
+ span_range: SpanRange,
level: &Level,
msg: &str,
- suggestions: &[(SuggestionKind, String, Option<Span>)],
+ suggestions: &[(SuggestionKind, String, Option<SpanRange>)],
) -> TokenStream {
if *level == Level::Warning {
return TokenStream::new();
@@ -181,14 +252,14 @@ impl ToTokens for Diagnostic {
Cow::Owned(message)
};
- let msg = syn::LitStr::new(&*message, end);
- let group = quote_spanned!(end=> { #msg } );
- quote_spanned!(start=> compile_error!#group)
+ let mut msg = proc_macro2::Literal::string(&message);
+ msg.set_span(span_range.last);
+ let group = quote_spanned!(span_range.last=> { #msg } );
+ quote_spanned!(span_range.first=> compile_error!#group)
}
ts.extend(diag_to_tokens(
- self.start,
- self.end,
+ self.span_range,
&self.level,
&self.msg,
&self.suggestions,
@@ -196,7 +267,7 @@ impl ToTokens for Diagnostic {
ts.extend(
self.children
.iter()
- .map(|(start, end, msg)| diag_to_tokens(*start, *end, &Level::Error, &msg, &[])),
+ .map(|(span_range, msg)| diag_to_tokens(*span_range, &Level::Error, &msg, &[])),
);
}
}
@@ -216,12 +287,13 @@ impl SuggestionKind {
}
}
+#[cfg(feature = "syn-error")]
impl From<syn::Error> for Diagnostic {
fn from(err: syn::Error) -> Self {
use proc_macro2::{Delimiter, TokenTree};
- fn gut_error(ts: &mut impl Iterator<Item = TokenTree>) -> Option<(Span, Span, String)> {
- let start = match ts.next() {
+ fn gut_error(ts: &mut impl Iterator<Item = TokenTree>) -> Option<(SpanRange, String)> {
+ let first = match ts.next() {
// compile_error
None => return None,
Some(tt) => tt.span(),
@@ -253,23 +325,23 @@ impl From<syn::Error> for Diagnostic {
_ => unreachable!(),
};
- let end = lit.span();
+ let last = lit.span();
let mut msg = lit.to_string();
// "abc" => abc
msg.pop();
msg.remove(0);
- Some((start, end, msg))
+ Some((SpanRange { first, last }, msg))
}
let mut ts = err.to_compile_error().into_iter();
- let (start, end, msg) = gut_error(&mut ts).unwrap();
- let mut res = Diagnostic::double_spanned(start, end, Level::Error, msg);
+ let (span_range, msg) = gut_error(&mut ts).unwrap();
+ let mut res = Diagnostic::spanned_range(span_range, Level::Error, msg);
- while let Some((start, end, msg)) = gut_error(&mut ts) {
- res = res.double_span_error(start, end, msg);
+ while let Some((span_range, msg)) = gut_error(&mut ts) {
+ res = res.span_range_error(span_range, msg);
}
res
diff --git a/src/imp/delegate.rs b/src/imp/delegate.rs
index c096803..07def2b 100644
--- a/src/imp/delegate.rs
+++ b/src/imp/delegate.rs
@@ -24,14 +24,13 @@ pub(crate) fn cleanup() -> Vec<Diagnostic> {
pub(crate) fn emit_diagnostic(diag: Diagnostic) {
let Diagnostic {
level,
- start,
- end,
+ span_range,
msg,
suggestions,
children,
} = diag;
- let span = start.join(end).unwrap_or(start);
+ let span = span_range.collapse().unwrap();
let level = match level {
Level::Warning => PLevel::Warning,
@@ -42,19 +41,23 @@ pub(crate) fn emit_diagnostic(diag: Diagnostic) {
_ => unreachable!(),
};
- let mut res = PDiag::spanned(span.unwrap(), level, msg);
+ let mut res = PDiag::spanned(span, level, msg);
for (kind, msg, span) in suggestions {
res = match (kind, span) {
- (SuggestionKind::Note, Some(span)) => res.span_note(span.unwrap(), msg),
- (SuggestionKind::Help, Some(span)) => res.span_help(span.unwrap(), msg),
+ (SuggestionKind::Note, Some(span_range)) => {
+ res.span_note(span_range.collapse().unwrap(), msg)
+ }
+ (SuggestionKind::Help, Some(span_range)) => {
+ res.span_help(span_range.collapse().unwrap(), msg)
+ }
(SuggestionKind::Note, None) => res.note(msg),
(SuggestionKind::Help, None) => res.help(msg),
}
}
- for (start, end, msg) in children {
- let span = start.join(end).unwrap_or(start).unwrap();
+ for (span_range, msg) in children {
+ let span = span_range.collapse().unwrap();
res = res.span_error(span, msg);
}
diff --git a/src/lib.rs b/src/lib.rs
index 0af2de3..fb867fd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,7 +3,29 @@
//! This crate aims to make error reporting in proc-macros simple and easy to use.
//! Migrate from `panic!`-based errors for as little effort as possible!
//!
-//! Also, there's ability to [append a dummy token stream](dummy/index.html) to your errors.
+//! (Also, you can explicitly [append a dummy token stream](dummy/index.html) to your errors).
+//!
+//! To achieve his, this crate serves as a tiny shim around `proc_macro::Diagnostic` and
+//! `compile_error!`. It detects the best way of emitting available based on compiler's version.
+//! When the underlying diagnostic type is finally stabilized, this crate will simply be
+//! delegating to it requiring no changes in your code!
+//!
+//! So you can just use this crate and have *both* some of `proc_macro::Diagnostic` functionality
+//! available on stable ahead of time *and* your error-reporting code future-proof.
+//!
+//! ## Cargo features
+//!
+//! This crate provides *enabled by default* `syn-error` feature that gates
+//! `impl From<syn::Error> for Diagnostic` conversion. If you don't use `syn` and want
+//! to cut off some of compilation time, you can disable it via
+//!
+//! ```toml
+//! [dependencies]
+//! proc-macro-error = { version = "1", default-features = false }
+//! ```
+//!
+//! ***Please note that disabling this feature makes sense only if you don't depend on `syn`
+//! directly or indirectly, and you very likely do.**
//!
//! ## Real world examples
//!
@@ -253,19 +275,16 @@
#![forbid(unsafe_code)]
#![allow(clippy::needless_doctest_main)]
-// reexports for use in macros
-#[doc(hidden)]
-pub extern crate proc_macro;
-#[doc(hidden)]
-pub extern crate proc_macro2;
+extern crate proc_macro;
pub use crate::{
- diagnostic::{Diagnostic, Level},
+ diagnostic::{Diagnostic, DiagnosticExt, Level},
dummy::{append_dummy, set_dummy},
};
pub use proc_macro_error_attr::proc_macro_error;
-use quote::quote;
+use proc_macro2::Span;
+use quote::{quote, ToTokens};
use std::cell::Cell;
use std::panic::{catch_unwind, resume_unwind, UnwindSafe};
@@ -274,6 +293,7 @@ pub mod dummy;
mod diagnostic;
mod macros;
+mod sealed;
#[cfg(use_fallback)]
#[path = "imp/fallback.rs"]
@@ -283,6 +303,57 @@ mod imp;
#[path = "imp/delegate.rs"]
mod imp;
+#[derive(Debug, Clone, Copy)]
+pub struct SpanRange {
+ pub first: Span,
+ pub last: Span,
+}
+
+impl SpanRange {
+ /// Create a range with the `first` and `last` spans being the same.
+ pub fn single_span(span: Span) -> Self {
+ SpanRange {
+ first: span,
+ last: span,
+ }
+ }
+
+ /// Create a `SpanRange` resolving at call site.
+ pub fn call_site() -> Self {
+ SpanRange::single_span(Span::call_site())
+ }
+
+ /// Construct span range from a `TokenStream`. This method always preserves all the
+ /// range.
+ ///
+ /// ### Note
+ ///
+ /// If the stream is empty, the result is `SpanRange::call_site()`. If the stream
+ /// consists of only one `TokenTree`, the result is `SpanRange::single_span(tt.span())`
+ /// that doesn't lose anything.
+ pub fn from_tokens(ts: &dyn ToTokens) -> Self {
+ let mut spans = ts.to_token_stream().into_iter().map(|tt| tt.span());
+ let first = spans.next().unwrap_or_else(|| Span::call_site());
+ let last = spans.last().unwrap_or(first);
+
+ SpanRange { first, last }
+ }
+
+ /// Join two span ranges. The resulting range will start at `self.first` and end at
+ /// `other.last`.
+ pub fn join_range(self, other: SpanRange) -> Self {
+ SpanRange {
+ first: self.first,
+ last: other.last,
+ }
+ }
+
+ /// Collapse the range into single span, preserving as much information as possible.
+ pub fn collapse(self) -> Span {
+ self.first.join(self.last).unwrap_or(self.first)
+ }
+}
+
/// This traits expands `Result<T, Into<Diagnostic>>` with some handy shortcuts.
pub trait ResultExt {
type Ok;
@@ -419,48 +490,71 @@ fn check_correctness() {
/// **ALL THE STUFF INSIDE IS NOT PUBLIC API!!!**
#[doc(hidden)]
pub mod __export {
+ // reexports for use in macros
+ pub extern crate proc_macro;
+ pub extern crate proc_macro2;
+
use proc_macro2::Span;
use quote::ToTokens;
+ use crate::SpanRange;
+
// inspired by
// https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md#simple-application
- pub trait DoubleSpanToTokens {
+ pub trait SpanAsSpanRange {
#[allow(non_snake_case)]
- fn FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS(&self) -> (Span, Span);
+ fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange;
}
- pub trait DoubleSpanSingleSpan2 {
+ pub trait Span2AsSpanRange {
#[allow(non_snake_case)]
- fn FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS(&self) -> (Span, Span);
+ fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange;
}
- pub trait DoubleSpanSingleSpan {
+ pub trait ToTokensAsSpanRange {
#[allow(non_snake_case)]
- fn FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS(&self) -> (Span, Span);
+ fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange;
}
- impl<T: ToTokens> DoubleSpanToTokens for &T {
- fn FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS(&self) -> (Span, Span) {
+ pub trait SpanRangeAsSpanRange {
+ #[allow(non_snake_case)]
+ fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange;
+ }
+
+ impl<T: ToTokens> ToTokensAsSpanRange for &T {
+ fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange {
let mut ts = self.to_token_stream().into_iter();
- let start = ts
+ let first = ts
.next()
.map(|tt| tt.span())
.unwrap_or_else(Span::call_site);
- let end = ts.last().map(|tt| tt.span()).unwrap_or(start);
- (start, end)
+ let last = ts.last().map(|tt| tt.span()).unwrap_or(first);
+ SpanRange { first, last }
+ }
+ }
+
+ impl Span2AsSpanRange for Span {
+ fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange {
+ SpanRange {
+ first: *self,
+ last: *self,
+ }
}
}
- impl DoubleSpanSingleSpan2 for Span {
- fn FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS(&self) -> (Span, Span) {
- (*self, *self)
+ impl SpanAsSpanRange for proc_macro::Span {
+ fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange {
+ SpanRange {
+ first: self.clone().into(),
+ last: self.clone().into(),
+ }
}
}
- impl DoubleSpanSingleSpan for proc_macro::Span {
- fn FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS(&self) -> (Span, Span) {
- (self.clone().into(), self.clone().into())
+ impl SpanRangeAsSpanRange for SpanRange {
+ fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange {
+ *self
}
}
}
diff --git a/src/macros.rs b/src/macros.rs
index ccf6547..747b684 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -15,12 +15,17 @@ macro_rules! diagnostic {
// span, message, help
($span:expr, $level:expr, $fmt:expr, $($args:expr),+ ; $($rest:tt)+) => {{
#[allow(unused_imports)]
- use $crate::__export::{DoubleSpanToTokens, DoubleSpanSingleSpan, DoubleSpanSingleSpan2};
- let (start, end) = (&$span).FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS();
+ use $crate::__export::{
+ ToTokensAsSpanRange,
+ Span2AsSpanRange,
+ SpanAsSpanRange,
+ SpanRangeAsSpanRange
+ };
+ use $crate::DiagnosticExt;
+ let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange();
- let diag = $crate::Diagnostic::double_spanned(
- start,
- end,
+ let diag = $crate::Diagnostic::spanned_range(
+ span_range,
$level,
format!($fmt, $($args),*)
);
@@ -30,10 +35,16 @@ macro_rules! diagnostic {
($span:expr, $level:expr, $msg:expr ; $($rest:tt)+) => {{
#[allow(unused_imports)]
- use $crate::__export::{DoubleSpanToTokens, DoubleSpanSingleSpan, DoubleSpanSingleSpan2};
- let (start, end) = (&$span).FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS();
+ use $crate::__export::{
+ ToTokensAsSpanRange,
+ Span2AsSpanRange,
+ SpanAsSpanRange,
+ SpanRangeAsSpanRange
+ };
+ use $crate::DiagnosticExt;
+ let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange();
- let diag = $crate::Diagnostic::double_spanned(start, end, $level, $msg.to_string());
+ let diag = $crate::Diagnostic::spanned_range(span_range, $level, $msg.to_string());
$crate::__pme__suggestions!(diag $($rest)*);
diag
}};
@@ -41,12 +52,17 @@ macro_rules! diagnostic {
// span, message, no help
($span:expr, $level:expr, $fmt:expr, $($args:expr),+) => {{
#[allow(unused_imports)]
- use $crate::__export::{DoubleSpanToTokens, DoubleSpanSingleSpan, DoubleSpanSingleSpan2};
- let (start, end) = (&$span).FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS();
+ use $crate::__export::{
+ ToTokensAsSpanRange,
+ Span2AsSpanRange,
+ SpanAsSpanRange,
+ SpanRangeAsSpanRange
+ };
+ use $crate::DiagnosticExt;
+ let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange();
- $crate::Diagnostic::double_spanned(
- start,
- end,
+ $crate::Diagnostic::spanned_range(
+ span_range,
$level,
format!($fmt, $($args),*)
)
@@ -54,10 +70,16 @@ macro_rules! diagnostic {
($span:expr, $level:expr, $msg:expr) => {{
#[allow(unused_imports)]
- use $crate::__export::{DoubleSpanToTokens, DoubleSpanSingleSpan, DoubleSpanSingleSpan2};
- let (start, end) = (&$span).FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS();
+ use $crate::__export::{
+ ToTokensAsSpanRange,
+ Span2AsSpanRange,
+ SpanAsSpanRange,
+ SpanRangeAsSpanRange
+ };
+ use $crate::DiagnosticExt;
+ let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange();
- $crate::Diagnostic::double_spanned(start, end, $level, $msg.to_string())
+ $crate::Diagnostic::spanned_range(span_range, $level, $msg.to_string())
}};
@@ -104,7 +126,7 @@ macro_rules! abort {
#[macro_export]
macro_rules! abort_call_site {
($($tts:tt)*) => {
- $crate::abort!($crate::proc_macro2::Span::call_site(), $($tts)*)
+ $crate::abort!($crate::__export::proc_macro2::Span::call_site(), $($tts)*)
};
}
@@ -136,7 +158,7 @@ macro_rules! emit_error {
#[macro_export]
macro_rules! emit_call_site_error {
($($tts:tt)*) => {
- $crate::emit_error!($crate::proc_macro2::Span::call_site(), $($tts)*)
+ $crate::emit_error!($crate::__export::proc_macro2::Span::call_site(), $($tts)*)
};
}
@@ -166,7 +188,7 @@ macro_rules! emit_warning {
#[macro_export]
macro_rules! emit_call_site_warning {
($($tts:tt)*) => {{
- $crate::emit_warning!($crate::proc_macro2::Span()::call_site(), $($tts)*)
+ $crate::emit_warning!($crate::__export::proc_macro2::Span::call_site(), $($tts)*)
}};
}
diff --git a/src/sealed.rs b/src/sealed.rs
new file mode 100644
index 0000000..a2d5081
--- /dev/null
+++ b/src/sealed.rs
@@ -0,0 +1,3 @@
+pub trait Sealed {}
+
+impl Sealed for crate::Diagnostic {}
diff --git a/tests/ui/abort.rs b/tests/ui/abort.rs
index 5b33b57..f631182 100644
--- a/tests/ui/abort.rs
+++ b/tests/ui/abort.rs
@@ -6,5 +6,6 @@ abort_to_string!(one, two);
abort_format!(one, two);
direct_abort!(one, two);
abort_notes!(one, two);
+abort_call_site_test!(one, two);
fn main() {}
diff --git a/tests/ui/abort.stderr b/tests/ui/abort.stderr
index d3e2738..c5399d9 100644
--- a/tests/ui/abort.stderr
+++ b/tests/ui/abort.stderr
@@ -38,3 +38,11 @@ error: This is an error
|
8 | abort_notes!(one, two);
| ^^^
+
+error: abort_call_site! test
+ --> $DIR/abort.rs:9:1
+ |
+9 | abort_call_site_test!(one, two);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/emit.rs b/tests/ui/emit.rs
index 81d4e0b..c5c7db0 100644
--- a/tests/ui/emit.rs
+++ b/tests/ui/emit.rs
@@ -1,7 +1,7 @@
extern crate test_crate;
use test_crate::*;
-emit!(one, two, three, four);
+emit!(one, two, three, four, five);
emit_notes!(one, two);
fn main() {}
diff --git a/tests/ui/emit.stderr b/tests/ui/emit.stderr
index 3c4c3e8..9484bd6 100644
--- a/tests/ui/emit.stderr
+++ b/tests/ui/emit.stderr
@@ -1,27 +1,35 @@
error: emit!(span, from) test
--> $DIR/emit.rs:4:7
|
-4 | emit!(one, two, three, four);
+4 | emit!(one, two, three, four, five);
| ^^^
error: emit!(span, expr1, expr2) test
--> $DIR/emit.rs:4:12
|
-4 | emit!(one, two, three, four);
+4 | emit!(one, two, three, four, five);
| ^^^
error: emit!(span, single_expr) test
--> $DIR/emit.rs:4:17
|
-4 | emit!(one, two, three, four);
+4 | emit!(one, two, three, four, five);
| ^^^^^
error: Diagnostic::emit() test
--> $DIR/emit.rs:4:24
|
-4 | emit!(one, two, three, four);
+4 | emit!(one, two, three, four, five);
| ^^^^
+error: emit_call_site_error!(expr) test
+ --> $DIR/emit.rs:4:1
+ |
+4 | emit!(one, two, three, four, five);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
error: This is an error
= note: simple note
diff --git a/tests/ui/explicit_span_range.rs b/tests/ui/explicit_span_range.rs
new file mode 100644
index 0000000..82bbebc
--- /dev/null
+++ b/tests/ui/explicit_span_range.rs
@@ -0,0 +1,6 @@
+extern crate test_crate;
+use test_crate::*;
+
+explicit_span_range!(one, two, three, four);
+
+fn main() {}
diff --git a/tests/ui/explicit_span_range.stderr b/tests/ui/explicit_span_range.stderr
new file mode 100644
index 0000000..781a71e
--- /dev/null
+++ b/tests/ui/explicit_span_range.stderr
@@ -0,0 +1,5 @@
+error: explicit SpanRange
+ --> $DIR/explicit_span_range.rs:4:22
+ |
+4 | explicit_span_range!(one, two, three, four);
+ | ^^^^^^^^^^^^^^^
diff --git a/tests/ui/misuse.stderr b/tests/ui/misuse.stderr
index 46e281a..8eaf645 100644
--- a/tests/ui/misuse.stderr
+++ b/tests/ui/misuse.stderr
@@ -1,14 +1,13 @@
-error[E0599]: no method named `FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS` found for reference `&Foo` in the current scope
+error[E0599]: no method named `FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange` found for reference `&Foo` in the current scope
--> $DIR/misuse.rs:8:5
|
+4 | struct Foo;
+ | ----------- doesn't satisfy `Foo: quote::to_tokens::ToTokens`
+...
8 | abort!(Foo, "BOOM");
| ^^^^^^^^^^^^^^^^^^^^ method not found in `&Foo`
|
- = note: the method `FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS` exists but the following trait bounds were not satisfied:
- `&Foo : proc_macro_error::__export::DoubleSpanToTokens`
- = help: items from traits can only be used if the trait is implemented and in scope
- = note: the following traits define an item `FIRST_ARG_MUST_EITHER_BE_SPAN_OR_IMPLEMENT_TO_TOKENS`, perhaps you need to implement one of them:
- candidate #1: `proc_macro_error::__export::DoubleSpanToTokens`
- candidate #2: `proc_macro_error::__export::DoubleSpanSingleSpan2`
- candidate #3: `proc_macro_error::__export::DoubleSpanSingleSpan`
- = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+ = note: the method `FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange` exists but the following trait bounds were not satisfied:
+ `Foo: quote::to_tokens::ToTokens`
+ which is required by `&Foo: proc_macro_error::__export::ToTokensAsSpanRange`
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/not_proc_macro.stderr b/tests/ui/not_proc_macro.stderr
index 35c14b8..f19f01b 100644
--- a/tests/ui/not_proc_macro.stderr
+++ b/tests/ui/not_proc_macro.stderr
@@ -1,8 +1,10 @@
-error: #[proc_macro_error] attribute can be used only with a proc-macro
+error: #[proc_macro_error] attribute can be used only with procedural macros
- = hint: if you are really sure that #[proc_macro_error] should be applied to this exact function use #[proc_macro_error(allow_not_macro)]
+ = hint: if you are really sure that #[proc_macro_error] should be applied to this exact function, use #[proc_macro_error(allow_not_macro)]
--> $DIR/not_proc_macro.rs:3:1
|
3 | #[proc_macro_error]
| ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/option_ext.stderr b/tests/ui/option_ext.stderr
index f63abc0..91b151e 100644
--- a/tests/ui/option_ext.stderr
+++ b/tests/ui/option_ext.stderr
@@ -2,4 +2,6 @@ error: Option::expect_or_abort() test
--> $DIR/option_ext.rs:4:1
|
4 | option_ext!(one, two);
- | ^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/proc_macro_hack.stderr b/tests/ui/proc_macro_hack.stderr
index 7f0876b..0e984f9 100644
--- a/tests/ui/proc_macro_hack.stderr
+++ b/tests/ui/proc_macro_hack.stderr
@@ -3,12 +3,16 @@ error: BOOM
|
8 | let nine = add_one!(two) + add_one!(2 + 3);
| ^^^
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: BOOM
--> $DIR/proc_macro_hack.rs:8:41
|
8 | let nine = add_one!(two) + add_one!(2 + 3);
| ^^^^^
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
warning: unreachable expression
--> $DIR/proc_macro_hack.rs:8:32
@@ -19,4 +23,4 @@ warning: unreachable expression
| any code following this expression is unreachable
|
= note: `#[warn(unreachable_code)]` on by default
- = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+ = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)