src/cmd/compile/internal/gc/subr.go | 12 ++++++++++-- src/cmd/compile/internal/gc/typecheck.go | 2 +- test/fixedbugs/issue38117.go | 17 +++++++++++++++++ diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index 3b085a0d6423040f26bd8d4888e9436fcb5db539..73ed34f86a51a3646ee2d224394f70d7ebd6ef23 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -542,7 +542,7 @@ // Is type src assignment compatible to type dst? // If so, return op code to use in conversion. // If not, return 0. -func assignop(src *types.Type, dst *types.Type, why *string) Op { +func assignop(src, dst *types.Type, why *string) Op { if why != nil { *why = "" } @@ -665,7 +665,8 @@ // Can we convert a value of type src to a value of type dst? // If so, return op code to use in conversion (maybe OCONVNOP). // If not, return 0. -func convertop(src *types.Type, dst *types.Type, why *string) Op { +// srcConstant indicates whether the value of type src is a constant. +func convertop(srcConstant bool, src, dst *types.Type, why *string) Op { if why != nil { *why = "" } @@ -738,6 +739,13 @@ if src.IsComplex() && dst.IsComplex() { if simtype[src.Etype] == simtype[dst.Etype] { return OCONVNOP } + return OCONV + } + + // Special case for constant conversions: any numeric + // conversion is potentially okay. We'll validate further + // within evconst. See #38117. + if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) { return OCONV } diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index ae2e16760d197743b10b22b7bc32de5602cb8c71..2ed736367f97cfb0be1bc0c44b1b3e96925596f1 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -1634,7 +1634,7 @@ n.Type = nil return n } var why string - n.Op = convertop(t, n.Type, &why) + n.Op = convertop(n.Left.Op == OLITERAL, t, n.Type, &why) if n.Op == 0 { if !n.Diag() && !n.Type.Broke() && !n.Left.Diag() { yyerror("cannot convert %L to type %v%s", n.Left, n.Type, why) diff --git a/test/fixedbugs/issue38117.go b/test/fixedbugs/issue38117.go new file mode 100644 index 0000000000000000000000000000000000000000..11edef7f2532d5078a2864f69e065c6e3b27c9d8 --- /dev/null +++ b/test/fixedbugs/issue38117.go @@ -0,0 +1,17 @@ +// errorcheck + +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// cmd/compile erroneously rejected conversions of constant values +// between int/float and complex types. + +package p + +const ( + _ = int(complex64(int(0))) + _ = float64(complex128(float64(0))) + + _ = int8(complex128(1000)) // ERROR "overflow" +)