diff options
Diffstat (limited to 'tests/cpp')
56 files changed, 1968 insertions, 0 deletions
diff --git a/tests/cpp/23962.h b/tests/cpp/23962.h new file mode 100644 index 000000000..2d8147bfb --- /dev/null +++ b/tests/cpp/23962.h @@ -0,0 +1,17 @@ +#include <iostream> + +struct Foo { + + Foo(int inX): x(inX) { + std::cout << "Ctor Foo(" << x << ")\n"; + } + ~Foo() { + std::cout << "Destory Foo(" << x << ")\n"; + } + + void print() { + std::cout << "Foo.x = " << x << '\n'; + } + + int x; +}; \ No newline at end of file diff --git a/tests/cpp/amodule.nim b/tests/cpp/amodule.nim new file mode 100644 index 000000000..2f3e34051 --- /dev/null +++ b/tests/cpp/amodule.nim @@ -0,0 +1,10 @@ +import os + +proc findlib: string = + let path = getEnv("MYLIB_DOES_NOT_EXIST_PATH") + if path.len > 0 and dirExists(path): + path / "alib_does_not_matter.dll" + else: + "alib_does_not_matter.dll" + +proc imported_func*(a: cint): cstring {.importc, dynlib: findlib().} \ No newline at end of file diff --git a/tests/cpp/enum.hpp b/tests/cpp/enum.hpp new file mode 100644 index 000000000..268999d68 --- /dev/null +++ b/tests/cpp/enum.hpp @@ -0,0 +1,3 @@ +namespace namespaced { +enum Enum { A, B, C }; +} diff --git a/tests/cpp/fam.h b/tests/cpp/fam.h new file mode 100644 index 000000000..ad576425b --- /dev/null +++ b/tests/cpp/fam.h @@ -0,0 +1,4 @@ +struct Test{ + ~Test() { + } +}; diff --git a/tests/cpp/foo.c b/tests/cpp/foo.c new file mode 100644 index 000000000..84fbbccd0 --- /dev/null +++ b/tests/cpp/foo.c @@ -0,0 +1,4 @@ + +char* myFunc() { + return "Hello world"; +} 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/t10148.nim b/tests/cpp/t10148.nim new file mode 100644 index 000000000..e8dd3098f --- /dev/null +++ b/tests/cpp/t10148.nim @@ -0,0 +1,29 @@ +discard """ + output: '''Expected successful exit''' + joinable: false +""" + +import os + +proc another_proc: string = + ## trigger many GC allocations + var x = @[""] + for i in 0..100: + x.add $i + result = "not_existent_path" + +proc findlib2: string = + let path = getEnv("MYLIB2_DOES_NOT_EXIST_PATH") + let another_path = another_proc() + GC_fullCollect() + + if path.len > 0 and dirExists(path): + path / "alib_does_not_matter.dll" + elif fileExists(another_path): + another_path + else: + quit("Expected successful exit", 0) + +proc imported_func*(a: cint): cstring {.importc, dynlib: findlib2().} + +echo imported_func(0) diff --git a/tests/cpp/t10241.nim b/tests/cpp/t10241.nim new file mode 100644 index 000000000..21d6a0f4e --- /dev/null +++ b/tests/cpp/t10241.nim @@ -0,0 +1,19 @@ +discard """ + targets: "cpp" + action: "compile" +""" + +type + String* {.importcpp: "std::string", header: "string".} = object + +proc initString*(): String + {.importcpp: "std::string()", header: "string".} + +proc append*(this: var String, str: String): var String + {.importcpp: "append", header: "string", discardable.} + +var + s1 = initString() + s2 = initString() + +s1.append s2 diff --git a/tests/cpp/t12946.nim b/tests/cpp/t12946.nim new file mode 100644 index 000000000..79cd56251 --- /dev/null +++ b/tests/cpp/t12946.nim @@ -0,0 +1,8 @@ +discard """ + targets: "c cpp" +""" + +import std/atomics +type Futex = distinct Atomic[int32] + +var x: Futex diff --git a/tests/cpp/t22679.nim b/tests/cpp/t22679.nim new file mode 100644 index 000000000..81defcb58 --- /dev/null +++ b/tests/cpp/t22679.nim @@ -0,0 +1,50 @@ +discard """ + cmd: "nim cpp $file" + output:''' +cppNZ.x = 123 +cppNZInit.x = 123 +hascpp.cppnz.x = 123 +hasCppInit.cppnz.x = 123 +hasCppCtor.cppnz.x = 123 +''' +""" +{.emit:"""/*TYPESECTION*/ +struct CppNonZero { + int x = 123; +}; +""".} + +import sugar +type + CppNonZero {.importcpp, inheritable.} = object + x: cint + + HasCpp = object + cppnz: CppNonZero + +proc initCppNonZero: CppNonZero = + CppNonZero() + +proc initHasCpp: HasCpp = + HasCpp() + +proc ctorHasCpp: HasCpp {.constructor.} = + discard + +proc main = + var cppNZ: CppNonZero + dump cppNZ.x + + var cppNZInit = initCppNonZero() + dump cppNZInit.x + + var hascpp: HasCpp + dump hascpp.cppnz.x + + var hasCppInit = initHasCpp() + dump hasCppInit.cppnz.x + + var hasCppCtor = ctorHasCpp() + dump hasCppCtor.cppnz.x + +main() \ No newline at end of file diff --git a/tests/cpp/t22680.nim b/tests/cpp/t22680.nim new file mode 100644 index 000000000..80f1a8319 --- /dev/null +++ b/tests/cpp/t22680.nim @@ -0,0 +1,50 @@ +discard """ + cmd: "nim cpp $file" + output:''' +cppNZ.x = 123 +cppNZInit.x = 123 +inheritCpp.x = 123 +inheritCppInit.x = 123 +inheritCppCtor.x = 123 +''' +""" +import std/sugar + +{.emit:"""/*TYPESECTION*/ +struct CppNonZero { + int x = 123; +}; +""".} + +type + CppNonZero {.importcpp, inheritable.} = object + x: cint + + InheritCpp = object of CppNonZero + +proc initCppNonZero: CppNonZero = + CppNonZero() + +proc initInheritCpp: InheritCpp = + InheritCpp() + +proc ctorInheritCpp: InheritCpp {.constructor.} = + discard + +proc main = + var cppNZ: CppNonZero + dump cppNZ.x + + var cppNZInit = initCppNonZero() + dump cppNZInit.x + + var inheritCpp: InheritCpp + dump inheritCpp.x + + var inheritCppInit = initInheritCpp() + dump inheritCppInit.x + + var inheritCppCtor = ctorInheritCpp() + dump inheritCppCtor.x + +main() \ No newline at end of file diff --git a/tests/cpp/t22712.nim b/tests/cpp/t22712.nim new file mode 100644 index 000000000..34ef67ac8 --- /dev/null +++ b/tests/cpp/t22712.nim @@ -0,0 +1,15 @@ +discard """ +targets: "cpp" +errormsg: "constructor in an imported type needs importcpp pragma" +line: 14 +""" +{.emit: """/*TYPESECTION*/ +struct CppStruct { + CppStruct(); +}; +""".} + +type CppStruct {.importcpp.} = object + +proc makeCppStruct(): CppStruct {.constructor.} = + discard \ No newline at end of file diff --git a/tests/cpp/t23306.nim b/tests/cpp/t23306.nim new file mode 100644 index 000000000..ebb4edb8d --- /dev/null +++ b/tests/cpp/t23306.nim @@ -0,0 +1,12 @@ +discard """ +targets: "cpp" +""" + +type K = object + h: iterator(f: K): K + +iterator d(g: K): K {.closure.} = + defer: + discard + +discard K(h: d) \ No newline at end of file diff --git a/tests/cpp/t23434.nim b/tests/cpp/t23434.nim new file mode 100644 index 000000000..04a83227e --- /dev/null +++ b/tests/cpp/t23434.nim @@ -0,0 +1,17 @@ +discard """ +cmd:"nim cpp $file" +errormsg: "type mismatch: got <proc (self: SomeObject){.member, gcsafe.}>" +line: 17 +""" +type SomeObject = object + value: int + +proc printValue(self: SomeObject) {.virtual.} = + echo "The value is ", self.value + +proc callAProc(p: proc(self: SomeObject){.noconv.}) = + let someObj = SomeObject(value: 4) + echo "calling param proc" + p(someObj) + +callAProc(printValue) \ No newline at end of file diff --git a/tests/cpp/t23657.nim b/tests/cpp/t23657.nim new file mode 100644 index 000000000..63deb7fb0 --- /dev/null +++ b/tests/cpp/t23657.nim @@ -0,0 +1,54 @@ +discard """ + targets: "cpp" + cmd: "nim cpp -r $file" + output: ''' +1.0 +1.0 +''' + +""" +{.emit:"""/*TYPESECTION*/ +struct Point { + float x, y, z; + Point(float x, float y, float z): x(x), y(y), z(z) {} + Point() = default; +}; +struct Direction { + float x, y, z; + Direction(float x, float y, float z): x(x), y(y), z(z) {} + Direction() = default; +}; +struct Axis { + Point origin; + Direction direction; + Axis(Point origin, Direction direction): origin(origin), direction(direction) {} + Axis() = default; +}; + +""".} + +type + Point {.importcpp.} = object + x, y, z: float + + Direction {.importcpp.} = object + x, y, z: float + + Axis {.importcpp.} = object + origin: Point + direction: Direction + +proc makeAxis(origin: Point, direction: Direction): Axis {. constructor, importcpp:"Axis(@)".} +proc makePoint(x, y, z: float): Point {. constructor, importcpp:"Point(@)".} +proc makeDirection(x, y, z: float): Direction {. constructor, importcpp:"Direction(@)".} + +var axis1 = makeAxis(Point(x: 1.0, y: 2.0, z: 3.0), Direction(x: 4.0, y: 5.0, z: 6.0)) #Triggers the error (T1) +var axis2Ctor = makeAxis(makePoint(1.0, 2.0, 3.0), makeDirection(4.0, 5.0, 6.0)) #Do not triggers + +proc main() = #Do not triggers as Tx are inside the body + let test = makeAxis(Point(x: 1.0, y: 2.0, z: 3.0), Direction(x: 4.0, y: 5.0, z: 6.0)) + echo test.origin.x + +main() + +echo $axis1.origin.x #Make sures it's init \ No newline at end of file diff --git a/tests/cpp/t23962.nim b/tests/cpp/t23962.nim new file mode 100644 index 000000000..c79d888df --- /dev/null +++ b/tests/cpp/t23962.nim @@ -0,0 +1,32 @@ +discard """ + cmd: "nim cpp $file" + output: ''' +Ctor Foo(-1) +Destory Foo(-1) +Ctor Foo(-1) +Destory Foo(-1) +Ctor Foo(-1) +Destory Foo(-1) +Foo.x = 1 +Foo.x = 2 +Foo.x = -1 +''' +""" + +type + Foo {.importcpp, header: "23962.h".} = object + x: cint + +proc print(f: Foo) {.importcpp.} + +#also tests the right constructor is used +proc makeFoo(x: int32 = -1): Foo {.importcpp:"Foo(#)", constructor.} + +proc test = + var xs = newSeq[Foo](3) + xs[0].x = 1 + xs[1].x = 2 + for x in xs: + x.print + +test() \ No newline at end of file diff --git a/tests/cpp/t4834.nim b/tests/cpp/t4834.nim new file mode 100644 index 000000000..0275b1b70 --- /dev/null +++ b/tests/cpp/t4834.nim @@ -0,0 +1,17 @@ +discard """ + targets: "cpp" +""" + +# issue #4834 +block: + defer: + let x = 0 + + +proc main() = + block: + defer: + raise newException(Exception, "foo") + +doAssertRaises(Exception): + main() diff --git a/tests/cpp/t6986.nim b/tests/cpp/t6986.nim new file mode 100644 index 000000000..16e455c3b --- /dev/null +++ b/tests/cpp/t6986.nim @@ -0,0 +1,19 @@ +discard """ + targets: "cpp" + action: "compile" +""" + +import sequtils, strutils + +when defined(nimPreviewSlimSystem): + import std/syncio + + +let rules = toSeq(lines("input")) + .mapIt(it.split(" => ").mapIt(it.replace("/", ""))) + .mapIt((it[0], it[1])) + + +proc pp(s: string): auto = + toSeq(lines(s)).mapIt(it.split(" => ").mapIt(it.replace("/", ""))).mapIt((it[0], it[1])) +echo pp("input") diff --git a/tests/cpp/t8241.nim b/tests/cpp/t8241.nim new file mode 100644 index 000000000..9aed13fcb --- /dev/null +++ b/tests/cpp/t8241.nim @@ -0,0 +1,32 @@ +discard """ + targets: "cpp" + action: "compile" +""" + +proc foo(): cstring {.importcpp: "", dynlib: "".} +echo foo() + + +## bug #9222 +import os +import amodule +proc findlib2: string = + let path = getEnv("MYLIB2_DOES_NOT_EXIST_PATH") + if path.len > 0 and dirExists(path): + path / "alib_does_not_matter.dll" + else: + "alib_does_not_matter.dll" + +proc imported_func2*(a: cint): cstring {.importc, dynlib: findlib2().} + +echo imported_func(1) +echo imported_func2(1) + +# issue #8946 + +from json import JsonParsingError +import marshal + +const nothing = "" +doAssertRaises(JsonParsingError): + var bar = marshal.to[int](nothing) diff --git a/tests/cpp/t9013.nim b/tests/cpp/t9013.nim new file mode 100644 index 000000000..6103cf2e7 --- /dev/null +++ b/tests/cpp/t9013.nim @@ -0,0 +1,9 @@ +discard """ + targets: "cpp" + cmd: "nim $target --debugger:native $options $file" +""" + +# The --debugger switch is needed in order to enable the defined(nimTypeNames) +# code path in hti.nim +import typeinfo +var tt: Any diff --git a/tests/cpp/tasync_cpp.nim b/tests/cpp/tasync_cpp.nim new file mode 100644 index 000000000..3f4ec6208 --- /dev/null +++ b/tests/cpp/tasync_cpp.nim @@ -0,0 +1,15 @@ +discard """ + targets: "cpp" + output: "hello" + cmd: "nim cpp --clearNimblePath --nimblePath:build/deps/pkgs2 $file" +""" + +# bug #3299 + +import jester +import asyncdispatch, asyncnet + +# bug #5081 +#import nre + +echo "hello" diff --git a/tests/cpp/tcasts.nim b/tests/cpp/tcasts.nim new file mode 100644 index 000000000..80527efff --- /dev/null +++ b/tests/cpp/tcasts.nim @@ -0,0 +1,20 @@ +discard """ + cmd: "nim cpp $file" + targets: "cpp" +""" + +block: #5979 + var a = 'a' + var p: pointer = cast[pointer](a) + var c = cast[char](p) + doAssert(c == 'a') + + +#---------------------------------------------------- +# bug #9739 +import tables + +var t = initTable[string, string]() +discard t.hasKeyOrPut("123", "123") +discard t.mgetOrPut("vas", "kas") +doAssert t.len == 2 diff --git a/tests/cpp/tcodegendecl.nim b/tests/cpp/tcodegendecl.nim new file mode 100644 index 000000000..e128c5eb7 --- /dev/null +++ b/tests/cpp/tcodegendecl.nim @@ -0,0 +1,17 @@ +discard """ + targets: "cpp" + cmd: "nim cpp $file" + output: "3" +""" + +{.emit:"""/*TYPESECTION*/ + int operate(int x, int y, int (*func)(const int&, const int&)){ + return func(x, y); + }; +""".} + +proc operate(x, y: int32, fn: proc(x, y: int32 ): int32 {.cdecl.}): int32 {.importcpp:"$1(@)".} + +proc add(a {.codegenDecl:"const $#& $#".}, b {.codegenDecl:"const $# $#", byref.}: int32): int32 {.cdecl.} = a + b + +echo operate(1, 2, add) \ No newline at end of file diff --git a/tests/cpp/tconstructor.nim b/tests/cpp/tconstructor.nim new file mode 100644 index 000000000..922ee54fd --- /dev/null +++ b/tests/cpp/tconstructor.nim @@ -0,0 +1,131 @@ +discard """ + targets: "cpp" + cmd: "nim cpp $file" + output: ''' +1 +0 +123 +0 +123 +___ +0 +777 +10 +123 +0 +777 +10 +123 +() +''' +""" + +{.emit:"""/*TYPESECTION*/ +struct CppClass { + int x; + int y; + CppClass(int inX, int inY) { + this->x = inX; + this->y = inY; + } + //CppClass() = default; +}; +""".} + +type CppClass* {.importcpp, inheritable.} = object + x: int32 + y: int32 + +proc makeCppClass(x, y: int32): CppClass {.importcpp: "CppClass(@)", constructor.} +#test globals are init with the constructor call +var shouldCompile {.used.} = makeCppClass(1, 2) + +proc newCpp*[T](): ptr T {.importcpp:"new '*0()".} + +#creation +type NimClassNoNarent* = object + x: int32 + +proc makeNimClassNoParent(x:int32): NimClassNoNarent {. constructor.} = + result.x = x + discard + +let nimClassNoParent = makeNimClassNoParent(1) +echo nimClassNoParent.x #acess to this just fine. Notice the field will appear last because we are dealing with constructor calls here + +var nimClassNoParentDef {.used.}: NimClassNoNarent #test has a default constructor. + +#inheritance +type NimClass* = object of CppClass + +proc makeNimClass(x:int32): NimClass {. constructor:"NimClass('1 #1) : CppClass(0, #1) ".} = + result.x = x + +#optinially define the default constructor so we get rid of the cpp warn and we can declare the obj (note: default constructor of 'tyObject_NimClass__apRyyO8cfRsZtsldq1rjKA' is implicitly deleted because base class 'CppClass' has no default constructor) +proc makeCppClass(): NimClass {. constructor: "NimClass() : CppClass(0, 0) ".} = + result.x = 1 + +let nimClass = makeNimClass(1) +var nimClassDef {.used.}: NimClass #since we explictly defined the default constructor we can declare the obj + +#bug: 22662 +type + BugClass* = object + x: int # Not initialized + +proc makeBugClass(): BugClass {.constructor.} = + discard + +proc main = + for i in 0 .. 1: + var n = makeBugClass() + echo n.x + n.x = 123 + echo n.x + +main() +#bug: +echo "___" +type + NimClassWithDefault = object + x: int + y = 777 + case kind: bool = true + of true: + z: int = 10 + else: discard + +proc makeNimClassWithDefault(): NimClassWithDefault {.constructor.} = + result = NimClassWithDefault() + +proc init = + for i in 0 .. 1: + var n = makeNimClassWithDefault() + echo n.x + echo n.y + echo n.z + n.x = 123 + echo n.x + +init() + +#tests that the ctor is not declared with nodecl. +#nodelc also prevents the creation of a default one when another is created. +type Foo {.exportc.} = object + +proc makeFoo(): Foo {.used, constructor, nodecl.} = discard + +echo $Foo() + +type Boo = object +proc `=copy`(dest: var Boo; src: Boo) = discard + +proc makeBoo(): Boo {.constructor.} = Boo() +proc makeBoo2(): Boo = Boo() + +block: + proc main = + var b = makeBoo() + var b2 = makeBoo2() + + main() \ No newline at end of file diff --git a/tests/cpp/tcovariancerules.nim b/tests/cpp/tcovariancerules.nim new file mode 100644 index 000000000..9d49f2cbd --- /dev/null +++ b/tests/cpp/tcovariancerules.nim @@ -0,0 +1,417 @@ +discard """ +targets: "cpp" +output: ''' +cat +cat +dog +dog +cat +cat +dog +dog X +cat +cat +dog +dog +dog +dog +dog 1 +dog 2 +''' +""" + +template accept(x) = + static: assert(compiles(x)) + +template reject(x) = + static: assert(not compiles(x)) + +import macros + +macro skipElse(n: untyped): untyped = n[0] + +template acceptWithCovariance(x, otherwise): untyped = + when defined nimEnableCovariance: + x + else: + reject(x) + skipElse(otherwise) + +type + Animal = object of RootObj + x: string + + Dog = object of Animal + y: int + + Cat = object of Animal + z: int + + AnimalRef = ref Animal + AnimalPtr = ptr Animal + + RefAlias[T] = ref T + +var dog = new(Dog) +dog.x = "dog" + +var cat = new(Cat) +cat.x = "cat" + +proc makeDerivedRef(x: string): ref Dog = + new(result) + result.x = x + +proc makeDerived(x: string): Dog = + result.x = x + +var covariantSeq = @[makeDerivedRef("dog 1"), makeDerivedRef("dog 2")] +var nonCovariantSeq = @[makeDerived("dog 1"), makeDerived("dog 2")] +var covariantArr = [makeDerivedRef("dog 1"), makeDerivedRef("dog 2")] +var nonCovariantArr = [makeDerived("dog 1"), makeDerived("dog 2")] + +proc wantsCovariantSeq1(s: seq[ref Animal]) = + for a in s: echo a.x + +proc wantsCovariantSeq2(s: seq[AnimalRef]) = + for a in s: echo a.x + +proc wantsCovariantSeq3(s: seq[RefAlias[Animal]]) = + for a in s: echo a.x + +proc wantsCovariantOpenArray(s: openArray[ref Animal]) = + for a in s: echo a.x + +proc modifiesCovariantOpenArray(s: var openArray[ref Animal]) = + for a in s: echo a.x + +proc modifiesDerivedOpenArray(s: var openArray[ref Dog]) = + for a in s: echo a.x + +proc wantsNonCovariantOpenArray(s: openArray[Animal]) = + for a in s: echo a.x + +proc wantsCovariantArray(s: array[2, ref Animal]) = + for a in s: echo a.x + +proc wantsNonCovariantSeq(s: seq[Animal]) = + for a in s: echo a.x + +proc wantsNonCovariantArray(s: array[2, Animal]) = + for a in s: echo a.x + +proc modifiesCovariantSeq(s: var seq[ref Animal]) = + for a in s: echo a.x + +proc modifiesCovariantArray(s: var array[2, ref Animal]) = + for a in s: echo a.x + +proc modifiesCovariantSeq(s: ptr seq[ref Animal]) = + for a in s[]: echo a.x + +proc modifiesCovariantArray(s: ptr array[2, ref Animal]) = + for a in s[]: echo a.x + +proc modifiesDerivedSeq(s: var seq[ref Dog]) = + for a in s: echo a.x + +proc modifiesDerivedArray(s: var array[2, ref Dog]) = + for a in s: echo a.x + +proc modifiesDerivedSeq(s: ptr seq[ref Dog]) = + for a in s[]: echo a.x + +proc modifiesDerivedArray(s: ptr array[2, ref Dog]) = + for a in s[]: echo a.x + +accept: + wantsCovariantArray([AnimalRef(dog), AnimalRef(dog)]) + wantsCovariantArray([AnimalRef(cat), AnimalRef(dog)]) + wantsCovariantArray([AnimalRef(cat), dog]) + + # there is a special rule that detects the base + # type of polymorphic arrays + wantsCovariantArray([cat, dog]) + +acceptWithCovariance: + wantsCovariantArray([cat, cat]) +else: + echo "cat" + echo "cat" + +var animalRefArray: array[2, ref Animal] + +accept: + animalRefArray = [AnimalRef(dog), AnimalRef(dog)] + animalRefArray = [AnimalRef(cat), dog] + +acceptWithCovariance: + animalRefArray = [dog, dog] + wantsCovariantArray animalRefArray +else: + echo "dog" + echo "dog" + +accept: + var animal: AnimalRef = dog + animal = cat + +var vdog: Dog +vdog.x = "dog value" +var vcat: Cat +vcat.x = "cat value" + +reject: + vcat = vdog + +# XXX: The next two cases seem inconsistent, perhaps we should change the rules +accept: + # truncating copies are allowed + var vanimal: Animal = vdog + vanimal = vdog + +reject: + # truncating copies are not allowed with arrays + var vanimalArray: array[2, Animal] + var vdogArray = [vdog, vdog] + vanimalArray = vdogArray + +accept: + # a more explicit version of a truncating copy that + # should probably always remain allowed + var vnextnimal: Animal = Animal(vdog) + +proc wantsRefSeq(x: seq[AnimalRef]) = discard + +accept: + wantsCovariantSeq1(@[AnimalRef(dog), AnimalRef(dog)]) + wantsCovariantSeq1(@[AnimalRef(cat), AnimalRef(dog)]) + wantsCovariantSeq1(@[AnimalRef(cat), dog]) + wantsCovariantSeq1(@[cat, dog]) + + wantsCovariantSeq2(@[AnimalRef(dog), AnimalRef(dog)]) + wantsCovariantSeq2(@[AnimalRef(cat), AnimalRef(dog)]) + wantsCovariantSeq2(@[AnimalRef(cat), dog]) + wantsCovariantSeq2(@[cat, dog]) + + wantsCovariantSeq3(@[AnimalRef(dog), AnimalRef(dog)]) + wantsCovariantSeq3(@[AnimalRef(cat), AnimalRef(dog)]) + wantsCovariantSeq3(@[AnimalRef(cat), dog]) + wantsCovariantSeq3(@[cat, dog]) + + wantsCovariantOpenArray([cat, dog]) + +acceptWithCovariance: + wantsCovariantSeq1(@[cat, cat]) + wantsCovariantSeq2(@[dog, makeDerivedRef("dog X")]) + # XXX: wantsCovariantSeq3(@[cat, cat]) + + wantsCovariantOpenArray(@[cat, cat]) + wantsCovariantOpenArray([dog, dog]) +else: + echo "cat" + echo "cat" + echo "dog" + echo "dog X" + echo "cat" + echo "cat" + echo "dog" + echo "dog" + +var dogRefs = @[dog, dog] +var dogRefsArray = [dog, dog] +var animalRefs = @[dog, cat] + +accept: + modifiesDerivedArray(dogRefsArray) + modifiesDerivedSeq(dogRefs) + +reject modifiesCovariantSeqd(ogRefs) +reject modifiesCovariantSeq(addr(dogRefs)) +reject modifiesCovariantSeq(dogRefs.addr) + +reject modifiesCovariantArray([dog, dog]) +reject modifiesCovariantArray(dogRefsArray) +reject modifiesCovariantArray(addr(dogRefsArray)) +reject modifiesCovariantArray(dogRefsArray.addr) + +var dogValues = @[vdog, vdog] +var dogValuesArray = [vdog, vdog] +when false: + var animalValues = @[Animal(vdog), Animal(vcat)] + var animalValuesArray = [Animal(vdog), Animal(vcat)] + + wantsNonCovariantSeq animalValues + wantsNonCovariantArray animalValuesArray + +reject wantsNonCovariantSeq(dogRefs) +reject modifiesCovariantOpenArray(dogRefs) +reject wantsNonCovariantArray(dogRefsArray) +reject wantsNonCovariantSeq(dogValues) +reject wantsNonCovariantArray(dogValuesArray) +reject modifiesValueArray() + +modifiesDerivedOpenArray dogRefs +reject modifiesDerivedOpenArray(dogValues) +reject modifiesDerivedOpenArray(animalRefs) + +reject wantsNonCovariantOpenArray(animalRefs) +reject wantsNonCovariantOpenArray(dogRefs) +reject wantsNonCovariantOpenArray(dogValues) + +var animalRefSeq: seq[ref Animal] + +accept: + animalRefSeq = @[AnimalRef(dog), AnimalRef(dog)] + animalRefSeq = @[AnimalRef(cat), dog] + +acceptWithCovariance: + animalRefSeq = @[makeDerivedRef("dog 1"), makeDerivedRef("dog 2")] + wantsCovariantSeq1(animalRefSeq) +else: + echo "dog 1" + echo "dog 2" + +var pdog: ptr Dog +var pcat: ptr Cat + +proc wantsPointer(x: ptr Animal) = + discard + +accept: + wantsPointer pdog + wantsPointer pcat + +# covariance should be disabled when var is involved +proc wantsVarPointer1(x: var ptr Animal) = + discard + +proc wantsVarPointer2(x: var AnimalPtr) = + discard + +reject wantsVarPointer1(pdog) +reject wantsVarPointer2(pcat) + +# covariance may be allowed for certain extern types + +{.emit: """/*TYPESECTION*/ +template <class T> struct FN { typedef void (*type)(T); }; +template <class T> struct ARR { typedef T DataType[2]; DataType data; }; +""".} + +type + MyPtr[out T] {.importcpp: "'0 *"} = object + + MySeq[out T] {.importcpp: "ARR<'0>", nodecl} = object + data: array[2, T] + + MyAction[in T] {.importcpp: "FN<'0>::type"} = object + +var + cAnimal: MyPtr[Animal] + cDog: MyPtr[Dog] + cCat: MyPtr[Cat] + + cAnimalFn: MyAction[Animal] + cCatFn: MyAction[Cat] + cDogFn: MyAction[Dog] + + cRefAnimalFn: MyAction[ref Animal] + cRefCatFn: MyAction[ref Cat] + cRefDogFn: MyAction[ref Dog] + +accept: + cAnimal = cDog + cAnimal = cCat + + cDogFn = cAnimalFn + cCatFn = cAnimalFn + + cRefDogFn = cRefAnimalFn + cRefCatFn = cRefAnimalFn + +reject: cDogFn = cRefAnimalFn +reject: cCatFn = cRefAnimalFn + +reject: cCat = cDog +reject: cAnimalFn = cDogFn +reject: cAnimalFn = cCatFn +reject: cRefAnimalFn = cRefDogFn +reject: cRefAnimalFn = cRefCatFn +reject: cRefAnimalFn = cDogFn + +var + ptrPtrDog: ptr ptr Dog + ptrPtrAnimal: ptr ptr Animal + +reject: ptrPtrDog = ptrPtrAnimal + +# Try to break the rules by introducing some tricky +# double indirection types: +var + cPtrRefAnimal: MyPtr[ref Animal] + cPtrRefDog: MyPtr[ref Dog] + + cPtrAliasRefAnimal: MyPtr[RefAlias[Animal]] + cPtrAliasRefDog: MyPtr[RefAlias[Dog]] + + cDoublePtrAnimal: MyPtr[MyPtr[Animal]] + cDoublePtrDog: MyPtr[MyPtr[Dog]] + +reject: cPtrRefAnimal = cPtrRefDog +reject: cDoublePtrAnimal = cDoublePtrDog +reject: cRefAliasPtrAnimal = cRefAliasPtrDog +reject: cPtrRefAnimal = cRefAliasPtrDog +reject: cPtrAliasRefAnimal = cPtrRefDog + +var + # Array and Sequence types are covariant only + # when instantiated with ref or ptr types: + cAnimals: MySeq[ref Animal] + cDogs: MySeq[ref Dog] + + # "User-defined" pointer types should be OK too: + cAnimalPtrSeq: MySeq[MyPtr[Animal]] + cDogPtrSeq: MySeq[MyPtr[Dog]] + + # Value types shouldn't work: + cAnimalValues: MySeq[Animal] + cDogValues: MySeq[Dog] + + # Double pointer types should not work either: + cAnimalRefPtrSeq: MySeq[ref MyPtr[Animal]] + cDogRefPtrSeq: MySeq[ref MyPtr[Dog]] + cAnimalPtrPtrSeq: MySeq[ptr ptr Animal] + cDogPtrPtrSeq: MySeq[ptr ptr Dog] + +accept: + cAnimals = cDogs + cAnimalPtrSeq = cDogPtrSeq + +reject: cAnimalValues = cDogValues +reject: cAnimalRefPtrSeq = cDogRefPtrSeq +reject: cAnimalPtrPtrSeq = cDogPtrPtrSeq + +proc wantsAnimalSeq(x: MySeq[Animal]) = discard +proc wantsAnimalRefSeq(x: MySeq[ref Animal]) = discard +proc modifiesAnimalRefSeq(x: var MySeq[ref Animal]) = discard +proc usesAddressOfAnimalRefSeq(x: ptr MySeq[ref Animal]) = discard + +accept wantsAnimalSeq(cAnimalValues) +reject wantsAnimalSeq(cDogValues) +reject wantsAnimalSeq(cAnimals) + +reject wantsAnimalRefSeq(cAnimalValues) +reject wantsAnimalRefSeq(cDogValues) +accept wantsAnimalRefSeq(cAnimals) +accept wantsAnimalRefSeq(cDogs) + +reject modifiesAnimalRefSeq(cAnimalValues) +reject modifiesAnimalRefSeq(cDogValues) +accept modifiesAnimalRefSeq(cAnimals) +reject modifiesAnimalRefSeq(cDogs) + +reject usesAddressOfAnimalRefSeq(addr cAnimalValues) +reject usesAddressOfAnimalRefSeq(addr cDogValues) +accept usesAddressOfAnimalRefSeq(addr cAnimals) +reject usesAddressOfAnimalRefSeq(addr cDogs) diff --git a/tests/cpp/tcppraise.nim b/tests/cpp/tcppraise.nim new file mode 100644 index 000000000..f03956d4c --- /dev/null +++ b/tests/cpp/tcppraise.nim @@ -0,0 +1,71 @@ +discard """ + targets: "cpp" + output: '''foo +bar +Need odd and >= 3 digits## +baz +caught +-------- +Triggered raises2 +Raising ValueError +''' +""" + +# bug #1888 +echo "foo" +try: + echo "bar" + raise newException(ValueError, "Need odd and >= 3 digits") +# echo "baz" +except ValueError: + echo getCurrentExceptionMsg(), "##" +echo "baz" + + +# bug 7232 +try: + discard +except KeyError, ValueError: + echo "except handler" # should not be invoked + + +#bug 7239 +try: + try: + raise newException(ValueError, "asdf") + except KeyError, ValueError: + raise +except: + echo "caught" + + +# issue 5549 + +var strs: seq[string] = @[] + +try: + discard +finally: + for foobar in strs: + discard + + +# issue #11118 +echo "--------" +proc raises() = + raise newException(ValueError, "Raising ValueError") + +proc raises2() = + try: + raises() + except ValueError as e: + echo "Triggered raises2" + raise e + +try: + raises2() +except: + echo getCurrentExceptionMsg() + discard + +doAssert: getCurrentException() == nil diff --git a/tests/cpp/tdont_init_instantiation.nim b/tests/cpp/tdont_init_instantiation.nim new file mode 100644 index 000000000..a13a3f6b4 --- /dev/null +++ b/tests/cpp/tdont_init_instantiation.nim @@ -0,0 +1,29 @@ +discard """ + targets: "cpp" + output: '''''' + disabled: true +""" + +# bug #5140 +{.emit:""" +#import <cassert> + +template <typename X> class C { + public: + int d; + + C(): d(1) { } + + C<X>& operator=(const C<X> other) { + assert(d == 1); + } +}; +""".} + +type C[X] {.importcpp, header: "<stdio.h>", nodecl.} = object +proc mkC[X]: C[X] {.importcpp: "C<'*0>()", constructor, nodecl.} + +proc foo(): C[int] = + result = mkC[int]() + +let gl = foo() diff --git a/tests/cpp/tembarrassing_generic_bug.nim b/tests/cpp/tembarrassing_generic_bug.nim new file mode 100644 index 000000000..4b5050948 --- /dev/null +++ b/tests/cpp/tembarrassing_generic_bug.nim @@ -0,0 +1,9 @@ +discard """ + targets: "cpp" + cmd: "nim cpp --threads:on $file" +""" + +# bug #5142 + +var ci: Channel[int] +ci.open diff --git a/tests/cpp/temitlist.nim b/tests/cpp/temitlist.nim new file mode 100644 index 000000000..9170be079 --- /dev/null +++ b/tests/cpp/temitlist.nim @@ -0,0 +1,38 @@ +discard """ + targets: "cpp" + output: ''' +6.0 +0''' +disabled: "windows" # pending bug #18011 +""" + +# bug #4730 + +type Vector*[T] {.importcpp: "std::vector", header: "<vector>".} = object + +template `[]=`*[T](v: var Vector[T], key: int, val: T) = + {.emit: [v, "[", key, "] = ", val, ";"].} + +proc setLen*[T](v: var Vector[T]; size: int) {.importcpp: "resize", nodecl.} +proc `[]`*[T](v: var Vector[T], key: int): T {.importcpp: "(#[#])", nodecl.} + +proc main = + var v: Vector[float] + v.setLen 1 + v[0] = 6.0 + echo v[0] + +main() + +#------------ + +#bug #6837 +type StdString {.importCpp: "std::string", header: "<string>", byref.} = object +proc initString(): StdString {.constructor, importCpp: "std::string(@)", header: "<string>".} +proc size(this: var StdString): csize_t {.importCpp: "size", header: "<string>".} + +proc f(): csize_t = + var myString: StdString = initString() + return myString.size() + +echo f() diff --git a/tests/cpp/tempty_generic_obj.nim b/tests/cpp/tempty_generic_obj.nim new file mode 100644 index 000000000..6125190b4 --- /dev/null +++ b/tests/cpp/tempty_generic_obj.nim @@ -0,0 +1,47 @@ +discard """ + targets: "cpp" + output: ''' +int +float''' +disabled: "windows" # pending bug #18011 +""" + +import typetraits + +# bug #4625 +type + Vector[T] {.importcpp: "std::vector<'0 >", header: "vector".} = object + +proc initVector[T](): Vector[T] {.importcpp: "'0(@)", header: "vector", constructor.} + +proc doSomething[T](v: var Vector[T]) = + echo T.name + +var v = initVector[int]() +v.doSomething() + +var vf = initVector[float]() +vf.doSomething() # Nim uses doSomething[int] here in C++ + +# Alternative definition: +# https://github.com/nim-lang/Nim/issues/7653 + +type VectorAlt*[T] {.importcpp: "std::vector", header: "<vector>", nodecl.} = object +proc mkVector*[T]: VectorAlt[T] {.importcpp: "std::vector<'*0>()", header: "<vector>", constructor, nodecl.} + +proc foo(): VectorAlt[cint] = + mkVector[cint]() + +proc bar(): VectorAlt[cstring] = + mkVector[cstring]() + +var x = foo() +var y = bar() + +proc init[T; Self: Vector[T]](_: typedesc[Self], n: csize_t): Vector[T] + {.importcpp: "std::vector<'*0>(@)", header: "<vector>", constructor, nodecl.} +proc size[T](x: Vector[T]): csize_t + {.importcpp: "#.size()", header: "<vector>", nodecl.} + +var z = Vector[int16].init(32) +assert z.size == 32 diff --git a/tests/cpp/tenum_set.nim b/tests/cpp/tenum_set.nim new file mode 100644 index 000000000..6afed722f --- /dev/null +++ b/tests/cpp/tenum_set.nim @@ -0,0 +1,9 @@ +discard """ +targets: "cpp" +output: "{A, B, C}" +""" + +type Enum {.importcpp: "namespaced::Enum", header: "enum.hpp".} = enum A, B, C + +var vals = {low(Enum) .. high(Enum)} +echo vals diff --git a/tests/cpp/tevalorder.nim b/tests/cpp/tevalorder.nim new file mode 100644 index 000000000..4764f3aca --- /dev/null +++ b/tests/cpp/tevalorder.nim @@ -0,0 +1,18 @@ +discard """ + output: '''0 +1 +2''' +targets: "cpp" +""" + +# bug #8202 +var current: int = 0 + +proc gen(): string = current.inc; $(current - 1) + +proc allOut(a, b, c: string) = + echo a + echo b + echo c + +allOut(gen(), gen(), gen()) 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 diff --git a/tests/cpp/tfam.nim b/tests/cpp/tfam.nim new file mode 100644 index 000000000..6bd89fe24 --- /dev/null +++ b/tests/cpp/tfam.nim @@ -0,0 +1,7 @@ +discard """ + targets: "cpp" +""" +type + Test {.importcpp, header: "fam.h".} = object + +let test = newSeq[Test]() \ No newline at end of file diff --git a/tests/cpp/tgen_prototype_for_importc.nim b/tests/cpp/tgen_prototype_for_importc.nim new file mode 100644 index 000000000..4e5a197a8 --- /dev/null +++ b/tests/cpp/tgen_prototype_for_importc.nim @@ -0,0 +1,10 @@ +discard """ + targets: "cpp" + output: '''Hello world''' +""" + +# bug #5136 + +{.compile: "foo.c".} +proc myFunc(): cstring {.importc.} +echo myFunc() diff --git a/tests/cpp/tget_subsystem.nim b/tests/cpp/tget_subsystem.nim new file mode 100644 index 000000000..6fb095a3d --- /dev/null +++ b/tests/cpp/tget_subsystem.nim @@ -0,0 +1,39 @@ +discard """ + targets: "cpp" +""" + +{.emit: """ + +namespace System { + struct Input {}; +} + +struct SystemManager { + template <class T> + static T* getSubsystem() { return new T; } +}; + +""".} + +type Input {.importcpp: "System::Input".} = object +proc getSubsystem*[T](): ptr T {. + importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.} + +let input: ptr Input = getSubsystem[Input]() + + +# bugs #4910, #6892 +proc modify(x: var int) = + x = 123 + +proc foo() = + var ts: array[2, int] + for t in mitems(ts): + discard + + for t in mitems(ts): + modify(t) + + for i, t in mpairs(ts): + modify(t) + diff --git a/tests/cpp/tinitializers.nim b/tests/cpp/tinitializers.nim new file mode 100644 index 000000000..0199fb96b --- /dev/null +++ b/tests/cpp/tinitializers.nim @@ -0,0 +1,60 @@ +discard """ + cmd: "nim cpp $file" +""" + +{.emit:"""/*TYPESECTION*/ +struct CppStruct { + CppStruct(int x, char* y): x(x), y(y){} + void doSomething() {} + int x; + char* y; +}; +""".} +type + CppStruct {.importcpp, inheritable.} = object + ChildStruct = object of CppStruct + HasCppStruct = object + cppstruct: CppStruct + +proc constructCppStruct(a:cint = 5, b:cstring = "hello"): CppStruct {.importcpp: "CppStruct(@)", constructor.} +proc doSomething(this: CppStruct) {.importcpp.} +proc returnCppStruct(): CppStruct = discard +proc initChildStruct: ChildStruct = ChildStruct() +proc makeChildStruct(): ChildStruct {.constructor:"""ChildStruct(): CppStruct(5, "10")""".} = discard +proc initHasCppStruct(x: cint): HasCppStruct = + HasCppStruct(cppstruct: constructCppStruct(x)) + +proc main = + var hasCppStruct = initHasCppStruct(2) #generates cppstruct = { 10 } inside the struct + hasCppStruct.cppstruct.doSomething() + discard returnCppStruct() #generates result = { 10 } + discard initChildStruct() #generates ChildStruct temp ({}) bypassed with makeChildStruct + (proc (s:CppStruct) = discard)(CppStruct()) #CppStruct temp ({10}) +main() + + +#Should handle ObjectCalls +{.emit:"""/*TYPESECTION*/ +struct Foo { +}; +struct Boo { + Boo(int x, char* y, Foo f): x(x), y(y), foo(f){} + int x; + char* y; + Foo foo; +}; +""".} +type + Foo {.importcpp, inheritable, bycopy.} = object + Boo {.importcpp, inheritable.} = object + x: int32 + y: cstring + foo: Foo + +proc makeBoo(a:cint = 10, b:cstring = "hello", foo: Foo = Foo()): Boo {.importcpp, constructor.} + +proc main2() = + let cppStruct = makeBoo() + (proc (s:Boo) = discard)(Boo()) + +main2() \ No newline at end of file diff --git a/tests/cpp/tmember.nim b/tests/cpp/tmember.nim new file mode 100644 index 000000000..1a5b6fd97 --- /dev/null +++ b/tests/cpp/tmember.nim @@ -0,0 +1,75 @@ +discard """ + targets: "cpp" + cmd: "nim cpp $file" + output: ''' +2 +false +hello foo +hello boo +hello boo +FunctorSupport! +static +static +destructing +destructing +''' +""" +proc print(s: cstring) {.importcpp:"printf(@)", header:"<stdio.h>".} + +type + Doo {.exportc.} = object + test: int + +proc memberProc(f: Doo) {.exportc, member.} = + echo $f.test + +proc destructor(f: Doo) {.member: "~'1()", used.} = + print "destructing\n" + +proc `==`(self, other: Doo): bool {.member:"operator==('2 const & #2) const -> '0"} = + self.test == other.test + +let doo = Doo(test: 2) +doo.memberProc() +echo doo == Doo(test: 1) + +#virtual +proc newCpp*[T](): ptr T {.importcpp:"new '*0()".} +type + Foo {.exportc.} = object of RootObj + FooPtr = ptr Foo + Boo = object of Foo + BooPtr = ptr Boo + +proc salute(self: FooPtr) {.member: "virtual $1()".} = + echo "hello foo" + +proc salute(self: BooPtr) {.member: "virtual $1()".} = + echo "hello boo" + +let foo = newCpp[Foo]() +let boo = newCpp[Boo]() +let booAsFoo = cast[FooPtr](newCpp[Boo]()) + +foo.salute() +boo.salute() +booAsFoo.salute() + +type + NimFunctor = object + discard +proc invoke(f: NimFunctor, n:int) {.member:"operator ()('2 #2)" .} = + echo "FunctorSupport!" + +{.experimental: "callOperator".} +proc `()`(f: NimFunctor, n:int) {.importcpp:"#(@)" .} +NimFunctor()(1) + +#static +proc staticProc(self: FooPtr) {.member: "static $1()".} = + echo "static" + +proc importedStaticProc() {.importcpp:"Foo::staticProc()".} + +foo.staticProc() +importedStaticProc() diff --git a/tests/cpp/tmember_forward_declaration.nim b/tests/cpp/tmember_forward_declaration.nim new file mode 100644 index 000000000..2f4a79daa --- /dev/null +++ b/tests/cpp/tmember_forward_declaration.nim @@ -0,0 +1,27 @@ +discard """ + targets: "cpp" + cmd: "nim cpp $file" + output: ''' +abc called +def called +abc called +''' +""" + +type Foo = object + +proc abc(this: Foo, x: int): void {.member: "$1('2 #2)".} +proc def(this: Foo, y: int): void {.virtual: "$1('2 #2)".} + +proc abc(this: Foo, x: int): void = + echo "abc called" + if x > 0: + this.def(x - 1) + +proc def(this: Foo, y: int): void = + echo "def called" + this.abc(y) + +var x = Foo() +x.abc(1) + diff --git a/tests/cpp/tnativesockets.nim b/tests/cpp/tnativesockets.nim new file mode 100644 index 000000000..1284811b5 --- /dev/null +++ b/tests/cpp/tnativesockets.nim @@ -0,0 +1,6 @@ +discard """ + targets: "cpp" +outputsub: "" +""" + +import nativesockets diff --git a/tests/cpp/tnoinitfield.nim b/tests/cpp/tnoinitfield.nim new file mode 100644 index 000000000..4deffece8 --- /dev/null +++ b/tests/cpp/tnoinitfield.nim @@ -0,0 +1,30 @@ +discard """ + targets: "cpp" + cmd: "nim cpp $file" + output: ''' +''' +""" +{.emit: """/*TYPESECTION*/ + struct Foo { + Foo(int a){}; + }; + struct Boo { + Boo(int a){}; + }; + + """.} + +type + Foo {.importcpp.} = object + Boo {.importcpp, noInit.} = object + Test {.exportc.} = object + foo {.noInit.}: Foo + boo: Boo + +proc makeTest(): Test {.constructor: "Test() : foo(10), boo(1)".} = + discard + +proc main() = + var t = makeTest() + +main() \ No newline at end of file diff --git a/tests/cpp/torc.nim b/tests/cpp/torc.nim new file mode 100644 index 000000000..9f1a41a21 --- /dev/null +++ b/tests/cpp/torc.nim @@ -0,0 +1,75 @@ +discard """ + targets: "cpp" + matrix: "--gc:orc" +""" + +import std/options + +# bug #18410 +type + O = object of RootObj + val: pointer + +proc p(): Option[O] = none(O) + +doAssert $p() == "none(O)" + +# bug #17351 +type + Foo = object of RootObj + Foo2 = object of Foo + Bar = object + x: Foo2 + +var b = Bar() +discard b + +# bug #4678 +{.emit: """/*TYPESECTION*/ +enum class SomeEnum {A,B,C}; +""".} +type + EnumVector[T: enum] {.importcpp: "std::vector", header: "vector".} = object + SomeEnum {.importcpp, nodecl.} = enum + A,B,C + +proc asVector*[T](t: T): EnumVector[T] = + discard +# Nim generates this signature here: +# N_NIMCALL(std::vector<> , asvector_106028_3197418230)(SomeEnum t0) + +discard asVector(SomeEnum.A) + + +block: # bug #10219 + type + Vector[T] {.importcpp: "std::vector", header: "vector".} = object + + proc initVector[T](n: csize_t): Vector[T] + {.importcpp: "std::vector<'*0>(@)", header: "vector".} + + proc unsafeIndex[T](this: var Vector[T], i: csize_t): var T + {.importcpp: "#[#]", header: "vector".} + + proc `[]`[T](this: var Vector[T], i: Natural): var T {.inline, noinit.} = + when compileOption("boundChecks"): + # this.checkIndex i + discard + result = this.unsafeIndex(csize_t(i)) + + var v1 = initVector[int](10) + doAssert v1[0] == 0 + +block: # bug #12703 bug #19588 + type + cstringConstImpl {.importc:"const char*".} = cstring + constChar = distinct cstringConstImpl + + {.emit: """ + const char* foo() { + return "hello"; + } + """.} + proc foo(): constChar {.importcpp.} # change to importcpp for C++ backend + doAssert $(foo().cstring) == "hello" + diff --git a/tests/cpp/tpassbypragmas.nim b/tests/cpp/tpassbypragmas.nim new file mode 100644 index 000000000..f4301656a --- /dev/null +++ b/tests/cpp/tpassbypragmas.nim @@ -0,0 +1,27 @@ +discard """ + targets: "cpp" + cmd: "nim cpp $file" +""" +{.emit:"""/*TYPESECTION*/ + + template<typename T> + struct Box { + T first; + }; + struct Foo { + void test(void (*func)(Box<Foo>& another)){ + + }; + }; +""".} + +type + Foo {.importcpp.} = object + Box[T] {.importcpp:"Box<'0>".} = object + first: T + +proc test(self: Foo, fn: proc(another {.byref.}: Box[Foo]) {.cdecl.}) {.importcpp.} + +proc fn(another {.byref.} : Box[Foo]) {.cdecl.} = discard + +Foo().test(fn) \ No newline at end of file diff --git a/tests/cpp/treturn_array.nim b/tests/cpp/treturn_array.nim new file mode 100644 index 000000000..432b9ce3b --- /dev/null +++ b/tests/cpp/treturn_array.nim @@ -0,0 +1,13 @@ +discard """ + targets: "cpp" +""" + +# bug #2259 +type Mat4f* = array[0..15, float] + +proc get_rot_mat*(): Mat4f = discard +var mat: Mat4f = get_rot_mat() + +# bug #1389 +proc calcSizes(): array[2, int] = discard +let sizes: array[2, int] = calcSizes() diff --git a/tests/cpp/tretvar.nim b/tests/cpp/tretvar.nim new file mode 100644 index 000000000..0c3765346 --- /dev/null +++ b/tests/cpp/tretvar.nim @@ -0,0 +1,39 @@ +discard """ + targets: "cpp" + output: '''test1 +xest1 +''' +""" +{.passC: "-std=c++14".} + +{.experimental: "dotOperators".} + +import macros + +type + stdString {.importcpp: "std::string", header: "<string>".} = object + stdUniquePtr[T] {.importcpp: "std::unique_ptr", header: "<memory>".} = object + +proc c_str(a: stdString): cstring {.importcpp: "(char *)(#.c_str())", header: "<string>".} + +proc len(a: stdString): csize_t {.importcpp: "(#.length())", header: "<string>".} + +proc setChar(a: var stdString, i: csize_t, c: char) {.importcpp: "(#[#] = #)", header: "<string>".} + +proc `*`*[T](this: stdUniquePtr[T]): var T {.noSideEffect, importcpp: "(* #)", header: "<memory>".} + +proc make_unique_str(a: cstring): stdUniquePtr[stdString] {.importcpp: "std::make_unique<std::string>(#)", header: "<string>".} + +macro `.()`*[T](this: stdUniquePtr[T], name: untyped, args: varargs[untyped]): untyped = + result = nnkCall.newTree( + nnkDotExpr.newTree( + newNimNode(nnkPar).add(prefix(this, "*")), + name + ) + ) + copyChildrenTo(args, result) + +var val = make_unique_str("test1") +echo val.c_str() +val.setChar(0, 'x') +echo val.c_str() diff --git a/tests/cpp/tsigbreak.nim b/tests/cpp/tsigbreak.nim new file mode 100644 index 000000000..14d29adf7 --- /dev/null +++ b/tests/cpp/tsigbreak.nim @@ -0,0 +1,29 @@ +discard """ + targets: "cpp" + action: compile +""" + +import tables, lists + +type + ListTable[K, V] = object + table: Table[K, DoublyLinkedNode[V]] + +proc initListTable*[K, V](initialSize = 64): ListTable[K, V] = + result.table = initTable[K, DoublyLinkedNode[V]]() + +proc `[]=`*[K, V](t: var ListTable[K, V], key: K, val: V) = + t.table[key].value = val + +type + SomeObj = object + OtherObj = object + +proc main() = + var someTable = initListTable[int, SomeObj]() + var otherTable = initListTable[int, OtherObj]() + + someTable[1] = SomeObj() + otherTable[42] = OtherObj() + +main() diff --git a/tests/cpp/tstaticvar_via_typedesc.nim b/tests/cpp/tstaticvar_via_typedesc.nim new file mode 100644 index 000000000..0d8f424d0 --- /dev/null +++ b/tests/cpp/tstaticvar_via_typedesc.nim @@ -0,0 +1,20 @@ +discard """ + targets: "cpp" + output: "42" +""" + +# bug #2324 + +static: assert defined(cpp), "compile in cpp mode" + +{.emit: """ +class Foo { +public: + static int x; +}; +int Foo::x = 42; +""".} + +type Foo {.importcpp:"Foo".} = object +proc x* (this: typedesc[Foo]): int {.importcpp:"Foo::x@", nodecl.} +echo Foo.x diff --git a/tests/cpp/ttemplatetype.nim b/tests/cpp/ttemplatetype.nim new file mode 100644 index 000000000..bf243ac43 --- /dev/null +++ b/tests/cpp/ttemplatetype.nim @@ -0,0 +1,13 @@ +discard """ + targets: "cpp" +""" + +type + Map[T,U] {.importcpp: "std::map", header: "<map>".} = object + +proc cInitMap(T: typedesc, U: typedesc): Map[T,U] {.importcpp: "std::map<'*1,'*2>()", nodecl.} + +proc initMap[T, U](): Map[T, U] = + result = cInitMap(T, U) + +var x: Map[cstring, cint] = initMap[cstring, cint]() diff --git a/tests/cpp/tterminate_handler.nim b/tests/cpp/tterminate_handler.nim new file mode 100644 index 000000000..c5ccef53c --- /dev/null +++ b/tests/cpp/tterminate_handler.nim @@ -0,0 +1,10 @@ +discard """ + targets: "cpp" + outputsub: "Error: unhandled unknown cpp exception" + exitcode: 1 + disabled: true +""" +type Crap {.importcpp: "int".} = object + +var c: Crap +raise c diff --git a/tests/cpp/tthread_createthread.nim b/tests/cpp/tthread_createthread.nim new file mode 100644 index 000000000..b46b876b7 --- /dev/null +++ b/tests/cpp/tthread_createthread.nim @@ -0,0 +1,15 @@ +discard """ + targets: "cpp" + cmd: "nim cpp --hints:on --threads:on $options $file" +""" + +proc threadMain(a: int) {.thread.} = + discard + +proc main() = + var thread: Thread[int] + + thread.createThread(threadMain, 0) + thread.joinThreads() + +main() diff --git a/tests/cpp/ttypeinfo1.nim b/tests/cpp/ttypeinfo1.nim new file mode 100644 index 000000000..97825f452 --- /dev/null +++ b/tests/cpp/ttypeinfo1.nim @@ -0,0 +1,22 @@ +discard """ + targets: "cpp" + output: '''100''' +""" + +import typeinfo + +#bug #6016 +type + Onion {.union.} = object + field1: int + field2: uint64 + + Stroom = Onion + + PStroom = ptr Stroom + +proc pstruct(u: PStroom) = + echo u.field2 + +var x = Onion(field1: 100) +pstruct(x.addr) \ No newline at end of file diff --git a/tests/cpp/ttypeinfo2.nim b/tests/cpp/ttypeinfo2.nim new file mode 100644 index 000000000..e3661c848 --- /dev/null +++ b/tests/cpp/ttypeinfo2.nim @@ -0,0 +1,6 @@ +discard """ + targets: "cpp" +""" +# bug #2841 +import typeinfo +var tt: Any diff --git a/tests/cpp/tvector_iterator.nim b/tests/cpp/tvector_iterator.nim new file mode 100644 index 000000000..c3886c547 --- /dev/null +++ b/tests/cpp/tvector_iterator.nim @@ -0,0 +1,19 @@ +discard """ + targets: "cpp" +""" + +{.emit: """/*TYPESECTION*/ + +template <class T> +struct Vector { + struct Iterator {}; +}; + +""".} + +type + Vector[T] {.importcpp: "Vector".} = object + VectorIterator[T] {.importcpp: "Vector<'0>::Iterator".} = object + +var x: VectorIterator[void] + diff --git a/tests/cpp/tvectorseq.nim b/tests/cpp/tvectorseq.nim new file mode 100644 index 000000000..4d9ffc3d6 --- /dev/null +++ b/tests/cpp/tvectorseq.nim @@ -0,0 +1,38 @@ +discard """ + targets: "cpp" + output: '''(x: 1.0) +(x: 0.0)''' + disabled: "true" +""" + +# This cannot work yet because we omit type information for importcpp'ed types. +# Fixing this is not hard, but also requires fixing Urhonimo. + +# bug #2536 + +{.emit: """/*TYPESECTION*/ +struct Vector3 { +public: + Vector3(): x(5) {} + Vector3(float x_): x(x_) {} + float x; +}; +""".} + +type Vector3 {.importcpp: "Vector3", nodecl} = object + x: cfloat + +proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl} + +# hack around another codegen issue: Generics are attached to where they came +# from: +proc `$!`(v: seq[Vector3]): string = "(x: " & $v[0].x & ")" + +proc vec3List*(): seq[Vector3] = + let s = @[constructVector3(cfloat(1))] + echo($!s) + result = s + echo($!result) + +let f = vec3List() +#echo($!f) diff --git a/tests/cpp/tvirtual.nim b/tests/cpp/tvirtual.nim new file mode 100644 index 000000000..385d052b8 --- /dev/null +++ b/tests/cpp/tvirtual.nim @@ -0,0 +1,126 @@ +discard """ + targets: "cpp" + cmd: "nim cpp $file" + output: ''' +hello foo +hello boo +hello boo +Const Message: hello world +NimPrinter: hello world +NimPrinterConstRef: hello world +NimPrinterConstRefByRef: hello world +''' +""" + +{.emit:"""/*TYPESECTION*/ +#include <iostream> + class CppPrinter { + public: + + virtual void printConst(char* message) const { + std::cout << "Const Message: " << message << std::endl; + } + virtual void printConstRef(char* message, const int& flag) const { + std::cout << "Const Ref Message: " << message << std::endl; + } + virtual void printConstRef2(char* message, const int& flag) const { + std::cout << "Const Ref2 Message: " << message << std::endl; + } + +}; +""".} + +proc newCpp*[T](): ptr T {.importcpp:"new '*0()".} +type + Foo = object of RootObj + FooPtr = ptr Foo + Boo = object of Foo + BooPtr = ptr Boo + CppPrinter {.importcpp, inheritable.} = object + NimPrinter {.exportc.} = object of CppPrinter + +proc salute(self: FooPtr) {.virtual.} = + echo "hello foo" + +proc salute(self: BooPtr) {.virtual.} = + echo "hello boo" + +let foo = newCpp[Foo]() +let boo = newCpp[Boo]() +let booAsFoo = cast[FooPtr](newCpp[Boo]()) + +#polymorphism works +foo.salute() +boo.salute() +booAsFoo.salute() +let message = "hello world".cstring + +proc printConst(self: CppPrinter, message: cstring) {.importcpp.} +CppPrinter().printConst(message) + +#notice override is optional. +#Will make the cpp compiler to fail if not virtual function with the same signature if found in the base type +proc printConst(self: NimPrinter, message: cstring) {.virtual:"$1('2 #2) const override".} = + echo "NimPrinter: " & $message + +proc printConstRef(self: NimPrinter, message: cstring, flag: int32) {.virtual:"$1('2 #2, const '3& #3 ) const override".} = + echo "NimPrinterConstRef: " & $message + +proc printConstRef2(self: NimPrinter, message: cstring, flag {.byref.}: int32) {.virtual:"$1('2 #2, const '3 #3 ) const override".} = + echo "NimPrinterConstRefByRef: " & $message + +NimPrinter().printConst(message) +var val : int32 = 10 +NimPrinter().printConstRef(message, val) +NimPrinter().printConstRef2(message, val) + +#bug 22269 +type Doo = object +proc naiveMember(x: Doo): int {. virtual .} = 2 +discard naiveMember(Doo()) + +#asmnostackframe works with virtual +{.emit:"""/*TYPESECTION*/ + template<typename T> + struct Box { + T* first; + + Box(int x){ + first = new T(x); + }; + }; + struct Inner { + int val; + //Coo() = default; + Inner(int x){ + val = x; + }; + }; + struct Base { + virtual Box<Inner> test() = 0; + }; +""".} + +type + Inner {.importcpp.} = object + Base {.importcpp, inheritable.} = object + Child = object of Base + Box[T] {.importcpp, inheritable.} = object + first: T + +proc makeBox[T](x:int32): Box[T] {.importcpp:"Box<'0>(@)", constructor.} + +proc test(self: Child): Box[Inner] {.virtual, asmnostackframe.} = + let res {.exportc.} = makeBox[Inner](100) + {.emit:"return res;".} + + +discard Child().test() + +import virtualptr + +#We dont want to pull Loo directly by using it as we are testing that the pointer pulls it. +proc makeMoo(): Moo {.importcpp:"{ new Loo() }".} + +makeMoo().loo.salute() + diff --git a/tests/cpp/virtualptr.nim b/tests/cpp/virtualptr.nim new file mode 100644 index 000000000..f96264081 --- /dev/null +++ b/tests/cpp/virtualptr.nim @@ -0,0 +1,9 @@ +type + Loo* {.exportc.} = object + LooPtr* = ptr Loo + Moo* {.exportc.} = object + loo*: LooPtr + + +proc salute*(foo: LooPtr) {.virtual.} = + discard |