nvro don't touch cdecl types [backport: 1.6] (#19461)

* nvro don't touch cdecl types; fix #19342 again
This commit is contained in:
flywind 2022-01-28 16:53:42 +08:00 • committed by GitHub
commit 0c3892c3c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 51 additions and 19 deletions

View file

@ -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

View file

@ -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}:

View file

@ -32,13 +32,20 @@ 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
# var v = f() elif n.kind in nkCallKinds and n[0] != nil and n[0].typ != nil and n[0].typ.skipTypes(abstractInst).kind == tyProc:
# is transformed into: var v; f(addr v) if isInvalidReturnType(conf, n[0].typ, true):
# where 'f' **does not** initialize the result! # var v = f()
return false # is transformed into: var v; f(addr v)
result = true # where 'f' **does not** initialize the result!
result = false
else:
result = true
elif isInvalidReturnType(conf, n.typ, false):
result = false
else:
result = true
proc inExceptBlockLen(p: BProc): int = proc inExceptBlockLen(p: BProc): int =
for x in p.nestedTryStmts: for x in p.nestedTryStmts:

View file

@ -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:

View file

@ -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)'

View file

@ -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)

View 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()