Skip to content

Inner statics all have the same symbol name #9188

Closed
@alexcrichton

Description

@alexcrichton

Turns out this is not only inconvenient, but also a serious problem.

// bar.rs
pub fn foo<T>() -> &'static int {
    if false {               
        static a: int = 4;       
        return &a;               
    } else {                     
        static a: int = 5;       
        return &a;               
    }                            
}                                

pub fn bar() -> &'static int {   
    foo::<int>()                 
}                                
// foo.rs
extern mod bar;                 

fn main() {                     
    let a = bar::bar();         
    let b = bar::foo::<int>();
    println!("{} {}", *a, *b);  
}                               
$ rustc --lib bar.rs
warning: missing crate link meta `name`, using `bar` as default
warning: missing crate link meta `vers`, using `0.0` as default
warning: no debug symbols in executable (-arch x86_64)
$ rustc foo.rs -L.
warning: no debug symbols in executable (-arch x86_64)
$ ./foo
5 4

Here's what's happening (to the best of my knowledge):

  1. When compiling bar.rs, the same symbol name, N, is generated for both statics. LLVM will silently rename the second to N1, so we have N = 4, N1 = 5. Note that both statics are walked through because this is a generic function, meaning that we still walk the statics to emit them into this crate (may have to do that for inner functions as well).
  2. The function bar is resolved in-crate, and because the symbol names have already been generated, N1 will be returned (5).
  3. When compiling foo.rs, the function bar::foo is again instantiated, but this time we have our clever optimization which ignores the first block of the if statement, hence only one of the statics is translated. In this case, it's declared with the name N.
  4. When linking is done, the version of bar::foo in bar returns N1, and the version of bar::foo in foo returns N, hence the difference.

There's a lot of things going wrong here, and I'm not entirely sure why, but I think that this would all be fixed if inner statics had different symbol names (no silent renamings from LLVM).

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-codegenArea: Code generation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions