Skip to content

Breaking change happened in rustc 1.74: lifetime error #118103

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
Slixe opened this issue Nov 20, 2023 · 3 comments
Closed

Breaking change happened in rustc 1.74: lifetime error #118103

Slixe opened this issue Nov 20, 2023 · 3 comments
Labels
C-bug Category: This is a bug.

Comments

@Slixe
Copy link

Slixe commented Nov 20, 2023

Hey there,

I found a breaking change bug about lifetime where the newly stable version raise an (incorrect ?) error.

My code is basically this:
xelis_common/src/rpc_server/mod.rs:52

pub async fn json_rpc<T, H>(server: Data<H>, body: web::Bytes) -> Result<impl Responder, RpcResponseError>
where
    T: Send + Sync + Clone,
    H: RPCServerHandler<T>
{
    let result = server.get_rpc_handler().handle_request(&body).await?;
    Ok(HttpResponse::Ok().json(result))
}

Where get_rpc_handler() come from this:
xelis_common/src/rpc_server/mod.rs:47

pub trait RPCServerHandler<T: Send + Clone> {
    fn get_rpc_handler(&self) -> &RPCHandler<T>;
}

Which expose this:
xelis_common/src/rpc_server/rpc_handler.rs:25

pub async fn handle_request(&self, body: &[u8]) -> Result<Value, RpcResponseError> {
    self.handle_request_with_context(Context::default(), body).await
}

this function come from this struct:
xelis_common/src/rpc_server/rpc_handler.rs:9

pub struct RPCHandler<T: Send + Clone + 'static> {
    methods: HashMap<String, Handler>, // all RPC methods registered
    data: T
}

impl<T> RPCHandler<T>
where
    T: Send + Sync + Clone + 'static
{

I expected to see this happen:
No error when building my project using rustc version 1.74 like it is with 1.73 and previous versions.

Instead, this happened:
I get an error about lifetime where my parameter type T may not live long enough when building it using 1.74.
This error is not thrown on older rustc versions.

Meta

rustc --version --verbose:

rustc 1.74.0 (79e9716c9 2023-11-13)
binary: rustc
commit-hash: 79e9716c980570bfd1f666e3b16ac583f0168962
commit-date: 2023-11-13
host: x86_64-unknown-linux-gnu
release: 1.74.0
LLVM version: 17.0.4
Backtrace

error[E0310]: the parameter type `T` may not live long enough
  --> xelis_common/src/rpc_server/mod.rs:57:18
   |
57 |     let result = server.get_rpc_handler().handle_request(&body).await?;
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
   |
help: consider adding an explicit lifetime bound...
   |
54 |     T: Send + Sync + Clone + 'static,
   |                            +++++++++

error[E0310]: the parameter type `T` may not live long enough
  --> xelis_common/src/rpc_server/mod.rs:57:18
   |
57 |     let result = server.get_rpc_handler().handle_request(&body).await?;
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
   |
help: consider adding an explicit lifetime bound...
   |
54 |     T: Send + Sync + Clone + 'static,
   |                            +++++++++

For more information about this error, try `rustc --explain E0310`.
error: could not compile `xelis_common` (lib) due to 2 previous errors

In case you want to reproduce it:
https://github.com/xelis-project/xelis-blockchain/tree/dev

and try to compile using:
cargo build --bin xelis_daemon

In case, I'm also using tokio for async runtime.

@Slixe Slixe added the C-bug Category: This is a bug. label Nov 20, 2023
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Nov 20, 2023
@Slixe
Copy link
Author

Slixe commented Nov 20, 2023

Here is the reproductible bug:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=fa53f729e82c22d14f8254e0edfff705

I found the reason why: when adding async to fn test<T, H>(handler: H) and pub async fn test(&self) {} it works in previous versions.

@lukas-code
Copy link
Member

Reduced harder:

struct Static<T: 'static>(T);

async fn use_static<T: 'static>(x: Static<T>) {}

async fn make_static<T>(x: T) {
    use_static(Static(x)).await;
}

The change in behavior is necessary to fix a soundness bug in Rust: In this example use_static has a T: 'static bound, but make_static does not. This is unsound, because use_static can assume that x contains no non-'static borrows, but callers of make_static do not have to promise that that is the case. (proof of unsoundness)

You likely have to add : 'static bounds like the compiler suggests to make your code sound.

For the record, this got changed in #107421

@Slixe
Copy link
Author

Slixe commented Nov 20, 2023

Thanks for the explanation lukas, I close the issue.

@Slixe Slixe closed this as completed Nov 20, 2023
@fmease fmease removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Nov 23, 2023
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

4 participants