mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-21 14:55:24 +00:00
Fix sizeof(T) in typedesc templates called from generic type when clauses (#25374)
The `hasValuelessStatics` function in `semtypinst.nim` only checked for `tyStatic`, missing `tyTypeDesc(tyGenericParam)`. This caused `sizeof(T)` inside a typedesc template called from a generic type's `when` clause to error with "'sizeof' requires '.importc' types to be '.completeStruct'". The fix adds a check for `tyTypeDesc` wrapping `tyGenericParam`, recognizing it as an unresolved generic parameter that needs resolution before evaluation. Also documents the `completeStruct` pragma in the manual.
This commit is contained in:
@@ -103,7 +103,15 @@ errors.
|
||||
|
||||
## Compiler changes
|
||||
|
||||
- Fixed a bug where `sizeof(T)` inside a `typedesc` template called from a generic type's
|
||||
`when` clause would error with "'sizeof' requires '.importc' types to be '.completeStruct'".
|
||||
The issue was that `hasValuelessStatics` in `semtypinst.nim` didn't recognize
|
||||
`tyTypeDesc(tyGenericParam)` as an unresolved generic parameter.
|
||||
|
||||
## Tool changes
|
||||
|
||||
- Added `--stdinfile` flag to name of the file used when running program from stdin (defaults to `stdinfile.nim`)
|
||||
|
||||
## Documentation changes
|
||||
|
||||
- Added documentation for the `completeStruct` pragma in the manual.
|
||||
|
||||
@@ -249,13 +249,24 @@ proc hasValuelessStatics(n: PNode): bool =
|
||||
a
|
||||
proc doThing(_: MyThing)
|
||||
]#
|
||||
result = false
|
||||
if n.safeLen == 0 and n.kind != nkEmpty: # Some empty nodes can get in here
|
||||
n.typ == nil or n.typ.kind == tyStatic
|
||||
if n.typ == nil:
|
||||
result = true
|
||||
elif n.typ.kind == tyStatic:
|
||||
result = true
|
||||
elif n.typ.kind == tyTypeDesc:
|
||||
# Check if the base type is an unresolved generic parameter.
|
||||
# This handles cases where a template containing sizeof(T) is called
|
||||
# inside a generic object's when clause - the T needs to be resolved
|
||||
# before we can evaluate the condition.
|
||||
let base = n.typ.skipTypes({tyTypeDesc})
|
||||
if base.kind == tyGenericParam:
|
||||
result = true
|
||||
else:
|
||||
for x in n:
|
||||
if hasValuelessStatics(x):
|
||||
return true
|
||||
false
|
||||
|
||||
proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PType = nil): PNode =
|
||||
if n == nil: return
|
||||
|
||||
@@ -7981,6 +7981,35 @@ underlying C `struct`:c: in a `sizeof` expression:
|
||||
```
|
||||
|
||||
|
||||
CompleteStruct pragma
|
||||
---------------------
|
||||
The `completeStruct` pragma is a contract indicating that an `importc` type
|
||||
declaration contains all fields of the corresponding C type, allowing
|
||||
`sizeof`, `alignof`, and `offsetof` to be computed at compile-time.
|
||||
|
||||
By default, `importc` types are assumed to be incomplete (their size is
|
||||
unknown at compile-time). Use `completeStruct` when you need compile-time
|
||||
size information and can guarantee the Nim definition matches the C layout:
|
||||
|
||||
```Nim
|
||||
type
|
||||
InotifyEvent {.importc: "struct inotify_event", header: "<sys/inotify.h>",
|
||||
completeStruct.} = object
|
||||
wd: cint
|
||||
mask: uint32
|
||||
cookie: uint32
|
||||
len: uint32
|
||||
# All fields must match the C struct exactly
|
||||
```
|
||||
|
||||
If the Nim fields don't match the C struct, a static assertion will fail
|
||||
during C code generation.
|
||||
|
||||
Without `completeStruct`, attempting to use `sizeof` on an `importc` type
|
||||
at compile-time will error with "'sizeof' requires '.importc' types to be
|
||||
'.completeStruct'".
|
||||
|
||||
|
||||
Compile pragma
|
||||
--------------
|
||||
The `compile` pragma can be used to compile and link a C/C++ source file
|
||||
|
||||
34
tests/generic/tgeneric_typedesc_sizeof.nim
Normal file
34
tests/generic/tgeneric_typedesc_sizeof.nim
Normal file
@@ -0,0 +1,34 @@
|
||||
discard """
|
||||
output: '''
|
||||
42
|
||||
'''
|
||||
"""
|
||||
|
||||
# Regression test for semtypinst.nim hasValuelessStatics bug.
|
||||
#
|
||||
# Bug: hasValuelessStatics only checked for tyStatic, missing tyTypeDesc(tyGenericParam)
|
||||
# Fix: Added check for tyTypeDesc wrapping tyGenericParam in compiler/semtypinst.nim
|
||||
#
|
||||
# The bug triggers when:
|
||||
# 1. A generic type has a when clause calling a typedesc template with sizeof(T)
|
||||
# 2. A generic proc on that type is called, triggering instantiation
|
||||
# 3. The T in sizeof(T) becomes tyTypeDesc(tyGenericParam), which wasn't recognized as unresolved
|
||||
#
|
||||
# Error without fix: 'sizeof' requires '.importc' types to be '.completeStruct'
|
||||
|
||||
template isSmall(T: typedesc): bool =
|
||||
sizeof(T) <= 8
|
||||
|
||||
type Foo[T] = object
|
||||
when isSmall(T):
|
||||
a: T
|
||||
else:
|
||||
b: ptr T
|
||||
|
||||
proc bar[T](x: var Foo[T]) =
|
||||
discard
|
||||
|
||||
var x: Foo[int]
|
||||
x.a = 42
|
||||
x.bar()
|
||||
echo x.a
|
||||
Reference in New Issue
Block a user