nvro don't touch cdecl types [backport: 1.6] (#19461)
* nvro don't touch cdecl types; fix #19342 again
This commit is contained in:
parent
6319b00ef7
commit
0c3892c3c7
7 changed files with 51 additions and 19 deletions
|
|
@ -501,7 +501,7 @@ type
|
||||||
nfHasComment # node has a comment
|
nfHasComment # node has a comment
|
||||||
|
|
||||||
TNodeFlags* = set[TNodeFlag]
|
TNodeFlags* = set[TNodeFlag]
|
||||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 43)
|
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 45)
|
||||||
tfVarargs, # procedure has C styled varargs
|
tfVarargs, # procedure has C styled varargs
|
||||||
# tyArray type represeting a varargs list
|
# tyArray type represeting a varargs list
|
||||||
tfNoSideEffect, # procedure type does not allow side effects
|
tfNoSideEffect, # procedure type does not allow side effects
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||||
# getUniqueType() is too expensive here:
|
# getUniqueType() is too expensive here:
|
||||||
var typ = skipTypes(ri[0].typ, abstractInst)
|
var typ = skipTypes(ri[0].typ, abstractInst)
|
||||||
if typ[0] != nil:
|
if typ[0] != nil:
|
||||||
if isInvalidReturnType(p.config, typ[0]):
|
if isInvalidReturnType(p.config, typ):
|
||||||
if params != nil: pl.add(~", ")
|
if params != nil: pl.add(~", ")
|
||||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||||
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
|
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) =
|
||||||
let rawProc = getClosureType(p.module, typ, clHalf)
|
let rawProc = getClosureType(p.module, typ, clHalf)
|
||||||
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
|
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
|
||||||
if typ[0] != nil:
|
if typ[0] != nil:
|
||||||
if isInvalidReturnType(p.config, typ[0]):
|
if isInvalidReturnType(p.config, typ):
|
||||||
if ri.len > 1: pl.add(~", ")
|
if ri.len > 1: pl.add(~", ")
|
||||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||||
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
|
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) =
|
||||||
pl.add(~": ")
|
pl.add(~": ")
|
||||||
pl.add(genArg(p, ri[i], param, ri))
|
pl.add(genArg(p, ri[i], param, ri))
|
||||||
if typ[0] != nil:
|
if typ[0] != nil:
|
||||||
if isInvalidReturnType(p.config, typ[0]):
|
if isInvalidReturnType(p.config, typ):
|
||||||
if ri.len > 1: pl.add(~" ")
|
if ri.len > 1: pl.add(~" ")
|
||||||
# beware of 'result = p(result)'. We always allocate a temporary:
|
# beware of 'result = p(result)'. We always allocate a temporary:
|
||||||
if d.k in {locTemp, locNone}:
|
if d.k in {locTemp, locNone}:
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,19 @@ proc registerTraverseProc(p: BProc, v: PSym, traverseProc: Rope) =
|
||||||
"$n\t#nimRegisterGlobalMarker($1);$n$n", [traverseProc])
|
"$n\t#nimRegisterGlobalMarker($1);$n$n", [traverseProc])
|
||||||
|
|
||||||
proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
|
proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
|
||||||
if n.kind == nkEmpty: return false
|
if n.kind == nkEmpty:
|
||||||
if isInvalidReturnType(conf, n.typ):
|
result = false
|
||||||
|
elif n.kind in nkCallKinds and n[0] != nil and n[0].typ != nil and n[0].typ.skipTypes(abstractInst).kind == tyProc:
|
||||||
|
if isInvalidReturnType(conf, n[0].typ, true):
|
||||||
# var v = f()
|
# var v = f()
|
||||||
# is transformed into: var v; f(addr v)
|
# is transformed into: var v; f(addr v)
|
||||||
# where 'f' **does not** initialize the result!
|
# where 'f' **does not** initialize the result!
|
||||||
return false
|
result = false
|
||||||
|
else:
|
||||||
|
result = true
|
||||||
|
elif isInvalidReturnType(conf, n.typ, false):
|
||||||
|
result = false
|
||||||
|
else:
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc inExceptBlockLen(p: BProc): int =
|
proc inExceptBlockLen(p: BProc): int =
|
||||||
|
|
|
||||||
|
|
@ -215,12 +215,18 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} =
|
||||||
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
|
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
|
||||||
(typ[0] == nil) or isPureObject(typ))
|
(typ[0] == nil) or isPureObject(typ))
|
||||||
|
|
||||||
proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
|
proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool =
|
||||||
# Arrays and sets cannot be returned by a C procedure, because C is
|
# Arrays and sets cannot be returned by a C procedure, because C is
|
||||||
# such a poor programming language.
|
# such a poor programming language.
|
||||||
# We exclude records with refs too. This enhances efficiency and
|
# We exclude records with refs too. This enhances efficiency and
|
||||||
# is necessary for proper code generation of assignments.
|
# is necessary for proper code generation of assignments.
|
||||||
if rettype == nil or (tfByCopy notin rettype.flags and getSize(conf, rettype) > conf.target.floatSize*3):
|
var rettype = typ
|
||||||
|
var isAllowedCall = true
|
||||||
|
if isProc:
|
||||||
|
rettype = rettype[0]
|
||||||
|
isAllowedCall = typ.callConv in {ccClosure, ccInline, ccNimCall}
|
||||||
|
if rettype == nil or (isAllowedCall and
|
||||||
|
getSize(conf, rettype) > conf.target.floatSize*3):
|
||||||
result = true
|
result = true
|
||||||
else:
|
else:
|
||||||
case mapType(conf, rettype, skResult)
|
case mapType(conf, rettype, skResult)
|
||||||
|
|
@ -257,11 +263,11 @@ proc addAbiCheck(m: BModule, t: PType, name: Rope) =
|
||||||
# see `testCodegenABICheck` for example error message it generates
|
# see `testCodegenABICheck` for example error message it generates
|
||||||
|
|
||||||
|
|
||||||
proc fillResult(conf: ConfigRef; param: PNode) =
|
proc fillResult(conf: ConfigRef; param: PNode, proctype: PType) =
|
||||||
fillLoc(param.sym.loc, locParam, param, ~"Result",
|
fillLoc(param.sym.loc, locParam, param, ~"Result",
|
||||||
OnStack)
|
OnStack)
|
||||||
let t = param.sym.typ
|
let t = param.sym.typ
|
||||||
if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, t):
|
if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, proctype):
|
||||||
incl(param.sym.loc.flags, lfIndirect)
|
incl(param.sym.loc.flags, lfIndirect)
|
||||||
param.sym.loc.storage = OnUnknown
|
param.sym.loc.storage = OnUnknown
|
||||||
|
|
||||||
|
|
@ -426,7 +432,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||||
check: var IntSet, declareEnvironment=true;
|
check: var IntSet, declareEnvironment=true;
|
||||||
weakDep=false) =
|
weakDep=false) =
|
||||||
params = nil
|
params = nil
|
||||||
if t[0] == nil or isInvalidReturnType(m.config, t[0]):
|
if t[0] == nil or isInvalidReturnType(m.config, t):
|
||||||
rettype = ~"void"
|
rettype = ~"void"
|
||||||
else:
|
else:
|
||||||
rettype = getTypeDescAux(m, t[0], check, skResult)
|
rettype = getTypeDescAux(m, t[0], check, skResult)
|
||||||
|
|
@ -461,7 +467,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
|
||||||
params.addf(", NI $1Len_$2", [param.loc.r, j.rope])
|
params.addf(", NI $1Len_$2", [param.loc.r, j.rope])
|
||||||
inc(j)
|
inc(j)
|
||||||
arr = arr[0].skipTypes({tySink})
|
arr = arr[0].skipTypes({tySink})
|
||||||
if t[0] != nil and isInvalidReturnType(m.config, t[0]):
|
if t[0] != nil and isInvalidReturnType(m.config, t):
|
||||||
var arr = t[0]
|
var arr = t[0]
|
||||||
if params != nil: params.add(", ")
|
if params != nil: params.add(", ")
|
||||||
if mapReturnType(m.config, t[0]) != ctArray:
|
if mapReturnType(m.config, t[0]) != ctArray:
|
||||||
|
|
|
||||||
|
|
@ -1039,7 +1039,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||||
internalError(m.config, prc.info, "proc has no result symbol")
|
internalError(m.config, prc.info, "proc has no result symbol")
|
||||||
let resNode = prc.ast[resultPos]
|
let resNode = prc.ast[resultPos]
|
||||||
let res = resNode.sym # get result symbol
|
let res = resNode.sym # get result symbol
|
||||||
if not isInvalidReturnType(m.config, prc.typ[0]):
|
if not isInvalidReturnType(m.config, prc.typ):
|
||||||
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
|
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
|
||||||
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
|
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
|
||||||
var decl = localVarDecl(p, resNode)
|
var decl = localVarDecl(p, resNode)
|
||||||
|
|
@ -1053,7 +1053,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||||
initLocalVar(p, res, immediateAsgn=false)
|
initLocalVar(p, res, immediateAsgn=false)
|
||||||
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
|
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
|
||||||
else:
|
else:
|
||||||
fillResult(p.config, resNode)
|
fillResult(p.config, resNode, prc.typ)
|
||||||
assignParam(p, res, prc.typ[0])
|
assignParam(p, res, prc.typ[0])
|
||||||
# We simplify 'unsureAsgn(result, nil); unsureAsgn(result, x)'
|
# We simplify 'unsureAsgn(result, nil); unsureAsgn(result, x)'
|
||||||
# to 'unsureAsgn(result, x)'
|
# to 'unsureAsgn(result, x)'
|
||||||
|
|
|
||||||
|
|
@ -2137,6 +2137,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
incl(s.flags, sfWasForwarded)
|
incl(s.flags, sfWasForwarded)
|
||||||
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
elif sfBorrow in s.flags: semBorrow(c, n, s)
|
||||||
sideEffectsCheck(c, s)
|
sideEffectsCheck(c, s)
|
||||||
|
|
||||||
closeScope(c) # close scope for parameters
|
closeScope(c) # close scope for parameters
|
||||||
# c.currentScope = oldScope
|
# c.currentScope = oldScope
|
||||||
popOwner(c)
|
popOwner(c)
|
||||||
|
|
|
||||||
18
tests/objects/t19342_2.nim
Normal file
18
tests/objects/t19342_2.nim
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
discard """
|
||||||
|
targets: "c cpp"
|
||||||
|
"""
|
||||||
|
|
||||||
|
{.compile: "m19342.c".}
|
||||||
|
|
||||||
|
# bug #19342
|
||||||
|
type
|
||||||
|
Node* {.byRef.} = object
|
||||||
|
data: array[25, cint]
|
||||||
|
|
||||||
|
proc myproc(name: cint): Node {.importc: "hello", cdecl.}
|
||||||
|
|
||||||
|
proc parse =
|
||||||
|
let node = myproc(10)
|
||||||
|
doAssert node.data[0] == 999
|
||||||
|
|
||||||
|
parse()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue