diff --git a/src/cmd/compile/internal/syntax/scanner.go b/src/cmd/compile/internal/syntax/scanner.go index 30ee6c0e5f7..fef87171bc4 100644 --- a/src/cmd/compile/internal/syntax/scanner.go +++ b/src/cmd/compile/internal/syntax/scanner.go @@ -35,8 +35,8 @@ type scanner struct { // current token, valid after calling next() line, col uint tok token - lit string // valid if tok is _Name, _Literal, or _Semi ("semicolon", "newline", or "EOF") - bad bool // valid if tok is _Literal, true if a syntax error occurred, lit may be incorrect + lit string // valid if tok is _Name, _Literal, or _Semi ("semicolon", "newline", or "EOF"); may be malformed if bad is true + bad bool // valid if tok is _Literal, true if a syntax error occurred, lit may be malformed kind LitKind // valid if tok is _Literal op Operator // valid if tok is _Operator, _AssignOp, or _IncOp prec int // valid if tok is _Operator, _AssignOp, or _IncOp @@ -50,8 +50,6 @@ func (s *scanner) init(src io.Reader, errh func(line, col uint, msg string), mod // errorf reports an error at the most recently read character position. func (s *scanner) errorf(format string, args ...interface{}) { - // TODO(gri) Consider using s.bad to consistently suppress multiple errors - // per token, here and below. s.bad = true s.error(fmt.Sprintf(format, args...)) } @@ -495,17 +493,19 @@ func (s *scanner) number(c rune) { digsep |= ds } - if digsep&1 == 0 { + if digsep&1 == 0 && !s.bad { s.errorf("%s has no digits", litname(prefix)) } // exponent if e := lower(c); e == 'e' || e == 'p' { - switch { - case e == 'e' && prefix != 0 && prefix != '0': - s.errorf("%q exponent requires decimal mantissa", c) - case e == 'p' && prefix != 'x': - s.errorf("%q exponent requires hexadecimal mantissa", c) + if !s.bad { + switch { + case e == 'e' && prefix != 0 && prefix != '0': + s.errorf("%q exponent requires decimal mantissa", c) + case e == 'p' && prefix != 'x': + s.errorf("%q exponent requires hexadecimal mantissa", c) + } } c = s.getr() s.kind = FloatLit @@ -514,10 +514,10 @@ func (s *scanner) number(c rune) { } c, ds = s.digits(c, 10, nil) digsep |= ds - if ds&1 == 0 { + if ds&1 == 0 && !s.bad { s.errorf("exponent has no digits") } - } else if prefix == 'x' && s.kind == FloatLit { + } else if prefix == 'x' && s.kind == FloatLit && !s.bad { s.errorf("hexadecimal mantissa requires a 'p' exponent") } @@ -532,11 +532,11 @@ func (s *scanner) number(c rune) { s.lit = string(s.stopLit()) s.tok = _Literal - if s.kind == IntLit && invalid >= 0 { + if s.kind == IntLit && invalid >= 0 && !s.bad { s.errorAtf(invalid, "invalid digit %q in %s", s.lit[invalid], litname(prefix)) } - if digsep&2 != 0 { + if digsep&2 != 0 && !s.bad { if i := invalidSep(s.lit); i >= 0 { s.errorAtf(i, "'_' must separate successive digits") } diff --git a/src/cmd/compile/internal/syntax/scanner_test.go b/src/cmd/compile/internal/syntax/scanner_test.go index 3030bfd4c04..717deb9073f 100644 --- a/src/cmd/compile/internal/syntax/scanner_test.go +++ b/src/cmd/compile/internal/syntax/scanner_test.go @@ -652,3 +652,25 @@ func TestIssue21938(t *testing.T) { t.Errorf("got %s %q; want %s %q", got.tok, got.lit, _Literal, ".5") } } + +func TestIssue33961(t *testing.T) { + literals := `08__ 0b.p 0b_._p 0x.e 0x.p` + for _, lit := range strings.Split(literals, " ") { + n := 0 + var got scanner + got.init(strings.NewReader(lit), func(_, _ uint, msg string) { + // fmt.Printf("%s: %s\n", lit, msg) // uncomment for debugging + n++ + }, 0) + got.next() + + if n != 1 { + t.Errorf("%q: got %d errors; want 1", lit, n) + continue + } + + if !got.bad { + t.Errorf("%q: got error but bad not set", lit) + } + } +}