Skip to content

[goal] modifying private method in another crate's impl should not require users of public methods to recompile #37333

Closed

Description

@nikomatsakis

This is an extension of #37121 but to support modification of a private method in another crate. This is currently complicated by the fact that when we write metadata, we make one metadata node per item. So any changes to the item at all are confounded together. IOW, we can't tell the difference between adding an inherent impl or method to a struct and changing the types of its fields. This results in really poor re-use.

Activity

  1. nikomatsakis commented on Oct 21, 2016

    @nikomatsakis
    ContributorAuthor
  2. nikomatsakis commented on Oct 21, 2016

    @nikomatsakis
    ContributorAuthor

    As far as priorities, I would put this goal somewhat secondary -- it's very important, but we should focus first on #37121 and of course correctness goals. IOW we can have a widely used version that doesn't handle this yet, since most people work primarily at a leaf crate when building. But we should link this goal perhaps to some issues that pertain to specific impl changes for fixing it.

  3. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    A-incr-compArea: Incremental compilation
    on Oct 21, 2016
  4. nikomatsakis commented on Oct 21, 2016

    @nikomatsakis
    ContributorAuthor

    triage: P-medium

  5. nagisa commented on Oct 22, 2016

    @nagisa
    Member

    The private callees might have been inlined through the public method.

  6. KalitaAlexey commented on Oct 23, 2016

    @KalitaAlexey
    Contributor

    @nagisa Good note. Is there any way to determine whether some private item was inlined? We must investigate this case.

  7. michaelwoerister commented on Oct 23, 2016

    @michaelwoerister
    Member

    Inlining should mostly be handled by splitting interfaces from bodies for Metadata dep-nodes, like we also plan to do for HIR dep-nodes.

    1. If the public extern method is neither generic nor marked with #[inline] then we should not need to care what got inlined into it.
    2. If the public extern method is generic or marked with #[inline], we must track what goes into its body. If inlining happens at the MIR level, this should already be covered by the current tracking system. At LLVM level it's more difficult. I could imagine that we give the Rust compiler a heuristic that decides which functions are very unlikely to be inlined and then mark those functions with #[inline(never)] at the LLVM level --- and add dependency edges to all other callees because we can't guarantee that they haven't been inlined.
  8. hanna-kruppe commented on Oct 23, 2016

    @hanna-kruppe
    Contributor

    Just because a function (in the same LLVM module) is noinline doesn't mean LLVM won't peek at its implementation. For example, consider this playground example:

    #[inline(never)]
    pub fn five() -> i32 {
        5
    }
    
    pub fn caller() -> i32 {
        five() + 1
    }

    The LLVM IR for five is noinline (in debug and in release), but in release mode, caller gets optimized to ret i32 6. It also adds various attributes to caller that can only be justified by analyzing or inlining five (e.g., nounwind).

  9. michaelwoerister commented on Oct 23, 2016

    @michaelwoerister
    Member

    @rkruppe Wow! That's a pretty blatant violation of what the documentation says about the attribute. Thanks for the info!

    Oh well, we can still fall back to the brute force method of preventing inlining by moving those functions into their own compilation unit.

  10. nagisa commented on Oct 23, 2016

    @nagisa
    Member

    Wow! That's a pretty blatant violation of what the documentation says about the attribute. Thanks for the info!

    This optimisation happens because of global (cross-function) constant propagation and not inlining, so no violations here. The way I see it, this goal cannot be achieved without instrumenting LLVM appropriately.

    As an aside, LLVM has quite a few module-wide optimisations (inlining and global constprop being two examples), all of which would have to be instrumented somehow. Separate compilation units sound quite inefficient to me at the first consideration.

  11. eddyb commented on Oct 23, 2016

    @eddyb
    Contributor

    Separate compilation units might work with ThinLTO, if we get the granularity just right.

  12. michaelwoerister commented on Oct 23, 2016

    @michaelwoerister
    Member

    Separate compilation units sound quite inefficient to me at the first consideration.

    They are probably not ideal from a compile-time point of view.

    One consequence of instrumenting LLVM would be that we have to push some of the dependency tracking past the LLVM passes. Probably not that big a deal.

    A short-term solution would be to add dependency edges to everything that is transitively called within the same compilation unit (i.e. the worst case result that LLVM instrumentation data could yield).

  13. 6 remaining items

  14. added a commit that references this issue on Jan 3, 2020
  15. added a commit that references this issue on Jan 4, 2020
  16. michalt commented on Jan 8, 2020

    @michalt
    Contributor

    With the test added, I think this can be closed now. :)

  17. michaelwoerister commented on Jan 9, 2020

    @michaelwoerister
    Member

    Yes, the test looks good. Thanks, @michalt!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-incr-compArea: Incremental compilationC-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCP-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions