cmd/compile/internal/syntax: add "~" operator

Change-Id: I7991103d97b97260d9615b7f5baf7ec75ad87d1f
Reviewed-on: https://go-review.googlesource.com/c/go/+/307370
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/src/cmd/compile/internal/syntax/operator_string.go b/src/cmd/compile/internal/syntax/operator_string.go
index a7cd40f..f045d8c 100644
--- a/src/cmd/compile/internal/syntax/operator_string.go
+++ b/src/cmd/compile/internal/syntax/operator_string.go
@@ -11,30 +11,31 @@
 	_ = x[Def-1]
 	_ = x[Not-2]
 	_ = x[Recv-3]
-	_ = x[OrOr-4]
-	_ = x[AndAnd-5]
-	_ = x[Eql-6]
-	_ = x[Neq-7]
-	_ = x[Lss-8]
-	_ = x[Leq-9]
-	_ = x[Gtr-10]
-	_ = x[Geq-11]
-	_ = x[Add-12]
-	_ = x[Sub-13]
-	_ = x[Or-14]
-	_ = x[Xor-15]
-	_ = x[Mul-16]
-	_ = x[Div-17]
-	_ = x[Rem-18]
-	_ = x[And-19]
-	_ = x[AndNot-20]
-	_ = x[Shl-21]
-	_ = x[Shr-22]
+	_ = x[Tilde-4]
+	_ = x[OrOr-5]
+	_ = x[AndAnd-6]
+	_ = x[Eql-7]
+	_ = x[Neq-8]
+	_ = x[Lss-9]
+	_ = x[Leq-10]
+	_ = x[Gtr-11]
+	_ = x[Geq-12]
+	_ = x[Add-13]
+	_ = x[Sub-14]
+	_ = x[Or-15]
+	_ = x[Xor-16]
+	_ = x[Mul-17]
+	_ = x[Div-18]
+	_ = x[Rem-19]
+	_ = x[And-20]
+	_ = x[AndNot-21]
+	_ = x[Shl-22]
+	_ = x[Shr-23]
 }
 
-const _Operator_name = ":!<-||&&==!=<<=>>=+-|^*/%&&^<<>>"
+const _Operator_name = ":!<-~||&&==!=<<=>>=+-|^*/%&&^<<>>"
 
-var _Operator_index = [...]uint8{0, 1, 2, 4, 6, 8, 10, 12, 13, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 28, 30, 32}
+var _Operator_index = [...]uint8{0, 1, 2, 4, 5, 7, 9, 11, 13, 14, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 31, 33}
 
 func (i Operator) String() string {
 	i -= 1
diff --git a/src/cmd/compile/internal/syntax/scanner.go b/src/cmd/compile/internal/syntax/scanner.go
index 9fe4965..218bc24 100644
--- a/src/cmd/compile/internal/syntax/scanner.go
+++ b/src/cmd/compile/internal/syntax/scanner.go
@@ -343,6 +343,11 @@
 		s.op, s.prec = Not, 0
 		s.tok = _Operator
 
+	case '~':
+		s.nextch()
+		s.op, s.prec = Tilde, 0
+		s.tok = _Operator
+
 	default:
 		s.errorf("invalid character %#U", s.ch)
 		s.nextch()
diff --git a/src/cmd/compile/internal/syntax/scanner_test.go b/src/cmd/compile/internal/syntax/scanner_test.go
index fbe7b71..2deb3bb 100644
--- a/src/cmd/compile/internal/syntax/scanner_test.go
+++ b/src/cmd/compile/internal/syntax/scanner_test.go
@@ -232,6 +232,9 @@
 	{_Literal, "`\r`", 0, 0},
 
 	// operators
+	{_Operator, "!", Not, 0},
+	{_Operator, "~", Tilde, 0},
+
 	{_Operator, "||", OrOr, precOrOr},
 
 	{_Operator, "&&", AndAnd, precAndAnd},
@@ -601,7 +604,7 @@
 		{"\U0001d7d8" /* 𝟘 */, "identifier cannot begin with digit U+1D7D8 '𝟘'", 0, 0},
 		{"foo\U0001d7d8_½" /* foo𝟘_½ */, "invalid character U+00BD '½' in identifier", 0, 8 /* byte offset */},
 
-		{"x + ~y", "invalid character U+007E '~'", 0, 4},
+		{"x + #y", "invalid character U+0023 '#'", 0, 4},
 		{"foo$bar = 0", "invalid character U+0024 '$'", 0, 3},
 		{"0123456789", "invalid digit '8' in octal literal", 0, 8},
 		{"0123456789. /* foobar", "comment not terminated", 0, 12},   // valid float constant
diff --git a/src/cmd/compile/internal/syntax/tokens.go b/src/cmd/compile/internal/syntax/tokens.go
index 2936b65..60eae36 100644
--- a/src/cmd/compile/internal/syntax/tokens.go
+++ b/src/cmd/compile/internal/syntax/tokens.go
@@ -111,9 +111,10 @@
 	_ Operator = iota
 
 	// Def is the : in :=
-	Def  // :
-	Not  // !
-	Recv // <-
+	Def   // :
+	Not   // !
+	Recv  // <-
+	Tilde // ~
 
 	// precOrOr
 	OrOr // ||
diff --git a/test/fixedbugs/issue23587.go b/test/fixedbugs/issue23587.go
index bd5df27..2308992 100644
--- a/test/fixedbugs/issue23587.go
+++ b/test/fixedbugs/issue23587.go
@@ -6,7 +6,10 @@
 
 package p
 
-func f(x int) {
-	_ = ~x    // ERROR "invalid character"
-	_ = x ~ x // ERROR "invalid character" "unexpected x at end of statement"
+func _(x int) {
+	_ = ~x    // ERROR "unexpected ~"
+}
+
+func _(x int) {
+	_ = x ~ x // ERROR "unexpected ~ at end of statement"
 }