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 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 { pub fn empty_comptime_const_expr() ComptTimeConstValue {
return EmptyExpr{} return EmptyExpr{}
@ -8,14 +8,21 @@ pub fn empty_comptime_const_expr() ComptTimeConstValue {
pub fn (val ComptTimeConstValue) i64() ?i64 { pub fn (val ComptTimeConstValue) i64() ?i64 {
match val { match val {
i64, byte { byte {
return i64(val)
}
i64 {
return i64(val) return i64(val)
} }
f64 { f64 {
if -9223372036854775808.0 <= val && val <= 9223372036854775807.0 { if -9223372036854775808.0 <= val && val <= 9223372036854775807.0 {
return i64(val) return i64(val)
} }
return none }
u64 {
if val <= 9223372036854775807 {
return i64(val)
}
} }
string { string {
return val.i64() return val.i64()
@ -23,26 +30,27 @@ pub fn (val ComptTimeConstValue) i64() ?i64 {
rune { rune {
return int(val) return int(val)
} }
EmptyExpr { EmptyExpr {}
return none
}
} }
return none return none
} }
pub fn (val ComptTimeConstValue) int() ?int { pub fn (val ComptTimeConstValue) int() ?int {
match val { match val {
u64 {
if val <= 2147483647 {
return int(val)
}
}
f64 { f64 {
if -2147483648.0 <= val && val <= 2147483647.0 { if -2147483648.0 <= val && val <= 2147483647.0 {
return int(val) return int(val)
} }
return none
} }
i64 { i64 {
if -2147483648 <= val && val <= 2147483647 { if -2147483648 <= val && val <= 2147483647 {
return int(val) return int(val)
} }
return none
} }
byte { byte {
return int(val) return int(val)
@ -50,52 +58,83 @@ pub fn (val ComptTimeConstValue) int() ?int {
string { string {
return val.int() return val.int()
} }
rune { rune, EmptyExpr {}
return none
}
EmptyExpr {
return none
}
} }
return none return none
} }
pub fn (val ComptTimeConstValue) string() ?string { pub fn (val ComptTimeConstValue) string() ?string {
match val { 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() return val.str()
} }
string { string {
return val return val
} }
rune { EmptyExpr {}
return val.str()
}
EmptyExpr {
return none
}
} }
return none return none
} }
pub fn (val ComptTimeConstValue) f64() ?f64 { pub fn (val ComptTimeConstValue) f64() ?f64 {
match val { match val {
i64 {
return f64(val)
}
u64 {
return f64(val)
}
byte {
return f64(val)
}
f64 { f64 {
return val return val
} }
i64, byte {
return f64(val)
}
string { string {
return val.f64() return val.f64()
} }
rune { rune {}
return none EmptyExpr {}
} }
EmptyExpr {
return none return none
}
pub fn (val ComptTimeConstValue) u64() ?u64 {
match val {
i64 {
if val >= 0 {
return u64(val)
} }
} }
u64 {
return val
}
byte {
return u64(val)
}
f64 {
if val <= 18446744073709551615.0 {
return u64(val)
}
}
string {
return val.u64()
}
rune {}
EmptyExpr {}
}
return none return none
} }
@ -104,35 +143,34 @@ pub fn (val ComptTimeConstValue) byte() ?byte {
byte { byte {
return val return val
} }
u64 {
if val <= 255 {
return byte(val)
}
}
f64 { f64 {
if 0 <= val && val <= 255 { if 0 <= val && val <= 255 {
return byte(val) return byte(val)
} }
return none
} }
i64 { i64 {
if 0 <= val && val <= 255 { if 0 <= val && val <= 255 {
return byte(val) return byte(val)
} }
return none
} }
string { string {
x := val.int() x := val.int()
if 0 <= x && x <= 255 { if 0 <= x && x <= 255 {
return byte(x) return byte(x)
} }
return none
} }
rune { rune {
x := u32(val) x := u32(val)
if 0 <= x && x <= 255 { if 0 <= x && x <= 255 {
return byte(x) return byte(x)
} }
return none
}
EmptyExpr {
return none
} }
EmptyExpr {}
} }
return none 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 { for i, mut field in node.fields {
c.const_decl = field.name c.const_decl = field.name
c.const_deps << 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) { if ct_value := eval_comptime_const_expr(field.expr, 0) {
field.comptime_expr_value = ct_value field.comptime_expr_value = ct_value
if ct_value is u64 {
typ = ast.u64_type
}
} }
node.fields[i].typ = c.table.mktyp(typ) node.fields[i].typ = c.table.mktyp(typ)
for cd in c.const_deps { 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 // protect against a too deep comptime eval recursion
return none return none
} }
x := expr
match expr { match expr {
ast.IntegerLiteral { ast.IntegerLiteral {
x := expr.val.u64()
if x > 9223372036854775807 {
return x
}
return expr.val.i64() return expr.val.i64()
} }
ast.StringLiteral { ast.StringLiteral {
return expr.val 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 { ast.CastExpr {
cast_expr_value := eval_comptime_const_expr(expr.expr, nlevel + 1) or { return none } cast_expr_value := eval_comptime_const_expr(expr.expr, nlevel + 1) or { return none }
if expr.typ == ast.byte_type { if expr.typ == ast.byte_type {
return cast_expr_value.byte() or { return none } return cast_expr_value.byte() or { return none }
} }
if expr.typ == ast.int_type { if expr.typ == ast.int_type {
match cast_expr_value { return i64(cast_expr_value.int() or { return none })
byte {
eprintln('>>>>>>> byte cast_expr_value: $cast_expr_value | x: $x')
return i64(cast_expr_value)
} }
i64 { if expr.typ == ast.u64_type {
eprintln('>>>>>>> i64 cast_expr_value: $cast_expr_value | x: $x') return cast_expr_value.u64() or { return none }
if int_min <= cast_expr_value && cast_expr_value <= int_max {
return i64(cast_expr_value)
}
}
else {}
}
return none
} }
} }
ast.InfixExpr { ast.InfixExpr {
@ -49,6 +55,20 @@ fn eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.ComptTimeConstValue
return none 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 { } else if left is i64 && right is i64 {
match expr.op { match expr.op {
.plus { return left + right } .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 { else {
// eprintln('>>> nlevel: $nlevel | another $expr.type_name() | $expr ') // eprintln('>>> nlevel: $nlevel | another $expr.type_name() | $expr ')
return none 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 { fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.ComptTimeConstValue, typ ast.Type) bool {
mut styp := g.typ(typ) mut styp := g.typ(typ)
cname := '_const_$name' cname := '_const_$name'
// eprintln('>> cname: $cname | styp: $styp | $ct_value.type_name() | $ct_value')
match ct_value { match ct_value {
byte { byte {
g.const_decl_write_precomputed(styp, cname, ct_value.str()) g.const_decl_write_precomputed(styp, cname, ct_value.str())
} }
rune { 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 { 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()) g.const_decl_write_precomputed(styp, cname, ct_value.str())
} }
u64 {
g.const_decl_write_precomputed(styp, cname, ct_value.str() + 'U')
}
f64 { f64 {
g.const_decl_write_precomputed(styp, cname, ct_value.str()) 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) { 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(24) // cmdsize
g.write32(addr) // entrypoint g.write32(addr) // entrypoint
g.write32(0) // initial_stacksize g.write32(0) // initial_stacksize
@ -242,7 +242,7 @@ pub fn (mut g Gen) generate_macho_object_header() {
g.write32(0x4) // alignment g.write32(0x4) // alignment
g.write32(0x160) // relocation offset g.write32(0x160) // relocation offset
g.write32(0x1) // # of relocations 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) g.write32(0)
g.write32(0) g.write32(0)