Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Breaking change happened in rustc 1.74: lifetime error #118103

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

4 participants