]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: avoid follow-on errors for literals with syntax errors
authorRobert Griesemer <gri@golang.org>
Thu, 29 Aug 2019 21:31:40 +0000 (14:31 -0700)
committerRobert Griesemer <gri@golang.org>
Thu, 29 Aug 2019 23:37:07 +0000 (23:37 +0000)
- only convert literal strings if there were no syntax errors
  (some of the conversion routines exit if there is an error)
- mark nodes for literals with syntax errors to avoid follow-on
  errors
- don't attempt to import packages whose path had syntax errors

Fixes #32133.

Change-Id: I1803ad48c65abfecf6f48ddff1e27eded5e282c5
Reviewed-on: https://go-review.googlesource.com/c/go/+/192437
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/gc/noder.go
test/fixedbugs/issue32133.go [new file with mode: 0644]

index 93d355278e1a03a1a75f93a881e29bd6922b0d1d..a60b854b2c7dd8d7bafc8309612373c921440edb 100644 (file)
@@ -309,6 +309,10 @@ func (p *noder) decls(decls []syntax.Decl) (l []*Node) {
 }
 
 func (p *noder) importDecl(imp *syntax.ImportDecl) {
+       if imp.Path.Bad {
+               return // avoid follow-on errors if there was a syntax error
+       }
+
        val := p.basicLit(imp.Path)
        ipkg := importfile(&val)
 
@@ -602,7 +606,9 @@ func (p *noder) expr(expr syntax.Expr) *Node {
        case *syntax.Name:
                return p.mkname(expr)
        case *syntax.BasicLit:
-               return nodlit(p.basicLit(expr))
+               n := nodlit(p.basicLit(expr))
+               n.SetDiag(expr.Bad) // avoid follow-on errors if there was a syntax error
+               return n
        case *syntax.CompositeLit:
                n := p.nod(expr, OCOMPLIT, nil, nil)
                if expr.Type != nil {
@@ -1351,55 +1357,60 @@ func checkLangCompat(lit *syntax.BasicLit) {
 }
 
 func (p *noder) basicLit(lit *syntax.BasicLit) Val {
-       // TODO: Don't try to convert if we had syntax errors (conversions may fail).
-       //       Use dummy values so we can continue to compile. Eventually, use a
-       //       form of "unknown" literals that are ignored during type-checking so
-       //       we can continue type-checking w/o spurious follow-up errors.
+       // We don't use the errors of the conversion routines to determine
+       // if a literal string is valid because the conversion routines may
+       // accept a wider syntax than the language permits. Rely on lit.Bad
+       // instead.
        switch s := lit.Value; lit.Kind {
        case syntax.IntLit:
                checkLangCompat(lit)
                x := new(Mpint)
-               x.SetString(s)
+               if !lit.Bad {
+                       x.SetString(s)
+               }
                return Val{U: x}
 
        case syntax.FloatLit:
                checkLangCompat(lit)
                x := newMpflt()
-               x.SetString(s)
+               if !lit.Bad {
+                       x.SetString(s)
+               }
                return Val{U: x}
 
        case syntax.ImagLit:
                checkLangCompat(lit)
                x := newMpcmplx()
-               x.Imag.SetString(strings.TrimSuffix(s, "i"))
+               if !lit.Bad {
+                       x.Imag.SetString(strings.TrimSuffix(s, "i"))
+               }
                return Val{U: x}
 
        case syntax.RuneLit:
-               var r rune
-               if u, err := strconv.Unquote(s); err == nil && len(u) > 0 {
-                       // Package syntax already reported any errors.
-                       // Check for them again though because 0 is a
-                       // better fallback value for invalid rune
-                       // literals than 0xFFFD.
+               x := new(Mpint)
+               x.Rune = true
+               if !lit.Bad {
+                       u, _ := strconv.Unquote(s)
+                       var r rune
                        if len(u) == 1 {
                                r = rune(u[0])
                        } else {
                                r, _ = utf8.DecodeRuneInString(u)
                        }
+                       x.SetInt64(int64(r))
                }
-               x := new(Mpint)
-               x.SetInt64(int64(r))
-               x.Rune = true
                return Val{U: x}
 
        case syntax.StringLit:
-               if len(s) > 0 && s[0] == '`' {
-                       // strip carriage returns from raw string
-                       s = strings.Replace(s, "\r", "", -1)
+               var x string
+               if !lit.Bad {
+                       if len(s) > 0 && s[0] == '`' {
+                               // strip carriage returns from raw string
+                               s = strings.Replace(s, "\r", "", -1)
+                       }
+                       x, _ = strconv.Unquote(s)
                }
-               // Ignore errors because package syntax already reported them.
-               u, _ := strconv.Unquote(s)
-               return Val{U: u}
+               return Val{U: x}
 
        default:
                panic("unhandled BasicLit kind")
diff --git a/test/fixedbugs/issue32133.go b/test/fixedbugs/issue32133.go
new file mode 100644 (file)
index 0000000..13e4658
--- /dev/null
@@ -0,0 +1,43 @@
+// errorcheck
+
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+// errors for the //line-adjusted code below
+// ERROR "newline in string"
+// ERROR "newline in character literal"
+// ERROR "newline in string"
+// ERROR "string not terminated"
+
+//line :10:1
+import "foo
+
+//line :19:1
+func _() {
+       0x // ERROR "hexadecimal literal has no digits"
+}
+
+func _() {
+       0x1.0 // ERROR "hexadecimal mantissa requires a 'p' exponent"
+}
+
+func _() {
+       0_i // ERROR "'_' must separate successive digits"
+}
+
+func _() {
+//line :11:1
+       '
+}
+
+func _() {
+//line :12:1
+       "
+}
+
+func _() {
+//line :13:1
+       `
\ No newline at end of file