strconv,checker,cgen: fix -cstrict compilation of hello_world.v

pull/10858/head
Delyan Angelov 2021-07-18 22:59:52 +03:00
parent 48546d0f45
commit 241a7b760d
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
5 changed files with 136 additions and 61 deletions

View File

@ -1,6 +1,6 @@
module ast
pub type ComptTimeConstValue = EmptyExpr | byte | f64 | i64 | rune | string
pub type ComptTimeConstValue = EmptyExpr | byte | f64 | i64 | rune | string | u64
pub fn empty_comptime_const_expr() ComptTimeConstValue {
return EmptyExpr{}
@ -8,14 +8,21 @@ pub fn empty_comptime_const_expr() ComptTimeConstValue {
pub fn (val ComptTimeConstValue) i64() ?i64 {
match val {
i64, byte {
byte {
return i64(val)
}
i64 {
return i64(val)
}
f64 {
if -9223372036854775808.0 <= val && val <= 9223372036854775807.0 {
return i64(val)
}
return none
}
u64 {
if val <= 9223372036854775807 {
return i64(val)
}
}
string {
return val.i64()
@ -23,26 +30,27 @@ pub fn (val ComptTimeConstValue) i64() ?i64 {
rune {
return int(val)
}
EmptyExpr {
return none
}
EmptyExpr {}
}
return none
}
pub fn (val ComptTimeConstValue) int() ?int {
match val {
u64 {
if val <= 2147483647 {
return int(val)
}
}
f64 {
if -2147483648.0 <= val && val <= 2147483647.0 {
return int(val)
}
return none
}
i64 {
if -2147483648 <= val && val <= 2147483647 {
return int(val)
}
return none
}
byte {
return int(val)
@ -50,51 +58,82 @@ pub fn (val ComptTimeConstValue) int() ?int {
string {
return val.int()
}
rune {
return none
}
EmptyExpr {
return none
}
rune, EmptyExpr {}
}
return none
}
pub fn (val ComptTimeConstValue) string() ?string {
match val {
i64, f64, byte {
u64 {
return val.str()
}
i64 {
return val.str()
}
f64 {
return val.str()
}
byte {
return val.str()
}
rune {
return val.str()
}
string {
return val
}
rune {
return val.str()
}
EmptyExpr {
return none
}
EmptyExpr {}
}
return none
}
pub fn (val ComptTimeConstValue) f64() ?f64 {
match val {
i64 {
return f64(val)
}
u64 {
return f64(val)
}
byte {
return f64(val)
}
f64 {
return val
}
i64, byte {
return f64(val)
}
string {
return val.f64()
}
rune {
return none
rune {}
EmptyExpr {}
}
return none
}
pub fn (val ComptTimeConstValue) u64() ?u64 {
match val {
i64 {
if val >= 0 {
return u64(val)
}
}
EmptyExpr {
return none
u64 {
return val
}
byte {
return u64(val)
}
f64 {
if val <= 18446744073709551615.0 {
return u64(val)
}
}
string {
return val.u64()
}
rune {}
EmptyExpr {}
}
return none
}
@ -104,35 +143,34 @@ pub fn (val ComptTimeConstValue) byte() ?byte {
byte {
return val
}
u64 {
if val <= 255 {
return byte(val)
}
}
f64 {
if 0 <= val && val <= 255 {
return byte(val)
}
return none
}
i64 {
if 0 <= val && val <= 255 {
return byte(val)
}
return none
}
string {
x := val.int()
if 0 <= x && x <= 255 {
return byte(x)
}
return none
}
rune {
x := u32(val)
if 0 <= x && x <= 255 {
return byte(x)
}
return none
}
EmptyExpr {
return none
}
EmptyExpr {}
}
return none
}

View File

@ -3611,9 +3611,12 @@ pub fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
for i, mut field in node.fields {
c.const_decl = field.name
c.const_deps << field.name
typ := c.check_expr_opt_call(field.expr, c.expr(field.expr))
mut typ := c.check_expr_opt_call(field.expr, c.expr(field.expr))
if ct_value := eval_comptime_const_expr(field.expr, 0) {
field.comptime_expr_value = ct_value
if ct_value is u64 {
typ = ast.u64_type
}
}
node.fields[i].typ = c.table.mktyp(typ)
for cd in c.const_deps {

View File

@ -7,34 +7,40 @@ fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue
// protect against a too deep comptime eval recursion
return none
}
x := expr
match expr {
ast.IntegerLiteral {
x := expr.val.u64()
if x > 9223372036854775807 {
return x
}
return expr.val.i64()
}
ast.StringLiteral {
return expr.val
}
ast.CharLiteral {
runes := expr.val.runes()
if runes.len > 0 {
return runes[0]
}
return none
}
ast.Ident {
if expr.obj is ast.ConstField {
// an existing constant?
return eval_comptime_const_expr(expr.obj.expr, nlevel + 1)
}
}
ast.CastExpr {
cast_expr_value := eval_comptime_const_expr(expr.expr, nlevel + 1) or { return none }
if expr.typ == ast.byte_type {
return cast_expr_value.byte() or { return none }
}
if expr.typ == ast.int_type {
match cast_expr_value {
byte {
eprintln('>>>>>>> byte cast_expr_value: $cast_expr_value | x: $x')
return i64(cast_expr_value)
}
i64 {
eprintln('>>>>>>> i64 cast_expr_value: $cast_expr_value | x: $x')
if int_min <= cast_expr_value && cast_expr_value <= int_max {
return i64(cast_expr_value)
}
}
else {}
}
return none
return i64(cast_expr_value.int() or { return none })
}
if expr.typ == ast.u64_type {
return cast_expr_value.u64() or { return none }
}
}
ast.InfixExpr {
@ -49,6 +55,20 @@ fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue
return none
}
}
} else if left is u64 && right is u64 {
match expr.op {
.plus { return left + right }
.minus { return left - right }
.mul { return left * right }
.div { return left / right }
.mod { return left % right }
.xor { return left ^ right }
.pipe { return left | right }
.amp { return left & right }
.left_shift { return left << right }
.right_shift { return left >> right }
else { return none }
}
} else if left is i64 && right is i64 {
match expr.op {
.plus { return left + right }
@ -79,12 +99,6 @@ fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue
}
}
}
ast.Ident {
if expr.obj is ast.ConstField {
// an existing constant?
return eval_comptime_const_expr(expr.obj.expr, nlevel + 1)
}
}
else {
// eprintln('>>> nlevel: $nlevel | another $expr.type_name() | $expr ')
return none

View File

@ -4917,17 +4917,37 @@ fn is_simple_define_const(obj ast.ScopeObject) bool {
fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.ComptTimeConstValue, typ ast.Type) bool {
mut styp := g.typ(typ)
cname := '_const_$name'
// eprintln('>> cname: $cname | styp: $styp | $ct_value.type_name() | $ct_value')
match ct_value {
byte {
g.const_decl_write_precomputed(styp, cname, ct_value.str())
}
rune {
g.const_decl_write_precomputed(styp, cname, ct_value.str())
rune_code := u32(ct_value)
if rune_code <= 255 {
if rune_code in [`"`, `\\`, `\'`] {
return false
}
escval := util.smart_quote(byte(rune_code).ascii_str(), false)
g.const_decl_write_precomputed(styp, cname, "'$escval'")
} else {
g.const_decl_write_precomputed(styp, cname, u32(ct_value).str())
}
}
i64 {
if typ == ast.int_type {
// TODO: use g.const_decl_write_precomputed here too.
// For now, use #define macros, so existing code compiles
// with -cstrict. Add checker errors for overflows instead,
// so V can catch them earlier, instead of relying on the
// C compiler for that.
g.const_decl_simple_define(name, ct_value.str())
return true
}
g.const_decl_write_precomputed(styp, cname, ct_value.str())
}
u64 {
g.const_decl_write_precomputed(styp, cname, ct_value.str() + 'U')
}
f64 {
g.const_decl_write_precomputed(styp, cname, ct_value.str())
}

View File

@ -174,7 +174,7 @@ fn (mut g Gen) macho_dylibs() {
}
fn (mut g Gen) macho_main(addr int) {
g.write32(native.lc_main) // LC_MAIN
g.write32(int(native.lc_main)) // LC_MAIN
g.write32(24) // cmdsize
g.write32(addr) // entrypoint
g.write32(0) // initial_stacksize
@ -242,7 +242,7 @@ pub fn (mut g Gen) generate_macho_object_header() {
g.write32(0x4) // alignment
g.write32(0x160) // relocation offset
g.write32(0x1) // # of relocations
g.write32(native.s_attr_some_instructions | native.s_attr_pure_instructions)
g.write32(int(native.s_attr_some_instructions | native.s_attr_pure_instructions))
g.write32(0)
g.write32(0)
g.write32(0)