cmd/compile: fix detection of duplicate cases for integer ranges

Previously, the check to make sure we only considered constant cases
for duplicates was skipping past integer ranges, because those use
n.List instead of n.Left. Thanks to Emmanuel Odeke for investigating
and helping to identify the root cause.

Fixes #17517.

Change-Id: I46fcda8ed9c346ff3a9647d50b83f1555587b740
Reviewed-on: https://go-review.googlesource.com/31716
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Matthew Dempsky 2016-10-21 14:43:59 -07:00
parent 2827923800
commit 6eede325ab
2 changed files with 30 additions and 18 deletions

View File

@ -600,6 +600,10 @@ func (s *exprSwitch) checkDupCases(cc []caseClause) {
if !s.exprname.Type.IsInterface() { if !s.exprname.Type.IsInterface() {
seen := make(map[interface{}]*Node) seen := make(map[interface{}]*Node)
for _, c := range cc { for _, c := range cc {
switch {
case c.node.Left != nil:
// Single constant.
// Can't check for duplicates that aren't constants, per the spec. Issue 15896. // Can't check for duplicates that aren't constants, per the spec. Issue 15896.
// Don't check for duplicate bools. Although the spec allows it, // Don't check for duplicate bools. Although the spec allows it,
// (1) the compiler hasn't checked it in the past, so compatibility mandates it, and // (1) the compiler hasn't checked it in the past, so compatibility mandates it, and
@ -610,8 +614,7 @@ func (s *exprSwitch) checkDupCases(cc []caseClause) {
if ct := consttype(c.node.Left); ct < 0 || ct == CTBOOL { if ct := consttype(c.node.Left); ct < 0 || ct == CTBOOL {
continue continue
} }
if c.node.Left != nil {
// Single constant.
val := c.node.Left.Val().Interface() val := c.node.Left.Val().Interface()
prev, dup := seen[val] prev, dup := seen[val]
if !dup { if !dup {
@ -619,10 +622,9 @@ func (s *exprSwitch) checkDupCases(cc []caseClause) {
continue continue
} }
setlineno(c.node) setlineno(c.node)
yyerror("duplicate case %v in switch\n\tprevious case at %v", prev.Left, prev.Line()) yyerror("duplicate case %#v in switch\n\tprevious case at %v", val, prev.Line())
continue
} case c.node.List.Len() == 2:
if c.node.List.Len() == 2 {
// Range of integers. // Range of integers.
low := c.node.List.Index(0).Int64() low := c.node.List.Index(0).Int64()
high := c.node.List.Index(1).Int64() high := c.node.List.Index(1).Int64()
@ -633,12 +635,13 @@ func (s *exprSwitch) checkDupCases(cc []caseClause) {
continue continue
} }
setlineno(c.node) setlineno(c.node)
yyerror("duplicate case %v in switch\n\tprevious case at %v", prev.Left, prev.Line()) yyerror("duplicate case %d in switch\n\tprevious case at %v", i, prev.Line())
}
continue
} }
default:
Fatalf("bad caseClause node in checkDupCases: %v", c.node) Fatalf("bad caseClause node in checkDupCases: %v", c.node)
} }
}
return return
} }
// s's expression is an interface. This is fairly rare, so keep this simple. // s's expression is an interface. This is fairly rare, so keep this simple.

View File

@ -90,3 +90,12 @@ func f6() int {
} }
return 2 return 2
} }
// Ensure duplicates in ranges are detected (issue #17517).
func f7(a int) {
switch a {
case 0:
case 0, 1: // ERROR "duplicate case 0"
case 1, 2, 3, 4: // ERROR "duplicate case 1"
}
}