Skip to content

Commit 07dca0f

Browse files
griesemergopherbot
authored andcommitted
go/types, types2: better error when trying to use ~ as bitwise operation
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 <[email protected]> Run-TryBot: Robert Griesemer <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> Reviewed-by: Robert Findley <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent cda461b commit 07dca0f

File tree

3 files changed

+34
-14
lines changed

3 files changed

+34
-14
lines changed

src/cmd/compile/internal/types2/expr.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,8 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) {
178178
return
179179
}
180180

181-
switch e.Op {
181+
op := e.Op
182+
switch op {
182183
case syntax.And:
183184
// spec: "As an exception to the addressability
184185
// requirement x may also be a composite literal."
@@ -215,13 +216,17 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) {
215216
return
216217

217218
case syntax.Tilde:
218-
// Provide a better error position and message than what check.op below could do.
219-
check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint")
220-
x.mode = invalid
221-
return
219+
// Provide a better error position and message than what check.op below would do.
220+
if !allInteger(x.typ) {
221+
check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint")
222+
x.mode = invalid
223+
return
224+
}
225+
check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint (use ^ for bitwise complement)")
226+
op = syntax.Xor
222227
}
223228

224-
if !check.op(unaryOpPredicates, x, e.Op) {
229+
if !check.op(unaryOpPredicates, x, op) {
225230
x.mode = invalid
226231
return
227232
}
@@ -235,7 +240,7 @@ func (check *Checker) unary(x *operand, e *syntax.Operation) {
235240
if isUnsigned(x.typ) {
236241
prec = uint(check.conf.sizeof(x.typ) * 8)
237242
}
238-
x.val = constant.UnaryOp(op2tok[e.Op], x.val, prec)
243+
x.val = constant.UnaryOp(op2tok[op], x.val, prec)
239244
x.expr = e
240245
check.overflow(x)
241246
return

src/go/types/expr.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,9 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
164164
if x.mode == invalid {
165165
return
166166
}
167-
switch e.Op {
167+
168+
op := e.Op
169+
switch op {
168170
case token.AND:
169171
// spec: "As an exception to the addressability
170172
// requirement x may also be a composite literal."
@@ -202,13 +204,17 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
202204
return
203205

204206
case token.TILDE:
205-
// Provide a better error position and message than what check.op below could do.
206-
check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint")
207-
x.mode = invalid
208-
return
207+
// Provide a better error position and message than what check.op below would do.
208+
if !allInteger(x.typ) {
209+
check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint")
210+
x.mode = invalid
211+
return
212+
}
213+
check.error(e, UndefinedOp, "cannot use ~ outside of interface or type constraint (use ^ for bitwise complement)")
214+
op = token.XOR
209215
}
210216

211-
if !check.op(unaryOpPredicates, x, e.Op) {
217+
if !check.op(unaryOpPredicates, x, op) {
212218
x.mode = invalid
213219
return
214220
}
@@ -222,7 +228,7 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
222228
if isUnsigned(x.typ) {
223229
prec = uint(check.conf.sizeof(x.typ) * 8)
224230
}
225-
x.val = constant.UnaryOp(e.Op, x.val, prec)
231+
x.val = constant.UnaryOp(op, x.val, prec)
226232
x.expr = e
227233
check.overflow(x, x.Pos())
228234
return

src/internal/types/testdata/check/expr0.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ var (
2424
b11 = &b0
2525
b12 = <-b0 /* ERROR "cannot receive" */
2626
b13 = & & /* ERROR "cannot take address" */ b0
27+
b14 = ~ /* ERROR "cannot use ~ outside of interface or type constraint" */ b0
2728

2829
// byte
2930
_ = byte(0)
3031
_ = byte(- /* ERROR "cannot convert" */ 1)
3132
_ = - /* ERROR "-byte(1) (constant -1 of type byte) overflows byte" */ byte(1) // test for issue 11367
3233
_ = byte /* ERROR "overflows byte" */ (0) - byte(1)
34+
_ = ~ /* ERROR "cannot use ~ outside of interface or type constraint (use ^ for bitwise complement)" */ byte(0)
3335

3436
// int
3537
i0 = 1
@@ -51,6 +53,7 @@ var (
5153
i16 = &i0
5254
i17 = *i16
5355
i18 = <-i16 /* ERROR "cannot receive" */
56+
i19 = ~ /* ERROR "cannot use ~ outside of interface or type constraint (use ^ for bitwise complement)" */ i0
5457

5558
// uint
5659
u0 = uint(1)
@@ -73,6 +76,7 @@ var (
7376
u17 = *u16
7477
u18 = <-u16 /* ERROR "cannot receive" */
7578
u19 = ^uint(0)
79+
u20 = ~ /* ERROR "cannot use ~ outside of interface or type constraint (use ^ for bitwise complement)" */ u0
7680

7781
// float64
7882
f0 = float64(1)
@@ -94,6 +98,7 @@ var (
9498
f16 = &f0
9599
f17 = *u16
96100
f18 = <-u16 /* ERROR "cannot receive" */
101+
f19 = ~ /* ERROR "cannot use ~ outside of interface or type constraint" */ f0
97102

98103
// complex128
99104
c0 = complex128(1)
@@ -115,6 +120,7 @@ var (
115120
c16 = &c0
116121
c17 = *u16
117122
c18 = <-u16 /* ERROR "cannot receive" */
123+
c19 = ~ /* ERROR "cannot use ~ outside of interface or type constraint" */ c0
118124

119125
// string
120126
s0 = "foo"
@@ -126,6 +132,7 @@ var (
126132
s6 = &s4
127133
s7 = *s6
128134
s8 = <-s7
135+
s9 = ~ /* ERROR "cannot use ~ outside of interface or type constraint" */ s0
129136

130137
// channel
131138
ch chan int
@@ -145,6 +152,8 @@ var (
145152
// ok is of type bool
146153
ch11, myok = <-ch
147154
_ mybool = myok /* ERRORx `cannot use .* in variable declaration` */
155+
ch12 = ~ /* ERROR "cannot use ~ outside of interface or type constraint" */ ch
156+
148157
)
149158

150159
// address of composite literals

0 commit comments

Comments
 (0)