]> Cypherpunks repositories - gostls13.git/commitdiff
text/template: compare reflect.Value instances differently
authorKeith Randall <khr@golang.org>
Fri, 9 Apr 2021 00:06:29 +0000 (17:06 -0700)
committerDaniel Martí <mvdan@mvdan.cc>
Mon, 22 Aug 2022 11:46:15 +0000 (11:46 +0000)
To avoid false positives from the reflectvaluecompare checker #43993

Use v.IsValid() instead of

var zero reflect.Value
v != zero

Also avoid comparing directly with the singleton reflect.Value
representing a missing value. Detect the missing value by type instead.

Change-Id: I3a00d63cf61c077e7c7ae816474aa1f032be325b
Reviewed-on: https://go-review.googlesource.com/c/go/+/308769
Reviewed-by: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Ian Lance Taylor <iant@google.com>
src/text/template/exec.go
src/text/template/funcs.go

index 37984cf91a0740127f448b81fb75c96bc7241a1b..66cb535c47f2ed9d66233ada6295aadf67bc1f90 100644 (file)
@@ -94,6 +94,12 @@ type missingValType struct{}
 
 var missingVal = reflect.ValueOf(missingValType{})
 
+var missingValReflectType = reflect.TypeOf(missingValType{})
+
+func isMissing(v reflect.Value) bool {
+       return v.IsValid() && v.Type() == missingValReflectType
+}
+
 // at marks the state to be on node n, for error reporting.
 func (s *state) at(node parse.Node) {
        s.node = node
@@ -471,7 +477,7 @@ func (s *state) evalPipeline(dot reflect.Value, pipe *parse.PipeNode) (value ref
 }
 
 func (s *state) notAFunction(args []parse.Node, final reflect.Value) {
-       if len(args) > 1 || final != missingVal {
+       if len(args) > 1 || !isMissing(final) {
                s.errorf("can't give argument to non-function %s", args[0])
        }
 }
@@ -629,7 +635,7 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
        if method := ptr.MethodByName(fieldName); method.IsValid() {
                return s.evalCall(dot, method, false, node, fieldName, args, final)
        }
-       hasArgs := len(args) > 1 || final != missingVal
+       hasArgs := len(args) > 1 || !isMissing(final)
        // It's not a method; must be a field of a struct or an element of a map.
        switch receiver.Kind() {
        case reflect.Struct:
@@ -700,7 +706,7 @@ func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node
        }
        typ := fun.Type()
        numIn := len(args)
-       if final != missingVal {
+       if !isMissing(final) {
                numIn++
        }
        numFixed := len(args)
@@ -763,7 +769,7 @@ func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node
                }
        }
        // Add final value if necessary.
-       if final != missingVal {
+       if !isMissing(final) {
                t := typ.In(typ.NumIn() - 1)
                if typ.IsVariadic() {
                        if numIn-1 < numFixed {
index 390d47ebbb65c3ad964939549dea1d8a5c2b05a2..42bb529e509e20f4448f66e8f48a13c7e4f67b45 100644 (file)
@@ -438,7 +438,7 @@ func basicKind(v reflect.Value) (kind, error) {
 
 // isNil returns true if v is the zero reflect.Value, or nil of its type.
 func isNil(v reflect.Value) bool {
-       if v == zero {
+       if !v.IsValid() {
                return true
        }
        switch v.Kind() {