Skip to content

Commit 0c3892c

Browse files
authored
nvro don't touch cdecl types [backport: 1.6] (#19461)
* nvro don't touch cdecl types; fix #19342 again
1 parent 6319b00 commit 0c3892c

File tree

7 files changed

+51
-19
lines changed

7 files changed

+51
-19
lines changed

compiler/ast.nim

+1-1
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ type
501501
nfHasComment # node has a comment
502502

503503
TNodeFlags* = set[TNodeFlag]
504-
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 43)
504+
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 45)
505505
tfVarargs, # procedure has C styled varargs
506506
# tyArray type represeting a varargs list
507507
tfNoSideEffect, # procedure type does not allow side effects

compiler/ccgcalls.nim

+3-3
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
7676
# getUniqueType() is too expensive here:
7777
var typ = skipTypes(ri[0].typ, abstractInst)
7878
if typ[0] != nil:
79-
if isInvalidReturnType(p.config, typ[0]):
79+
if isInvalidReturnType(p.config, typ):
8080
if params != nil: pl.add(~", ")
8181
# beware of 'result = p(result)'. We may need to allocate a temporary:
8282
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
@@ -439,7 +439,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
439439
let rawProc = getClosureType(p.module, typ, clHalf)
440440
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
441441
if typ[0] != nil:
442-
if isInvalidReturnType(p.config, typ[0]):
442+
if isInvalidReturnType(p.config, typ):
443443
if ri.len > 1: pl.add(~", ")
444444
# beware of 'result = p(result)'. We may need to allocate a temporary:
445445
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
@@ -737,7 +737,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
737737
pl.add(~": ")
738738
pl.add(genArg(p, ri[i], param, ri))
739739
if typ[0] != nil:
740-
if isInvalidReturnType(p.config, typ[0]):
740+
if isInvalidReturnType(p.config, typ):
741741
if ri.len > 1: pl.add(~" ")
742742
# beware of 'result = p(result)'. We always allocate a temporary:
743743
if d.k in {locTemp, locNone}:

compiler/ccgstmts.nim

+14-7
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,20 @@ proc registerTraverseProc(p: BProc, v: PSym, traverseProc: Rope) =
3232
"$n\t#nimRegisterGlobalMarker($1);$n$n", [traverseProc])
3333

3434
proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
35-
if n.kind == nkEmpty: return false
36-
if isInvalidReturnType(conf, n.typ):
37-
# var v = f()
38-
# is transformed into: var v; f(addr v)
39-
# where 'f' **does not** initialize the result!
40-
return false
41-
result = true
35+
if n.kind == nkEmpty:
36+
result = false
37+
elif n.kind in nkCallKinds and n[0] != nil and n[0].typ != nil and n[0].typ.skipTypes(abstractInst).kind == tyProc:
38+
if isInvalidReturnType(conf, n[0].typ, true):
39+
# var v = f()
40+
# is transformed into: var v; f(addr v)
41+
# where 'f' **does not** initialize the result!
42+
result = false
43+
else:
44+
result = true
45+
elif isInvalidReturnType(conf, n.typ, false):
46+
result = false
47+
else:
48+
result = true
4249

4350
proc inExceptBlockLen(p: BProc): int =
4451
for x in p.nestedTryStmts:

compiler/ccgtypes.nim

+12-6
Original file line numberDiff line numberDiff line change
@@ -215,12 +215,18 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} =
215215
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
216216
(typ[0] == nil) or isPureObject(typ))
217217

218-
proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
218+
proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool =
219219
# Arrays and sets cannot be returned by a C procedure, because C is
220220
# such a poor programming language.
221221
# We exclude records with refs too. This enhances efficiency and
222222
# is necessary for proper code generation of assignments.
223-
if rettype == nil or (tfByCopy notin rettype.flags and getSize(conf, rettype) > conf.target.floatSize*3):
223+
var rettype = typ
224+
var isAllowedCall = true
225+
if isProc:
226+
rettype = rettype[0]
227+
isAllowedCall = typ.callConv in {ccClosure, ccInline, ccNimCall}
228+
if rettype == nil or (isAllowedCall and
229+
getSize(conf, rettype) > conf.target.floatSize*3):
224230
result = true
225231
else:
226232
case mapType(conf, rettype, skResult)
@@ -257,11 +263,11 @@ proc addAbiCheck(m: BModule, t: PType, name: Rope) =
257263
# see `testCodegenABICheck` for example error message it generates
258264

259265

260-
proc fillResult(conf: ConfigRef; param: PNode) =
266+
proc fillResult(conf: ConfigRef; param: PNode, proctype: PType) =
261267
fillLoc(param.sym.loc, locParam, param, ~"Result",
262268
OnStack)
263269
let t = param.sym.typ
264-
if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, t):
270+
if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, proctype):
265271
incl(param.sym.loc.flags, lfIndirect)
266272
param.sym.loc.storage = OnUnknown
267273

@@ -426,7 +432,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
426432
check: var IntSet, declareEnvironment=true;
427433
weakDep=false) =
428434
params = nil
429-
if t[0] == nil or isInvalidReturnType(m.config, t[0]):
435+
if t[0] == nil or isInvalidReturnType(m.config, t):
430436
rettype = ~"void"
431437
else:
432438
rettype = getTypeDescAux(m, t[0], check, skResult)
@@ -461,7 +467,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
461467
params.addf(", NI $1Len_$2", [param.loc.r, j.rope])
462468
inc(j)
463469
arr = arr[0].skipTypes({tySink})
464-
if t[0] != nil and isInvalidReturnType(m.config, t[0]):
470+
if t[0] != nil and isInvalidReturnType(m.config, t):
465471
var arr = t[0]
466472
if params != nil: params.add(", ")
467473
if mapReturnType(m.config, t[0]) != ctArray:

compiler/cgen.nim

+2-2
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,7 @@ proc genProcAux(m: BModule, prc: PSym) =
10391039
internalError(m.config, prc.info, "proc has no result symbol")
10401040
let resNode = prc.ast[resultPos]
10411041
let res = resNode.sym # get result symbol
1042-
if not isInvalidReturnType(m.config, prc.typ[0]):
1042+
if not isInvalidReturnType(m.config, prc.typ):
10431043
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
10441044
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
10451045
var decl = localVarDecl(p, resNode)
@@ -1053,7 +1053,7 @@ proc genProcAux(m: BModule, prc: PSym) =
10531053
initLocalVar(p, res, immediateAsgn=false)
10541054
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
10551055
else:
1056-
fillResult(p.config, resNode)
1056+
fillResult(p.config, resNode, prc.typ)
10571057
assignParam(p, res, prc.typ[0])
10581058
# We simplify 'unsureAsgn(result, nil); unsureAsgn(result, x)'
10591059
# to 'unsureAsgn(result, x)'

compiler/semstmts.nim

+1
Original file line numberDiff line numberDiff line change
@@ -2137,6 +2137,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
21372137
incl(s.flags, sfWasForwarded)
21382138
elif sfBorrow in s.flags: semBorrow(c, n, s)
21392139
sideEffectsCheck(c, s)
2140+
21402141
closeScope(c) # close scope for parameters
21412142
# c.currentScope = oldScope
21422143
popOwner(c)

tests/objects/t19342_2.nim

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
discard """
2+
targets: "c cpp"
3+
"""
4+
5+
{.compile: "m19342.c".}
6+
7+
# bug #19342
8+
type
9+
Node* {.byRef.} = object
10+
data: array[25, cint]
11+
12+
proc myproc(name: cint): Node {.importc: "hello", cdecl.}
13+
14+
proc parse =
15+
let node = myproc(10)
16+
doAssert node.data[0] == 999
17+
18+
parse()

0 commit comments

Comments
 (0)