cmd/compile: reject large floating point exponents without math/big

For #11326 (but not a fix).

Change-Id: Ic51814f5cd7357427c3fd990a5522775d05e7987
Reviewed-on: https://go-review.googlesource.com/11673
Reviewed-by: Robert Griesemer <gri@golang.org>
diff --git a/src/cmd/compile/internal/gc/mparith3.go b/src/cmd/compile/internal/gc/mparith3.go
index bda35bc..bf37f2d 100644
--- a/src/cmd/compile/internal/gc/mparith3.go
+++ b/src/cmd/compile/internal/gc/mparith3.go
@@ -9,6 +9,7 @@
 	"cmd/internal/obj"
 	"fmt"
 	"math"
+	"strings"
 )
 
 /// implements float arihmetic
@@ -153,6 +154,30 @@
 		as = as[1:]
 	}
 
+	// The spec requires accepting exponents that fit in int32.
+	// Don't accept much more than that.
+	// Count digits in exponent and stop early if there are too many.
+	if i := strings.Index(as, "e"); i >= 0 {
+		i++
+		if i < len(as) && (as[i] == '-' || as[i] == '+') {
+			i++
+		}
+		for i < len(as) && as[i] == '0' {
+			i++
+		}
+		// TODO(rsc): This should be > 10, because we're supposed
+		// to accept any signed 32-bit int as an exponent.
+		// But that's not working terribly well, so we deviate from the
+		// spec in order to make sure that what we accept works.
+		// We can remove this restriction once those larger exponents work.
+		// See golang.org/issue/11326 and test/fixedbugs/issue11326*.go.
+		if len(as)-i > 8 {
+			Yyerror("malformed constant: %s (exponent too large)", as)
+			a.Val.SetUint64(0)
+			return
+		}
+	}
+
 	f, ok := a.Val.SetString(as)
 	if !ok {
 		// At the moment we lose precise error cause;
@@ -164,11 +189,13 @@
 		// TODO(gri) use different conversion function or check separately
 		Yyerror("malformed constant: %s", as)
 		a.Val.SetUint64(0)
+		return
 	}
 
 	if f.IsInf() {
 		Yyerror("constant too large: %s", as)
 		a.Val.SetUint64(0)
+		return
 	}
 }
 
diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go
index c7fe8df..2014e98 100644
--- a/src/go/types/stdlib_test.go
+++ b/src/go/types/stdlib_test.go
@@ -144,10 +144,12 @@
 
 	testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
 		"bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
-		"bug459.go",    // possibly incorrect test - see issue 6703 (pending spec clarification)
-		"issue3924.go", // possibly incorrect test - see issue 6671 (pending spec clarification)
-		"issue6889.go", // gc-specific test
-		"issue7746.go", // large constants - consumes too much memory
+		"bug459.go",      // possibly incorrect test - see issue 6703 (pending spec clarification)
+		"issue3924.go",   // possibly incorrect test - see issue 6671 (pending spec clarification)
+		"issue6889.go",   // gc-specific test
+		"issue7746.go",   // large constants - consumes too much memory
+		"issue11326.go",  // large constants
+		"issue11326b.go", // large constants
 	)
 }
 
diff --git a/test/fixedbugs/issue11326.go b/test/fixedbugs/issue11326.go
new file mode 100644
index 0000000..fd1fab3
--- /dev/null
+++ b/test/fixedbugs/issue11326.go
@@ -0,0 +1,28 @@
+// errorcheck
+
+// Copyright 2015 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 main
+
+import "fmt"
+
+func main() {
+	var g = 1e81391777742999 // ERROR "exponent too large"
+	// The next should only cause a problem when converted to float64
+	// by the assignment, but instead the compiler rejects it outright,
+	// rather than mishandle it. Specifically, when handled, 'var h' prints:
+	//	issue11326.go:N: constant 0.93342e+536870911 overflows float64
+	// The rejection of 'var i' is just insurance. It seems to work correctly.
+	// See golang.org/issue/11326.
+	// var h = 1e2147483647     // should be "1.00000e+2147483647 overflows float64"
+	var h = 1e2147483647 // ERROR "exponent too large"
+	// var i = 1e214748364  // should be "1.00000e\+214748364 overflows float64"
+	var i = 1e214748364 // ERROR "exponent too large"
+	var j = 1e21474836  // ERROR "1.00000e\+21474836 overflows float64"
+	var k = 1e2147483   // ERROR "1.00000e\+2147483 overflows float64"
+	var l = 1e214748    // ERROR "1.00000e\+214748 overflows float64"
+	var m = 1e21474     // ERROR "1.00000e\+21474 overflows float64"
+	fmt.Println(g)
+}
diff --git a/test/fixedbugs/issue11326b.go b/test/fixedbugs/issue11326b.go
new file mode 100644
index 0000000..00effbc
--- /dev/null
+++ b/test/fixedbugs/issue11326b.go
@@ -0,0 +1,44 @@
+// run
+
+// Copyright 2015 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 main
+
+func main() {
+	/* TODO(rsc): Should work but does not. See golang.org/issue/11326.
+	{
+		const n = 1e2147483647
+		const d = 1e2147483646
+		x := n / d
+		if x != 10.0 {
+			println("incorrect value:", x)
+		}
+	}
+	{
+		const n = 1e214748364
+		const d = 1e214748363
+		x := n / d
+		if x != 10.0 {
+			println("incorrect value:", x)
+		}
+	}
+	*/
+	{
+		const n = 1e21474836
+		const d = 1e21474835
+		x := n / d
+		if x != 10.0 {
+			println("incorrect value:", x)
+		}
+	}
+	{
+		const n = 1e2147483
+		const d = 1e2147482
+		x := n / d
+		if x != 10.0 {
+			println("incorrect value:", x)
+		}
+	}
+}