'constructor' pragma for C++ support

This commit is contained in:
Araq
2015-03-18 00:46:10 +01:00
parent 1fc590b6ea
commit 910ef7b2d1
7 changed files with 98 additions and 82 deletions

View File

@@ -257,7 +257,7 @@ type
sfThread, # proc will run as a thread
# variable is a thread variable
sfCompileTime, # proc can be evaluated at compile time
sfMerge, # proc can be merged with itself
sfConstructor, # proc is a C++ constructor
sfDeadCodeElim, # dead code elimination for the module is turned on
sfBorrow, # proc is borrowed
sfInfixCall, # symbol needs infix call syntax in target language;
@@ -663,7 +663,9 @@ type
locOther # location is something other
TLocFlag* = enum
lfIndirect, # backend introduced a pointer
lfParamCopy, # backend introduced a parameter copy (LLVM)
lfFullExternalName, # only used when 'gCmd == cmdPretty': Indicates
# that the symbol has been imported via 'importc: "fullname"' and
# no format string.
lfNoDeepCopy, # no need for a deep copy
lfNoDecl, # do not declare it in C
lfDynamicLib, # link symbol to dynamic library
@@ -915,10 +917,6 @@ const
skIterators* = {skIterator, skClosureIterator}
lfFullExternalName* = lfParamCopy # \
# only used when 'gCmd == cmdPretty': Indicates that the symbol has been
# imported via 'importc: "fullname"' and no format string.
var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
proc isCallExpr*(n: PNode): bool =

View File

@@ -202,7 +202,8 @@ proc genSingleVar(p: BProc, a: PNode) =
genVarPrototypeAux(generatedHeader, v)
registerGcRoot(p, v)
else:
let imm = isAssignedImmediately(a.sons[2])
let value = a.sons[2]
let imm = isAssignedImmediately(value)
if imm and p.module.compileToCpp and p.splitDecls == 0 and
not containsHiddenPointer(v.typ):
# C++ really doesn't like things like 'Foo f; f = x' as that invokes a
@@ -211,8 +212,19 @@ proc genSingleVar(p: BProc, a: PNode) =
genLineDir(p, a)
let decl = localVarDecl(p, v)
var tmp: TLoc
initLocExprSingleUse(p, a.sons[2], tmp)
lineF(p, cpsStmts, "$# = $#;$n", decl, tmp.rdLoc)
if value.kind in nkCallKinds and value[0].kind == nkSym and
sfConstructor in value[0].sym.flags:
var params: PRope
let typ = skipTypes(value.sons[0].typ, abstractInst)
assert(typ.kind == tyProc)
for i in 1.. <value.len:
if params != nil: params.app(~", ")
assert(sonsLen(typ) == sonsLen(typ.n))
app(params, genOtherArg(p, value, i, typ))
lineF(p, cpsStmts, "$#($#);$n", decl, params)
else:
initLocExprSingleUse(p, value, tmp)
lineF(p, cpsStmts, "$# = $#;$n", decl, tmp.rdLoc)
return
assignLocalVar(p, v)
initLocalVar(p, v, imm)

View File

@@ -358,17 +358,6 @@ proc deinitGCFrame(p: BProc): PRope =
result = ropecg(p.module,
"if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n")
proc allocParam(p: BProc, s: PSym) =
assert(s.kind == skParam)
if lfParamCopy notin s.loc.flags:
inc(p.labels)
var tmp = con("%LOC", toRope(p.labels))
incl(s.loc.flags, lfParamCopy)
incl(s.loc.flags, lfIndirect)
lineF(p, cpsInit, "$1 = alloca $3$n" & "store $3 $2, $3* $1$n",
[tmp, s.loc.r, getTypeDesc(p.module, s.loc.t)])
s.loc.r = tmp
proc localDebugInfo(p: BProc, s: PSym) =
if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return
# XXX work around a bug: No type information for open arrays possible:
@@ -471,6 +460,7 @@ proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
proc intLiteral(i: BiggestInt): PRope
proc genLiteral(p: BProc, n: PNode): PRope
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): PRope
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, e.typ, OnUnknown)

View File

@@ -25,7 +25,7 @@ const
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
wOverride}
wOverride, wConstructor}
converterPragmas* = procPragmas
methodPragmas* = procPragmas
templatePragmas* = {wImmediate, wDeprecated, wError, wGensym, wInject, wDirty,
@@ -665,8 +665,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
incl(sym.flags, sfGlobal)
incl(sym.flags, sfPure)
of wMerge:
# only supported for backwards compat, doesn't do anything anymore
noVal(it)
incl(sym.flags, sfMerge)
of wConstructor:
noVal(it)
incl(sym.flags, sfConstructor)
of wHeader:
var lib = getLib(c, libHeader, getStrLitNode(c, it))
addToLib(lib, sym)

View File

@@ -579,8 +579,7 @@ proc getMergeOp(n: PNode): PSym =
case n.kind
of nkCall, nkHiddenCallConv, nkCommand, nkInfix, nkPrefix, nkPostfix,
nkCallStrLit:
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.kind == skProc) and
(sfMerge in n.sons[0].sym.flags):
if n.sons[0].kind == nkSym and n.sons[0].sym.magic == mConStrStr:
result = n.sons[0].sym
else: discard

View File

@@ -13,44 +13,44 @@
# does not support strings. Without this the code would
# be slow and unreadable.
import
import
hashes, strutils, idents
# Keywords must be kept sorted and within a range
type
TSpecialWord* = enum
wInvalid,
wAddr, wAnd, wAs, wAsm, wAtomic,
wBind, wBlock, wBreak, wCase, wCast, wConst,
wContinue, wConverter, wDefer, wDiscard, wDistinct, wDiv, wDo,
TSpecialWord* = enum
wInvalid,
wAddr, wAnd, wAs, wAsm, wAtomic,
wBind, wBlock, wBreak, wCase, wCast, wConst,
wContinue, wConverter, wDefer, wDiscard, wDistinct, wDiv, wDo,
wElif, wElse, wEnd, wEnum, wExcept, wExport,
wFinally, wFor, wFrom, wFunc, wGeneric, wIf, wImport, wIn,
wFinally, wFor, wFrom, wFunc, wGeneric, wIf, wImport, wIn,
wInclude, wInterface, wIs, wIsnot, wIterator, wLet,
wMacro, wMethod, wMixin, wMod, wNil,
wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn,
wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wUsing, wVar,
wMacro, wMethod, wMixin, wMod, wNil,
wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn,
wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wUsing, wVar,
wWhen, wWhile, wWith, wWithout, wXor, wYield,
wColon, wColonColon, wEquals, wDot, wDotDot,
wStar, wMinus,
wMagic, wThread, wFinal, wProfiler, wObjChecks,
wDestroy,
wImmediate, wDestructor, wDelegator, wOverride,
wImmediate, wConstructor, wDestructor, wDelegator, wOverride,
wImportCpp, wImportObjC,
wImportCompilerProc,
wImportc, wExportc, wIncompleteStruct, wRequiresInit,
wAlign, wNodecl, wPure, wSideeffect, wHeader,
wNosideeffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib,
wCompilerproc, wProcVar,
wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef,
wLinedir, wStacktrace, wLinetrace, wLink, wCompile,
wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger,
wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline,
wFastcall, wClosure, wNoconv, wOn, wOff, wChecks, wRangechecks,
wNosideeffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib,
wCompilerproc, wProcVar,
wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef,
wLinedir, wStacktrace, wLinetrace, wLink, wCompile,
wLinksys, wDeprecated, wVarargs, wCallconv, wBreakpoint, wDebugger,
wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline,
wFastcall, wClosure, wNoconv, wOn, wOff, wChecks, wRangechecks,
wBoundchecks, wOverflowchecks, wNilchecks,
wFloatchecks, wNanChecks, wInfChecks,
wAssertions, wPatterns, wWarnings,
@@ -59,11 +59,11 @@ type
wPragma,
wCompileTime, wNoInit,
wPassc, wPassl, wBorrow, wDiscardable,
wFieldChecks,
wWatchPoint, wSubsChar,
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto,
wFieldChecks,
wWatchPoint, wSubsChar,
wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto,
wInjectStmt, wExperimental,
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
wAsmNoStackFrame,
wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks,
@@ -82,38 +82,38 @@ type
wStdIn, wStdOut, wStdErr,
wInOut, wByCopy, wByRef, wOneWay,
TSpecialWords* = set[TSpecialWord]
const
const
oprLow* = ord(wColon)
oprHigh* = ord(wDotDot)
nimKeywordsLow* = ord(wAsm)
nimKeywordsHigh* = ord(wYield)
ccgKeywordsLow* = ord(wAuto)
ccgKeywordsHigh* = ord(wOneWay)
cppNimSharedKeywords* = {
wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport,
wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile, wUsing}
specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["",
"addr", "and", "as", "asm", "atomic",
"bind", "block", "break", "case", "cast",
specialWords*: array[low(TSpecialWord)..high(TSpecialWord), string] = ["",
"addr", "and", "as", "asm", "atomic",
"bind", "block", "break", "case", "cast",
"const", "continue", "converter",
"defer", "discard", "distinct", "div", "do",
"elif", "else", "end", "enum", "except", "export",
"finally", "for", "from", "func", "generic", "if",
"elif", "else", "end", "enum", "except", "export",
"finally", "for", "from", "func", "generic", "if",
"import", "in", "include", "interface", "is", "isnot", "iterator",
"let",
"macro", "method", "mixin", "mod", "nil", "not", "notin",
"object", "of", "or",
"object", "of", "or",
"out", "proc", "ptr", "raise", "ref", "return",
"shl", "shr", "static",
"template", "try", "tuple", "type", "using", "var",
"template", "try", "tuple", "type", "using", "var",
"when", "while", "with", "without", "xor",
"yield",
@@ -122,22 +122,22 @@ const
"magic", "thread", "final", "profiler", "objchecks",
"destroy",
"immediate", "destructor", "delegator", "override",
"immediate", "constructor", "destructor", "delegator", "override",
"importcpp", "importobjc",
"importcompilerproc", "importc", "exportc", "incompletestruct",
"requiresinit", "align", "nodecl", "pure", "sideeffect",
"header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib",
"compilerproc", "procvar", "fatal", "error", "warning", "hint", "line",
"push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace",
"link", "compile", "linksys", "deprecated", "varargs",
"callconv", "breakpoint", "debugger", "nimcall", "stdcall",
"header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib",
"compilerproc", "procvar", "fatal", "error", "warning", "hint", "line",
"push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace",
"link", "compile", "linksys", "deprecated", "varargs",
"callconv", "breakpoint", "debugger", "nimcall", "stdcall",
"cdecl", "safecall", "syscall", "inline", "noinline", "fastcall", "closure",
"noconv", "on", "off", "checks", "rangechecks", "boundchecks",
"noconv", "on", "off", "checks", "rangechecks", "boundchecks",
"overflowchecks", "nilchecks",
"floatchecks", "nanchecks", "infchecks",
"assertions", "patterns", "warnings", "hints",
"assertions", "patterns", "warnings", "hints",
"optimization", "raises", "writes", "reads", "size", "effects", "tags",
"deadcodeelim", "safecode", "noforward",
"pragma",
@@ -149,7 +149,7 @@ const
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
"asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
"guard", "locks",
"auto", "bool", "catch", "char", "class",
"const_cast", "default", "delete", "double",
"dynamic_cast", "explicit", "extern", "false",
@@ -169,22 +169,22 @@ const
"inout", "bycopy", "byref", "oneway",
]
proc findStr*(a: openArray[string], s: string): int =
for i in countup(low(a), high(a)):
if cmpIgnoreStyle(a[i], s) == 0:
proc findStr*(a: openArray[string], s: string): int =
for i in countup(low(a), high(a)):
if cmpIgnoreStyle(a[i], s) == 0:
return i
result = - 1
proc whichKeyword*(id: PIdent): TSpecialWord =
proc whichKeyword*(id: PIdent): TSpecialWord =
if id.id < 0: result = wInvalid
else: result = TSpecialWord(id.id)
proc whichKeyword*(id: string): TSpecialWord =
proc whichKeyword*(id: string): TSpecialWord =
result = whichKeyword(getIdent(id))
proc initSpecials() =
proc initSpecials() =
# initialize the keywords:
for s in countup(succ(low(specialWords)), high(specialWords)):
for s in countup(succ(low(specialWords)), high(specialWords)):
getIdent(specialWords[s], hashIgnoreStyle(specialWords[s])).id = ord(s)
initSpecials()

View File

@@ -545,6 +545,20 @@ instead:
let x = newFoo(3, 4)
Wrapping constructors
~~~~~~~~~~~~~~~~~~~~~
Sometimes a C++ class has a private copy constructor and so code like
``Class c = Class(1,2);`` must not be generated but instead ``Class c(1,2);``.
For this purpose the Nim proc that wraps a C++ constructor needs to be
annotated with the `constructor`:idx: pragma. This pragma also helps to generate
faster C++ code since construction then doesn't invoke the copy constructor:
.. code-block:: nim
# a better constructor of 'Foo':
proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)", constructor.}
Wrapping destructors
~~~~~~~~~~~~~~~~~~~~
@@ -608,7 +622,7 @@ allows *sloppy* interfacing with libraries written in Objective C:
- (void)greet:(long)x y:(long)dummy
{
printf("Hello, World!\n");
printf("Hello, World!\n");
}
@end