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

unused function is not monomorphized, so post-mono lints do not show up (in particular affects associated and inline consts) #106617

Closed
zirconium-n opened this issue Jan 9, 2023 · 12 comments
Labels
A-monomorphization Area: Monomorphization C-bug Category: This is a bug. F-inline_const Inline constants (aka: const blocks, const expressions, anonymous constants)

Comments

@zirconium-n
Copy link
Contributor

I tried this code:

#![feature(inline_const)]

fn run() {
    const { assert!(false) };
}

I expected to see this happen: compile error.

Instead, this happened: compile passes.

If I change the visibility of fn run to pub, it will throw a compile error.

For comparison, const value always throw a compile error even if the const is never used.

const X: i32 = {
    assert!(false);   // This will error!
    1
};
@zirconium-n zirconium-n added the C-bug Category: This is a bug. label Jan 9, 2023
@scottmcm scottmcm added the I-lang-nominated Nominated for discussion during a lang team meeting. label Jan 9, 2023
@scottmcm
Copy link
Member

scottmcm commented Jan 9, 2023

Hi lang (and maybe @RalfJung)! I'll miss the meeting on Tuesday, but I figured I'd nominate this since the feature is in FCP now, and this looks breaking to fix.

Do we expect that inline consts in non-generic unused private functions aren't evaluated?

@nbdd0121
Copy link
Contributor

nbdd0121 commented Jan 9, 2023

This is intentional, as the same behaviour is true for associated consts.

fn run() {
    struct Foo;
    impl Foo {
        const A: () = assert!(false);
    }
    Foo::A
}

The use is not collected and evaluated if not monomorphized.

@zirconium-n
Copy link
Contributor Author

This is intentional, as the same behaviour is true for associated consts.

fn run() {
    struct Foo;
    impl Foo {
        const A: () = assert!(false);
    }
    Foo::A
}

The use is not collected and evaluated if not monomorphized.

Actually I won't expect this would compile either. 😕

Are you sure this is intentional, instead of some accidental behavior?

@nbdd0121
Copy link
Contributor

nbdd0121 commented Jan 9, 2023

It's documented that they are not evaluated if not used, and generic associated consts are evaluated at mono (https://doc.rust-lang.org/beta/reference/items/associated-items.html#associated-constants).

It's not documented when a non-generic associated will evaluated, but it sounds rather inconsistent if it's not also evaluated at monomorphization time.

@zirconium-n
Copy link
Contributor Author

zirconium-n commented Jan 9, 2023

It's documented that they are not evaluated if not used, and generic associated consts are evaluated at mono (https://doc.rust-lang.org/beta/reference/items/associated-items.html#associated-constants).

It's not documented when a non-generic associated will evaluated, but it sounds rather inconsistent if it's not also evaluated at monomorphization time.

Learning something new every day, really.

But back to my case, I think my code in OP translate to

fn run() {
    const _: () = assert!(false);
}

which throws a compile time error.

@nbdd0121
Copy link
Contributor

nbdd0121 commented Jan 9, 2023

No, const blocks are handled similar to associated consts as opposed to const items. The latter cannot use generics.

@RalfJung
Copy link
Member

RalfJung commented Jan 9, 2023

The problem is that could can write code like this

fn run<T>() {
    const { assert!(std::mem::size_of::<T>() > 0) };
}

Asking to evaluate inline consts in an unused generic function is meaningless, since we can't know the generic parameters.

We could in principle add a special case that applies only to monomorphic functions like your original example. That would not have any direct relation to inline consts though, it affects associated consts just as much.

@zirconium-n
Copy link
Contributor Author

The problem is that could can write code like this

fn run<T>() {
    const { assert!(std::mem::size_of::<T>() > 0) };
}

Asking to evaluate inline consts in an unused generic function is meaningless, since we can't know the generic parameters.

Yes, I agree this is meaningless.

We could in principle add a special case that applies only to monomorphic functions like your original example. That would not have any direct relation to inline consts though, it affects associated consts just as much.

@nbdd0121 gave a pretty good reason why it's handled like this. It's the combined behavior surprised me, but it's understandable.

I'm ok with either way, compile or not. Actually I would prefer less special cases (if we consider it one).

@nbdd0121
Copy link
Contributor

There is a -C link-dead-code option to force non-generic functions being monomorphized.

@lukas-code
Copy link
Member

For what it's worth, the behavior of inline_const here matches overflowing generics: playground

pub const fn overflow(x: impl Sized) {
    overflow((x,))
}

fn ok() {
    overflow(())
}

pub fn error() {
    overflow(())
}

@tmandry
Copy link
Member

tmandry commented Feb 14, 2023

Deferring discussion for now to the design meeting in rust-lang/lang-team#195.

@rustbot label: -I-lang-nominated

@rustbot rustbot removed the I-lang-nominated Nominated for discussion during a lang team meeting. label Feb 14, 2023
@workingjubilee workingjubilee added the F-inline_const Inline constants (aka: const blocks, const expressions, anonymous constants) label Mar 5, 2023
@RalfJung RalfJung changed the title inline_const does not evaluate in unused function unused function is not monomorphized, so post-mono lints only show up in debug builds (in particular affects associated and inline consts) May 17, 2023
@RalfJung RalfJung added the A-monomorphization Area: Monomorphization label May 17, 2023
@RalfJung RalfJung changed the title unused function is not monomorphized, so post-mono lints only show up in debug builds (in particular affects associated and inline consts) unused function is not monomorphized, so post-mono lints do not show up (in particular affects associated and inline consts) May 17, 2023
@RalfJung
Copy link
Member

Closing in favor of #107503 which is basically the same underlying issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-monomorphization Area: Monomorphization C-bug Category: This is a bug. F-inline_const Inline constants (aka: const blocks, const expressions, anonymous constants)
Projects
None yet
Development

No branches or pull requests

8 participants