Commit f9d0594a authored by Rémy Oudompheng's avatar Rémy Oudompheng Committed by Brad Fitzpatrick

[release-branch.go1.12] cmd/cgo: simplify and fix handling of untyped constants

Instead of trying to guess type of constants in the AST,
which is hard, use the "var cgo%d Type = Constant"
so that typechecking is left to the Go compiler.

The previous code could still fail in some cases
for constants imported from other modules
or defined in other, non-cgo files.

Fixes #30527

Change-Id: I2120cd90e90a74b9d765eeec53f6a3d2cfc1b642
Reviewed-on: https://go-review.googlesource.com/c/go/+/164897
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
(cherry picked from commit 711ea1e7)
Reviewed-on: https://go-review.googlesource.com/c/go/+/165748
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: default avatarEmmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 7294ede9
// Copyright 2019 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.
// Issue 30527: function call rewriting casts untyped
// constants to int because of ":=" usage.
package cgotest
import "cgotest/issue30527"
func issue30527G() {
issue30527.G(nil)
}
// Copyright 2019 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.
package issue30527
import "math"
/*
#include <inttypes.h>
static void issue30527F(char **p, uint64_t mod, uint32_t unused) {}
*/
import "C"
func G(p **C.char) {
C.issue30527F(p, math.MaxUint64, 1)
C.issue30527F(p, 1<<64-1, Z)
}
// Copyright 2019 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.
package issue30527
const (
X = 1 << iota
Y
Z
)
...@@ -200,18 +200,6 @@ func (f *File) saveExprs(x interface{}, context astContext) { ...@@ -200,18 +200,6 @@ func (f *File) saveExprs(x interface{}, context astContext) {
} }
case *ast.CallExpr: case *ast.CallExpr:
f.saveCall(x, context) f.saveCall(x, context)
case *ast.GenDecl:
if x.Tok == token.CONST {
for _, spec := range x.Specs {
vs := spec.(*ast.ValueSpec)
if vs.Type == nil {
for _, name := range spec.(*ast.ValueSpec).Names {
consts[name.Name] = true
}
}
}
}
} }
} }
......
...@@ -897,21 +897,16 @@ func (p *Package) rewriteCall(f *File, call *Call) (string, bool) { ...@@ -897,21 +897,16 @@ func (p *Package) rewriteCall(f *File, call *Call) (string, bool) {
needsUnsafe = true needsUnsafe = true
} }
// Explicitly convert untyped constants to the // Use "var x T = ..." syntax to explicitly convert untyped
// parameter type, to avoid a type mismatch. // constants to the parameter type, to avoid a type mismatch.
if p.isConst(f, arg) { ptype := p.rewriteUnsafe(param.Go)
ptype := p.rewriteUnsafe(param.Go)
if !p.needsPointerCheck(f, param.Go, args[i]) {
if ptype != param.Go { if ptype != param.Go {
needsUnsafe = true needsUnsafe = true
} }
arg = &ast.CallExpr{ fmt.Fprintf(&sb, "var _cgo%d %s = %s; ", i,
Fun: ptype, gofmtLine(ptype), gofmtPos(arg, origArg.Pos()))
Args: []ast.Expr{arg},
}
}
if !p.needsPointerCheck(f, param.Go, args[i]) {
fmt.Fprintf(&sb, "_cgo%d := %s; ", i, gofmtPos(arg, origArg.Pos()))
continue continue
} }
...@@ -1254,47 +1249,6 @@ func (p *Package) isType(t ast.Expr) bool { ...@@ -1254,47 +1249,6 @@ func (p *Package) isType(t ast.Expr) bool {
return false return false
} }
// isConst reports whether x is an untyped constant expression.
func (p *Package) isConst(f *File, x ast.Expr) bool {
switch x := x.(type) {
case *ast.BasicLit:
return true
case *ast.SelectorExpr:
id, ok := x.X.(*ast.Ident)
if !ok || id.Name != "C" {
return false
}
name := f.Name[x.Sel.Name]
if name != nil {
return name.IsConst()
}
case *ast.Ident:
return x.Name == "nil" ||
strings.HasPrefix(x.Name, "_Ciconst_") ||
strings.HasPrefix(x.Name, "_Cfconst_") ||
strings.HasPrefix(x.Name, "_Csconst_") ||
consts[x.Name]
case *ast.UnaryExpr:
return p.isConst(f, x.X)
case *ast.BinaryExpr:
return p.isConst(f, x.X) && p.isConst(f, x.Y)
case *ast.ParenExpr:
return p.isConst(f, x.X)
case *ast.CallExpr:
// Calling the builtin function complex on two untyped
// constants returns an untyped constant.
// TODO: It's possible to construct a case that will
// erroneously succeed if there is a local function
// named "complex", shadowing the builtin, that returns
// a numeric type. I can't think of any cases that will
// erroneously fail.
if id, ok := x.Fun.(*ast.Ident); ok && id.Name == "complex" && len(x.Args) == 2 {
return p.isConst(f, x.Args[0]) && p.isConst(f, x.Args[1])
}
}
return false
}
// isVariable reports whether x is a variable, possibly with field references. // isVariable reports whether x is a variable, possibly with field references.
func (p *Package) isVariable(x ast.Expr) bool { func (p *Package) isVariable(x ast.Expr) bool {
switch x := x.(type) { switch x := x.(type) {
......
...@@ -71,9 +71,6 @@ type File struct { ...@@ -71,9 +71,6 @@ type File struct {
Edit *edit.Buffer Edit *edit.Buffer
} }
// Untyped constants in the current package.
var consts = make(map[string]bool)
func (f *File) offset(p token.Pos) int { func (f *File) offset(p token.Pos) int {
return fset.Position(p).Offset return fset.Position(p).Offset
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment