Further derailing the thread. Sorry, casts really got me thinking and I
need to probe this issue a bit because a lot of near-term work depends
on it:
On 10/05/2012 7:57 AM, Graydon Hoare wrote:
So uh .. in the specific case of 'as' I'm not deeply worried what it
changes to, if anything. But I think we need to look at constant folding
first before making a move on it.
Thought about this a bit more:
- 'const fn' is, I think, overkill. Obliges the compiler to do a ton
of additional work simulating runtime semantics, and gets the phases
really mixed up, circular.
- The scary case is integers sneaking into types, as in fixed-size
arrays. I think the main case for this is actually C interop, where
a syntax extension that reaches into clang, grabs C type-size
information, and returns a literal is probably sufficient. I don't
think it's necessary to generalize to "any constant expression can
appear in a type". Which is good, because that would be a huge
undertaking and very likely make the phases circular, to the point
of total confusion.
- Given that, sizeof/alignof/offsetof probably don't need to be
const exprs. The other use-case for distinct integer-const exprs
(as opposed to general const exprs) is in enum discriminant values,
and I don't know exactly why they can't be pushed back to "some LLVM
constant we'll get the actual value of later". I'm willing to find
out, if someone can enlighten me!
- Very little compiler-work is saved -- in fact I think it's more work
-- to spill, emit a call to a visitor, and reload (and inline that),
instead of just emitting integer-add or fp-mul. At least for types
already well understood to the compiler, LLVM, and machine.
- The primitive types already have privileged status in a few places,
such as literal forms, presence in types (again, fixed vectors),
and permitting multiple integer types for the RHS of << and [] and
whatnot.
- All this combines to make me think:
- Integer, fp, raw pointer, region pointer, literal, addr-of,
concatenation and indexing is an ok set of constant exprs.
Evaluation happens in target mode, operands must themselves
be constants, and we can do it in LLVM. It's just a line
distinguishing "what we can define a 'const' as and have in
read-only memory".
- All such constant expressions (including literals, raw
and region-pointer ops, fp and integer ops), have fixed
compiler-implemented meaning. Anything more complex you want
to do _at compile time_ you have to shell out to a syntax
extension for. Maybe we provide a variable-precision fp
calculator extension for fancy math constants.
- All _nontrivial_ operations are routed through visitors, where
"trivial" means that the operation _could_ have been a constant
expr if only it had been applied to constant operands. IOW
anything that boils down to 0 or 1 LLVM operation, memcmp or
memmove is trivial. Anything touching the heap or a dynamic-sized
value is nontrivial.
I understand this is a somewhat ragged line cut through the space of
constant-ness, but I think it can be defended in a principled way: the
compiler does what compilers are good at -- primitives of various sorts,
read-only memory slabs and addresses -- and the libraries do the rest.
This does mean that sizeof, alignof and offsetof, applied to rust types,
remain "runtime" values, even though the compiler implements them as
intrinsics and they wind up as emitted / inlined constants. Again, I
_think_ the main reason we'd want to have these functions evaluated much
earlier -- i.e. "before types" -- has to do with C interop, and can be
handled by a syntax extension that returns literals calculated by clang,
but I could be wrong. Input welcome.
(I'll paste this into the relevant bug, #2317, momentarily)
-Graydon
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev