Repository: pest-parser/pest (language: rust)

Issue:
Expansion error in `pest-derive` with tags
**Describe the bug**
On Rust 1.70 and 1.71, when using tags, the derive macro errors out with the following:

```
error[E0433]: failed to resolve: use of undeclared crate or module `alloc`
 --> src/lib.rs:3:10
  |
3 | #[derive(Parser)]
  |          ^^^^^^ use of undeclared crate or module `alloc`
  |
  = help: add `extern crate alloc` to use the `alloc` crate
  = help: consider importing this enum:
          std::borrow::Cow
  = note: this error originates in the derive macro `Parser` (in Nightly builds, run with -Z macro-backtrace for more info)
```

**To Reproduce**
Here is a minimum reproducible example:

```toml
# Cargo.toml
[package]
name = "pest-issue"
version = "0.1.0"
edition = "2021"

[dependencies]
pest = "2.7.1"
pest_derive = { version = "2.7.1", features = ["std", "grammar-extras"] }
```

```pest
program = { SOI ~ rule* ~ EOI }
rule = !{ "{" ~ (item ~ ";")* ~ (#tail_item = item)? ~ "}" }
item = _{ "foo" | "bar" }
```

```rust
// lib.rs
use pest_derive::Parser;

#[derive(Parser)]
#[grammar = "grammar.pest"]
struct ExampleParser;
```

**Expected behavior**
The generated code should not emit the error.

**Additional context**
- Adding `extern crate alloc` at the top of `lib.rs` makes the error go away -- it is a feasible workaround, but it should probably not be asked of the users to do that.
- This is the only snippet that appears to reference `alloc` in the expanded code:
  ```rust
  state
      .optional(|state| {
          self::item(state)
              .and_then(|state| {
                  state.tag_node(alloc::borrow::Cow::Borrowed("tail_item"))
              })
      })
  ```
- I found [this](https://github.com/pest-parser/pest/blob/4d51b5b75c56b03e13eb21d3e36a5bbe8285a640/generator/src/generator.rs#L544). I haven't had time to try it myself yet, but could prepending `::` so that we have `::alloc` be a potential solution?

Thank you for all your work on this library!


Discussion / hints:
> haven't had time to try it myself yet, but could prepending :: so that we have ::alloc be a potential solution?

Possibly, that will resolve it from the crate root, so that should normally work with default features?

Fix patch:
diff --git a/generator/src/generator.rs b/generator/src/generator.rs
index e41f9663..7677c35a 100644
--- a/generator/src/generator.rs
+++ b/generator/src/generator.rs
@@ -540,8 +540,14 @@ fn generate_expr(expr: OptimizedExpr) -> TokenStream {
         #[cfg(feature = "grammar-extras")]
         OptimizedExpr::NodeTag(expr, tag) => {
             let expr = generate_expr(*expr);
+            let tag_cow = {
+                #[cfg(feature = "std")]
+                quote! { ::std::borrow::Cow::Borrowed(#tag) }
+                #[cfg(not(feature = "std"))]
+                quote! { ::alloc::borrow::Cow::Borrowed(#tag) }
+            };
             quote! {
-                #expr.and_then(|state| state.tag_node(alloc::borrow::Cow::Borrowed(#tag)))
+                #expr.and_then(|state| state.tag_node(#tag_cow))
             }
         }
     }
@@ -695,8 +701,14 @@ fn generate_expr_atomic(expr: OptimizedExpr) -> TokenStream {
         #[cfg(feature = "grammar-extras")]
         OptimizedExpr::NodeTag(expr, tag) => {
             let expr = generate_expr_atomic(*expr);
+            let tag_cow = {
+                #[cfg(feature = "std")]
+                quote! { ::std::borrow::Cow::Borrowed(#tag) }
+                #[cfg(not(feature = "std"))]
+                quote! { ::alloc::borrow::Cow::Borrowed(#tag) }
+            };
             quote! {
-                #expr.and_then(|state| state.tag_node(alloc::borrow::Cow::Borrowed(#tag)))
+                #expr.and_then(|state| state.tag_node(#tag_cow))
             }
         }
     }


Test patch: