Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

complex constant doesn't work at c++ backend #9622

Closed
haltcase opened this issue Nov 4, 2018 · 12 comments · Fixed by #17557
Closed

complex constant doesn't work at c++ backend #9622

haltcase opened this issue Nov 4, 2018 · 12 comments · Fixed by #17557
Assignees
Labels
Object Variants VM see also `const` label

Comments

@haltcase
Copy link
Contributor

haltcase commented Nov 4, 2018

Example

Sorry the source is a bit long, I've tried for a long time to reduce but couldn't narrow down as much as we'd all like.

source file
import strutils, parseutils

type
  GlobTokenKind {.pure.} = enum
    WildcardCharacter,
    WildcardString,
    WildcardDirectory,
    ClassStart,
    ClassNegation,
    ClassEnd,
    GroupStart,
    GroupSeparator,
    GroupEnd,
    Escape,
    PathSeparator,
    Literal,
    PatternEnd

  GlobNodeKind {.pure.} = enum
    LiteralIdent,
    MatchCharacter,
    MatchString,
    MatchDirectory,
    Class,
    Group

  GlobNode = object
    case kind: GlobNodeKind
    of LiteralIdent:
      value: string
    of MatchCharacter..MatchDirectory:
      nil
    of Class:
      negated: bool
      rawChars: string
      chars: set[char]
    of Group:
      values: seq[string]

  PathSegment = object
    children*: seq[GlobNode]

  GlobPattern = seq[PathSegment]

  ParserState {.pure.} = enum
    StateStart, StateClass, StateGroup, StateEnd

  GlobParser = object
    pattern*: string
    pos*: int
    a*: string
    tok*: GlobTokenKind
    state*: seq[ParserState]

const
  GlobIdentChars = IdentChars + {'-', '.'}

proc getToken (parser: var GlobParser) =
  if parser.pos == parser.pattern.len:
    parser.tok = PatternEnd
    return

  case parser.pattern[parser.pos]
  of '\\':
    inc parser.pos
    parser.a = $parser.pattern[parser.pos]
    inc parser.pos
    parser.tok = Literal
  of '*':
    inc parser.pos
    parser.tok = WildcardString

    var extra = 0
    while parser.pattern[parser.pos] == '*': inc extra
    if extra > 0:
      inc(parser.pos, extra)
      parser.tok = WildcardDirectory
  of '?':
    inc parser.pos
    parser.tok = WildcardCharacter
  of '[':
    inc parser.pos
    parser.tok = ClassStart
  of '!':
    inc parser.pos
    parser.tok = ClassNegation
  of ']':
    inc parser.pos
    parser.tok = ClassEnd
  of '{':
    inc parser.pos
    parser.tok = GroupStart
  of ',':
    inc parser.pos
    parser.tok = GroupSeparator
  of '}':
    inc parser.pos
    parser.tok = GroupEnd
  of '/':
    inc parser.pos
    parser.tok = PathSeparator
  of GlobIdentChars:
    var value: string
    let count = parseWhile(parser.pattern, value, GlobIdentChars, parser.pos)
    parser.a = value
    parser.tok = Literal
    inc(parser.pos, count)
  of '\0':
    parser.tok = PatternEnd
  else:
    raise newException(ValueError, "Unexpected token: " & parser.pattern[parser.pos])

proc parseImpl (parser: var GlobParser): GlobPattern =
  var res: GlobPattern

  proc add (node: GlobNode) =
    if res.len == 0: res.add PathSegment()
    res[^1].children.add node

  while parser.tok != PatternEnd:
    case parser.tok
    of PathSeparator:
      result.add PathSegment()
      parser.getToken
    of Literal:
      add GlobNode(kind: LiteralIdent, value: parser.a)
      parser.getToken
    else:
      parser.getToken

  result = res

proc parseGlob (pattern: string): GlobPattern =
  var parser = GlobParser(pattern: pattern)
  parser.getToken
  return parser.parseImpl

when isMainModule:
  const pattern = parseGlob("foo/[a-f]d.{nim,js}")
  echo pattern

Current Output

» nim c -r t2
Hint: used config file 'C:\Users\cc\.choosenim\toolchains\nim-0.19.0\config\nim.cfg' [Conf]
Hint: system [Processing]
Hint: t2 [Processing]
Hint: strutils [Processing]
Hint: parseutils [Processing]
Hint: math [Processing]
Hint: bitops [Processing]
Hint: algorithm [Processing]
Hint: unicode [Processing]
CC: glob_t2
Error: execution of an external compiler program 'gcc.exe -c  -w -mno-ms-bitfields  -IC:\Users\cc\.choosenim\toolchains\nim-0.19.0\lib -o C:\Users\cc\nimcache\t2_d\glob_t2.c.o C:\Users\cc\nimcache\t2_d\glob_t2.c' failed with exit code: 1

C:\Users\cc\nimcache\t2_d\glob_t2.c:151:210: error: extra brace group at end of initializer
 } TM_30ZZBnPzgU4pBMV9c9a9av9beQ_15 = {{5, 5 | NIM_STRLIT_FLAG}, {{((tyEnum_GlobNodeKind_e7TFsmF3J7sXWF9aYHB8fFw) 0), ((NimStringDesc*) &TM_30ZZBnPzgU4pBMV9c9a9av9beQ_5), NIM_FALSE, ((NimStringDesc*) NIM_NIL), {

            ^
C:\Users\cc\nimcache\t2_d\glob_t2.c:151:210: note: (near initialization for 'TM_30ZZBnPzgU4pBMV9c9a9av9beQ_15.data[0]')
C:\Users\cc\nimcache\t2_d\glob_t2.c:157:145: error: extra brace group at end of initializer
 {((tyEnum_GlobNodeKind_e7TFsmF3J7sXWF9aYHB8fFw) 0), ((NimStringDesc*) &TM_30ZZBnPzgU4pBMV9c9a9av9beQ_7), NIM_FALSE, ((NimStringDesc*) NIM_NIL), {
                                                                                                                                                 ^
C:\Users\cc\nimcache\t2_d\glob_t2.c:157:145: note: (near initialization for 'TM_30ZZBnPzgU4pBMV9c9a9av9beQ_15.data[1]')
C:\Users\cc\nimcache\t2_d\glob_t2.c:163:145: error: extra brace group at end of initializer
 {((tyEnum_GlobNodeKind_e7TFsmF3J7sXWF9aYHB8fFw) 0), ((NimStringDesc*) &TM_30ZZBnPzgU4pBMV9c9a9av9beQ_9), NIM_FALSE, ((NimStringDesc*) NIM_NIL), {
                                                                                                                                                 ^
C:\Users\cc\nimcache\t2_d\glob_t2.c:163:145: note: (near initialization for 'TM_30ZZBnPzgU4pBMV9c9a9av9beQ_15.data[2]')
C:\Users\cc\nimcache\t2_d\glob_t2.c:169:146: error: extra brace group at end of initializer
 {((tyEnum_GlobNodeKind_e7TFsmF3J7sXWF9aYHB8fFw) 0), ((NimStringDesc*) &TM_30ZZBnPzgU4pBMV9c9a9av9beQ_11), NIM_FALSE, ((NimStringDesc*) NIM_NIL), {
                                                                                                                                                  ^
C:\Users\cc\nimcache\t2_d\glob_t2.c:169:146: note: (near initialization for 'TM_30ZZBnPzgU4pBMV9c9a9av9beQ_15.data[3]')
C:\Users\cc\nimcache\t2_d\glob_t2.c:175:146: error: extra brace group at end of initializer
 {((tyEnum_GlobNodeKind_e7TFsmF3J7sXWF9aYHB8fFw) 0), ((NimStringDesc*) &TM_30ZZBnPzgU4pBMV9c9a9av9beQ_13), NIM_FALSE, ((NimStringDesc*) NIM_NIL), {
                                                                                                                                                  ^
C:\Users\cc\nimcache\t2_d\glob_t2.c:175:146: note: (near initialization for 'TM_30ZZBnPzgU4pBMV9c9a9av9beQ_15.data[4]')

Expected Output

No errors

Possible Solution

Additional Information

I tried on both these versions (stable & devel):

» nim -v
Nim Compiler Version 0.19.0 [Windows: amd64]
Compiled at 2018-09-26
Copyright (c) 2006-2018 by Andreas Rumpf

git hash: f6c5c636bb1a1f4e1301ae0ba5a8afecef439132
active boot switches: -d:release

» nim -v
Nim Compiler Version 0.19.9 [Windows: amd64]
Compiled at 2018-11-04
Copyright (c) 2006-2018 by Andreas Rumpf

active boot switches: -d:release
@ghost
Copy link

ghost commented Nov 4, 2018

Changing const pattern = parseGlob("foo/[a-f]d.{nim,js}") to var pattern = parseGlob("foo/[a-f]d.{nim,js}") makes compilation work.

@haltcase
Copy link
Contributor Author

haltcase commented Nov 4, 2018

I did notice that - I should have listed that as a workaround but this should work at compile-time.

@krux02 krux02 changed the title Bad codegen? error: extra brace group at end of initializer complex constant doesn't work at c++ backend Nov 4, 2018
@krux02
Copy link
Contributor

krux02 commented Nov 4, 2018

I tried with both C and C++ backend. Only with the c++ backend I could reproduce the problem.

@haltcase
Copy link
Contributor Author

haltcase commented Nov 4, 2018

It happens for me using C backend as well though (Win 10, WSL, and just tried on Ubuntu). Is it related to gcc and maybe you're on a different compiler?

@krux02
Copy link
Contributor

krux02 commented Nov 4, 2018

I am on clang on Manjaro Linux.

@LemonBoy
Copy link
Contributor

This is just the VM being a stupid like #8015 or #8007. When an object is created by the VM all the slots are filled with their initial value: as you can see in the c code there are way too many zero-init values, that's what GCC is telling you.

@timotheecour
Copy link
Member

timotheecour commented Oct 23, 2020

using nim 64016dd 1.5.1, it works (no codegen error) with either C or C++

all that's needed to close this issue is to minimize the above test case (too large IMO) and add a regression test

@ringabout
Copy link
Member

all that's needed to close this issue is to minimize the above test case (too large IMO) and add a regression test

no need to minimize, they compile and run fast.

@ghost
Copy link

ghost commented Mar 28, 2021

@xflywind minimized test case is better since it's less code to read and much more obvious to where the compiler was wrong before

@ringabout
Copy link
Member

@Yardanico ok

@ringabout ringabout self-assigned this Mar 28, 2021
@ringabout
Copy link
Member

ringabout commented Mar 28, 2021

Reduced with Nim 0.19.2:

type
  GlobNodeKind = enum
    LiteralIdent,
    Group

  GlobNode = object
    case kind: GlobNodeKind
    of LiteralIdent:
      value: string
    of Group:
      values: seq[string]

  PathSegment = object
    children: seq[GlobNode]

  GlobPattern = seq[PathSegment]

proc parseImpl(): GlobPattern =
  if result.len == 0:
    result.add PathSegment()
  result[^1].children.add GlobNode(kind: LiteralIdent)

block:
  const pattern = parseImpl()
  doAssert $pattern == """@[(children: @[(kind: LiteralIdent, value: "")])]"""

ringabout added a commit to ringabout/Nim that referenced this issue Mar 28, 2021
Clyybber pushed a commit that referenced this issue Mar 28, 2021
* fix nim js cmp fails at CT

* close #9622 add testcase
@timotheecour
Copy link
Member

timotheecour commented Mar 29, 2021

@xflywind

minimized test case is better since it's less code to read and much more obvious to where the compiler was wrong before

indeed. And also future changes in compiler/stdlib may hide the bug, so the un-minimized test would stop testing for the actual bug and act as a regression test.

example

import std/strutils
proc main =
  var s = ""
  stripLineEnd(s) # was bug because of [^1] didn't work in VM (refs https://github.com/nim-lang/Nim/issues/16226)
static main()

this would be a bad (or at least insufficient) regression test, because implementation of stripLineEnd could change and not use [^1] anymore.

instead, a good regression test for that would not use strutils (eg #15987)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Object Variants VM see also `const` label
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants