From 3eb04e346c20d116198dbf05590d487e94cbacfe Mon Sep 17 00:00:00 2001 From: kbkpbot Date: Thu, 3 Jul 2025 03:29:16 +0800 Subject: [PATCH] cgen,checker: add `$if sizeof(T) == int_literal {` support (#24831) --- vlib/v/checker/comptime.v | 3 + vlib/v/checker/if.v | 55 ++++++++ vlib/v/gen/c/comptime.v | 36 +++++ .../tests/comptime/comptime_if_sizeof_test.v | 131 ++++++++++++++++++ 4 files changed, 225 insertions(+) create mode 100644 vlib/v/tests/comptime/comptime_if_sizeof_test.v diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 748c699ae8..43aad5175b 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -891,6 +891,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, pos token.Pos) ComptimeBr ComptimeBranchSkipState.skip } } + } else if cond.left is ast.SizeOf { } else { c.error('invalid `\$if` condition: ${cond.left.type_name()}', cond.pos) @@ -920,6 +921,8 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, pos token.Pos) ComptimeBr if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral && c.comptime.is_comptime_selector_field_name(cond.left, 'indirections') { return .unknown + } else if cond.left is ast.SizeOf { + return .unknown } c.error('invalid `\$if` condition', cond.pos) } diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index 6d16d9e07c..1c2be9e9c7 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -349,6 +349,61 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { } else {} } + } else if left is ast.SizeOf && right is ast.IntegerLiteral { + // TODO: support struct.fieldname + typ := c.unwrap_generic(left.typ) + if typ == 0 { + c.error('invalid `\$if` condition: expected a type', branch.cond.left.pos()) + } else { + s, _ := c.table.type_size(c.unwrap_generic(typ)) + skip_state = match branch.cond.op { + .gt { + if s > right.val.i64() { + ComptimeBranchSkipState.eval + } else { + ComptimeBranchSkipState.skip + } + } + .lt { + if s < right.val.i64() { + ComptimeBranchSkipState.eval + } else { + ComptimeBranchSkipState.skip + } + } + .ge { + if s >= right.val.i64() { + ComptimeBranchSkipState.eval + } else { + ComptimeBranchSkipState.skip + } + } + .le { + if s <= right.val.i64() { + ComptimeBranchSkipState.eval + } else { + ComptimeBranchSkipState.skip + } + } + .ne { + if s != right.val.i64() { + ComptimeBranchSkipState.eval + } else { + ComptimeBranchSkipState.skip + } + } + .eq { + if s == right.val.i64() { + ComptimeBranchSkipState.eval + } else { + ComptimeBranchSkipState.skip + } + } + else { + ComptimeBranchSkipState.skip + } + } + } } } } diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 560a4a4667..f8d0e4d7af 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -685,6 +685,23 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) { g.write(' ${cond.op} ') r, d2 := g.comptime_if_cond(cond.right, pkg_exist) return if cond.op == .eq { l == r } else { l != r }, d1 && d1 == d2 + } + if cond.left is ast.SizeOf && cond.left.typ != 0 + && cond.right is ast.IntegerLiteral { + // TODO: support struct.fieldname + s, _ := g.table.type_size(g.unwrap_generic(cond.left.typ)) + right := cond.right as ast.IntegerLiteral + is_true := match cond.op { + .eq { s == right.val.i64() } + .ne { s != right.val.i64() } + else { false } + } + if is_true { + g.write('1') + } else { + g.write('0') + } + return is_true, true } else { g.write('1') return true, true @@ -748,6 +765,25 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) { g.write('0') } return is_true, true + } + if cond.left is ast.SizeOf && cond.left.typ != 0 + && cond.right is ast.IntegerLiteral { + // TODO: support struct.fieldname + s, _ := g.table.type_size(g.unwrap_generic(cond.left.typ)) + right := cond.right as ast.IntegerLiteral + is_true := match cond.op { + .gt { s > right.val.i64() } + .lt { s < right.val.i64() } + .ge { s >= right.val.i64() } + .le { s <= right.val.i64() } + else { false } + } + if is_true { + g.write('1') + } else { + g.write('0') + } + return is_true, true } else { return true, false } diff --git a/vlib/v/tests/comptime/comptime_if_sizeof_test.v b/vlib/v/tests/comptime/comptime_if_sizeof_test.v new file mode 100644 index 0000000000..e390037dd7 --- /dev/null +++ b/vlib/v/tests/comptime/comptime_if_sizeof_test.v @@ -0,0 +1,131 @@ +struct MyStruct { + a u16 + b u8 + c u32 + d u64 +} + +fn test_comptime_if_sizeof() { + f[u16]() + g[MyStruct]() + + x := MyStruct{} + // TODO: support struct.fieldname + //$if sizeof(x.a) == 2 { + // assert true + //} $else { + // assert false + //} + // + //$if sizeof(x.d) != 2 { + // assert false + //} $else { + // assert true + //} +} + +fn f[T]() { + $if sizeof(T) == 2 { + assert true + } $else { + assert false + } + $if sizeof(T) != 2 { + assert false + } $else { + assert true + } + $if sizeof(T) < 1 { + assert false + } $else { + assert true + } + $if sizeof(T) < 3 { + assert true + } $else { + assert false + } + $if sizeof(T) > 1 { + assert true + } $else { + assert false + } + $if sizeof(T) > 2 { + assert false + } $else { + assert true + } + $if sizeof(T) <= 2 { + assert true + } $else { + assert false + } + $if sizeof(T) <= 1 { + assert false + } $else { + assert true + } + $if sizeof(T) >= 2 { + assert true + } $else { + assert false + } + $if sizeof(T) >= 3 { + assert false + } $else { + assert true + } +} + +fn g[T]() { + $if sizeof(T) == 16 { + assert true + } $else { + assert false + } + $if sizeof(T) != 16 { + assert false + } $else { + assert true + } + $if sizeof(T) < 17 { + assert true + } $else { + assert false + } + $if sizeof(T) < 15 { + assert false + } $else { + assert true + } + $if sizeof(T) > 15 { + assert true + } $else { + assert false + } + $if sizeof(T) > 16 { + assert false + } $else { + assert true + } + $if sizeof(T) <= 16 { + assert true + } $else { + assert false + } + $if sizeof(T) <= 15 { + assert false + } $else { + assert true + } + $if sizeof(T) >= 16 { + assert true + } $else { + assert false + } + $if sizeof(T) >= 17 { + assert false + } $else { + assert true + } +}