@@ -624,19 +624,22 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
624
624
625
625
case _Alignof :
626
626
// unsafe.Alignof(x T) uintptr
627
- if asTypeParam (x .typ ) != nil {
628
- check .errorf (call , invalidOp + "unsafe.Alignof undefined for %s" , x )
629
- return
630
- }
631
627
check .assignment (x , nil , "argument to unsafe.Alignof" )
632
628
if x .mode == invalid {
633
629
return
634
630
}
635
631
636
- x .mode = constant_
637
- x .val = constant .MakeInt64 (check .conf .alignof (x .typ ))
632
+ if hasVarSize (x .typ ) {
633
+ x .mode = value
634
+ if check .Types != nil {
635
+ check .recordBuiltinType (call .Fun , makeSig (Typ [Uintptr ], x .typ ))
636
+ }
637
+ } else {
638
+ x .mode = constant_
639
+ x .val = constant .MakeInt64 (check .conf .alignof (x .typ ))
640
+ // result is constant - no need to record signature
641
+ }
638
642
x .typ = Typ [Uintptr ]
639
- // result is constant - no need to record signature
640
643
641
644
case _Offsetof :
642
645
// 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) (
674
677
return
675
678
}
676
679
677
- // TODO(gri) Should we pass x.typ instead of base (and indirect report if derefStructPtr indirected)?
680
+ // TODO(gri) Should we pass x.typ instead of base (and have indirect report if derefStructPtr indirected)?
678
681
check .recordSelection (selx , FieldVal , base , obj , index , false )
679
682
680
- offs := check .conf .offsetof (base , index )
681
- x .mode = constant_
682
- x .val = constant .MakeInt64 (offs )
683
+ // The field offset is considered a variable even if the field is declared before
684
+ // the part of the struct which is variable-sized. This makes both the rules
685
+ // simpler and also permits (or at least doesn't prevent) a compiler from re-
686
+ // arranging struct fields if it wanted to.
687
+ if hasVarSize (base ) {
688
+ x .mode = value
689
+ if check .Types != nil {
690
+ check .recordBuiltinType (call .Fun , makeSig (Typ [Uintptr ], obj .Type ()))
691
+ }
692
+ } else {
693
+ x .mode = constant_
694
+ x .val = constant .MakeInt64 (check .conf .offsetof (base , index ))
695
+ // result is constant - no need to record signature
696
+ }
683
697
x .typ = Typ [Uintptr ]
684
- // result is constant - no need to record signature
685
698
686
699
case _Sizeof :
687
700
// unsafe.Sizeof(x T) uintptr
688
- if asTypeParam (x .typ ) != nil {
689
- check .errorf (call , invalidOp + "unsafe.Sizeof undefined for %s" , x )
690
- return
691
- }
692
701
check .assignment (x , nil , "argument to unsafe.Sizeof" )
693
702
if x .mode == invalid {
694
703
return
695
704
}
696
705
697
- x .mode = constant_
698
- x .val = constant .MakeInt64 (check .conf .sizeof (x .typ ))
706
+ if hasVarSize (x .typ ) {
707
+ x .mode = value
708
+ if check .Types != nil {
709
+ check .recordBuiltinType (call .Fun , makeSig (Typ [Uintptr ], x .typ ))
710
+ }
711
+ } else {
712
+ x .mode = constant_
713
+ x .val = constant .MakeInt64 (check .conf .sizeof (x .typ ))
714
+ // result is constant - no need to record signature
715
+ }
699
716
x .typ = Typ [Uintptr ]
700
- // result is constant - no need to record signature
701
717
702
718
case _Slice :
703
719
// unsafe.Slice(ptr *T, len IntegerType) []T
@@ -769,6 +785,25 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
769
785
return true
770
786
}
771
787
788
+ // hasVarSize reports if the size of type t is variable due to type parameters.
789
+ func hasVarSize (t Type ) bool {
790
+ switch t := under (t ).(type ) {
791
+ case * Array :
792
+ return hasVarSize (t .elem )
793
+ case * Struct :
794
+ for _ , f := range t .fields {
795
+ if hasVarSize (f .typ ) {
796
+ return true
797
+ }
798
+ }
799
+ case * TypeParam :
800
+ return true
801
+ case * Named , * Union , * instance , * top :
802
+ unreachable ()
803
+ }
804
+ return false
805
+ }
806
+
772
807
// applyTypeFunc applies f to x. If x is a type parameter,
773
808
// the result is a type parameter constrained by an new
774
809
// interface bound. The type bounds for that interface
0 commit comments