]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: better error when trying to use ~ as bitwise operation
authorRobert Griesemer <gri@golang.org>
Tue, 31 Jan 2023 19:34:16 +0000 (11:34 -0800)
committerGopher Robot <gobot@golang.org>
Wed, 1 Feb 2023 21:30:59 +0000 (21:30 +0000)
When coming from C, the bitwise integer complement (bitwise negation)
operator is ~, but in Go it is ^. Report an error mentioning ^ when
~ is used with an integer operand.

Background: Some articles on the web claim that Go doesn't have a
bitwise complement operator.

Change-Id: I41185cae4a70d528754e44f42c13c013ed91bf27
Reviewed-on: https://go-review.googlesource.com/c/go/+/463747
Auto-Submit: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/types2/expr.go
src/go/types/expr.go
src/internal/types/testdata/check/expr0.go

index 0433f8af952afd605f210e13fa8a20b6852c3ba2..472e30a0698a645ca41dc0a2b9cbc55436ce241f 100644 (file)
@@ -178,7 +178,8 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) {
                return
        }
 
-       switch e.Op {
+       op := e.Op
+       switch op {
        case syntax.And:
                // spec: "As an exception to the addressability
                // requirement x may also be a composite literal."
@@ -215,13 +216,17 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) {
                return
 
        case syntax.Tilde:
-               // Provide a better error position and message than what check.op below could do.
-               check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint")
-               x.mode = invalid
-               return
+               // Provide a better error position and message than what check.op below would do.
+               if !allInteger(x.typ) {
+                       check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint")
+                       x.mode = invalid
+                       return
+               }
+               check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint (use ^ for bitwise complement)")
+               op = syntax.Xor
        }
 
-       if !check.op(unaryOpPredicates, x, e.Op) {
+       if !check.op(unaryOpPredicates, x, op) {
                x.mode = invalid
                return
        }
@@ -235,7 +240,7 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) {
                if isUnsigned(x.typ) {
                        prec = uint(check.conf.sizeof(x.typ) * 8)
                }
-               x.val = constant.UnaryOp(op2tok[e.Op], x.val, prec)
+               x.val = constant.UnaryOp(op2tok[op], x.val, prec)
                x.expr = e
                check.overflow(x)
                return
index b85a2c7466192801c6749178447ace5b3bc135cb..f09a29b1260096d553a3316c6a835fe5fa1798a6 100644 (file)
@@ -164,7 +164,9 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
        if x.mode == invalid {
                return
        }
-       switch e.Op {
+
+       op := e.Op
+       switch op {
        case token.AND:
                // spec: "As an exception to the addressability
                // requirement x may also be a composite literal."
@@ -202,13 +204,17 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
                return
 
        case token.TILDE:
-               // Provide a better error position and message than what check.op below could do.
-               check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint")
-               x.mode = invalid
-               return
+               // Provide a better error position and message than what check.op below would do.
+               if !allInteger(x.typ) {
+                       check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint")
+                       x.mode = invalid
+                       return
+               }
+               check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint (use ^ for bitwise complement)")
+               op = token.XOR
        }
 
-       if !check.op(unaryOpPredicates, x, e.Op) {
+       if !check.op(unaryOpPredicates, x, op) {
                x.mode = invalid
                return
        }
@@ -222,7 +228,7 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
                if isUnsigned(x.typ) {
                        prec = uint(check.conf.sizeof(x.typ) * 8)
                }
-               x.val = constant.UnaryOp(e.Op, x.val, prec)
+               x.val = constant.UnaryOp(op, x.val, prec)
                x.expr = e
                check.overflow(x, x.Pos())
                return
index 552bd8fa8f5964f8477a3f66f74e2a3c34d364f1..eba991ecd3ce0f78af3a08d24be55fd1a5f35861 100644 (file)
@@ -24,12 +24,14 @@ var (
        b11 = &b0
        b12 = <-b0 /* ERROR "cannot receive" */
        b13 = & & /* ERROR "cannot take address" */ b0
+       b14 = ~ /* ERROR "cannot use ~ outside of interface or type constraint" */ b0
 
        // byte
        _ = byte(0)
        _ = byte(- /* ERROR "cannot convert" */ 1)
        _ = - /* ERROR "-byte(1) (constant -1 of type byte) overflows byte" */ byte(1) // test for issue 11367
        _ = byte /* ERROR "overflows byte" */ (0) - byte(1)
+       _ = ~ /* ERROR "cannot use ~ outside of interface or type constraint (use ^ for bitwise complement)" */ byte(0)
 
        // int
        i0 = 1
@@ -51,6 +53,7 @@ var (
        i16 = &i0
        i17 = *i16
        i18 = <-i16 /* ERROR "cannot receive" */
+       i19 = ~ /* ERROR "cannot use ~ outside of interface or type constraint (use ^ for bitwise complement)" */ i0
 
        // uint
        u0 = uint(1)
@@ -73,6 +76,7 @@ var (
        u17 = *u16
        u18 = <-u16 /* ERROR "cannot receive" */
        u19 = ^uint(0)
+       u20 = ~ /* ERROR "cannot use ~ outside of interface or type constraint (use ^ for bitwise complement)" */ u0
 
        // float64
        f0 = float64(1)
@@ -94,6 +98,7 @@ var (
        f16 = &f0
        f17 = *u16
        f18 = <-u16 /* ERROR "cannot receive" */
+       f19 = ~ /* ERROR "cannot use ~ outside of interface or type constraint" */ f0
 
        // complex128
        c0 = complex128(1)
@@ -115,6 +120,7 @@ var (
        c16 = &c0
        c17 = *u16
        c18 = <-u16 /* ERROR "cannot receive" */
+       c19 = ~ /* ERROR "cannot use ~ outside of interface or type constraint" */ c0
 
        // string
        s0 = "foo"
@@ -126,6 +132,7 @@ var (
        s6 = &s4
        s7 = *s6
        s8 = <-s7
+       s9 = ~ /* ERROR "cannot use ~ outside of interface or type constraint" */ s0
 
        // channel
        ch chan int
@@ -145,6 +152,8 @@ var (
        // ok is of type bool
        ch11, myok = <-ch
        _ mybool = myok /* ERRORx `cannot use .* in variable declaration` */
+       ch12 = ~ /* ERROR "cannot use ~ outside of interface or type constraint" */ ch
+
 )
 
 // address of composite literals