Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Allow arbitrary constant expressions to be assigned to const items #570

Closed
brson opened this Issue · 19 comments

6 participants

@brson
Owner

Right now constants have to be literals and this is getting pretty painful.

@brson
Owner

This is a pretty good starter project.

@jwise

I took a look at this earlier tonight, since I ran into it.

There are a few things; my first attempt was to go after trans_const_expr, and make that function recursive; I'm not sure what the result it would generate would be, though. I tried adding, for instance, a Shl() call, but Shl() takes a block_ctxt, and I've only got a crate_ctxt... Would LLVM be able to reduce this down if I emitted the operations for it? I don't really understand this path very well.

The other option would be to have a reduction mechanism that constant folds down to a literal. This seems like it would be somewhat painful in light of how complex trans_crate_lit is... and it also seems like it is somewhat overly specific to one particular task, whereas constant folding is a pretty general thing.

How do others think that one should approach this?

(I'm not claiming this one just yet. But it's a possibility.)

@brson
Owner

There's going to have to be a pass before trans that at least reports errors for non-constant const expressions. It could possibly fold the constants and build up a side table in the session object, but then I'm not sure what you would do when constant expressions referred to constants in external crates.

@pcwalton
Owner

"There are a few things; my first attempt was to go after trans_const_expr, and make that function recursive; I'm not sure what the result it would generate would be, though. I tried adding, for instance, a Shl() call, but Shl() takes a block_ctxt, and I've only got a crate_ctxt... Would LLVM be able to reduce this down if I emitted the operations for it? I don't really understand this path very well."

You need to use the Constant variants of all the operations. These don't need contexts. See the instructions prefixed with LLVMConst in comp/lib/llvm.rs (e.g. LLVMConstShl).

"There's going to have to be a pass before trans that at least reports errors for non-constant const expressions. It could possibly fold the constants and build up a side table in the session object, but then I'm not sure what you would do when constant expressions referred to constants in external crates."

The pass also needs to make sure that constants aren't recursive, rejecting e.g. const a : int = b; const b : int = a + 1.

If we want to support constant expressions that refer to cross-crate constant values, we need an IR. We want an IR for other reasons (monomorphizing), but creating an IR makes this bug decidedly not 'easy' :) For now it would be much easier to support only constant expressions that can be fully resolved by looking in the current crate.

@jwise

Right, yeah. I just rolled out of bed and looked at my e-mail, and I saw "[...] constants in external crates [...]", and went "Uh-oh... I'm not sure on what planet this is 'easy'..." :)

So I guess the next thing to look at is where to insert another pass. I'll take a look at that if I get some free time today.

@jwise

We discussed this on IRC today, and here are the conclusions so far:

  • A pass should be added in rustc::driver::rustc::compile_input before translation just to verify that constant expressions are 1) constant, and 2) non-recursive. The way to do this would be to set up an AST visitor looking for ast::item_const.
  • By the time trans_const_expr is invoked, the crate_ctxt already has a translation from every AST node_id (i.e., every other const) to a ValueRef. So, for constants that reference other constants, they can be translated on demand, and then their ValueRef can be used. To generate ValueRefs for other constants, look at LLVMConstShl and friends.

I think I'm going to take a swing at the constant verification pass first, since I know that if I do the trans pass first, I won't want to bother coming back to the verification pass. We'll see how it goes.

@jwise

So, here's a question -- which AST nodes do we wish to allow? There are plenty of things that "can" be constant, but would be a huge pain -- consider:

const a : int = {
    let b = 5;
    b
};

This doesn't translate obviously to an LLVMConst expression. Similarly, the following is constant, and even provably constant!, but a big pain:

const a : int = if true then {3; 5} else {4; 6};

But, the following should presumably be permitted:

const a : int = true ? 5 : 6;

How do we decide what to allow? Rust doesn't have a meaningful definition of an "expression", like C does, so we can't very well just say "only expressions, not blocks, are allowed". Thoughts?

@jwise

Well, actually, the "if" example is not so big of a pain ... but the "let" example certainly is.

@brson
Owner

I would start with something small, that has an obvious implementation, like scalars with binops and unops. Nothing that involves branching. We can always expand what's legal later.

@jwise jwise referenced this issue from a commit
@jwise jwise trans: Add binops (except for logic and comparators) and unops to tra…
…ns_const_expr. Working towards issue #570.
51af171
@jwise

I have bits in flight -- see the above referenced commits. Since make check seemed to crash and burn on my OS X laptop even before I touched anything, I'm kicking off a make check on my (slow) Linux machine; if all goes well, I'll submit a pull request when I wake up.

@brson
Owner

Why was make check failing on OS X?

@jwise

Tests ended up being fine, so I'm opening a pull request. I had to test with --disable-valgrind, otherwise I got:

location should start with fun: or obj:
==21742== FATAL: in suppressions file '../src/etc/x86.supp': location should start with 'fun:' or 'obj:'
==21742== exiting now.

make check was failing on OS X because my laptop's valgrind install is also completely toast.

@brson brson referenced this issue from a commit
@jwise jwise trans: Add binops (except for logic and comparators) and unops to tra…
…ns_const_expr. Working towards issue #570.
c8fae5d
@boggle

Can you please consider #1215 in this context?

@jwise

@boggle, I could add this as a special case in this logic, but it seems that the mechanism you described in #1215 -- dropping it in a pass -- seems like the right thing. Thoughts from others?

@boggle

Have submitted a patch for #1215 that allows trivial casts (cast to machine-equivalent type) in const exprs. Are you aware of #571? Are you working on allowing references to other consts in const exprs? As soon as that is there, I could simplify std::math* once more.

@catamorphism catamorphism was assigned
@catamorphism

@jwise - are you still working on this? If not, I'll take over.

@jwise
@catamorphism

@jwise -- Ok, I have quite a few issues on my plate, so feel free to do more work on it if you're not seeing progress here, but otherwise I'll get around to it eventually.

@brson
Owner

@boggle: consts can reference other consts now, but only within the same crate.

@graydon graydon closed this in f0775d7
@jayanderson jayanderson referenced this issue from a commit
Commit has since been removed from the repository and is no longer available.
@catamorphism catamorphism was unassigned by brson
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.