Repository: actix/actix-web (language: rust)

Issue:
Compile errors after actix-web-codegen v4.2.0 -> v4.2.1
After running `cargo update`, with the ONLY update being `actix-web-codegen v4.2.0 -> v4.2.1` (I updated all other ones one-by-one using `cargo update -p <...>`), i gets compilation errors of the [martin](https://github.com/maplibre/martin) project:

```
error: unexpected token
  --> martin/src/srv/server.rs:95:12
   |
95 |     wrap = "middleware::Compress::default()"
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
```

## Steps to Reproduce (for bugs)

1. `git clone https://github.com/maplibre/martin.git`
2. `cd martin`
3. `git reset --hard b5902aa`
4. `cargo build`  <-- this should pass
5. `cargo update -p actix-web-codegen` <-- this will show updating `v4.2.0 -> v4.2.1`
6. `cargo build`  <-- this will now fail with lots of errors

## Context

<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->

## Your Environment

- Linux Mint
- Rust Version (I.e, output of `rustc -V`): `rustc 1.72.0 (5680fa18f 2023-08-23)`
- Actix Web Version: `4.4.0`



Discussion / hints:
Thanks for posting this regression. I've yanked v4.2.1 for now.

Fix patch:
diff --git a/actix-web-codegen/CHANGES.md b/actix-web-codegen/CHANGES.md
index d5a3f5d317f..00e36b037a7 100644
--- a/actix-web-codegen/CHANGES.md
+++ b/actix-web-codegen/CHANGES.md
@@ -2,6 +2,10 @@
 
 ## Unreleased
 
+## 4.2.2
+
+- Fix regression when declaring `wrap` attribute using an expression.
+
 ## 4.2.1
 
 - Update `syn` dependency to `2`.
diff --git a/actix-web-codegen/Cargo.toml b/actix-web-codegen/Cargo.toml
index 0eee5004a5b..748984b4983 100644
--- a/actix-web-codegen/Cargo.toml
+++ b/actix-web-codegen/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "actix-web-codegen"
-version = "4.2.1"
+version = "4.2.2"
 description = "Routing and runtime macros for Actix Web"
 homepage = "https://actix.rs"
 repository = "https://github.com/actix/actix-web.git"
diff --git a/actix-web-codegen/README.md b/actix-web-codegen/README.md
index a53159e0395..e9a1f9c7e22 100644
--- a/actix-web-codegen/README.md
+++ b/actix-web-codegen/README.md
@@ -3,11 +3,11 @@
 > Routing and runtime macros for Actix Web.
 
 [![crates.io](https://img.shields.io/crates/v/actix-web-codegen?label=latest)](https://crates.io/crates/actix-web-codegen)
-[![Documentation](https://docs.rs/actix-web-codegen/badge.svg?version=4.2.1)](https://docs.rs/actix-web-codegen/4.2.1)
+[![Documentation](https://docs.rs/actix-web-codegen/badge.svg?version=4.2.2)](https://docs.rs/actix-web-codegen/4.2.2)
 ![Version](https://img.shields.io/badge/rustc-1.68+-ab6000.svg)
 ![License](https://img.shields.io/crates/l/actix-web-codegen.svg)
 <br />
-[![dependency status](https://deps.rs/crate/actix-web-codegen/4.2.1/status.svg)](https://deps.rs/crate/actix-web-codegen/4.2.1)
+[![dependency status](https://deps.rs/crate/actix-web-codegen/4.2.2/status.svg)](https://deps.rs/crate/actix-web-codegen/4.2.2)
 [![Download](https://img.shields.io/crates/d/actix-web-codegen.svg)](https://crates.io/crates/actix-web-codegen)
 [![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/NWpN5mmg3x)
 
diff --git a/actix-web-codegen/src/route.rs b/actix-web-codegen/src/route.rs
index 525a1c8bab8..7a2dfc051ce 100644
--- a/actix-web-codegen/src/route.rs
+++ b/actix-web-codegen/src/route.rs
@@ -224,7 +224,7 @@ struct Args {
     path: syn::LitStr,
     resource_name: Option<syn::LitStr>,
     guards: Vec<Path>,
-    wrappers: Vec<syn::Type>,
+    wrappers: Vec<syn::Expr>,
     methods: HashSet<MethodTypeExt>,
 }
 
@@ -251,7 +251,7 @@ impl Args {
                 } else {
                     return Err(syn::Error::new_spanned(
                         nv.value,
-                        "Attribute name expects literal string!",
+                        "Attribute name expects literal string",
                     ));
                 }
             } else if nv.path.is_ident("guard") {
@@ -264,7 +264,7 @@ impl Args {
                 } else {
                     return Err(syn::Error::new_spanned(
                         nv.value,
-                        "Attribute guard expects literal string!",
+                        "Attribute guard expects literal string",
                     ));
                 }
             } else if nv.path.is_ident("wrap") {
@@ -283,9 +283,9 @@ impl Args {
             } else if nv.path.is_ident("method") {
                 if !is_route_macro {
                     return Err(syn::Error::new_spanned(
-                                &nv,
-                                "HTTP method forbidden here. To handle multiple methods, use `route` instead",
-                            ));
+                        &nv,
+                        "HTTP method forbidden here; to handle multiple methods, use `route` instead",
+                    ));
                 } else if let syn::Expr::Lit(syn::ExprLit {
                     lit: syn::Lit::Str(lit),
                     ..
@@ -300,13 +300,13 @@ impl Args {
                 } else {
                     return Err(syn::Error::new_spanned(
                         nv.value,
-                        "Attribute method expects literal string!",
+                        "Attribute method expects literal string",
                     ));
                 }
             } else {
                 return Err(syn::Error::new_spanned(
                     nv.path,
-                    "Unknown attribute key is specified. Allowed: guard, method and wrap",
+                    "Unknown attribute key is specified; allowed: guard, method and wrap",
                 ));
             }
         }


Test patch:
diff --git a/actix-web-codegen/tests/test_macro.rs b/actix-web-codegen/tests/test_macro.rs
index f28654cd96a..fb50d4ae065 100644
--- a/actix-web-codegen/tests/test_macro.rs
+++ b/actix-web-codegen/tests/test_macro.rs
@@ -212,6 +212,19 @@ async fn get_wrap(_: web::Path<String>) -> impl Responder {
     HttpResponse::Ok()
 }
 
+/// Using expression, not just path to type, in wrap attribute.
+///
+/// Regression from <https://github.com/actix/actix-web/issues/3118>.
+#[route(
+    "/catalog",
+    method = "GET",
+    method = "HEAD",
+    wrap = "actix_web::middleware::Compress::default()"
+)]
+async fn get_catalog() -> impl Responder {
+    HttpResponse::Ok().body("123123123")
+}
+
 #[actix_rt::test]
 async fn test_params() {
     let srv = actix_test::start(|| {
diff --git a/actix-web-codegen/tests/trybuild/simple-fail.stderr b/actix-web-codegen/tests/trybuild/simple-fail.stderr
index 3b3f9d8507a..ab81599edf2 100644
--- a/actix-web-codegen/tests/trybuild/simple-fail.stderr
+++ b/actix-web-codegen/tests/trybuild/simple-fail.stderr
@@ -38,7 +38,7 @@ error: Multiple paths specified! There should be only one.
    |
    = note: this error originates in the attribute macro `delete` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: HTTP method forbidden here. To handle multiple methods, use `route` instead
+error: HTTP method forbidden here; to handle multiple methods, use `route` instead
   --> $DIR/simple-fail.rs:25:19
    |
 25 | #[delete("/five", method="GET")]