diff options
author | Robert Griesemer <gri@golang.org> | 2021-07-18 15:51:31 -0700 |
---|---|---|
committer | Robert Griesemer <gri@golang.org> | 2021-07-22 17:53:51 +0000 |
commit | 80127a7dfe6951fb16d2b67dbe9badb5952e3a2f (patch) | |
tree | 50cc3650f8a1d9645ea2aa26c34044e96ac29577 /src/cmd/compile/internal/types2/builtins.go | |
parent | fca3e5c4452e8dac6c7ae028dcccc323e1d57ed5 (diff) | |
download | go-80127a7dfe6951fb16d2b67dbe9badb5952e3a2f.tar.gz go-80127a7dfe6951fb16d2b67dbe9badb5952e3a2f.zip |
[dev.typeparams] cmd/compile/internal/types2: adjust unsafe.Alignof/Offsetof/Sizeof
Changed the implementation such that the result is a variable rather than
a constant if the argument type (or the struct in case of unsafe.Offsetof)
has a size that depends on type parameters.
Minor unrelated adjustments.
For #40301.
Change-Id: I1e988f1479b95648ad95a455c764ead829d75749
Reviewed-on: https://go-review.googlesource.com/c/go/+/335413
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
Diffstat (limited to 'src/cmd/compile/internal/types2/builtins.go')
-rw-r--r-- | src/cmd/compile/internal/types2/builtins.go | 73 |
1 files changed, 54 insertions, 19 deletions
diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index 14be24e251..2af2679d5e 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -624,19 +624,22 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( case _Alignof: // unsafe.Alignof(x T) uintptr - if asTypeParam(x.typ) != nil { - check.errorf(call, invalidOp+"unsafe.Alignof undefined for %s", x) - return - } check.assignment(x, nil, "argument to unsafe.Alignof") if x.mode == invalid { return } - x.mode = constant_ - x.val = constant.MakeInt64(check.conf.alignof(x.typ)) + if hasVarSize(x.typ) { + x.mode = value + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ)) + } + } else { + x.mode = constant_ + x.val = constant.MakeInt64(check.conf.alignof(x.typ)) + // result is constant - no need to record signature + } x.typ = Typ[Uintptr] - // result is constant - no need to record signature case _Offsetof: // unsafe.Offsetof(x T) uintptr, where x must be a selector @@ -674,30 +677,43 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( return } - // TODO(gri) Should we pass x.typ instead of base (and indirect report if derefStructPtr indirected)? + // TODO(gri) Should we pass x.typ instead of base (and have indirect report if derefStructPtr indirected)? check.recordSelection(selx, FieldVal, base, obj, index, false) - offs := check.conf.offsetof(base, index) - x.mode = constant_ - x.val = constant.MakeInt64(offs) + // The field offset is considered a variable even if the field is declared before + // the part of the struct which is variable-sized. This makes both the rules + // simpler and also permits (or at least doesn't prevent) a compiler from re- + // arranging struct fields if it wanted to. + if hasVarSize(base) { + x.mode = value + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], obj.Type())) + } + } else { + x.mode = constant_ + x.val = constant.MakeInt64(check.conf.offsetof(base, index)) + // result is constant - no need to record signature + } x.typ = Typ[Uintptr] - // result is constant - no need to record signature case _Sizeof: // unsafe.Sizeof(x T) uintptr - if asTypeParam(x.typ) != nil { - check.errorf(call, invalidOp+"unsafe.Sizeof undefined for %s", x) - return - } check.assignment(x, nil, "argument to unsafe.Sizeof") if x.mode == invalid { return } - x.mode = constant_ - x.val = constant.MakeInt64(check.conf.sizeof(x.typ)) + if hasVarSize(x.typ) { + x.mode = value + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(Typ[Uintptr], x.typ)) + } + } else { + x.mode = constant_ + x.val = constant.MakeInt64(check.conf.sizeof(x.typ)) + // result is constant - no need to record signature + } x.typ = Typ[Uintptr] - // result is constant - no need to record signature case _Slice: // unsafe.Slice(ptr *T, len IntegerType) []T @@ -769,6 +785,25 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( return true } +// hasVarSize reports if the size of type t is variable due to type parameters. +func hasVarSize(t Type) bool { + switch t := under(t).(type) { + case *Array: + return hasVarSize(t.elem) + case *Struct: + for _, f := range t.fields { + if hasVarSize(f.typ) { + return true + } + } + case *TypeParam: + return true + case *Named, *Union, *instance, *top: + unreachable() + } + return false +} + // applyTypeFunc applies f to x. If x is a type parameter, // the result is a type parameter constrained by an new // interface bound. The type bounds for that interface |