summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorTimothee Cour <timothee.cour2@gmail.com>2019-09-06 03:54:44 -0700
committerAndreas Rumpf <rumpf_a@web.de>2019-09-06 12:54:44 +0200
commit32769c478bb15bb7b290992a85dbea702dbc1f95 (patch)
tree99174185f1254828da0a385ae958b189b428b4a6
parent83975543154f03b7803c1cb86a27e9c99e445b50 (diff)
downloadNim-32769c478bb15bb7b290992a85dbea702dbc1f95.tar.gz
exportc now mangles same as importc, fixes #10578 (#12144)
* fixes #10578
* add tests
* add changelog
* add {.exportcpp.}
-rw-r--r--changelog.md2
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/cgen.nim3
-rw-r--r--compiler/pragmas.nim69
-rw-r--r--compiler/wordrecg.nim4
-rw-r--r--tests/cpp/mexportc.nim9
-rw-r--r--tests/cpp/texportc.nim22
7 files changed, 76 insertions, 34 deletions
diff --git a/changelog.md b/changelog.md
index f135fa585..5735dd033 100644
--- a/changelog.md
+++ b/changelog.md
@@ -31,6 +31,8 @@ type
 
 ```
 
+- `exportc` now uses C instead of C++ mangling with `nim cpp`, matching behavior of `importc`, see #10578
+  Use the new `exportcpp` to mangle as C++ when using `nim cpp`.
 
 ### Breaking changes in the compiler
 
diff --git a/compiler/ast.nim b/compiler/ast.nim
index f3012cd8a..758cd7cfe 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -239,6 +239,7 @@ type
     sfForward,        # symbol is forward declared
     sfImportc,        # symbol is external; imported
     sfExportc,        # symbol is exported (under a specified name)
+    sfMangleCpp,      # mangle as cpp (combines with `sfExportc`)
     sfVolatile,       # variable is volatile
     sfRegister,       # variable should be placed in a register
     sfPure,           # object is "pure" that means it has no type-information
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 6e79b2d7b..ba240a020 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -1039,7 +1039,8 @@ proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
   result = (sfCompileToCpp in m.module.flags and
            sfCompileToCpp notin sym.getModule().flags and
            m.config.cmd != cmdCompileToCpp) or (
-           sym.flags * {sfImportc, sfInfixCall, sfCompilerProc} == {sfImportc} and
+           sym.flags * {sfInfixCall, sfCompilerProc, sfMangleCpp} == {} and
+           sym.flags * {sfImportc, sfExportc} != {} and
            sym.magic == mNone and
            m.config.cmd == cmdCompileToCpp)
 
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 6c70e4bad..a314277be 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -19,25 +19,27 @@ const
   LastCallConv* = wNoconv
 
 const
-  procPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
+  declPragmas = {wImportc, wImportObjC, wImportCpp, wExportc, wExportCpp,
+    wExportNims, wExtern, wDeprecated, wNodecl, wError, wUsed}
+    ## common pragmas for declarations, to a good approximation
+  procPragmas* = declPragmas + {FirstCallConv..LastCallConv,
     wMagic, wNoSideEffect, wSideEffect, wNoreturn, wDynlib, wHeader,
-    wCompilerProc, wNonReloadable, wCore, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
-    wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
-    wAsmNoStackFrame, wError, wDiscardable, wNoInit, wCodegenDecl,
+    wCompilerProc, wNonReloadable, wCore, wProcVar, wVarargs, wCompileTime, wMerge,
+    wBorrow, wImportCompilerProc, wThread,
+    wAsmNoStackFrame, wDiscardable, wNoInit, wCodegenDecl,
     wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe,
-    wConstructor, wExportNims, wUsed, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy}
+    wConstructor, wLiftLocals, wStackTrace, wLineTrace, wNoDestroy}
   converterPragmas* = procPragmas - {wNoDestroy}
   methodPragmas* = procPragmas+{wBase}-{wImportCpp, wNoDestroy}
   templatePragmas* = {wDeprecated, wError, wGensym, wInject, wDirty,
     wDelegator, wExportNims, wUsed, wPragma}
-  macroPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc,
-    wNodecl, wMagic, wNoSideEffect, wCompilerProc, wNonReloadable, wCore, wDeprecated, wExtern,
-    wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wDelegator,
-    wExportNims, wUsed}
-  iteratorPragmas* = {FirstCallConv..LastCallConv, wNoSideEffect, wSideEffect,
-    wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
-    wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
-    wTags, wLocks, wGcSafe, wExportNims, wUsed}
+  macroPragmas* = declPragmas + {FirstCallConv..LastCallConv,
+    wMagic, wNoSideEffect, wCompilerProc, wNonReloadable, wCore,
+    wDiscardable, wGensym, wInject, wDelegator}
+  iteratorPragmas* = declPragmas + {FirstCallConv..LastCallConv, wNoSideEffect, wSideEffect,
+    wMagic, wBorrow,
+    wDiscardable, wGensym, wInject, wRaises,
+    wTags, wLocks, wGcSafe}
   exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe, wNoSideEffect}
   stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangeChecks,
     wBoundChecks, wOverflowChecks, wNilChecks, wStyleChecks, wAssertions,
@@ -49,25 +51,25 @@ const
     wDeprecated,
     wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
     wLinearScanEnd, wPatterns, wTrMacros, wEffects, wNoForward, wReorder, wComputedGoto,
-    wInjectStmt, wDeprecated, wExperimental, wThis, wUsed}
-  lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
+    wInjectStmt, wExperimental, wThis, wUsed}
+  lambdaPragmas* = declPragmas + {FirstCallConv..LastCallConv,
     wNoSideEffect, wSideEffect, wNoreturn, wDynlib, wHeader,
-    wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
-    wRaises, wLocks, wTags, wGcSafe, wCodegenDecl}
-  typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
-    wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wExtern, wShallow,
-    wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef,
+    wThread, wAsmNoStackFrame,
+    wRaises, wLocks, wTags, wGcSafe, wCodegenDecl} - {wExportNims, wError, wUsed}  # why exclude these?
+  typePragmas* = declPragmas + {wMagic, wAcyclic,
+    wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow,
+    wIncompleteStruct, wByCopy, wByRef,
     wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked,
-    wBorrow, wGcSafe, wExportNims, wPartial, wUsed, wExplain, wPackage}
-  fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
-    wImportCpp, wImportObjC, wError, wGuard, wBitsize, wUsed}
-  varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
-    wMagic, wHeader, wDeprecated, wCompilerProc, wCore, wDynlib, wExtern,
-    wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal,
-    wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims, wUsed, wCursor}
-  constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
-    wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims,
-    wIntDefine, wStrDefine, wBoolDefine, wUsed, wCompilerProc, wCore}
+    wBorrow, wGcSafe, wPartial, wExplain, wPackage}
+  fieldPragmas* = declPragmas + {
+    wGuard, wBitsize} - {wExportNims, wNodecl} # why exclude these?
+  varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar,
+    wMagic, wHeader, wCompilerProc, wCore, wDynlib,
+    wNoInit, wCompileTime, wGlobal,
+    wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor}
+  constPragmas* = declPragmas + {wHeader, wMagic,
+    wGensym, wInject,
+    wIntDefine, wStrDefine, wBoolDefine, wCompilerProc, wCore}
   letPragmas* = varPragmas
   procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect,
                       wThread, wRaises, wLocks, wTags, wGcSafe}
@@ -775,8 +777,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
       if {optStyleHint, optStyleError} * c.config.globalOptions != {}:
         checkPragmaUse(c.config, key.info, k, ident.s)
       case k
-      of wExportc:
+      of wExportc, wExportCpp:
         makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info)
+        if k == wExportCpp:
+          if c.config.cmd != cmdCompileToCpp:
+            localError(c.config, it.info, "exportcpp requires `nim cpp`, got " & $c.config.cmd)
+          else:
+            incl(sym.flags, sfMangleCpp)
         incl(sym.flags, sfUsed) # avoid wrong hints
       of wImportc:
         let name = getOptionalStr(c, it, "$1")
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 62b26adf3..23c87ac39 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -42,7 +42,7 @@ type
     wImmediate, wConstructor, wDestructor, wDelegator, wOverride,
     wImportCpp, wImportObjC,
     wImportCompilerProc,
-    wImportc, wExportc, wExportNims, wIncompleteStruct, wRequiresInit,
+    wImportc, wExportc, wExportCpp, wExportNims, wIncompleteStruct, wRequiresInit,
     wAlign, wNodecl, wPure, wSideEffect, wHeader,
     wNoSideEffect, wGcSafe, wNoreturn, wMerge, wLib, wDynlib,
     wCompilerProc, wCore, wProcVar, wBase, wUsed,
@@ -129,7 +129,7 @@ const
 
     "immediate", "constructor", "destructor", "delegator", "override",
     "importcpp", "importobjc",
-    "importcompilerproc", "importc", "exportc", "exportnims",
+    "importcompilerproc", "importc", "exportc", "exportcpp", "exportnims",
     "incompletestruct",
     "requiresinit", "align", "nodecl", "pure", "sideeffect",
     "header", "nosideeffect", "gcsafe", "noreturn", "merge", "lib", "dynlib",
diff --git a/tests/cpp/mexportc.nim b/tests/cpp/mexportc.nim
new file mode 100644
index 000000000..dee51f157
--- /dev/null
+++ b/tests/cpp/mexportc.nim
@@ -0,0 +1,9 @@
+{.used.} # ideally, would not be needed
+
+var fun0 {.exportc.} = 10
+proc fun1() {.exportc.} = discard
+proc fun2() {.exportc: "$1".} = discard
+proc fun3() {.exportc: "fun3Bis".} = discard
+
+when defined cpp:
+  proc funx1() {.exportcpp.} = discard
diff --git a/tests/cpp/texportc.nim b/tests/cpp/texportc.nim
new file mode 100644
index 000000000..3a2fa8748
--- /dev/null
+++ b/tests/cpp/texportc.nim
@@ -0,0 +1,22 @@
+discard """
+  targets: "c cpp"
+"""
+
+var fun0 {.importc.}: int
+proc fun1() {.importc.}
+proc fun2() {.importc: "$1".}
+proc fun3() {.importc: "fun3Bis".}
+
+when defined cpp:
+  # proc funx1() {.importcpp.} # this does not work yet
+  proc funx1() {.importc: "_Z5funx1v".}
+
+doAssert fun0 == 10
+fun1()
+fun2()
+fun3()
+
+when defined cpp:
+  funx1()
+
+import ./mexportc