From cbd059aa85c81fefb40159773182fafaf2de9617 Mon Sep 17 00:00:00 2001 From: zah Date: Thu, 8 Mar 2018 16:10:45 +0200 Subject: [PATCH] Fix #6415 (#7281) * hangle static generic params when used in the importcpp pragma * importcpp works for generic types with fields; fixes #6415 * revert a too agressive safety check that ended up breaking the tests --- changelog.md | 5 +++ compiler/ccgtypes.nim | 9 ++++- compiler/semtypes.nim | 10 +++-- tests/statictypes/tstaticimportcpp.nim | 53 ++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 tests/statictypes/tstaticimportcpp.nim diff --git a/changelog.md b/changelog.md index 00c638f1d3..46428f9ab4 100644 --- a/changelog.md +++ b/changelog.md @@ -25,3 +25,8 @@ ### Compiler changes ### Bugfixes + +- The `importcpp` pragma now allows importing the listed fields of generic + C++ types. Support for numeric parameters have also been added through + the use of `static[T]` types. + (#6415) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 6f9da56e34..bdba34e361 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -617,8 +617,10 @@ proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool = return false proc resolveStarsInCppType(typ: PType, idx, stars: int): PType = - # XXX: we should catch this earlier and report it as a semantic error - if idx >= typ.len: internalError "invalid apostrophe type parameter index" + # Make sure the index refers to one of the generic params of the type. + # XXX: we should catch this earlier and report it as a semantic error. + if idx >= typ.len: + internalError "invalid apostrophe type parameter index" result = typ.sons[idx] for i in 1..stars: @@ -820,6 +822,9 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = let typeInSlot = resolveStarsInCppType(origTyp, idx + 1, stars) if typeInSlot == nil or typeInSlot.kind == tyVoid: result.add(~"void") + elif typeInSlot.kind == tyStatic: + internalAssert typeInSlot.n != nil + result.add typeInSlot.n.renderTree else: result.add getTypeDescAux(m, typeInSlot, check) else: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 50c2e287e2..e9f4e1a989 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -632,16 +632,18 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, else: typ = semTypeNode(c, n.sons[length-2], nil) propagateToOwner(rectype, typ) - let rec = rectype.sym + var fieldOwner = if c.inGenericContext > 0: c.getCurrOwner + else: rectype.sym for i in countup(0, sonsLen(n)-3): var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported}) suggestSym(n.sons[i].info, f, c.graph.usageSym) f.typ = typ f.position = pos - if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and - (f.loc.r == nil): + if fieldOwner != nil and + {sfImportc, sfExportc} * fieldOwner.flags != {} and + f.loc.r == nil: f.loc.r = rope(f.name.s) - f.flags = f.flags + ({sfImportc, sfExportc} * rec.flags) + f.flags = f.flags + ({sfImportc, sfExportc} * fieldOwner.flags) inc(pos) if containsOrIncl(check, f.name.id): localError(n.sons[i].info, errAttemptToRedefine, f.name.s) diff --git a/tests/statictypes/tstaticimportcpp.nim b/tests/statictypes/tstaticimportcpp.nim new file mode 100644 index 0000000000..e13cc36b45 --- /dev/null +++ b/tests/statictypes/tstaticimportcpp.nim @@ -0,0 +1,53 @@ +discard """ +targets: "cpp" +output: "[0, 0, 10, 0]\n5\n1.2\n15\ntest" +""" + +{.emit: """ + +template +struct GenericIntType { + T data[N]; +}; + +template +struct GenericTType { + T field; +}; + +struct SimpleStruct { + int field; +}; + + +""" .} + +type + GenericIntType {.importcpp: "GenericIntType<'0, '1>".} [N: static[int]; T] = object + data: array[N, T] + + GenericTType {.importcpp: "GenericTType<'0>".} [T] = object + field: T + + GenInt4 = GenericIntType[4, int] + + SimpleStruct {.importcpp: "SimpleStruct"} = object + field: int + +var + a = GenInt4() + b = SimpleStruct() + c = GenericTType[float]() + d = SimpleStruct(field: 15) + e = GenericTType[string](field: "test") + +a.data[2] = 10 +b.field = 5 +c.field = 1.2 + +echo a.data +echo b.field +echo c.field +echo d.field +echo e.field +