-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Only instantiate inline- and const-fns if they are referenced (again). #45575
Only instantiate inline- and const-fns if they are referenced (again). #45575
Conversation
Looks great to me! r=me with passing tests |
CI is still failing. These tests compiled successfully while they should not:
|
4f785a5
to
8d4c92f
Compare
This looks great to me, thanks @michaelwoerister! I'm a little hesitant to personally r+ due to the change in semantics here. We chatted on IRC and it sounded like you're going to wait for discussion amongst the @rust-lang/compiler team, so I'll tag the PR appropriately for that. |
I should note that this mainly has to do with unstable features (e.g. direct uses of intrinsics).
We could turn these into warnings and generate runtime panics instead, in fact the warnings could be done ahead-of-time and distinct from codegen anyway. |
Yes, I think this should be the preferred way to do it anyway. What does the rest of @rust-lang/compiler say? Can we land this? I think the general goal of being as lazy as possible is worth pursuing. |
#[no_mangle] | ||
pub extern fn fail() { | ||
} | ||
} | ||
|
||
mod b { | ||
pub mod b { | ||
#[no_mangle] | ||
pub extern fn fail() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't private no_mangle
functions always be compiled in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like it would be good if that were true.
@@ -21,4 +21,8 @@ fn b() { | |||
fn c() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we check the inline
attribute for functions that aren't translated? I don't want people to create functions with an inline
attribute that explode when a child crate finally instantiates them.
I'm not sure this is a difference in kind, merely a difference in degree: even today you can write things that depend on reachability and blow up only when a downstream crate uses them, for example: #![feature(core_intrinsics)]
use std::intrinsics;
#[inline(fail)]
pub fn foo<T>(_t: T) {
unsafe {
intrinsics::atomic_load(1 as *const [u8; 1048576]);
}
}
#[inline(always)]
pub fn bar() {
unsafe {
intrinsics::atomic_load(1 as *const [u8; 1048576]);
}
}
fn main() {} I still think we want to sanitize attributes during type-checking, but intrinsics (which are unstable and intentionally error on monomorphization time) and resource limits (which are always a problem) should be OK. |
Discussed in the @rust-lang/compiler team meeting yesterday and the conclusion was to proceed with this. The main concern was that @bors r=nikomatsakis |
📌 Commit 8d4c92f has been approved by |
⌛ Testing commit 8d4c92f80d97bc0e42d935ce7d23f6e3083a4937 with merge df38d994283db81c5176dc109d1894cd5232625f... |
💔 Test failed - status-travis |
Test failed,
|
So I think these new failures are because #45710 got merged in between. The custom allocator implementations in these test cases fail linking because (I assume) the respective functions are not instantiated because they are not considered exported? Does that sound right, @alexcrichton? I don't quite understand where these functions are supposed to come from ( |
@michaelwoerister oh dear sorry about that! The static FOO: MyAllocator = ...;
mod some_internal_name {
#[std_special_symbol]
#[no_mangle]
fn __rg_alloc(...) -> ... {
FOO.some_method(...)
}
...
} So the symbols are injected by the compiler and their attributes are generated here. IIRC the |
Ah ok, the collector does not see the functions generated in librustc_trans/allocator.rs, and since we are creating an executable, these seemingly unreferenced |
@alexcrichton Do you think that there's a case where a |
@michaelwoerister nah I think everything tagged with that should be unconditionally instantiated. They're all tiny anyway and will get gc'd by the linker if they're not used. |
678be7d
to
d141abf
Compare
OK, travis looks good. Let's give it another try. @bors r=nikomatsakis |
📌 Commit d141abf has been approved by |
⌛ Testing commit d141abf with merge 6dc72035c92f954c39240fbe4eeec544ef159331... |
💔 Test failed - status-travis |
|
Updated test case. @bors r=nikomatsakis |
📌 Commit 081ef8e has been approved by |
…ikomatsakis Only instantiate inline- and const-fns if they are referenced (again). It seems that we have regressed on not translating `#[inline]` functions unless they are actually used. This should bring back this optimization. I also added a regression test this time so it doesn't happen again accidentally. Fixes #40392. r? @alexcrichton UPDATE & PSA --------------------- This patch **makes translation very lazy** -- in general this is a good thing (we don't want the compiler to do unnecessary work) but it has two consequences: 1. Some error messages are only generated when an item is actually translated. Consequently, this patch will lead to more cases where the compiler will only start emitting errors when the erroneous function is actually used. This has always been true to some extend (e.g. when passing generic values to an intrinsic) but since this is something user-facing it's worth mentioning. 2. When writing tests, one has to make sure that the functions in question are actually generated. In other words, it must not be dead code. This can usually be achieved by either 1. making sure the function is exported from the resulting binary or 2. by making sure the function is called from something that is exported (or `main()`). Note that it depends on the crate type what functions are exported: 1. For rlibs and dylibs everything that is reachable from the outside is exported. 2. For executables, cdylibs, and staticlibs, items are only exported if they are additionally `#[no_mangle]` or have an `#[export_name]`. The commits in this PR contain many examples of how tests can be updated to comply to the new requirements.
☀️ Test successful - status-appveyor, status-travis |
Wow, cool |
It seems that we have regressed on not translating
#[inline]
functions unless they are actually used. This should bring back this optimization. I also added a regression test this time so it doesn't happen again accidentally.Fixes #40392.
r? @alexcrichton
UPDATE & PSA
This patch makes translation very lazy -- in general this is a good thing (we don't want the compiler to do unnecessary work) but it has two consequences:
main()
).Note that it depends on the crate type what functions are exported:
#[no_mangle]
or have an#[export_name]
.The commits in this PR contain many examples of how tests can be updated to comply to the new requirements.