From 9a9aad449fddb1d3f66e6200d2c6c63a0eed63a4 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 8 Apr 2021 17:06:29 -0700 Subject: [PATCH] text/template: compare reflect.Value instances differently MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 TryBot-Result: Gopher Robot Run-TryBot: Keith Randall Reviewed-by: Daniel Martí Reviewed-by: Ian Lance Taylor --- src/text/template/exec.go | 14 ++++++++++---- src/text/template/funcs.go | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/text/template/exec.go b/src/text/template/exec.go index 37984cf91a0..66cb535c47f 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -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 { diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go index 390d47ebbb6..42bb529e509 100644 --- a/src/text/template/funcs.go +++ b/src/text/template/funcs.go @@ -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() {