summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorReimer Behrends <behrends@gmail.com>2015-12-15 13:33:38 +0100
committerReimer Behrends <behrends@gmail.com>2015-12-15 13:33:38 +0100
commitf664c576c2aab2b2d7f72693bff5a106eb6ef794 (patch)
tree0aaa71241b53117849f1454996ad35aae75ac71d
parent31ebb11d73f7ad58afc497f20d9723503b83ca75 (diff)
downloadNim-f664c576c2aab2b2d7f72693bff5a106eb6ef794.tar.gz
Fix code generation issues with TNimType.
This is an alternative attempt to fix issue #2841 in a way that does not
rely on non-standard C compiler behavior.

The underlying problem is that the typeinfo module includes
system/hti.nim, but system/hti.nim is also included by system.nim. The
result is that the compiler at any given point has two instances of
TNimType with the same external name and will generate code either for
one or both of them. Code generation for the second version is normally
suppressed by using {.importc.}, but that results in a missing type
declaration for modules that only use the second version. This happens
for modules that import typeinfo, because the the second component of
typeinfo.Any has type PNimType = ptr TNimType, which generates a
"TNimType *" struct member.

The previous solution was to have a typedef for TNimType in nimbase.h;
however, this results in duplicate typedefs (specifically, but not only
for the code generated for typeinfo.nim). Duplicate typedefs with the
same type name are allowed in C++ and C11, but are explicitly forbidden
in C89 and C99. Modern versions of gcc and clang accept them anyway, but
this is not standard-compliant and may break for other C compilers or
older versions of gcc and clang.

This patch attempts to fix the issue by making the second component of
typeinfo.Nim a pointer instead of a PNimType and casting back and forth
as needed. Thus, the second version of TNimType occurs only within the
code for typeinfo.nim, where it can be safely omitted.
-rw-r--r--lib/core/typeinfo.nim20
-rw-r--r--lib/nimbase.h4
2 files changed, 15 insertions, 9 deletions
diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim
index 1f9fb1072..db5a83755 100644
--- a/lib/core/typeinfo.nim
+++ b/lib/core/typeinfo.nim
@@ -61,7 +61,10 @@ type
                           ## wrapped value and **must not** live longer than
                           ## its wrapped value.
     value: pointer
-    rawType: PNimType
+    when defined(js):
+      rawType: PNimType
+    else:
+      rawTypePtr: pointer
 
   ppointer = ptr pointer
   pbyteArray = ptr array[0.. 0xffff, int8]
@@ -71,6 +74,14 @@ type
     when defined(gogc):
       elemSize: int
   PGenSeq = ptr TGenericSeq
+
+when not defined(js):
+  template rawType(x: Any): PNimType =
+    cast[PNimType](x.rawTypePtr)
+
+  template `rawType=`(x: var Any, p: PNimType) =
+    x.rawTypePtr = cast[pointer](p)
+
 {.deprecated: [TAny: Any, TAnyKind: AnyKind].}
 
 when defined(gogc):
@@ -108,7 +119,7 @@ proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode =
   else:
     result = n.sons[n.len]
 
-proc newAny(value: pointer, rawType: PNimType): Any =
+proc newAny(value: pointer, rawType: PNimType): Any {.inline.} =
   result.value = value
   result.rawType = rawType
 
@@ -126,8 +137,7 @@ proc toAny*[T](x: var T): Any {.inline.} =
   ## constructs a ``Any`` object from `x`. This captures `x`'s address, so
   ## `x` can be modified with its ``Any`` wrapper! The client needs to ensure
   ## that the wrapper **does not** live longer than `x`!
-  result.value = addr(x)
-  result.rawType = cast[PNimType](getTypeInfo(x))
+  newAny(addr(x), cast[PNimType](getTypeInfo(x)))
 
 proc kind*(x: Any): AnyKind {.inline.} =
   ## get the type kind
@@ -345,7 +355,7 @@ proc `[]`*(x: Any, fieldName: string): Any =
     result.value = x.value +!! n.offset
     result.rawType = n.typ
   elif x.rawType.kind == tyObject and x.rawType.base != nil:
-    return `[]`(Any(value: x.value, rawType: x.rawType.base), fieldName)
+    return `[]`(newAny(x.value, x.rawType.base), fieldName)
   else:
     raise newException(ValueError, "invalid field name: " & fieldName)
 
diff --git a/lib/nimbase.h b/lib/nimbase.h
index 0946b9a1f..bba5ac023 100644
--- a/lib/nimbase.h
+++ b/lib/nimbase.h
@@ -418,10 +418,6 @@ typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(
 #  define NIM_EXTERNC
 #endif
 
-/* we have to tinker with TNimType as it's both part of system.nim and
-   typeinfo.nim but system.nim doesn't export it cleanly... */
-typedef struct TNimType TNimType;
-
 /* ---------------- platform specific includes ----------------------- */
 
 /* VxWorks related includes */