summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim2
-rw-r--r--compiler/ccgtypes.nim22
-rw-r--r--compiler/cgen.nim4
-rw-r--r--compiler/pragmas.nim10
-rw-r--r--compiler/semstmts.nim15
-rw-r--r--compiler/wordrecg.nim2
6 files changed, 32 insertions, 23 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index eccf5a985..aba877187 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -314,6 +314,7 @@ type
                       # an infinite loop, this flag is used as a sentinel to stop it.
     sfVirtual         # proc is a C++ virtual function
     sfByCopy          # param is marked as pass bycopy
+    sfMember          # proc is a C++ member of a type
     sfCodegenDecl     # type, proc, global or proc param is marked as codegenDecl
 
   TSymFlags* = set[TSymFlag]
@@ -347,6 +348,7 @@ const
   sfBase* = sfDiscriminant
   sfCustomPragma* = sfRegister        # symbol is custom pragma template
   sfTemplateRedefinition* = sfExportc # symbol is a redefinition of an earlier template
+  sfCppMember* = { sfVirtual, sfMember, sfConstructor } # proc is a C++ member, meaning it will be attached to the type definition
 
 const
   # getting ready for the future expr/stmt merge
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 205031a91..6bac84e95 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -493,12 +493,12 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr
 template cgDeclFrmt*(s: PSym): string =
   s.constraint.strVal
 
-proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var string,
+proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params: var string,
                    check: var IntSet, declareEnvironment=true;
                    weakDep=false;) =
   let t = prc.typ
   let isCtor = sfConstructor in prc.flags
-  if isCtor:
+  if isCtor or (name[0] == '~' and sfMember in prc.flags): #destructors cant have void
     rettype = ""
   elif t[0] == nil or isInvalidReturnType(m.config, t):
     rettype = "void"
@@ -555,6 +555,7 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var
 
   multiFormat(params, @['\'', '#'], [types, names])
   multiFormat(superCall, @['\'', '#'], [types, names])
+  multiFormat(name, @['\'', '#'], [types, names]) #so we can ~'1 on members
   if params == "()":
     if types.len == 0:
       params = "(void)"
@@ -1148,11 +1149,14 @@ proc isReloadable(m: BModule; prc: PSym): bool =
 proc isNonReloadable(m: BModule; prc: PSym): bool =
   return m.hcrOn and sfNonReloadable in prc.flags
 
-proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride: var bool; isCtor: bool) =
+proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride, isMemberVirtual: var bool; isCtor: bool) =
   var afterParams: string = ""
   if scanf(val, "$*($*)$s$*", name, params, afterParams):
     isFnConst = afterParams.find("const") > -1
     isOverride = afterParams.find("override") > -1
+    isMemberVirtual = name.find("virtual ") > -1
+    if isMemberVirtual:
+      name = name.replace("virtual ", "")
     if isCtor:
       discard scanf(afterParams, ":$s$*", superCall)
     else:
@@ -1161,9 +1165,8 @@ proc parseVFunctionDecl(val: string; name, params, retType, superCall: var strin
   params = "(" & params & ")"
 
 proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl : bool = false) =
-  assert {sfVirtual, sfConstructor} * prc.flags != {}
+  assert sfCppMember * prc.flags != {}
   let isCtor = sfConstructor in prc.flags
-  let isVirtual = not isCtor
   var check = initIntSet()
   fillBackendName(m, prc)
   fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown)
@@ -1179,9 +1182,10 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool =
   var typDesc = getTypeDescWeak(m, typ, check, dkParam)
   let asPtrStr = rope(if asPtr: "_PTR" else: "")
   var name, params, rettype, superCall: string = ""
-  var isFnConst, isOverride: bool = false
-  parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isCtor)
-  genMemberProcParams(m, prc, superCall, rettype, params, check, true, false) 
+  var isFnConst, isOverride, isMemberVirtual: bool = false
+  parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isMemberVirtual, isCtor)
+  genMemberProcParams(m, prc, superCall, rettype, name, params, check, true, false) 
+  let isVirtual = sfVirtual in prc.flags or isMemberVirtual
   var fnConst, override: string = ""
   if isCtor:
     name = typDesc
@@ -1194,7 +1198,7 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool =
         override = " override"
     superCall = ""
   else:
-    if isVirtual:
+    if not isCtor:
       prc.loc.r = "$1$2(@)" % [memberOp, name]
     elif superCall != "":
       superCall = " : " & superCall
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 2643e6edd..a3b74c408 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1149,7 +1149,7 @@ proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
 proc genProcAux*(m: BModule, prc: PSym) =
   var p = newProc(prc, m)
   var header = newRopeAppender()
-  if m.config.backend == backendCpp and {sfVirtual, sfConstructor} * prc.flags != {}:
+  if m.config.backend == backendCpp and sfCppMember * prc.flags != {}:
     genMemberProcHeader(m, prc, header)
   else:
     genProcHeader(m, prc, header)
@@ -1260,7 +1260,7 @@ proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
 
 proc genProcPrototype(m: BModule, sym: PSym) =
   useHeader(m, sym)
-  if lfNoDecl in sym.loc.flags or {sfVirtual, sfConstructor} * sym.flags != {}: return
+  if lfNoDecl in sym.loc.flags or sfCppMember * sym.flags != {}: return
   if lfDynamicLib in sym.loc.flags:
     if sym.itemId.module != m.module.position and
         not containsOrIncl(m.declaredThings, sym.id):
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index e0fdba566..56e25c0b4 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -34,7 +34,7 @@ const
     wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl,
     wGensym, wInject, wRaises, wEffectsOf, wTags, wForbids, wLocks, wDelegator, wGcSafe,
     wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy,
-    wRequires, wEnsures, wEnforceNoRaises, wSystemRaisesDefect, wVirtual, wQuirky}
+    wRequires, wEnsures, wEnforceNoRaises, wSystemRaisesDefect, wVirtual, wQuirky, wMember}
   converterPragmas* = procPragmas
   methodPragmas* = procPragmas+{wBase}-{wImportCpp}
   templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
@@ -245,10 +245,10 @@ proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
   if n.kind in nkPragmaCallKinds: result = expectStrLit(c, n)
   else: result = defaultStr
 
-proc processVirtual(c: PContext, n: PNode, s: PSym) =
+proc processVirtual(c: PContext, n: PNode, s: PSym, flag: TSymFlag) =
   s.constraint = newEmptyStrNode(c, n, getOptionalStr(c, n, "$1"))
   s.constraint.strVal = s.constraint.strVal % s.name.s
-  s.flags.incl {sfVirtual, sfInfixCall, sfExportc, sfMangleCpp}
+  s.flags.incl {flag, sfInfixCall, sfExportc, sfMangleCpp}
 
   s.typ.callConv = ccNoConvention
   incl c.config.globalOptions, optMixedMode
@@ -1284,7 +1284,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
       of wSystemRaisesDefect:
         sym.flags.incl sfSystemRaisesDefect
       of wVirtual:
-        processVirtual(c, it, sym)
+        processVirtual(c, it, sym, sfVirtual)
+      of wMember:
+        processVirtual(c, it, sym, sfMember)
 
       else: invalidPragma(c, it)
     elif comesFromPush and whichKeyword(ident) != wInvalid:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 448c26cf2..302ccc8b9 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -2269,26 +2269,27 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   if sfBorrow in s.flags and c.config.cmd notin cmdDocLike:
     result[bodyPos] = c.graph.emptyNode
 
-  if {sfVirtual, sfConstructor} * s.flags != {} and sfImportc notin s.flags:
+  if sfCppMember * s.flags != {} and sfImportc notin s.flags:
     let isVirtual = sfVirtual in s.flags
-    let pragmaName = if isVirtual: "virtual" else: "constructor"
+    let isCtor = sfConstructor in s.flags
+    let pragmaName = if isVirtual: "virtual" elif isCtor: "constructor" else: "member"
     if c.config.backend == backendCpp:
-      if s.typ.sons.len < 2 and isVirtual:
-        localError(c.config, n.info, "virtual must have at least one parameter")
+      if s.typ.sons.len < 2 and not isCtor:
+        localError(c.config, n.info, pragmaName & " must have at least one parameter")
       for son in s.typ.sons:
         if son!=nil and son.isMetaType:
           localError(c.config, n.info, pragmaName & " unsupported for generic routine")
       var typ: PType
-      if sfConstructor in s.flags:
+      if isCtor:
         typ = s.typ.sons[0]
         if typ == nil or typ.kind != tyObject:
           localError(c.config, n.info, "constructor must return an object")
       else:
         typ = s.typ.sons[1]
-      if typ.kind == tyPtr and isVirtual:
+      if typ.kind == tyPtr and not isCtor:
         typ = typ[0]
       if typ.kind != tyObject:
-        localError(c.config, n.info, "virtual must be either ptr to object or object type.")
+        localError(c.config, n.info, pragmaName & " must be either ptr to object or object type.")
       if typ.owner.id == s.owner.id and c.module.id == s.owner.id:
         c.graph.memberProcsPerType.mgetOrPut(typ.itemId, @[]).add s
       else:
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index f784f0a75..b2b0c8ae2 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -103,7 +103,7 @@ type
     wSwitch = "switch", wThis = "this", wThrow = "throw", wTrue = "true", wTypedef = "typedef",
     wTypeid = "typeid", wTypeof = "typeof",  wTypename = "typename",
     wUnion = "union", wPacked = "packed", wUnsigned = "unsigned", wVirtual = "virtual",
-    wVoid = "void", wVolatile = "volatile", wWchar = "wchar_t",
+    wVoid = "void", wVolatile = "volatile", wWchar = "wchar_t", wMember = "member",
 
     wAlignas = "alignas", wAlignof = "alignof", wConstexpr = "constexpr", wDecltype = "decltype",
     wNullptr = "nullptr", wNoexcept = "noexcept",