mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
Merge c5579c426c
into a8d200ac0e
This commit is contained in:
commit
ee38b34ec9
17 changed files with 143 additions and 13 deletions
|
@ -193,7 +193,7 @@ by using any of the following commands in a terminal:
|
|||
* [Trace](#trace)
|
||||
* [Memory-unsafe code](#memory-unsafe-code)
|
||||
* [Structs with reference fields](#structs-with-reference-fields)
|
||||
* [sizeof and __offsetof](#sizeof-and-__offsetof)
|
||||
* [sizeof, alignof and __offsetof](#sizeof-alignof-and-__offsetof)
|
||||
* [Limited operator overloading](#limited-operator-overloading)
|
||||
* [Performance tuning](#performance-tuning)
|
||||
* [Atomics](#atomics)
|
||||
|
@ -6980,9 +6980,10 @@ println(baz)
|
|||
println(qux)
|
||||
```
|
||||
|
||||
## sizeof and __offsetof
|
||||
## sizeof, alignof and __offsetof
|
||||
|
||||
* `sizeof(Type)` gives the size of a type in bytes.
|
||||
* `alignof(Type)` gives the alignment of a type in bytes.
|
||||
* `__offsetof(Struct, field_name)` gives the offset in bytes of a struct field.
|
||||
|
||||
```v
|
||||
|
@ -6992,6 +6993,7 @@ struct Foo {
|
|||
}
|
||||
|
||||
assert sizeof(Foo) == 8
|
||||
assert alignof[Foo]() == 4
|
||||
assert __offsetof(Foo, a) == 0
|
||||
assert __offsetof(Foo, b) == 4
|
||||
```
|
||||
|
|
|
@ -33,6 +33,7 @@ pub const int_type_name = $if new_int ? {
|
|||
}
|
||||
|
||||
pub type Expr = NodeError
|
||||
| AlignOf
|
||||
| AnonFn
|
||||
| ArrayDecompose
|
||||
| ArrayInit
|
||||
|
@ -1956,6 +1957,16 @@ pub mut:
|
|||
scope &Scope = unsafe { nil }
|
||||
}
|
||||
|
||||
pub struct AlignOf {
|
||||
pub:
|
||||
guessed_type bool // a legacy `alignof( GuessedType )` => a deprecation notice, suggesting `v fmt -w .` => `alignof[ Type ]()`
|
||||
is_type bool
|
||||
pos token.Pos
|
||||
pub mut:
|
||||
expr Expr // checker uses this to set typ, when !is_type
|
||||
typ Type
|
||||
}
|
||||
|
||||
pub struct SizeOf {
|
||||
pub:
|
||||
guessed_type bool // a legacy `sizeof( GuessedType )` => a deprecation notice, suggesting `v fmt -w .` => `sizeof[ Type ]()`
|
||||
|
@ -2275,11 +2286,11 @@ pub fn (expr Expr) pos() token.Pos {
|
|||
// println('compiler bug, unhandled EmptyExpr pos()')
|
||||
token.Pos{}
|
||||
}
|
||||
NodeError, ArrayDecompose, ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr,
|
||||
CastExpr, ChanInit, CharLiteral, ConcatExpr, Comment, ComptimeCall, ComptimeSelector,
|
||||
EnumVal, DumpExpr, FloatLiteral, GoExpr, SpawnExpr, Ident, IfExpr, IntegerLiteral,
|
||||
IsRefType, Likely, LockExpr, MapInit, MatchExpr, None, OffsetOf, OrExpr, ParExpr,
|
||||
PostfixExpr, PrefixExpr, RangeExpr, SelectExpr, SelectorExpr, SizeOf, SqlExpr,
|
||||
NodeError, AlignOf, ArrayDecompose, ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral,
|
||||
CallExpr, CastExpr, ChanInit, CharLiteral, ConcatExpr, Comment, ComptimeCall,
|
||||
ComptimeSelector, EnumVal, DumpExpr, FloatLiteral, GoExpr, SpawnExpr, Ident, IfExpr,
|
||||
IntegerLiteral, IsRefType, Likely, LockExpr, MapInit, MatchExpr, None, OffsetOf, OrExpr,
|
||||
ParExpr, PostfixExpr, PrefixExpr, RangeExpr, SelectExpr, SelectorExpr, SizeOf, SqlExpr,
|
||||
StringInterLiteral, StringLiteral, StructInit, TypeNode, TypeOf, UnsafeExpr, ComptimeType,
|
||||
LambdaExpr, Nil {
|
||||
expr.pos
|
||||
|
@ -2817,7 +2828,7 @@ pub fn (expr Expr) is_literal() bool {
|
|||
!expr.has_arg && expr.expr.is_literal() && (expr.typ.is_any_kind_of_pointer()
|
||||
|| expr.typ in [i8_type, i16_type, int_type, i64_type, u8_type, u16_type, u32_type, u64_type, f32_type, f64_type, char_type, bool_type, rune_type])
|
||||
}
|
||||
SizeOf, IsRefType {
|
||||
AlignOf, SizeOf, IsRefType {
|
||||
expr.is_type || expr.expr.is_literal()
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -413,6 +413,12 @@ pub fn (x Expr) str() string {
|
|||
stdatomic.sub_i64(&nested_expr_str_calls, 1)
|
||||
}
|
||||
match x {
|
||||
AlignOf {
|
||||
if x.is_type {
|
||||
return 'alignof(${global_table.type_to_str(x.typ)})'
|
||||
}
|
||||
return 'alignof(${x.expr.str()})'
|
||||
}
|
||||
AnonFn {
|
||||
return 'anon_fn'
|
||||
}
|
||||
|
|
|
@ -1310,6 +1310,13 @@ pub fn (t &Table) type_size(typ Type) (int, int) {
|
|||
return size, align
|
||||
}
|
||||
|
||||
// type_align returns the alignment (in bytes) of `typ`, just like C's alignof().
|
||||
pub fn (t &Table) type_align(typ Type) int {
|
||||
// we only care about the second (alignment) return value
|
||||
_, align := t.type_size(typ)
|
||||
return align
|
||||
}
|
||||
|
||||
// round_up rounds the number `n` up to the next multiple `multiple`.
|
||||
// Note: `multiple` must be a power of 2.
|
||||
@[inline]
|
||||
|
|
|
@ -3288,7 +3288,7 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type {
|
|||
}
|
||||
return ret_type
|
||||
}
|
||||
ast.SizeOf {
|
||||
ast.AlignOf, ast.SizeOf {
|
||||
if !node.is_type {
|
||||
node.typ = c.expr(mut node.expr)
|
||||
}
|
||||
|
|
|
@ -435,6 +435,10 @@ fn (mut c Checker) eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.Comp
|
|||
return val
|
||||
}
|
||||
}
|
||||
ast.AlignOf {
|
||||
a := c.table.type_align(expr.typ)
|
||||
return i64(a)
|
||||
}
|
||||
ast.SizeOf {
|
||||
s, _ := c.table.type_size(c.unwrap_generic(expr.typ))
|
||||
return i64(s)
|
||||
|
|
|
@ -491,6 +491,9 @@ pub fn (mut e Eval) expr(expr ast.Expr, expecting ast.Type) Object {
|
|||
// eprintln('unhandled struct init at line $expr.pos.line_nr')
|
||||
return ''
|
||||
}
|
||||
ast.AlignOf {
|
||||
return Uint{e.type_to_align(expr.typ), 64}
|
||||
}
|
||||
ast.SizeOf {
|
||||
return Uint{e.type_to_size(expr.typ), 64}
|
||||
}
|
||||
|
@ -635,6 +638,12 @@ fn (e &Eval) type_to_size(typ ast.Type) u64 {
|
|||
}
|
||||
}
|
||||
|
||||
// type_to_align returns the natural alignment (in bits) of `typ`.
|
||||
fn (e &Eval) type_to_align(typ ast.Type) u64 {
|
||||
// on most ABIs the alignment of a type == its size
|
||||
return e.type_to_size(typ)
|
||||
}
|
||||
|
||||
fn (e &Eval) get_escape(r rune) rune {
|
||||
res := match r {
|
||||
`\\` {
|
||||
|
|
|
@ -572,6 +572,9 @@ pub fn (mut f Fmt) expr(node_ ast.Expr) {
|
|||
match mut node {
|
||||
ast.NodeError {}
|
||||
ast.EmptyExpr {}
|
||||
ast.AlignOf {
|
||||
f.align_of(node)
|
||||
}
|
||||
ast.AnonFn {
|
||||
f.anon_fn(node)
|
||||
}
|
||||
|
@ -2996,6 +2999,20 @@ pub fn (mut f Fmt) selector_expr(node ast.SelectorExpr) {
|
|||
f.or_expr(node.or_block)
|
||||
}
|
||||
|
||||
pub fn (mut f Fmt) align_of(node ast.AlignOf) {
|
||||
f.write('alignof')
|
||||
if node.is_type {
|
||||
f.write('[')
|
||||
f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias))
|
||||
f.write(']()')
|
||||
return
|
||||
} else {
|
||||
f.write('(')
|
||||
f.expr(node.expr)
|
||||
f.write(')')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut f Fmt) size_of(node ast.SizeOf) {
|
||||
f.write('sizeof')
|
||||
if node.is_type && !node.guessed_type {
|
||||
|
|
|
@ -3624,6 +3624,9 @@ fn (mut g Gen) expr(node_ ast.Expr) {
|
|||
ast.EmptyExpr {
|
||||
g.error('g.expr(): unhandled EmptyExpr', token.Pos{})
|
||||
}
|
||||
ast.AlignOf {
|
||||
g.align_of(node)
|
||||
}
|
||||
ast.AnonFn {
|
||||
g.gen_anon_fn(mut node)
|
||||
}
|
||||
|
@ -7738,6 +7741,17 @@ fn (mut g Gen) get_type(typ ast.Type) ast.Type {
|
|||
return if typ == g.field_data_type { g.comptime.comptime_for_field_value.typ } else { typ }
|
||||
}
|
||||
|
||||
fn (mut g Gen) align_of(node ast.AlignOf) {
|
||||
typ := g.type_resolver.typeof_type(node.expr, g.get_type(node.typ))
|
||||
node_typ := g.unwrap_generic(typ)
|
||||
sym := g.table.sym(node_typ)
|
||||
if sym.language == .v && sym.kind in [.placeholder, .any] {
|
||||
g.error('unknown type `${sym.name}`', node.pos)
|
||||
}
|
||||
styp := g.styp(node_typ)
|
||||
g.write('alignof(${util.no_dots(styp)})')
|
||||
}
|
||||
|
||||
fn (mut g Gen) size_of(node ast.SizeOf) {
|
||||
typ := g.type_resolver.typeof_type(node.expr, g.get_type(node.typ))
|
||||
node_typ := g.unwrap_generic(typ)
|
||||
|
|
|
@ -339,6 +339,7 @@ typedef int (*qsort_callback_func)(const void*, const void*);
|
|||
#include <string.h>
|
||||
|
||||
#include <stdarg.h> // for va_list
|
||||
#include <stdalign.h> // for alignof
|
||||
|
||||
#ifdef __TERMUX__
|
||||
#if defined __BIONIC_AVAILABILITY_GUARD && __BIONIC_AVAILABILITY_GUARD(28)
|
||||
|
|
|
@ -633,6 +633,9 @@ pub fn (mut f Gen) expr(node_ ast.Expr) {
|
|||
ast.SelectorExpr {
|
||||
f.selector_expr(node)
|
||||
}
|
||||
ast.AlignOf {
|
||||
f.align_of(node)
|
||||
}
|
||||
ast.SizeOf {
|
||||
f.size_of(node)
|
||||
}
|
||||
|
@ -2147,6 +2150,16 @@ pub fn (mut f Gen) selector_expr(node ast.SelectorExpr) {
|
|||
f.write(node.field_name)
|
||||
}
|
||||
|
||||
pub fn (mut f Gen) align_of(node ast.AlignOf) {
|
||||
f.write('alignof(')
|
||||
if node.is_type {
|
||||
f.write(f.table.type_to_str_using_aliases(node.typ, f.mod2alias))
|
||||
} else {
|
||||
f.expr(node.expr)
|
||||
}
|
||||
f.write(')')
|
||||
}
|
||||
|
||||
pub fn (mut f Gen) size_of(node ast.SizeOf) {
|
||||
f.write('sizeof(')
|
||||
if node.is_type {
|
||||
|
|
|
@ -1032,7 +1032,7 @@ fn (mut g JsGen) expr(node_ ast.Expr) {
|
|||
ast.SelectorExpr {
|
||||
g.gen_selector_expr(node)
|
||||
}
|
||||
ast.SizeOf, ast.IsRefType {
|
||||
ast.AlignOf, ast.SizeOf, ast.IsRefType {
|
||||
// TODO
|
||||
}
|
||||
ast.OffsetOf {
|
||||
|
|
|
@ -782,7 +782,7 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
|||
w.expr(node.high)
|
||||
}
|
||||
}
|
||||
ast.SizeOf, ast.IsRefType {
|
||||
ast.AlignOf, ast.SizeOf, ast.IsRefType {
|
||||
w.expr(node.expr)
|
||||
w.mark_by_type(node.typ)
|
||||
}
|
||||
|
|
|
@ -332,8 +332,9 @@ fn (mut p Parser) check_expr(precedence int) !ast.Expr {
|
|||
}
|
||||
}
|
||||
}
|
||||
.key_sizeof, .key_isreftype {
|
||||
.key_alignof, .key_sizeof, .key_isreftype {
|
||||
is_reftype := p.tok.kind == .key_isreftype
|
||||
is_alignof := p.tok.kind == .key_alignof
|
||||
p.next() // sizeof
|
||||
|
||||
if p.tok.kind == .lsbr {
|
||||
|
@ -351,6 +352,12 @@ fn (mut p Parser) check_expr(precedence int) !ast.Expr {
|
|||
typ: typ
|
||||
pos: type_pos
|
||||
}
|
||||
} else if is_alignof {
|
||||
node = ast.AlignOf{
|
||||
is_type: true
|
||||
typ: typ
|
||||
pos: type_pos
|
||||
}
|
||||
} else {
|
||||
node = ast.SizeOf{
|
||||
is_type: true
|
||||
|
@ -381,6 +388,12 @@ fn (mut p Parser) check_expr(precedence int) !ast.Expr {
|
|||
expr: expr
|
||||
pos: pos
|
||||
}
|
||||
} else if is_alignof {
|
||||
node = ast.AlignOf{
|
||||
is_type: false
|
||||
expr: expr
|
||||
pos: pos
|
||||
}
|
||||
} else {
|
||||
node = ast.SizeOf{
|
||||
is_type: false
|
||||
|
@ -403,6 +416,13 @@ fn (mut p Parser) check_expr(precedence int) !ast.Expr {
|
|||
typ: arg_type
|
||||
pos: pos
|
||||
}
|
||||
} else if is_alignof {
|
||||
node = ast.AlignOf{
|
||||
guessed_type: true
|
||||
is_type: true
|
||||
typ: arg_type
|
||||
pos: pos
|
||||
}
|
||||
} else {
|
||||
node = ast.SizeOf{
|
||||
guessed_type: true
|
||||
|
|
|
@ -2670,7 +2670,7 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
|
|||
ast.FloatLiteral {
|
||||
typ = ast.f64_type
|
||||
}
|
||||
ast.IntegerLiteral, ast.SizeOf {
|
||||
ast.AlignOf, ast.IntegerLiteral, ast.SizeOf {
|
||||
typ = ast.int_type
|
||||
}
|
||||
ast.StringLiteral, ast.StringInterLiteral {
|
||||
|
|
23
vlib/v/tests/alignof_test.v
Normal file
23
vlib/v/tests/alignof_test.v
Normal file
|
@ -0,0 +1,23 @@
|
|||
struct S1 {
|
||||
p voidptr
|
||||
}
|
||||
|
||||
struct S2 {
|
||||
i int
|
||||
}
|
||||
|
||||
fn test_alignof() {
|
||||
assert alignof[rune]() == 4
|
||||
assert alignof[[44]u8]() == 1
|
||||
assert alignof(`€`) == 4
|
||||
// depends on -m32/64
|
||||
assert alignof[S1]() in [u32(4), 8]
|
||||
s := S2{}
|
||||
assert alignof(s.i) == 4
|
||||
|
||||
assert alignof('hello') == $if x64 {
|
||||
8
|
||||
} $else {
|
||||
4
|
||||
}
|
||||
}
|
|
@ -121,6 +121,7 @@ pub enum Kind {
|
|||
key_select
|
||||
key_like
|
||||
key_ilike
|
||||
key_alignof
|
||||
key_sizeof
|
||||
key_isreftype
|
||||
key_likely
|
||||
|
@ -305,6 +306,7 @@ fn build_token_str() []string {
|
|||
s[Kind.key_asm] = 'asm'
|
||||
s[Kind.key_return] = 'return'
|
||||
s[Kind.key_module] = 'module'
|
||||
s[Kind.key_alignof] = 'alignof'
|
||||
s[Kind.key_sizeof] = 'sizeof'
|
||||
s[Kind.key_isreftype] = 'isreftype'
|
||||
s[Kind.key_likely] = '_likely_'
|
||||
|
@ -657,6 +659,7 @@ pub fn kind_to_string(k Kind) string {
|
|||
.key_select { 'key_select' }
|
||||
.key_like { 'key_like' }
|
||||
.key_ilike { 'key_ilike' }
|
||||
.key_alignof { 'key_alignof' }
|
||||
.key_sizeof { 'key_sizeof' }
|
||||
.key_isreftype { 'key_isreftype' }
|
||||
.key_likely { 'key_likely' }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue