fixes #25459; hashType returns different hash from instantiated generics with distinct types (#25471)

`hashType` proc returned the same hash value from different instanced
generics types like `D[int64]` and `D[F]`.
That caused the struct type with wrong field types.

object/tuple type size check code is generated when it is compiled with
`-d:checkAbi` option.
This commit is contained in:
Tomohiro
2026-02-01 15:01:55 +09:00
committed by GitHub
parent abf434a336
commit 88e7adfcb7
7 changed files with 69 additions and 3 deletions

View File

@@ -294,7 +294,12 @@ proc cacheGetType(tab: TypeCache; sig: SigHash): Rope =
result = tab.getOrDefault(sig)
proc addAbiCheck(m: BModule; t: PType, name: Rope) =
if isDefined(m.config, "checkAbi") and (let size = getSize(m.config, t); size != szUnknownSize):
if isDefined(m.config, "checkAbi") and (let size = getSize(m.config, t); size != szUnknownSize) and
not (t.kind == tyObject and searchTypeFor(t, proc (t: PType): bool {.nimcall.} = t.kind == tyUncheckedArray)):
# `UncheckedArray`, not `ptr UncheckedArray` type field in object types is a flexible array.
# `sizeof` in C and Nim doesn't always return the same value for object types containing it.
# making `getSize` in Nim always returns the same value as `sizeof` in C from flexible arrays seems hard.
# See `SEQ_DECL_SIZE` in lib/nimbase.h
var msg = "backend & Nim disagree on size for: "
msg.addTypeHeader(m.config, t)
var msg2 = ""
@@ -1067,6 +1072,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
else: getTupleDesc(m, t, result, check)
if not isImportedType(t):
m.s[cfsTypes].add(recdesc)
addAbiCheck(m, t, result)
elif tfIncompleteStruct notin t.flags:
discard # addAbiCheck(m, t, result) # already handled elsewhere
of tySet:

View File

@@ -154,7 +154,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]; conf: Confi
assert inst.kind == tyGenericInst
c.hashType inst.genericHead, flags, conf
for _, a in inst.genericInstParams:
c.hashType a, flags, conf
c.hashType a, flags+{CoDistinct}, conf
t.typeInstImpl = inst
return
c &= char(t.kind)

View File

@@ -143,7 +143,7 @@ proc getFloatValue*(n: PNode): BiggestFloat =
proc addTypeHeader*(result: var string, conf: ConfigRef; typ: PType; prefer: TPreferedDesc = preferMixed; getDeclarationPath = true) =
result.add typeToString(typ, prefer)
if getDeclarationPath: result.addDeclaredLoc(conf, typ.sym)
if getDeclarationPath and typ.sym != nil: result.addDeclaredLoc(conf, typ.sym)
proc getProcHeader*(conf: ConfigRef; sym: PSym; prefer: TPreferedDesc = preferName; getDeclarationPath = true): string =
assert sym != nil

View File

@@ -0,0 +1,11 @@
proc v[T](_: typedesc[T]): int =
if T is int64: 6 else: 4
type
D*[T] = object
c*: seq[T]
k*: array[v(T), int]
F = distinct int64
W* = object
y: D[F]
j*: D[int64]

View File

@@ -0,0 +1,8 @@
import ./g
export g
proc a*(): W =
var e = D[int64]()
e.c.setLen(8)
e.k[1] = 0
result = W(j: e)

10
tests/ccgbugs2/t25459.nim Normal file
View File

@@ -0,0 +1,10 @@
discard """
targets: "c cpp"
matrix: "-d:checkAbi"
"""
import ./m25459/h
for _ in 0 ..< 500:
let u = new W
u[] = a()

View File

@@ -0,0 +1,31 @@
discard """
targets: "c cpp"
matrix: "-d:checkAbi"
"""
proc v[T](_: typedesc[T]): int =
if T is int64: 2 else: 1
type
D[T] = object
k: array[v(T), int]
E[T] = object
k: array[v(T), int]
F = distinct int64
W = object
a: D[int64]
b: D[F]
proc csizeof[T](x {.bycopy.} : T): cint {.importc: "sizeof", nodecl.}
var w: W
assert sizeof(w) == csizeof(w)
var
e0: E[F]
e1: E[int64]
assert sizeof(e0) == csizeof(e0)
assert sizeof(e1) == csizeof(e1)
var tup: (E[F], E[int64])
assert sizeof(tup) == csizeof(tup)