fmt: fix incorrect format of whole-number floats when using %#v

This fixes the unwanted behaviour where printing a zero float with the
#v fmt verb outputs "0" - e.g. missing the trailing decimal. This means
that the output would be interpreted as an int rather than a float when
parsed as Go source. After this change the the output is "0.0".

Fixes #26363

Change-Id: Ic5c060522459cd5ce077675d47c848b22ddc34fa
GitHub-Last-Rev: adfb061363f0566acec134c81be9a3dcb1f4cac8
GitHub-Pull-Request: golang/go#26383
Reviewed-on: https://go-review.googlesource.com/123956
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Rob Pike <r@golang.org>
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go
index edfd1ee..9581bec 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -690,6 +690,14 @@
 	{"%#v", []int32(nil), "[]int32(nil)"},
 	{"%#v", 1.2345678, "1.2345678"},
 	{"%#v", float32(1.2345678), "1.2345678"},
+
+	// Whole number floats should have a single trailing zero added, but not
+	// for exponent notation.
+	{"%#v", 1.0, "1.0"},
+	{"%#v", 1000000.0, "1e+06"},
+	{"%#v", float32(1.0), "1.0"},
+	{"%#v", float32(1000000.0), "1e+06"},
+
 	// Only print []byte and []uint8 as type []byte if they appear at the top level.
 	{"%#v", []byte(nil), "[]byte(nil)"},
 	{"%#v", []uint8(nil), "[]byte(nil)"},
diff --git a/src/fmt/format.go b/src/fmt/format.go
index 91103f2..3a3cd8d 100644
--- a/src/fmt/format.go
+++ b/src/fmt/format.go
@@ -481,15 +481,19 @@
 		return
 	}
 	// The sharp flag forces printing a decimal point for non-binary formats
-	// and retains trailing zeros, which we may need to restore.
-	if f.sharp && verb != 'b' {
+	// and retains trailing zeros, which we may need to restore. For the sharpV
+	// flag, we ensure a single trailing zero is present if the output is not
+	// in exponent notation.
+	if f.sharpV || (f.sharp && verb != 'b') {
 		digits := 0
-		switch verb {
-		case 'v', 'g', 'G':
-			digits = prec
-			// If no precision is set explicitly use a precision of 6.
-			if digits == -1 {
-				digits = 6
+		if !f.sharpV {
+			switch verb {
+			case 'g', 'G':
+				digits = prec
+				// If no precision is set explicitly use a precision of 6.
+				if digits == -1 {
+					digits = 6
+				}
 			}
 		}
 
@@ -498,25 +502,32 @@
 		var tailBuf [5]byte
 		tail := tailBuf[:0]
 
-		hasDecimalPoint := false
+		var hasDecimalPoint, hasExponent bool
 		// Starting from i = 1 to skip sign at num[0].
 		for i := 1; i < len(num); i++ {
 			switch num[i] {
 			case '.':
 				hasDecimalPoint = true
 			case 'e', 'E':
+				hasExponent = true
 				tail = append(tail, num[i:]...)
 				num = num[:i]
 			default:
 				digits--
 			}
 		}
-		if !hasDecimalPoint {
-			num = append(num, '.')
-		}
-		for digits > 0 {
-			num = append(num, '0')
-			digits--
+		if f.sharpV {
+			if !hasDecimalPoint && !hasExponent {
+				num = append(num, '.', '0')
+			}
+		} else {
+			if !hasDecimalPoint {
+				num = append(num, '.')
+			}
+			for digits > 0 {
+				num = append(num, '0')
+				digits--
+			}
 		}
 		num = append(num, tail...)
 	}
diff --git a/test/switch5.go b/test/switch5.go
index ce95bf8..6641d58 100644
--- a/test/switch5.go
+++ b/test/switch5.go
@@ -24,8 +24,8 @@
 func f1(x float32) {
 	switch x {
 	case 5:
-	case 5: // ERROR "duplicate case 5 in switch"
-	case 5.0: // ERROR "duplicate case 5 in switch"
+	case 5: // ERROR "duplicate case 5 .value 5\.0. in switch"
+	case 5.0: // ERROR "duplicate case 5 .value 5\.0. in switch"
 	}
 }
 
@@ -44,9 +44,9 @@
 	case 0: // ERROR "duplicate case 0 in switch"
 	case int64(0):
 	case float32(10):
-	case float32(10): // ERROR "duplicate case float32\(10\) .value 10. in switch"
+	case float32(10): // ERROR "duplicate case float32\(10\) .value 10\.0. in switch"
 	case float64(10):
-	case float64(10): // ERROR "duplicate case float64\(10\) .value 10. in switch"
+	case float64(10): // ERROR "duplicate case float64\(10\) .value 10\.0. in switch"
 	}
 }