summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:04:13 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:04:13 +0000
commitc7a97c61c946d1f946a8149253769274d068d4a6 (patch)
tree6b24ddd0d0285a3b0e3ee80782f20a11ca2703dc
parent9dc72f48683fbc16c68a1e531f38daae431e63a1 (diff)
parent0adf6dae3163b2719eb1baee269a652ba0e96698 (diff)
downloadpin-project-internal-android13-mainline-extservices-release.tar.gz
Snap for 8564071 from 0adf6dae3163b2719eb1baee269a652ba0e96698 to mainline-extservices-releaseaml_ext_331814220aml_ext_331412000aml_ext_331312000aml_ext_331112010aml_ext_331012020android13-mainline-extservices-release
Change-Id: I1202bdb7d505566c9cdf32f88408993b525b9087
-rw-r--r--.cargo_vcs_info.json7
-rw-r--r--Android.bp27
-rw-r--r--Cargo.toml13
-rw-r--r--Cargo.toml.orig4
-rw-r--r--METADATA8
-rw-r--r--TEST_MAPPING8
-rw-r--r--cargo2android.json4
-rw-r--r--src/lib.rs16
-rw-r--r--src/pin_project/args.rs56
-rw-r--r--src/pin_project/attribute.rs15
-rw-r--r--src/pin_project/derive.rs230
-rw-r--r--src/pinned_drop.rs46
-rw-r--r--src/utils.rs45
13 files changed, 250 insertions, 229 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 6cfdedc..60d79af 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,6 @@
{
"git": {
- "sha1": "a51d39fcdb31fe78cc61c0053ead2beb65a4156d"
- }
-}
+ "sha1": "0273e6ecd64057f47c3b2ada6fb4e5c37357c185"
+ },
+ "path_in_vcs": "pin-project-internal"
+} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index d84760b..8a0e560 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,4 +1,4 @@
-// This file is generated by cargo2android.py --run --dependencies --tests.
+// This file is generated by cargo2android.py --config cargo2android.json.
// Do not modify this file as changes will be overridden on upgrade.
package {
@@ -42,6 +42,8 @@ license {
rust_proc_macro {
name: "libpin_project_internal",
crate_name: "pin_project_internal",
+ cargo_env_compat: true,
+ cargo_pkg_version: "1.0.10",
srcs: ["src/lib.rs"],
edition: "2018",
rustlibs: [
@@ -50,26 +52,3 @@ rust_proc_macro {
"libsyn",
],
}
-
-rust_test_host {
- name: "pin-project-internal_host_test_src_lib",
- crate_name: "pin_project_internal",
- srcs: ["src/lib.rs"],
- test_suites: ["general-tests"],
- auto_gen_config: true,
- test_options: {
- unit_test: true,
- },
- edition: "2018",
- rustlibs: [
- "libproc_macro2",
- "libquote",
- "libsyn",
- ],
-}
-
-// dependent_library ["feature_list"]
-// proc-macro2-1.0.26 "default,proc-macro"
-// quote-1.0.9 "default,proc-macro"
-// syn-1.0.68 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
-// unicode-xid-0.2.1 "default"
diff --git a/Cargo.toml b/Cargo.toml
index 83d10cd..1d5cfef 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,20 +3,17 @@
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
#
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "pin-project-internal"
-version = "1.0.6"
-authors = ["Taiki Endo <te316e89@gmail.com>"]
+version = "1.0.10"
description = "Implementation detail of the `pin-project` crate.\n"
-documentation = "https://docs.rs/pin-project-internal"
keywords = ["pin", "macros", "attribute"]
categories = ["no-std", "rust-patterns"]
license = "Apache-2.0 OR MIT"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 707c32b..78c2f44 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,11 +1,9 @@
[package]
name = "pin-project-internal"
-version = "1.0.6"
-authors = ["Taiki Endo <te316e89@gmail.com>"]
+version = "1.0.10"
edition = "2018"
license = "Apache-2.0 OR MIT"
repository = "https://github.com/taiki-e/pin-project"
-documentation = "https://docs.rs/pin-project-internal"
keywords = ["pin", "macros", "attribute"]
categories = ["no-std", "rust-patterns"]
description = """
diff --git a/METADATA b/METADATA
index 381f041..caa1eef 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/pin-project-internal/pin-project-internal-1.0.6.crate"
+ value: "https://static.crates.io/crates/pin-project-internal/pin-project-internal-1.0.10.crate"
}
- version: "1.0.6"
+ version: "1.0.10"
license_type: NOTICE
last_upgrade_date {
- year: 2021
- month: 4
+ year: 2022
+ month: 3
day: 1
}
}
diff --git a/TEST_MAPPING b/TEST_MAPPING
deleted file mode 100644
index 7e10dd0..0000000
--- a/TEST_MAPPING
+++ /dev/null
@@ -1,8 +0,0 @@
-// Generated by update_crate_tests.py for tests that depend on this crate.
-{
- "presubmit": [
- {
- "name": "futures-util_device_test_src_lib"
- }
- ]
-}
diff --git a/cargo2android.json b/cargo2android.json
new file mode 100644
index 0000000..341300b
--- /dev/null
+++ b/cargo2android.json
@@ -0,0 +1,4 @@
+{
+ "run": true,
+ "tests": true
+} \ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 3e908b6..04c4ce2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,8 +8,8 @@
)
))]
#![warn(unsafe_code)]
-#![warn(future_incompatible, rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
-#![warn(clippy::all, clippy::default_trait_access)]
+#![warn(rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
+#![warn(clippy::default_trait_access, clippy::wildcard_imports)]
#![allow(clippy::needless_doctest_main)]
// older compilers require explicit `extern crate`.
@@ -29,9 +29,9 @@ use proc_macro::TokenStream;
///
/// This attribute creates projection types according to the following rules:
///
-/// * For the fields that use `#[pin]` attribute, create the pinned reference to
+/// - For the fields that use `#[pin]` attribute, create the pinned reference to
/// the field.
-/// * For the other fields, create a normal reference to the field.
+/// - For the other fields, create a normal reference to the field.
///
/// And the following methods are implemented on the original type:
///
@@ -351,8 +351,8 @@ use proc_macro::TokenStream;
/// This impl block acts just like a normal [`Drop`] impl,
/// except for the following two:
///
-/// * `drop` method takes [`Pin`]`<&mut Self>`
-/// * Name of the trait is `PinnedDrop`.
+/// - `drop` method takes [`Pin`]`<&mut Self>`
+/// - Name of the trait is `PinnedDrop`.
///
/// ```rust
/// # use std::pin::Pin;
@@ -495,8 +495,8 @@ pub fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream {
/// The impl block annotated with this attribute acts just like a normal
/// [`Drop`] impl, except for the following two:
///
-/// * `drop` method takes [`Pin`]`<&mut Self>`
-/// * Name of the trait is `PinnedDrop`.
+/// - `drop` method takes [`Pin`]`<&mut Self>`
+/// - Name of the trait is `PinnedDrop`.
///
/// ```rust
/// # use std::pin::Pin;
diff --git a/src/pin_project/args.rs b/src/pin_project/args.rs
index c321260..d0d4f36 100644
--- a/src/pin_project/args.rs
+++ b/src/pin_project/args.rs
@@ -28,7 +28,7 @@ pub(super) fn parse_args(attrs: &[Attribute]) -> Result<Args> {
}
if let Some(attr) = attrs.find("pin_project") {
- return Err(error!(attr, "duplicate #[pin_project] attribute"));
+ bail!(attr, "duplicate #[pin_project] attribute");
}
let mut attrs = attrs.iter().filter(|attr| attr.path.is_ident(PIN));
@@ -37,7 +37,7 @@ pub(super) fn parse_args(attrs: &[Attribute]) -> Result<Args> {
(attr, syn::parse2::<Input>(attr.tokens.clone()).unwrap().0)
} else {
// This only fails if another macro removes `#[pin]`.
- return Err(error!(TokenStream::new(), "#[pin_project] attribute has been removed"));
+ bail!(TokenStream::new(), "#[pin_project] attribute has been removed");
};
if let Some(attr) = attrs.next() {
@@ -51,11 +51,10 @@ pub(super) fn parse_args(attrs: &[Attribute]) -> Result<Args> {
(Some(_), _) => attr,
(None, _) => prev_attr,
};
- Err(error!(span, "duplicate #[pin] attribute"))
- } else {
- // This `unwrap` only fails if another macro removes `#[pin]` and inserts own `#[pin]`.
- syn::parse2(prev.1.unwrap())
+ bail!(span, "duplicate #[pin] attribute");
}
+ // This `unwrap` only fails if another macro removes `#[pin]` and inserts own `#[pin]`.
+ syn::parse2(prev.1.unwrap())
}
pub(super) struct Args {
@@ -84,20 +83,19 @@ impl Parse for Args {
has_prev: bool,
) -> Result<(Ident, TokenStream)> {
if input.is_empty() {
- return Err(error!(name, "expected `{0} = <identifier>`, found `{0}`", name));
+ bail!(name, "expected `{0} = <identifier>`, found `{0}`", name);
}
let eq_token: Token![=] = input.parse()?;
if input.is_empty() {
let span = quote!(#name #eq_token);
- return Err(error!(span, "expected `{0} = <identifier>`, found `{0} =`", name));
+ bail!(span, "expected `{0} = <identifier>`, found `{0} =`", name);
}
let value: Ident = input.parse()?;
let span = quote!(#name #value);
if has_prev {
- Err(error!(span, "duplicate `{}` argument", name))
- } else {
- Ok((value, span))
+ bail!(span, "duplicate `{}` argument", name);
}
+ Ok((value, span))
}
let mut pinned_drop = None;
@@ -112,24 +110,24 @@ impl Parse for Args {
if input.peek(Token![!]) {
let bang: Token![!] = input.parse()?;
if input.is_empty() {
- return Err(error!(bang, "expected `!Unpin`, found `!`"));
+ bail!(bang, "expected `!Unpin`, found `!`");
}
let unpin: kw::Unpin = input.parse()?;
let span = quote!(#bang #unpin);
if not_unpin.replace(span.span()).is_some() {
- return Err(error!(span, "duplicate `!Unpin` argument"));
+ bail!(span, "duplicate `!Unpin` argument");
}
} else {
let token = input.parse::<Ident>()?;
match &*token.to_string() {
"PinnedDrop" => {
if pinned_drop.replace(token.span()).is_some() {
- return Err(error!(token, "duplicate `PinnedDrop` argument"));
+ bail!(token, "duplicate `PinnedDrop` argument");
}
}
"UnsafeUnpin" => {
if unsafe_unpin.replace(token.span()).is_some() {
- return Err(error!(token, "duplicate `UnsafeUnpin` argument"));
+ bail!(token, "duplicate `UnsafeUnpin` argument");
}
}
"project" => {
@@ -145,18 +143,18 @@ impl Parse for Args {
project_replace_value = Some(value);
project_replace_span = Some(span.span());
} else if project_replace_span.is_some() {
- return Err(error!(token, "duplicate `project_replace` argument"));
+ bail!(token, "duplicate `project_replace` argument");
} else {
project_replace_span = Some(token.span());
}
}
"Replace" => {
- return Err(error!(
+ bail!(
token,
"`Replace` argument was removed, use `project_replace` argument instead"
- ));
+ );
}
- _ => return Err(error!(token, "unexpected argument: {}", token)),
+ _ => bail!(token, "unexpected argument: {}", token),
}
}
@@ -168,23 +166,17 @@ impl Parse for Args {
if project.is_some() || project_ref.is_some() {
if project == project_ref {
- return Err(error!(
+ bail!(
project_ref,
"name `{}` is already specified by `project` argument",
project_ref.as_ref().unwrap()
- ));
+ );
}
if let Some(ident) = &project_replace_value {
if project == project_replace_value {
- return Err(error!(
- ident,
- "name `{}` is already specified by `project` argument", ident
- ));
+ bail!(ident, "name `{}` is already specified by `project` argument", ident);
} else if project_ref == project_replace_value {
- return Err(error!(
- ident,
- "name `{}` is already specified by `project_ref` argument", ident
- ));
+ bail!(ident, "name `{}` is already specified by `project_ref` argument", ident);
}
}
}
@@ -253,6 +245,10 @@ impl ProjReplace {
}
pub(super) fn ident(&self) -> Option<&Ident> {
- if let Self::Named { ident, .. } = self { Some(ident) } else { None }
+ if let Self::Named { ident, .. } = self {
+ Some(ident)
+ } else {
+ None
+ }
}
}
diff --git a/src/pin_project/attribute.rs b/src/pin_project/attribute.rs
index 92ed547..c8811cb 100644
--- a/src/pin_project/attribute.rs
+++ b/src/pin_project/attribute.rs
@@ -17,9 +17,9 @@ use crate::utils::SliceExt;
//
// At this stage, only attributes are parsed and the following attributes are
// added to the attributes of the item.
-// * `#[derive(InternalDerive)]` - An internal helper macro that does the above
+// - `#[derive(InternalDerive)]` - An internal helper macro that does the above
// processing.
-// * `#[pin(__private(#args))]` - Pass the argument of `#[pin_project]` to
+// - `#[pin(__private(#args))]` - Pass the argument of `#[pin_project]` to
// proc-macro-derive (`InternalDerive`).
pub(super) fn parse_attribute(args: &TokenStream, input: TokenStream) -> Result<TokenStream> {
@@ -51,16 +51,15 @@ impl Parse for Input {
if !ahead.peek(Token![struct]) && !ahead.peek(Token![enum]) {
// If we check this only on proc-macro-derive, it may generate unhelpful error
// messages. So it is preferable to be able to detect it here.
- Err(error!(
+ bail!(
input.parse::<TokenStream>()?,
"#[pin_project] attribute may only be used on structs or enums"
- ))
+ );
} else if let Some(attr) = attrs.find(PIN) {
- Err(error!(attr, "#[pin] attribute may only be used on fields of structs or variants"))
+ bail!(attr, "#[pin] attribute may only be used on fields of structs or variants");
} else if let Some(attr) = attrs.find("pin_project") {
- Err(error!(attr, "duplicate #[pin_project] attribute"))
- } else {
- Ok(Self { attrs, body: input.parse()? })
+ bail!(attr, "duplicate #[pin_project] attribute");
}
+ Ok(Self { attrs, body: input.parse()? })
}
}
diff --git a/src/pin_project/derive.rs b/src/pin_project/derive.rs
index 82539ca..3e578f7 100644
--- a/src/pin_project/derive.rs
+++ b/src/pin_project/derive.rs
@@ -3,7 +3,7 @@ use quote::{format_ident, quote, quote_spanned, ToTokens};
use syn::{
parse_quote, token, visit_mut::VisitMut, Attribute, Data, DataEnum, DeriveInput, Error, Field,
Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Index, Lifetime, LifetimeDef, Meta,
- MetaList, NestedMeta, Result, Token, Type, Variant, Visibility, WhereClause,
+ MetaList, MetaNameValue, NestedMeta, Result, Token, Type, Variant, Visibility, WhereClause,
};
use super::{
@@ -38,10 +38,7 @@ pub(super) fn parse_derive(input: TokenStream) -> Result<TokenStream> {
parse_enum(&mut cx, data, &mut generate)?;
}
Data::Union(_) => {
- return Err(error!(
- input,
- "#[pin_project] attribute may only be used on structs or enums"
- ));
+ bail!(input, "#[pin_project] attribute may only be used on structs or enums");
}
}
@@ -83,13 +80,17 @@ impl GenerateTokens {
// but it is now removed.
//
// Refs:
- // * https://github.com/rust-lang/rust/issues/63281
- // * https://github.com/taiki-e/pin-project/pull/53#issuecomment-525906867
- // * https://github.com/taiki-e/pin-project/pull/70
+ // - https://github.com/rust-lang/rust/issues/63281
+ // - https://github.com/taiki-e/pin-project/pull/53#issuecomment-525906867
+ // - https://github.com/taiki-e/pin-project/pull/70
#allowed_lints
+ #[allow(unused_qualifications)]
#[allow(clippy::semicolon_if_nothing_returned)]
+ #[allow(clippy::use_self)]
#[allow(clippy::used_underscore_binding)]
const _: () = {
+ #[allow(unused_extern_crates)]
+ extern crate pin_project as _pin_project;
#scoped
#unpin_impl
#drop_impl
@@ -112,12 +113,13 @@ fn global_allowed_lints() -> TokenStream {
#[allow(clippy::unknown_clippy_lints)]
#[allow(clippy::pattern_type_mismatch)]
#[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct.
+ #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326
}
}
/// Returns attributes used on projected types.
-fn proj_allowed_lints(kind: TypeKind) -> (TokenStream, TokenStream, TokenStream) {
- let large_enum_variant = if kind == Enum {
+fn proj_allowed_lints(cx: &Context<'_>) -> (TokenStream, TokenStream, TokenStream) {
+ let large_enum_variant = if cx.kind == Enum {
Some(quote! {
#[allow(variant_size_differences)]
#[allow(clippy::large_enum_variant)]
@@ -126,20 +128,22 @@ fn proj_allowed_lints(kind: TypeKind) -> (TokenStream, TokenStream, TokenStream)
None
};
let global_allowed_lints = global_allowed_lints();
+ let proj_mut_allowed_lints = if cx.project { Some(&global_allowed_lints) } else { None };
let proj_mut = quote! {
- #global_allowed_lints
+ #proj_mut_allowed_lints
#[allow(dead_code)] // This lint warns unused fields/variants.
#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
- #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326}
};
+ let proj_ref_allowed_lints = if cx.project_ref { Some(&global_allowed_lints) } else { None };
let proj_ref = quote! {
- #global_allowed_lints
+ #proj_ref_allowed_lints
#[allow(dead_code)] // This lint warns unused fields/variants.
#[allow(clippy::ref_option_ref)] // This lint warns `&Option<&<ty>>`.
- #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326
};
+ let proj_own_allowed_lints =
+ if cx.project_replace.ident().is_some() { Some(&global_allowed_lints) } else { None };
let proj_own = quote! {
- #global_allowed_lints
+ #proj_own_allowed_lints
#[allow(dead_code)] // This lint warns unused fields/variants.
#large_enum_variant
};
@@ -152,7 +156,7 @@ struct Context<'a> {
/// The projected types.
proj: ProjectedType,
/// Types of the pinned fields.
- pinned_fields: Vec<Type>,
+ pinned_fields: Vec<&'a Type>,
/// Kind of the original type: struct or enum
kind: TypeKind,
@@ -184,7 +188,7 @@ impl<'a> Context<'a> {
.filter_map(Option::as_ref)
.find(|name| **name == ident)
{
- return Err(error!(name, "name `{}` is the same as the original type name", name));
+ bail!(name, "name `{}` is the same as the original type name", name);
}
let mut lifetime_name = String::from("'pin");
@@ -289,10 +293,12 @@ struct ProjectedFields {
fn validate_struct(ident: &Ident, fields: &Fields) -> Result<()> {
if fields.is_empty() {
let msg = "#[pin_project] attribute may not be used on structs with zero fields";
- if let Fields::Unit = fields { Err(error!(ident, msg)) } else { Err(error!(fields, msg)) }
- } else {
- Ok(())
+ if let Fields::Unit = fields {
+ bail!(ident, msg)
+ }
+ bail!(fields, msg)
}
+ Ok(())
}
fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> {
@@ -304,9 +310,9 @@ fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> {
}
let has_field = variants.iter().try_fold(false, |has_field, v| {
if let Some((_, e)) = &v.discriminant {
- Err(error!(e, "#[pin_project] attribute may not be used on enums with discriminants"))
+ bail!(e, "#[pin_project] attribute may not be used on enums with discriminants");
} else if let Some(attr) = v.attrs.find(PIN) {
- Err(error!(attr, "#[pin] attribute may only be used on fields of structs or variants"))
+ bail!(attr, "#[pin] attribute may only be used on fields of structs or variants");
} else if v.fields.is_empty() {
Ok(has_field)
} else {
@@ -316,17 +322,17 @@ fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> {
if has_field {
Ok(())
} else {
- Err(error!(variants, "#[pin_project] attribute may not be used on enums with zero fields"))
+ bail!(variants, "#[pin_project] attribute may not be used on enums with zero fields");
}
}
-fn parse_struct(
- cx: &mut Context<'_>,
- fields: &Fields,
+fn parse_struct<'a>(
+ cx: &mut Context<'a>,
+ fields: &'a Fields,
generate: &mut GenerateTokens,
) -> Result<()> {
// Do this first for a better error message.
- let packed_check = ensure_not_packed(&cx.orig, fields)?;
+ let packed_check = ensure_not_packed(&cx.orig, Some(fields))?;
validate_struct(cx.orig.ident, fields)?;
@@ -368,7 +374,7 @@ fn parse_struct(
Fields::Unit => unreachable!(),
};
- let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx.kind);
+ let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx);
generate.extend(cx.project, quote! {
#proj_attrs
#vis struct #proj_ident #proj_generics #where_clause_fields
@@ -402,9 +408,9 @@ fn parse_struct(
Ok(())
}
-fn parse_enum(
- cx: &mut Context<'_>,
- DataEnum { brace_token, variants, .. }: &DataEnum,
+fn parse_enum<'a>(
+ cx: &mut Context<'a>,
+ DataEnum { brace_token, variants, .. }: &'a DataEnum,
generate: &mut GenerateTokens,
) -> Result<()> {
if let ProjReplace::Unnamed { span } = &cx.project_replace {
@@ -414,8 +420,12 @@ fn parse_enum(
));
}
- // We don't need to check for `#[repr(packed)]`,
- // since it does not apply to enums.
+ // #[repr(packed)] cannot be apply on enums and will be rejected by rustc.
+ // However, we should not rely on the behavior of rustc that rejects this.
+ // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
+ //
+ // Do this first for a better error message.
+ ensure_not_packed(&cx.orig, None)?;
validate_enum(*brace_token, variants)?;
@@ -437,7 +447,7 @@ fn parse_enum(
let proj_generics = &cx.proj.generics;
let proj_where_clause = &cx.proj.where_clause;
- let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx.kind);
+ let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx);
if cx.project {
generate.extend(true, quote! {
#proj_attrs
@@ -483,7 +493,7 @@ fn parse_enum(
Ok(())
}
-fn visit_variants(cx: &mut Context<'_>, variants: &Variants) -> Result<ProjectedVariants> {
+fn visit_variants<'a>(cx: &mut Context<'a>, variants: &'a Variants) -> Result<ProjectedVariants> {
let mut proj_variants = TokenStream::new();
let mut proj_ref_variants = TokenStream::new();
let mut proj_own_variants = TokenStream::new();
@@ -540,10 +550,10 @@ fn visit_variants(cx: &mut Context<'_>, variants: &Variants) -> Result<Projected
})
}
-fn visit_fields(
- cx: &mut Context<'_>,
+fn visit_fields<'a>(
+ cx: &mut Context<'a>,
variant_ident: Option<&Ident>,
- fields: &Fields,
+ fields: &'a Fields,
delim: Delimiter,
) -> Result<ProjectedFields> {
fn surround(delim: Delimiter, tokens: TokenStream) -> TokenStream {
@@ -561,8 +571,8 @@ fn visit_fields(
for (i, Field { attrs, vis, ident, colon_token, ty }) in fields.iter().enumerate() {
let binding = ident.clone().unwrap_or_else(|| format_ident!("_{}", i));
proj_pat.extend(quote!(#binding,));
+ let lifetime = &cx.proj.lifetime;
if attrs.position_exact(PIN)?.is_some() {
- let lifetime = &cx.proj.lifetime;
proj_fields.extend(quote! {
#vis #ident #colon_token ::pin_project::__private::Pin<&#lifetime mut (#ty)>,
});
@@ -573,16 +583,15 @@ fn visit_fields(
#vis #ident #colon_token ::pin_project::__private::PhantomData<#ty>,
});
proj_body.extend(quote! {
- #ident #colon_token ::pin_project::__private::Pin::new_unchecked(#binding),
+ #ident #colon_token _pin_project::__private::Pin::new_unchecked(#binding),
});
proj_move.extend(quote! {
- #ident #colon_token ::pin_project::__private::PhantomData,
+ #ident #colon_token _pin_project::__private::PhantomData,
});
- cx.pinned_fields.push(ty.clone());
+ cx.pinned_fields.push(ty);
pinned_bindings.push(binding);
} else {
- let lifetime = &cx.proj.lifetime;
proj_fields.extend(quote! {
#vis #ident #colon_token &#lifetime mut (#ty),
});
@@ -596,7 +605,7 @@ fn visit_fields(
#binding,
});
proj_move.extend(quote! {
- #ident #colon_token ::pin_project::__private::ptr::read(#binding),
+ #ident #colon_token _pin_project::__private::ptr::read(#binding),
});
}
}
@@ -608,7 +617,7 @@ fn visit_fields(
let proj_own_fields = surround(delim, proj_own_fields);
let proj_move = Group::new(delim, proj_move);
- let proj_own_body = proj_own_body(cx, variant_ident, Some(proj_move), &pinned_bindings);
+ let proj_own_body = proj_own_body(cx, variant_ident, Some(&proj_move), &pinned_bindings);
Ok(ProjectedFields {
proj_pat,
@@ -626,7 +635,7 @@ fn visit_fields(
fn proj_own_body(
cx: &Context<'_>,
variant_ident: Option<&Ident>,
- proj_move: Option<Group>,
+ proj_move: Option<&Group>,
pinned_fields: &[Ident],
) -> TokenStream {
let ident = &cx.proj.own_ident;
@@ -651,7 +660,7 @@ fn proj_own_body(
// if any of the destructors panic.
{
#(
- let __guard = ::pin_project::__private::UnsafeDropInPlaceGuard(#pinned_fields);
+ let __guard = _pin_project::__private::UnsafeDropInPlaceGuard::new(#pinned_fields);
)*
}
@@ -663,9 +672,9 @@ fn proj_own_body(
/// Creates `Unpin` implementation for the original type.
///
/// The kind of `Unpin` impl generated depends on `unpin_impl` field:
-/// * `UnpinImpl::Unsafe` - Implements `Unpin` via `UnsafeUnpin` impl.
-/// * `UnpinImpl::Negative` - Generates `Unpin` impl with bounds that will never be true.
-/// * `UnpinImpl::Default` - Generates `Unpin` impl that requires `Unpin` for all pinned fields.
+/// - `UnpinImpl::Unsafe` - Implements `Unpin` via `UnsafeUnpin` impl.
+/// - `UnpinImpl::Negative` - Generates `Unpin` impl with bounds that will never be true.
+/// - `UnpinImpl::Default` - Generates `Unpin` impl that requires `Unpin` for all pinned fields.
fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
match cx.unpin_impl {
UnpinImpl::Unsafe(span) => {
@@ -675,14 +684,14 @@ fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
// Make the error message highlight `UnsafeUnpin` argument.
proj_generics.make_where_clause().predicates.push(parse_quote_spanned! { span =>
- ::pin_project::__private::Wrapper<#lifetime, Self>: ::pin_project::UnsafeUnpin
+ _pin_project::__private::Wrapper<#lifetime, Self>: _pin_project::UnsafeUnpin
});
let (impl_generics, _, where_clause) = proj_generics.split_for_impl();
let ty_generics = cx.orig.generics.split_for_impl().1;
quote_spanned! { span =>
- impl #impl_generics ::pin_project::__private::Unpin for #orig_ident #ty_generics
+ impl #impl_generics _pin_project::__private::Unpin for #orig_ident #ty_generics
#where_clause
{
}
@@ -694,9 +703,9 @@ fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
let lifetime = &cx.proj.lifetime;
proj_generics.make_where_clause().predicates.push(parse_quote! {
- ::pin_project::__private::Wrapper<
- #lifetime, ::pin_project::__private::PhantomPinned
- >: ::pin_project::__private::Unpin
+ _pin_project::__private::Wrapper<
+ #lifetime, _pin_project::__private::PhantomPinned
+ >: _pin_project::__private::Unpin
});
let (proj_impl_generics, _, proj_where_clause) = proj_generics.split_for_impl();
@@ -706,7 +715,7 @@ fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
// call-site span.
let unsafety = <Token![unsafe]>::default();
quote_spanned! { span =>
- impl #proj_impl_generics ::pin_project::__private::Unpin
+ impl #proj_impl_generics _pin_project::__private::Unpin
for #orig_ident #ty_generics
#proj_where_clause
{
@@ -719,7 +728,7 @@ fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
// impl, they'll get a "conflicting implementations of trait" error when
// coherence checks are run.
#[doc(hidden)]
- #unsafety impl #proj_impl_generics ::pin_project::UnsafeUnpin
+ #unsafety impl #proj_impl_generics _pin_project::UnsafeUnpin
for #orig_ident #ty_generics
#proj_where_clause
{
@@ -774,7 +783,7 @@ fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
let (_, ty_generics, where_clause) = cx.orig.generics.split_for_impl();
full_where_clause.predicates.push(parse_quote! {
- #struct_ident #proj_ty_generics: ::pin_project::__private::Unpin
+ #struct_ident #proj_ty_generics: _pin_project::__private::Unpin
});
quote! {
@@ -790,15 +799,15 @@ fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
// this 'public' type by creating this type in the inside of `const`.
#[allow(missing_debug_implementations)]
#vis struct #struct_ident #proj_generics #where_clause {
- __pin_project_use_generics: ::pin_project::__private::AlwaysUnpin<
- #lifetime, (#(::pin_project::__private::PhantomData<#type_params>),*)
+ __pin_project_use_generics: _pin_project::__private::AlwaysUnpin<
+ #lifetime, (#(_pin_project::__private::PhantomData<#type_params>),*)
>,
#(#fields,)*
#(#lifetime_fields,)*
}
- impl #proj_impl_generics ::pin_project::__private::Unpin
+ impl #proj_impl_generics _pin_project::__private::Unpin
for #orig_ident #ty_generics
#full_where_clause
{
@@ -811,7 +820,7 @@ fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
// impl, they'll get a "conflicting implementations of trait" error when
// coherence checks are run.
#[doc(hidden)]
- unsafe impl #proj_impl_generics ::pin_project::UnsafeUnpin
+ unsafe impl #proj_impl_generics _pin_project::UnsafeUnpin
for #orig_ident #ty_generics
#full_where_clause
{
@@ -824,8 +833,8 @@ fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
/// Creates `Drop` implementation for the original type.
///
/// The kind of `Drop` impl generated depends on `pinned_drop` field:
-/// * `Some` - implements `Drop` via `PinnedDrop` impl.
-/// * `None` - generates code that ensures that `Drop` trait is not implemented,
+/// - `Some` - implements `Drop` via `PinnedDrop` impl.
+/// - `None` - generates code that ensures that `Drop` trait is not implemented,
/// instead of generating `Drop` impl.
fn make_drop_impl(cx: &Context<'_>) -> TokenStream {
let ident = cx.orig.ident;
@@ -836,18 +845,18 @@ fn make_drop_impl(cx: &Context<'_>) -> TokenStream {
// call-site span.
let unsafety = <Token![unsafe]>::default();
quote_spanned! { span =>
- impl #impl_generics ::pin_project::__private::Drop for #ident #ty_generics
+ impl #impl_generics _pin_project::__private::Drop for #ident #ty_generics
#where_clause
{
fn drop(&mut self) {
#unsafety {
// Safety - we're in 'drop', so we know that 'self' will
// never move again.
- let __pinned_self = ::pin_project::__private::Pin::new_unchecked(self);
+ let __pinned_self = _pin_project::__private::Pin::new_unchecked(self);
// We call `pinned_drop` only once. Since `PinnedDrop::drop`
// is an unsafe method and a private API, it is never called again in safe
// code *unless the user uses a maliciously crafted macro*.
- ::pin_project::__private::PinnedDrop::drop(__pinned_self);
+ _pin_project::__private::PinnedDrop::drop(__pinned_self);
}
}
}
@@ -879,24 +888,24 @@ fn make_drop_impl(cx: &Context<'_>) -> TokenStream {
// This will result in a compilation error, which is exactly what we want.
trait #trait_ident {}
#[allow(clippy::drop_bounds, drop_bounds)]
- impl<T: ::pin_project::__private::Drop> #trait_ident for T {}
+ impl<T: _pin_project::__private::Drop> #trait_ident for T {}
impl #impl_generics #trait_ident for #ident #ty_generics #where_clause {}
// Generate a dummy impl of `PinnedDrop`, to ensure that the user cannot implement it.
// Since the user did not pass `PinnedDrop` to `#[pin_project]`, any `PinnedDrop`
// impl will not actually be called. Unfortunately, we can't detect this situation
// directly from either the `#[pin_project]` or `#[pinned_drop]` attributes, since
- // we don't know what other attirbutes/impl may exist.
+ // we don't know what other attributes/impl may exist.
//
// To ensure that users don't accidentally write a non-functional `PinnedDrop`
// impls, we emit one ourselves. If the user ends up writing a `PinnedDrop` impl,
// they'll get a "conflicting implementations of trait" error when coherence
// checks are run.
#[doc(hidden)]
- impl #impl_generics ::pin_project::__private::PinnedDrop for #ident #ty_generics
+ impl #impl_generics _pin_project::__private::PinnedDrop for #ident #ty_generics
#where_clause
{
- unsafe fn drop(self: ::pin_project::__private::Pin<&mut Self>) {}
+ unsafe fn drop(self: _pin_project::__private::Pin<&mut Self>) {}
}
}
}
@@ -927,7 +936,7 @@ fn make_proj_impl(
let mut project = Some(quote! {
#vis fn project<#lifetime>(
- self: ::pin_project::__private::Pin<&#lifetime mut Self>,
+ self: _pin_project::__private::Pin<&#lifetime mut Self>,
) -> #proj_ident #proj_ty_generics {
unsafe {
#proj_body
@@ -937,7 +946,7 @@ fn make_proj_impl(
let mut project_ref = Some(quote! {
#[allow(clippy::missing_const_for_fn)]
#vis fn project_ref<#lifetime>(
- self: ::pin_project::__private::Pin<&#lifetime Self>,
+ self: _pin_project::__private::Pin<&#lifetime Self>,
) -> #proj_ref_ident #proj_ty_generics {
unsafe {
#proj_ref_body
@@ -948,7 +957,7 @@ fn make_proj_impl(
// It is enough to only set the span of the signature.
let sig = quote_spanned! { span =>
#vis fn project_replace(
- self: ::pin_project::__private::Pin<&mut Self>,
+ self: _pin_project::__private::Pin<&mut Self>,
__replacement: Self,
) -> #proj_own_ident #orig_ty_generics
};
@@ -959,10 +968,10 @@ fn make_proj_impl(
// Destructors will run in reverse order, so next create a guard to overwrite
// `self` with the replacement value without calling destructors.
- let __guard = ::pin_project::__private::UnsafeOverwriteGuard {
- target: __self_ptr,
- value: ::pin_project::__private::ManuallyDrop::new(__replacement),
- };
+ let __guard = _pin_project::__private::UnsafeOverwriteGuard::new(
+ __self_ptr,
+ __replacement,
+ );
#proj_own_body
}
@@ -994,10 +1003,10 @@ fn make_proj_impl(
/// Checks that the `[repr(packed)]` attribute is not included.
///
/// This currently does two checks:
-/// * Checks the attributes of structs to ensure there is no `[repr(packed)]`.
-/// * Generates a function that borrows fields without an unsafe block and
-/// forbidding `safe_packed_borrows` lint.
-fn ensure_not_packed(orig: &OriginalType<'_>, fields: &Fields) -> Result<TokenStream> {
+/// - Checks the attributes of structs to ensure there is no `[repr(packed)]`.
+/// - Generates a function that borrows fields without an unsafe block and
+/// forbidding `unaligned_references` lint.
+fn ensure_not_packed(orig: &OriginalType<'_>, fields: Option<&Fields>) -> Result<TokenStream> {
for meta in orig.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) {
if let Meta::List(list) = meta {
if list.path.is_ident("repr") {
@@ -1005,22 +1014,36 @@ fn ensure_not_packed(orig: &OriginalType<'_>, fields: &Fields) -> Result<TokenSt
match repr {
NestedMeta::Meta(Meta::Path(path))
| NestedMeta::Meta(Meta::List(MetaList { path, .. }))
- if path.is_ident("packed") =>
- {
- return Err(error!(
- repr,
- "#[pin_project] attribute may not be used on #[repr(packed)] types"
- ));
+ | NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, .. })) => {
+ if path.is_ident("packed") {
+ let msg = if fields.is_none() {
+ // #[repr(packed)] cannot be apply on enums and will be rejected by rustc.
+ // However, we should not rely on the behavior of rustc that rejects this.
+ // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
+ "#[repr(packed)] attribute should be applied to a struct or union"
+ } else if let NestedMeta::Meta(Meta::NameValue(..)) = repr {
+ // #[repr(packed = "")] is not valid format of #[repr(packed)] and will be
+ // rejected by rustc.
+ // However, we should not rely on the behavior of rustc that rejects this.
+ // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
+ "#[repr(packed)] attribute should not be name-value pair"
+ } else {
+ "#[pin_project] attribute may not be used on #[repr(packed)] types"
+ };
+ bail!(repr, msg);
+ }
}
- _ => {}
+ NestedMeta::Lit(..) => {}
}
}
}
}
}
- // As proc-macro-derive can't rewrite the structure definition,
- // it's probably no longer necessary, but it keeps it for now.
+ let fields = match fields {
+ Some(fields) => fields,
+ None => return Ok(TokenStream::new()),
+ };
// Workaround for https://github.com/taiki-e/pin-project/issues/32
// Through the tricky use of proc macros, it's possible to bypass
@@ -1029,7 +1052,7 @@ fn ensure_not_packed(orig: &OriginalType<'_>, fields: &Fields) -> Result<TokenSt
// struct, we generate code like this:
//
// ```rust
- // #[forbid(safe_packed_borrows)]
+ // #[forbid(unaligned_references)]
// fn assert_not_repr_packed(val: &MyStruct) {
// let _field1 = &val.field1;
// let _field2 = &val.field2;
@@ -1038,10 +1061,8 @@ fn ensure_not_packed(orig: &OriginalType<'_>, fields: &Fields) -> Result<TokenSt
// }
// ```
//
- // Taking a reference to a packed field is unsafe, and applying
- // `#[forbid(safe_packed_borrows)]` makes sure that doing this without
- // an `unsafe` block (which we deliberately do not generate)
- // is a hard error.
+ // Taking a reference to a packed field is UB, and applying
+ // `#[forbid(unaligned_references)]` makes sure that doing this is a hard error.
//
// If the struct ends up having `#[repr(packed)]` applied somehow,
// this will generate an (unfriendly) error message. Under all reasonable
@@ -1061,6 +1082,21 @@ fn ensure_not_packed(orig: &OriginalType<'_>, fields: &Fields) -> Result<TokenSt
// `#[repr(packed)]` in the first place.
//
// See also https://github.com/taiki-e/pin-project/pull/34.
+ //
+ // Note:
+ // - pin-project v0.4.3 or later (#135, v0.4.0-v0.4.2 are already yanked for
+ // another reason) is internally proc-macro-derive, so they are not
+ // affected by the problem that the struct definition is rewritten by
+ // another macro after the #[pin_project] is expanded.
+ // So this is probably no longer necessary, but it keeps it for now.
+ //
+ // - Lint-based tricks aren't perfect, but they're much better than nothing:
+ // https://github.com/taiki-e/pin-project-lite/issues/26
+ //
+ // - Enable both unaligned_references and safe_packed_borrows lints
+ // because unaligned_references lint does not exist in older compilers:
+ // https://github.com/taiki-e/pin-project-lite/pull/55
+ // https://github.com/rust-lang/rust/pull/82525
let mut field_refs = vec![];
match fields {
Fields::Named(FieldsNamed { named, .. }) => {
@@ -1080,7 +1116,7 @@ fn ensure_not_packed(orig: &OriginalType<'_>, fields: &Fields) -> Result<TokenSt
let (impl_generics, ty_generics, where_clause) = orig.generics.split_for_impl();
let ident = orig.ident;
Ok(quote! {
- #[forbid(safe_packed_borrows)]
+ #[forbid(unaligned_references, safe_packed_borrows)]
fn __assert_not_repr_packed #impl_generics (this: &#ident #ty_generics) #where_clause {
#(let _ = #field_refs;)*
}
diff --git a/src/pinned_drop.rs b/src/pinned_drop.rs
index ecf52dd..912989d 100644
--- a/src/pinned_drop.rs
+++ b/src/pinned_drop.rs
@@ -53,47 +53,44 @@ fn validate_impl(item: &ItemImpl) -> Result<()> {
"#[pinned_drop] may only be used on implementation for the `PinnedDrop` trait";
if let Some(attr) = item.attrs.find("pinned_drop") {
- return Err(error!(attr, "duplicate #[pinned_drop] attribute"));
+ bail!(attr, "duplicate #[pinned_drop] attribute");
}
if let Some((_, path, _)) = &item.trait_ {
if !path.is_ident("PinnedDrop") {
- return Err(error!(path, INVALID_ITEM));
+ bail!(path, INVALID_ITEM);
}
} else {
- return Err(error!(item.self_ty, INVALID_ITEM));
+ bail!(item.self_ty, INVALID_ITEM);
}
if item.unsafety.is_some() {
- return Err(error!(item.unsafety, "implementing the trait `PinnedDrop` is not unsafe"));
+ bail!(item.unsafety, "implementing the trait `PinnedDrop` is not unsafe");
}
if item.items.is_empty() {
- return Err(error!(item, "not all trait items implemented, missing: `drop`"));
+ bail!(item, "not all trait items implemented, missing: `drop`");
}
match &*item.self_ty {
Type::Path(_) => {}
ty => {
- return Err(error!(
- ty,
- "implementing the trait `PinnedDrop` on this type is unsupported"
- ));
+ bail!(ty, "implementing the trait `PinnedDrop` on this type is unsupported");
}
}
item.items.iter().enumerate().try_for_each(|(i, item)| match item {
ImplItem::Const(item) => {
- Err(error!(item, "const `{}` is not a member of trait `PinnedDrop`", item.ident))
+ bail!(item, "const `{}` is not a member of trait `PinnedDrop`", item.ident)
}
ImplItem::Type(item) => {
- Err(error!(item, "type `{}` is not a member of trait `PinnedDrop`", item.ident))
+ bail!(item, "type `{}` is not a member of trait `PinnedDrop`", item.ident)
}
ImplItem::Method(method) => {
validate_sig(&method.sig)?;
if i == 0 {
Ok(())
} else {
- Err(error!(method, "duplicate definitions with name `drop`"))
+ bail!(method, "duplicate definitions with name `drop`")
}
}
_ => unreachable!("unexpected ImplItem"),
@@ -105,29 +102,30 @@ fn validate_impl(item: &ItemImpl) -> Result<()> {
/// The correct signature is: `(mut) self: (<path>::)Pin<&mut Self>`
fn validate_sig(sig: &Signature) -> Result<()> {
fn get_ty_path(ty: &Type) -> Option<&Path> {
- if let Type::Path(TypePath { qself: None, path }) = ty { Some(path) } else { None }
+ if let Type::Path(TypePath { qself: None, path }) = ty {
+ Some(path)
+ } else {
+ None
+ }
}
const INVALID_ARGUMENT: &str = "method `drop` must take an argument `self: Pin<&mut Self>`";
if sig.ident != "drop" {
- return Err(error!(
- sig.ident,
- "method `{}` is not a member of trait `PinnedDrop", sig.ident,
- ));
+ bail!(sig.ident, "method `{}` is not a member of trait `PinnedDrop", sig.ident,);
}
if let ReturnType::Type(_, ty) = &sig.output {
match &**ty {
Type::Tuple(ty) if ty.elems.is_empty() => {}
- _ => return Err(error!(ty, "method `drop` must return the unit type")),
+ _ => bail!(ty, "method `drop` must return the unit type"),
}
}
match sig.inputs.len() {
1 => {}
0 => return Err(Error::new(sig.paren_token.span, INVALID_ARGUMENT)),
- _ => return Err(error!(sig.inputs, INVALID_ARGUMENT)),
+ _ => bail!(sig.inputs, INVALID_ARGUMENT),
}
if let Some(FnArg::Typed(arg)) = sig.receiver() {
@@ -148,10 +146,7 @@ fn validate_sig(sig: &Signature) -> Result<()> {
&& get_ty_path(elem).map_or(false, |path| path.is_ident("Self"))
{
if sig.unsafety.is_some() {
- return Err(error!(
- sig.unsafety,
- "implementing the method `drop` is not unsafe"
- ));
+ bail!(sig.unsafety, "implementing the method `drop` is not unsafe");
}
return Ok(());
}
@@ -160,7 +155,7 @@ fn validate_sig(sig: &Signature) -> Result<()> {
}
}
- Err(error!(sig.inputs[0], INVALID_ARGUMENT))
+ bail!(sig.inputs[0], INVALID_ARGUMENT)
}
// from:
@@ -189,6 +184,9 @@ fn expand_impl(item: &mut ItemImpl) {
None
}
+ // `PinnedDrop` is a private trait and should not appear in docs.
+ item.attrs.push(parse_quote!(#[doc(hidden)]));
+
let path = &mut item.trait_.as_mut().unwrap().1;
*path = parse_quote_spanned! { path.span() =>
::pin_project::__private::PinnedDrop
diff --git a/src/utils.rs b/src/utils.rs
index 37f35ba..27373ef 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -15,12 +15,18 @@ use syn::{
pub(crate) type Variants = Punctuated<Variant, Token![,]>;
-macro_rules! error {
- ($span:expr, $msg:expr) => {
- syn::Error::new_spanned(&$span, $msg)
+macro_rules! format_err {
+ ($span:expr, $msg:expr $(,)?) => {
+ syn::Error::new_spanned(&$span as &dyn quote::ToTokens, &$msg as &dyn std::fmt::Display)
};
($span:expr, $($tt:tt)*) => {
- error!($span, format!($($tt)*))
+ format_err!($span, format!($($tt)*))
+ };
+}
+
+macro_rules! bail {
+ ($($tt:tt)*) => {
+ return Err(format_err!($($tt)*))
};
}
@@ -98,7 +104,11 @@ pub(crate) fn determine_visibility(vis: &Visibility) -> Visibility {
/// This is almost equivalent to `syn::parse2::<Nothing>()`, but produces
/// a better error message and does not require ownership of `tokens`.
pub(crate) fn parse_as_empty(tokens: &TokenStream) -> Result<()> {
- if tokens.is_empty() { Ok(()) } else { Err(error!(tokens, "unexpected token: {}", tokens)) }
+ if tokens.is_empty() {
+ Ok(())
+ } else {
+ bail!(tokens, "unexpected token: `{}`", tokens)
+ }
}
pub(crate) fn respan<T>(node: &T, span: Span) -> T
@@ -131,14 +141,14 @@ pub(crate) trait SliceExt {
impl SliceExt for [Attribute] {
/// # Errors
///
- /// * There are multiple specified attributes.
- /// * The `Attribute::tokens` field of the specified attribute is not empty.
+ /// - There are multiple specified attributes.
+ /// - The `Attribute::tokens` field of the specified attribute is not empty.
fn position_exact(&self, ident: &str) -> Result<Option<usize>> {
self.iter()
.try_fold((0, None), |(i, mut prev), attr| {
if attr.path.is_ident(ident) {
if prev.replace(i).is_some() {
- return Err(error!(attr, "duplicate #[{}] attribute", ident));
+ bail!(attr, "duplicate #[{}] attribute", ident);
}
parse_as_empty(&attr.tokens)?;
}
@@ -176,7 +186,9 @@ impl<'a> ParseBufferExt<'a> for ParseBuffer<'a> {
// visitors
// Replace `self`/`Self` with `__self`/`self_ty`.
-// Based on https://github.com/dtolnay/async-trait/blob/0.1.35/src/receiver.rs
+// Based on:
+// - https://github.com/dtolnay/async-trait/blob/0.1.35/src/receiver.rs
+// - https://github.com/dtolnay/async-trait/commit/6029cbf375c562ca98fa5748e9d950a8ff93b0e7
pub(crate) struct ReplaceReceiver<'a>(pub(crate) &'a TypePath);
@@ -259,7 +271,7 @@ impl ReplaceReceiver<'_> {
match iter.peek() {
Some(TokenTree::Punct(p)) if p.as_char() == ':' => {
let span = ident.span();
- out.extend(quote_spanned!(span=> <#self_ty>))
+ out.extend(quote_spanned!(span=> <#self_ty>));
}
_ => out.extend(quote!(#self_ty)),
}
@@ -313,7 +325,6 @@ impl VisitMut for ReplaceReceiver<'_> {
// `Self::method` -> `<Receiver>::method`
fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
if expr.qself.is_none() {
- prepend_underscore_to_self(&mut expr.path.segments[0].ident);
self.self_to_qself(&mut expr.qself, &mut expr.path);
}
visit_mut::visit_expr_path_mut(self, expr);
@@ -341,11 +352,21 @@ impl VisitMut for ReplaceReceiver<'_> {
visit_mut::visit_pat_tuple_struct_mut(self, pat);
}
+ fn visit_path_mut(&mut self, path: &mut Path) {
+ if path.segments.len() == 1 {
+ // Replace `self`, but not `self::function`.
+ prepend_underscore_to_self(&mut path.segments[0].ident);
+ }
+ for segment in &mut path.segments {
+ self.visit_path_arguments_mut(&mut segment.arguments);
+ }
+ }
+
fn visit_item_mut(&mut self, item: &mut Item) {
match item {
// Visit `macro_rules!` because locally defined macros can refer to `self`.
Item::Macro(item) if item.mac.path.is_ident("macro_rules") => {
- self.visit_macro_mut(&mut item.mac)
+ self.visit_macro_mut(&mut item.mac);
}
// Otherwise, do not recurse into nested items.
_ => {}