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

rustc: Add const globals to the language #17853

Merged
merged 24 commits into from
Oct 10, 2014
Merged

Conversation

alexcrichton
Copy link
Member

This change is an implementation of RFC 69 which adds a third kind of
global to the language, const. This global is most similar to what the old
static was, and if you're unsure about what to use then you should use a
const.

The semantics of these three kinds of globals are:

  • A const does not represent a memory location, but only a value. Constants
    are translated as rvalues, which means that their values are directly inlined
    at usage location (similar to a #define in C/C++). Constant values are, well,
    constant, and can not be modified. Any "modification" is actually a
    modification to a local value on the stack rather than the actual constant
    itself.

    Almost all values are allowed inside constants, whether they have interior
    mutability or not. There are a few minor restrictions listed in the RFC, but
    they should in general not come up too often.

  • A static now always represents a memory location (unconditionally). Any
    references to the same static are actually a reference to the same memory
    location. Only values whose types ascribe to Sync are allowed in a static.
    This restriction is in place because many threads may access a static
    concurrently. Lifting this restriction (and allowing unsafe access) is a
    future extension not implemented at this time.

  • A static mut continues to always represent a memory location. All references
    to a static mut continue to be unsafe.

This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:

  • Statics may no longer be used in patterns. Statics now always represent a
    memory location, which can sometimes be modified. To fix code, repurpose the
    matched-on-static to a const.

    static FOO: uint = 4;
    match n {
        FOO => { /* ... */ }
        _ => { /* ... */ }
    }
    

    change this code to:

    const FOO: uint = 4;
    match n {
        FOO => { /* ... */ }
        _ => { /* ... */ }
    }
    
  • Statics may no longer refer to other statics by value. Due to statics being
    able to change at runtime, allowing them to reference one another could
    possibly lead to confusing semantics. If you are in this situation, use a
    constant initializer instead. Note, however, that statics may reference other
    statics by address, however.

  • Statics may no longer be used in constant expressions, such as array lengths.
    This is due to the same restrictions as listed above. Use a const instead.

[breaking-change]
Closes #17718

@rust-highfive
Copy link
Collaborator

warning Warning warning

  • These commits modify unsafe code. Please review it carefully!

@alexcrichton
Copy link
Member Author

I'll note that this is very much a break-the-world change due to the new restrictions being placed on statics. I don't really know a great way to provide a smooth path forward in all respects, so I didn't put forth any effort in this patch for a deprecation path.

I'll also note that this implements a clarified version of the RFC which may be surprising at first. The PR description/commit messages should have the info though.

I'm always open to suggestions for more tests, I tried to write a test for everything I could think of along the way, but I surely missed something here or there!

@pcwalton
Copy link
Contributor

pcwalton commented Oct 8, 2014

OK, this looks great overall, just a few nits. r=me with changes, awesome!

Remove a bunch of two-space tabs
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.

The semantics of these three kinds of globals are:

* A `const` does not represent a memory location, but only a value. Constants
  are translated as rvalues, which means that their values are directly inlined
  at usage location (similar to a #define in C/C++). Constant values are, well,
  constant, and can not be modified. Any "modification" is actually a
  modification to a local value on the stack rather than the actual constant
  itself.

  Almost all values are allowed inside constants, whether they have interior
  mutability or not. There are a few minor restrictions listed in the RFC, but
  they should in general not come up too often.

* A `static` now always represents a memory location (unconditionally). Any
  references to the same `static` are actually a reference to the same memory
  location. Only values whose types ascribe to `Sync` are allowed in a `static`.
  This restriction is in place because many threads may access a `static`
  concurrently. Lifting this restriction (and allowing unsafe access) is a
  future extension not implemented at this time.

* A `static mut` continues to always represent a memory location. All references
  to a `static mut` continue to be `unsafe`.

This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:

* Statics may no longer be used in patterns. Statics now always represent a
  memory location, which can sometimes be modified. To fix code, repurpose the
  matched-on-`static` to a `const`.

      static FOO: uint = 4;
      match n {
          FOO => { /* ... */ }
          _ => { /* ... */ }
      }

  change this code to:

      const FOO: uint = 4;
      match n {
          FOO => { /* ... */ }
          _ => { /* ... */ }
      }

* Statics may no longer refer to other statics by value. Due to statics being
  able to change at runtime, allowing them to reference one another could
  possibly lead to confusing semantics. If you are in this situation, use a
  constant initializer instead. Note, however, that statics may reference other
  statics by address, however.

* Statics may no longer be used in constant expressions, such as array lengths.
  This is due to the same restrictions as listed above. Use a `const` instead.

[breaking-change]

[rfc]: rust-lang/rfcs#246
The tables in libunicode are far too large to want to be inlined into any other
program, so these tables are all going to remain `static`. For them to be legal,
they cannot reference one another by value, but instead use references now.

This commit also modifies the src/etc/unicode.py script to generate the right
tables.
This crate is largely just one giant header file, so there's no need for any of
these values to actually have a memory location, they're all just basically a
regular #define.
This leaves the ziggurat tables as `pub static` as they're likely too large to
want to go into the metadata anyway.
This commit repurposes most statics as constants in the standard library itself,
with the exception of TLS keys which precisely have their own memory location as
an implementation detail.

This commit also rewrites the bitflags syntax to use `const` instead of
`static`. All invocations will need to replace the word `static` with `const`
when declaring flags.

Due to the modification of the `bitflags!` syntax, this is a:

[breaking-change]
This require a bit of finesse to work around the changes with libunicode, but
nothing too major!
At the same time, migrate statics to constants.
Instead of returning &'static [u8], an invocation of `bytes!()` now returns
`&'static [u8, ..N]` where `N` is the length of the byte vector. This should
functionally be the same, but there are some cases where an explicit cast may be
needed, so this is a:

[breaking-change]
Additionally, add lots of tests for new functionality around statics and
`static mut`.
@nikomatsakis
Copy link
Contributor

👯

bors added a commit that referenced this pull request Oct 10, 2014
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.

The semantics of these three kinds of globals are:

* A `const` does not represent a memory location, but only a value. Constants
  are translated as rvalues, which means that their values are directly inlined
  at usage location (similar to a #define in C/C++). Constant values are, well,
  constant, and can not be modified. Any "modification" is actually a
  modification to a local value on the stack rather than the actual constant
  itself.

  Almost all values are allowed inside constants, whether they have interior
  mutability or not. There are a few minor restrictions listed in the RFC, but
  they should in general not come up too often.

* A `static` now always represents a memory location (unconditionally). Any
  references to the same `static` are actually a reference to the same memory
  location. Only values whose types ascribe to `Sync` are allowed in a `static`.
  This restriction is in place because many threads may access a `static`
  concurrently. Lifting this restriction (and allowing unsafe access) is a
  future extension not implemented at this time.

* A `static mut` continues to always represent a memory location. All references
  to a `static mut` continue to be `unsafe`.

This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:

* Statics may no longer be used in patterns. Statics now always represent a
  memory location, which can sometimes be modified. To fix code, repurpose the
  matched-on-`static` to a `const`.

      static FOO: uint = 4;
      match n {
          FOO => { /* ... */ }
          _ => { /* ... */ }
      }

  change this code to:

      const FOO: uint = 4;
      match n {
          FOO => { /* ... */ }
          _ => { /* ... */ }
      }

* Statics may no longer refer to other statics by value. Due to statics being
  able to change at runtime, allowing them to reference one another could
  possibly lead to confusing semantics. If you are in this situation, use a
  constant initializer instead. Note, however, that statics may reference other
  statics by address, however.

* Statics may no longer be used in constant expressions, such as array lengths.
  This is due to the same restrictions as listed above. Use a `const` instead.

[breaking-change]
Closes #17718 

[rfc]: rust-lang/rfcs#246
@bors bors closed this Oct 10, 2014
@bors bors merged commit 0b51711 into rust-lang:master Oct 10, 2014
@alexcrichton alexcrichton deleted the issue-17718 branch October 10, 2014 01:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement global constants, alter the meaning of static
5 participants