gotosocial/vendor/modernc.org/cc/v3/type.go
tobi ebdee5aed8
[chore] Downgrade sqlite v1.29.2 -> v1.28.0 (#2736)
* [chore] Downgrade sqlite v1.29.2 -> v1.29.0

* go down to v1.28.0
2024-03-08 11:45:15 +01:00

3267 lines
85 KiB
Go

// Copyright 2019 The CC Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Parts of the documentation are modified versions originating in the Go
// project, particularly the reflect package, license of which is reproduced
// below.
// ----------------------------------------------------------------------------
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the GO-LICENSE file.
package cc // import "modernc.org/cc/v3"
import (
"bytes"
"fmt"
"math"
"sort"
"strings"
"sync"
)
var (
_ Field = (*field)(nil)
_ Type = (*aliasType)(nil)
_ Type = (*arrayType)(nil)
_ Type = (*attributedType)(nil)
_ Type = (*bitFieldType)(nil)
_ Type = (*functionType)(nil)
_ Type = (*pointerType)(nil)
_ Type = (*structType)(nil)
_ Type = (*taggedType)(nil)
_ Type = (*typeBase)(nil)
_ Type = (*vectorType)(nil)
_ Type = noType
bytesBufferPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
idBool = dict.sid("_Bool")
idImag = dict.sid("imag")
idReal = dict.sid("real")
idVectorSize = dict.sid("vector_size")
idVectorSize2 = dict.sid("__vector_size__")
noType = &typeBase{}
_ typeDescriptor = (*DeclarationSpecifiers)(nil)
_ typeDescriptor = (*SpecifierQualifierList)(nil)
_ typeDescriptor = (*TypeQualifiers)(nil)
_ typeDescriptor = noTypeDescriptor
noTypeDescriptor = &DeclarationSpecifiers{}
// [0]6.3.1.1-1
//
// Every integer type has an integer conversion rank defined as
// follows:
intConvRank = [maxKind]int{ // Keep Bool first and sorted by rank.
Bool: 1,
Char: 2,
SChar: 2,
UChar: 2,
Short: 3,
UShort: 3,
Int: 4,
UInt: 4,
Long: 5,
ULong: 5,
LongLong: 6,
ULongLong: 6,
Int128: 7,
UInt128: 7,
}
complexIntegerTypes = [maxKind]bool{
ComplexChar: true,
ComplexInt: true,
ComplexLong: true,
ComplexLongLong: true,
ComplexShort: true,
ComplexUInt: true,
ComplexULong: true,
ComplexULongLong: true,
ComplexUShort: true,
}
complexTypes = [maxKind]bool{
ComplexChar: true,
ComplexDouble: true,
ComplexFloat: true,
ComplexInt: true,
ComplexLong: true,
ComplexLongDouble: true,
ComplexLongLong: true,
ComplexShort: true,
ComplexUInt: true,
ComplexULong: true,
ComplexULongLong: true,
ComplexUShort: true,
}
integerTypes = [maxKind]bool{
Bool: true,
Char: true,
Enum: true,
Int: true,
Long: true,
LongLong: true,
SChar: true,
Short: true,
UChar: true,
UInt: true,
ULong: true,
ULongLong: true,
UShort: true,
Int8: true,
Int16: true,
Int32: true,
Int64: true,
Int128: true,
UInt8: true,
UInt16: true,
UInt32: true,
UInt64: true,
UInt128: true,
}
arithmeticTypes = [maxKind]bool{
Bool: true,
Char: true,
ComplexChar: true,
ComplexDouble: true,
ComplexFloat: true,
ComplexInt: true,
ComplexLong: true,
ComplexLongDouble: true,
ComplexLongLong: true,
ComplexShort: true,
ComplexUInt: true,
ComplexUShort: true,
Double: true,
Enum: true,
Float: true,
Int: true,
Long: true,
LongDouble: true,
LongLong: true,
SChar: true,
Short: true,
UChar: true,
UInt: true,
ULong: true,
ULongLong: true,
UShort: true,
Int8: true,
Int16: true,
Int32: true,
Int64: true,
Int128: true,
UInt8: true,
UInt16: true,
UInt32: true,
UInt64: true,
UInt128: true,
}
realTypes = [maxKind]bool{
Bool: true,
Char: true,
Double: true,
Enum: true,
Float: true,
Int128: true,
Int: true,
Long: true,
LongDouble: true,
LongLong: true,
SChar: true,
Short: true,
UChar: true,
UInt: true,
ULong: true,
ULongLong: true,
UShort: true,
UInt128: true,
}
)
type noStorageClass struct{}
func (noStorageClass) auto() bool { return false }
func (noStorageClass) extern() bool { return false }
func (noStorageClass) register() bool { return false }
func (noStorageClass) static() bool { return false }
func (noStorageClass) threadLocal() bool { return false }
func (noStorageClass) typedef() bool { return false }
// InvalidType creates a new invalid type.
func InvalidType() Type {
return noType
}
// Type is the representation of a C type.
//
// Not all methods apply to all kinds of types. Restrictions, if any, are noted
// in the documentation for each method. Use the Kind method to find out the
// kind of type before calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run-time panic.
//
// Calling a method on a type of kind Invalid yields an undefined result, but
// does not panic.
type Type interface {
//TODO bits()
// Alias returns the type this type aliases. Non typedef types return
// themselves.
Alias() Type
// Align returns the alignment in bytes of a value of this type when
// allocated in memory.
Align() int
// Attributes returns type's attributes, if any.
Attributes() []*AttributeSpecifier
// UnionCommon reports the kind that unifies all union members, if any,
// or Invalid. For example
//
// union { int i; double d; }
//
// Has no unifying kind and will report kind Invalid, but
//
// union { int *p; double *p; }
//
// will report kind Ptr.
//
// UnionCommon panics if the type's Kind is valid but not Enum.
UnionCommon() Kind
// Decay returns itself for non array types and the pointer to array
// element otherwise.
Decay() Type
// Elem returns a type's element type. It panics if the type's Kind is
// valid but not Array or Ptr.
Elem() Type
// EnumType returns the undelying integer type of an enumerated type. It
// panics if the type's Kind is valid but not Enum.
EnumType() Type
// BitField returns the associated Field of a type. It panics if the
// type IsBitFieldType returns false.
BitField() Field
// FieldAlign returns the alignment in bytes of a value of this type
// when used as a field in a struct.
FieldAlign() int
// FieldByIndex returns the nested field corresponding to the index
// sequence. It is equivalent to calling Field successively for each
// index i. It panics if the type's Kind is valid but not Struct or
// any complex kind.
FieldByIndex(index []int) Field
// FieldByName returns the struct field with the given name and a
// boolean indicating if the field was found.
FieldByName(name StringID) (Field, bool)
// FieldByName2 is like FieldByName but additionally returns the
// indices that form the path to the field.
FieldByName2(name StringID) (Field, []int, bool)
// IsAggregate reports whether type is an aggregate type, [0]6.2.5.
//
// 21) Array and structure types are collectively called aggregate types.
//
// 37) Note that aggregate type does not include union type because an object
// with union type can only contain one member at a time.
IsAggregate() bool
// IsPacked reports whether type is packed. It panics if the type's
// Kind is valid but not Struct or Union.
IsPacked() bool
// IsIncomplete reports whether type is incomplete.
IsIncomplete() bool
// IsComplexIntegerType report whether a type is an integer complex
// type.
IsComplexIntegerType() bool
// IsComplexType report whether a type is a complex type.
IsComplexType() bool
// IsArithmeticType report whether a type is an arithmetic type.
IsArithmeticType() bool
// IsBitFieldType report whether a type is for a bit field.
IsBitFieldType() bool
// IsIntegerType report whether a type is an integer type.
IsIntegerType() bool
// IsRealType report whether a type is a real type.
IsRealType() bool
// IsScalarType report whether a type is a scalar type.
IsScalarType() bool
// HasFlexibleMember reports whether a struct has a flexible array
// member. It panics if the type's Kind is valid but not Struct or
// Union.
//
// https://en.wikipedia.org/wiki/Flexible_array_member
HasFlexibleMember() bool
// IsAliasType returns whether a type is an alias name of another type
// For eample
//
// typedef int foo;
// foo x; // The type of x reports true from IsAliasType().
IsAliasType() bool
// IsAssingmentCompatible reports whether a type can be assigned from rhs. [0], 6.5.16.1.
IsAssingmentCompatible(rhs Type) bool
// isAssingmentCompatibleOperand reports whether a type can be assigned from rhs. [0], 6.5.16.1.
isAssingmentCompatibleOperand(rhs Operand) bool
// IsCompatible reports whether the two types are compatible. [0], 6.2.7.
IsCompatible(Type) bool
isCompatibleIgnoreQualifiers(Type) bool
// IsCompatibleLayout reports whether the two types have identical layouts.
IsCompatibleLayout(Type) bool
// AliasDeclarator returns the typedef declarator of the alias type. It panics
// if the type is not an alias type.
AliasDeclarator() *Declarator
// IsTaggedType returns whether a type is a tagged reference of a enum,
// struct or union type. For example
//
// struct s { int x; } y; // The type of y reports false from IsTaggedType.
// struct s z; // The type of z reports true from IsTaggedType.
IsTaggedType() bool
// IsVariadic reports whether a function type is variadic. It panics if
// the type's Kind is valid but not Function.
IsVariadic() bool
// IsVLA reports whether array is a variable length array. It panics if
// the type's Kind is valid but not Array.
IsVLA() bool
// Kind returns the specific kind of this type.
Kind() Kind
// Len returns an array type's length for array types and vector size
// for vector types. It panics if the type's Kind is valid but not
// Array or Vector.
Len() uintptr
// LenExpr returns an array type's length expression. It panics if the
// type's Kind is valid but not Array or the array is not a VLA.
LenExpr() *AssignmentExpression
// NumField returns a struct type's field count. It panics if the
// type's Kind is valid but not Struct or any complex kind.
NumField() int
// Parameters returns the parameters of a function type. It panics if
// the type's Kind is valid but not Function.
Parameters() []*Parameter
// Real returns the real field of a type. It panics if the type's Kind
// is valid but not a complex kind.
Real() Field
// Imag returns the imaginary field of a type. It panics if the type's
// Kind is valid but not a complex kind.
Imag() Field
// Result returns the result type of a function type. It panics if the
// type's Kind is valid but not Function.
Result() Type
// Size returns the number of bytes needed to store a value of the
// given type. It panics if type is valid but incomplete.
Size() uintptr
// String implements fmt.Stringer.
String() string
// Tag returns the tag, of a tagged type or of a struct or union type.
// Tag panics if the type is not tagged type or a struct or union type.
Tag() StringID
// Name returns type name, if any.
Name() StringID
// IsAtomic reports whether type has type qualifier "_Atomic".
IsAtomic() bool
// hasConst reports whether type has type qualifier "const".
hasConst() bool
// Inline reports whether type has function specifier "inline".
Inline() bool
IsSignedType() bool
// noReturn reports whether type has function specifier "_NoReturn".
noReturn() bool
// restrict reports whether type has type qualifier "restrict".
restrict() bool
setLen(uintptr)
setFnSpecs(inline, noret bool)
setKind(Kind)
string(*bytes.Buffer)
base() typeBase
baseP() *typeBase
underlyingType() Type
// IsVolatile reports whether type has type qualifier "volatile".
IsVolatile() bool
isVectorType() bool
}
// A Field describes a single field in a struct/union.
type Field interface {
BitFieldBlockFirst() Field
BitFieldBlockWidth() int
BitFieldOffset() int
BitFieldWidth() int
Declarator() *StructDeclarator
InUnion() bool // Directly or indirectly
Index() int
IsBitField() bool
IsFlexible() bool // https://en.wikipedia.org/wiki/Flexible_array_member
Mask() uint64
Name() StringID // Can be zero.
Offset() uintptr // In bytes from the beginning of the struct/union.
Padding() int // In bytes after the field. N/A for bit fields, fields preceding bit fields or union fields.
Parent() Type // The struct/union type that contains the field.
Promote() Type
Type() Type // Field type.
}
// A Kind represents the specific kind of type that a Type represents. The zero Kind is not a valid kind.
type Kind uint
const (
maxTypeSpecifiers = 4 // eg. long long unsigned int
)
var (
validTypeSpecifiers = map[[maxTypeSpecifiers]TypeSpecifierCase]byte{
// [2], 6.7.2 Type specifiers, 2.
//TODO atomic-type-specifier
{TypeSpecifierBool}: byte(Bool),
{TypeSpecifierChar, TypeSpecifierSigned}: byte(SChar),
{TypeSpecifierChar, TypeSpecifierUnsigned}: byte(UChar),
{TypeSpecifierChar}: byte(Char),
{TypeSpecifierDouble, TypeSpecifierComplex}: byte(ComplexDouble),
{TypeSpecifierDouble}: byte(Double),
{TypeSpecifierEnum}: byte(Enum),
{TypeSpecifierFloat, TypeSpecifierComplex}: byte(ComplexFloat),
{TypeSpecifierFloat}: byte(Float),
{TypeSpecifierInt, TypeSpecifierLong, TypeSpecifierLong, TypeSpecifierSigned}: byte(LongLong),
{TypeSpecifierInt, TypeSpecifierLong, TypeSpecifierLong, TypeSpecifierUnsigned}: byte(ULongLong),
{TypeSpecifierInt, TypeSpecifierLong, TypeSpecifierLong}: byte(LongLong),
{TypeSpecifierInt, TypeSpecifierLong, TypeSpecifierSigned}: byte(Long),
{TypeSpecifierInt, TypeSpecifierLong, TypeSpecifierUnsigned}: byte(ULong),
{TypeSpecifierInt, TypeSpecifierLong}: byte(Long),
{TypeSpecifierInt, TypeSpecifierSigned}: byte(Int),
{TypeSpecifierInt, TypeSpecifierUnsigned}: byte(UInt),
{TypeSpecifierInt}: byte(Int),
{TypeSpecifierLong, TypeSpecifierDouble, TypeSpecifierComplex}: byte(ComplexLongDouble),
{TypeSpecifierLong, TypeSpecifierDouble}: byte(LongDouble),
{TypeSpecifierLong, TypeSpecifierLong, TypeSpecifierSigned}: byte(LongLong),
{TypeSpecifierLong, TypeSpecifierLong, TypeSpecifierUnsigned}: byte(ULongLong),
{TypeSpecifierLong, TypeSpecifierLong}: byte(LongLong),
{TypeSpecifierLong, TypeSpecifierSigned}: byte(Long),
{TypeSpecifierLong, TypeSpecifierUnsigned}: byte(ULong),
{TypeSpecifierLong}: byte(Long),
{TypeSpecifierShort, TypeSpecifierInt, TypeSpecifierSigned}: byte(Short),
{TypeSpecifierShort, TypeSpecifierInt, TypeSpecifierUnsigned}: byte(UShort),
{TypeSpecifierShort, TypeSpecifierInt}: byte(Short),
{TypeSpecifierShort, TypeSpecifierSigned}: byte(Short),
{TypeSpecifierShort, TypeSpecifierUnsigned}: byte(UShort),
{TypeSpecifierShort}: byte(Short),
{TypeSpecifierSigned}: byte(Int),
{TypeSpecifierStructOrUnion}: byte(Struct),
{TypeSpecifierTypedefName}: byte(TypedefName), //TODO
{TypeSpecifierUnsigned}: byte(UInt),
{TypeSpecifierVoid}: byte(Void),
// GCC Extensions.
{TypeSpecifierChar, TypeSpecifierComplex}: byte(ComplexChar),
{TypeSpecifierComplex}: byte(ComplexDouble),
{TypeSpecifierDecimal128}: byte(Decimal128),
{TypeSpecifierDecimal32}: byte(Decimal32),
{TypeSpecifierDecimal64}: byte(Decimal64),
{TypeSpecifierFloat128}: byte(Float128),
{TypeSpecifierFloat32x}: byte(Float32x),
{TypeSpecifierFloat32}: byte(Float32),
{TypeSpecifierFloat64x}: byte(Float64x),
{TypeSpecifierFloat64}: byte(Float64),
{TypeSpecifierInt, TypeSpecifierComplex}: byte(ComplexInt),
{TypeSpecifierInt, TypeSpecifierLong, TypeSpecifierComplex}: byte(ComplexLong),
{TypeSpecifierInt8, TypeSpecifierSigned}: byte(Int8),
{TypeSpecifierInt16, TypeSpecifierSigned}: byte(Int16),
{TypeSpecifierInt32, TypeSpecifierSigned}: byte(Int32),
{TypeSpecifierInt64, TypeSpecifierSigned}: byte(Int64),
{TypeSpecifierInt128, TypeSpecifierSigned}: byte(Int128),
{TypeSpecifierInt8, TypeSpecifierUnsigned}: byte(UInt8),
{TypeSpecifierInt16, TypeSpecifierUnsigned}: byte(UInt16),
{TypeSpecifierInt32, TypeSpecifierUnsigned}: byte(UInt32),
{TypeSpecifierInt64, TypeSpecifierUnsigned}: byte(UInt64),
{TypeSpecifierInt128, TypeSpecifierUnsigned}: byte(UInt128),
{TypeSpecifierInt8}: byte(Int8),
{TypeSpecifierInt16}: byte(Int16),
{TypeSpecifierInt32}: byte(Int32),
{TypeSpecifierInt64}: byte(Int64),
{TypeSpecifierInt128}: byte(Int128),
{TypeSpecifierLong, TypeSpecifierComplex}: byte(ComplexLong),
{TypeSpecifierLong, TypeSpecifierDouble, TypeSpecifierFloat64x}: byte(LongDouble),
{TypeSpecifierLong, TypeSpecifierLong, TypeSpecifierComplex}: byte(ComplexLongLong),
{TypeSpecifierShort, TypeSpecifierComplex}: byte(ComplexUShort),
{TypeSpecifierShort, TypeSpecifierUnsigned, TypeSpecifierComplex}: byte(ComplexShort),
{TypeSpecifierTypeofExpr}: byte(typeofExpr), //TODO
{TypeSpecifierTypeofType}: byte(typeofType), //TODO
{TypeSpecifierUnsigned, TypeSpecifierComplex}: byte(ComplexUInt),
}
)
type typeDescriptor interface {
Node
auto() bool
extern() bool
register() bool
static() bool
threadLocal() bool
typedef() bool
}
type storageClass byte
const (
fAuto storageClass = 1 << iota
fExtern
fRegister
fStatic
fThreadLocal
fTypedef
)
type flag uint16
const (
// function specifier
fInline flag = 1 << iota //TODO should go elsewhere
fNoReturn
// type qualifier
fAtomic
fConst
fRestrict
fVolatile
// other
fIncomplete
fSigned // Valid only for integer types.
fPacked
fAligned // __attribute__((aligned(n))) applied.
)
type typeBase struct {
size uintptr
flags flag
align byte
fieldAlign byte
kind byte
}
func (t *typeBase) check(ctx *context, td typeDescriptor, defaultInt bool) (r Type) {
k0 := t.kind
var alignmentSpecifiers []*AlignmentSpecifier
var attributeSpecifiers []*AttributeSpecifier
var typeSpecifiers []*TypeSpecifier
switch n := td.(type) {
case *DeclarationSpecifiers:
for ; n != nil; n = n.DeclarationSpecifiers {
switch n.Case {
case DeclarationSpecifiersStorage: // StorageClassSpecifier DeclarationSpecifiers
// nop
case DeclarationSpecifiersTypeSpec: // TypeSpecifier DeclarationSpecifiers
typeSpecifiers = append(typeSpecifiers, n.TypeSpecifier.list()...)
case DeclarationSpecifiersTypeQual: // TypeQualifier DeclarationSpecifiers
// nop
case DeclarationSpecifiersFunc: // FunctionSpecifier DeclarationSpecifiers
// nop
case DeclarationSpecifiersAlignSpec: // AlignmentSpecifier DeclarationSpecifiers
alignmentSpecifiers = append(alignmentSpecifiers, n.AlignmentSpecifier)
case DeclarationSpecifiersAttribute: // AttributeSpecifier DeclarationSpecifiers
attributeSpecifiers = append(attributeSpecifiers, n.AttributeSpecifier)
default:
panic(internalError())
}
}
case *SpecifierQualifierList:
for ; n != nil; n = n.SpecifierQualifierList {
switch n.Case {
case SpecifierQualifierListTypeSpec: // TypeSpecifier SpecifierQualifierList
typeSpecifiers = append(typeSpecifiers, n.TypeSpecifier.list()...)
case SpecifierQualifierListTypeQual: // TypeQualifier SpecifierQualifierList
// nop
case SpecifierQualifierListAlignSpec: // AlignmentSpecifier SpecifierQualifierList
alignmentSpecifiers = append(alignmentSpecifiers, n.AlignmentSpecifier)
case SpecifierQualifierListAttribute: // AttributeSpecifier SpecifierQualifierList
attributeSpecifiers = append(attributeSpecifiers, n.AttributeSpecifier)
default:
panic(internalError())
}
}
case *TypeQualifiers:
for ; n != nil; n = n.TypeQualifiers {
if n.Case == TypeQualifiersAttribute {
attributeSpecifiers = append(attributeSpecifiers, n.AttributeSpecifier)
}
}
default:
panic(internalError())
}
if len(typeSpecifiers) > maxTypeSpecifiers {
ctx.err(typeSpecifiers[maxTypeSpecifiers].Position(), "too many type specifiers")
typeSpecifiers = typeSpecifiers[:maxTypeSpecifiers]
}
sort.Slice(typeSpecifiers, func(i, j int) bool {
return typeSpecifiers[i].Case < typeSpecifiers[j].Case
})
var k [maxTypeSpecifiers]TypeSpecifierCase
for i, v := range typeSpecifiers {
k[i] = v.Case
}
switch {
case len(typeSpecifiers) == 0:
if !defaultInt {
break
}
k[0] = TypeSpecifierInt
fallthrough
default:
var ok bool
if t.kind, ok = validTypeSpecifiers[k]; !ok {
s := k[:]
for len(s) > 1 && s[len(s)-1] == TypeSpecifierVoid {
s = s[:len(s)-1]
}
ctx.err(td.Position(), "invalid type specifiers combination: %v", s)
return t
}
if t.kind == byte(LongDouble) && ctx.cfg.LongDoubleIsDouble {
t.kind = byte(Double)
}
}
switch len(alignmentSpecifiers) {
case 0:
//TODO set alignment from model
case 1:
align := alignmentSpecifiers[0].align()
if align > math.MaxUint8 {
panic(internalError())
}
t.align = byte(align)
t.fieldAlign = t.align
default:
ctx.err(alignmentSpecifiers[1].Position(), "multiple alignment specifiers")
}
abi := ctx.cfg.ABI
switch k := t.Kind(); k {
case typeofExpr, typeofType, Struct, Union, Enum:
// nop
default:
if integerTypes[k] && abi.isSignedInteger(k) {
t.flags |= fSigned
}
if v, ok := abi.Types[k]; ok {
t.size = uintptr(abi.size(k))
if t.align != 0 {
break
}
t.align = byte(v.Align)
t.fieldAlign = byte(v.FieldAlign)
break
}
//TODO ctx.err(td.Position(), "missing model item for %s", t.Kind())
}
typ := Type(t)
switch k := t.Kind(); k {
case TypedefName:
ts := typeSpecifiers[0]
tok := ts.Token
nm := tok.Value
d := ts.resolvedIn.typedef(nm, tok)
typ = &aliasType{typeBase: t, nm: nm, d: d}
case Enum:
typ = typeSpecifiers[0].EnumSpecifier.typ
case Struct, Union:
t.kind = k0
typ = typeSpecifiers[0].StructOrUnionSpecifier.typ
case typeofExpr, typeofType:
typ = typeSpecifiers[0].typ
default:
if complexTypes[k] {
typ = ctx.cfg.ABI.Type(k)
}
}
return typ
}
func (t *typeBase) setAligned(n int) {
t.flags |= fAligned
t.align = byte(n)
}
// IsAssingmentCompatible implements Type.
func (t *typeBase) IsAssingmentCompatible(rhs Type) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
if t == rhs {
return true
}
// [0], 6.5.16.1 Simple assignment
//
// 1 One of the following shall hold:
//
// — the left operand has qualified or unqualified arithmetic type and the
// right has arithmetic type;
//
// — the left operand has a qualified or unqualified version of a structure or
// union type compatible with the type of the right;
//
// — both operands are pointers to qualified or unqualified versions of
// compatible types, and the type pointed to by the left has all the qualifiers
// of the type pointed to by the right;
//
// — one operand is a pointer to an object or incomplete type and the other is
// a pointer to a qualified or unqualified version of void, and the type
// pointed to by the left has all the qualifiers of the type pointed to by the
// right;
//
// — the left operand is a pointer and the right is a null pointer constant; or
//
// — the left operand has type _Bool and the right is a pointer.
if t.IsArithmeticType() && rhs.IsArithmeticType() {
return true
}
if x, ok := rhs.(*aliasType); ok {
if x.nm == idBool && rhs.Kind() == Ptr {
return true
}
}
if t.IsIntegerType() && rhs.Kind() == Ptr {
// 6.3.2.3 Pointers
//
// 6 Any pointer type may be converted to an integer type. Except as previously specified, the
// result is implementation-defined. If the result cannot be represented in the integer type,
// the behavior is undefined. The result need not be in the range of values of any integer
// type.
return true
}
return false
}
// isAssingmentCompatibleOperand implements Type.
func (t *typeBase) isAssingmentCompatibleOperand(rhs Operand) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
rhsType := rhs.Type().Decay()
if t == rhsType {
return true
}
return t.IsAssingmentCompatible(rhsType)
}
// IsCompatible implements Type.
func (t *typeBase) IsCompatible(u Type) (r bool) {
// defer func() {
// u0 := u
// if !r {
// trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO-
// }
// }()
if t == nil || u == nil {
return false
}
if t == u {
return true
}
if !t.IsScalarType() && t.Kind() != Void {
panic(internalErrorf("IsCompatible of invalid type: %v", t.Kind()))
}
v := u.base()
// [0], 6.7.3
//
// 9 For two qualified types to be compatible, both shall have the identically
// qualified version of a compatible type; the order of type qualifiers within
// a list of specifiers or qualifiers does not affect the specified type.
if t.flags&(fAtomic|fConst|fRestrict|fVolatile|fSigned) != v.flags&(fAtomic|fConst|fRestrict|fVolatile|fSigned) {
return false
}
if t.Kind() == u.Kind() {
return true
}
if t.Kind() == Enum && u.IsIntegerType() && t.Size() == u.Size() {
return true
}
return t.IsIntegerType() && u.Kind() == Enum && t.Size() == u.Size()
}
// isCompatibleIgnoreQualifiers implements Type.
func (t *typeBase) isCompatibleIgnoreQualifiers(u Type) (r bool) {
// defer func() {
// u0 := u
// if !r {
// trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO-
// }
// }()
if t == nil || u == nil {
return false
}
if t == u {
return true
}
if !t.IsScalarType() && t.Kind() != Void {
panic(internalErrorf("isCompatibleIgnoreQualifiers of invalid type: %v", t.Kind()))
}
if t.Kind() == u.Kind() {
return true
}
if t.Kind() == Enum && u.IsIntegerType() && t.Size() == u.Size() {
return true
}
return t.IsIntegerType() && u.Kind() == Enum && t.Size() == u.Size()
}
// IsCompatibleLayout implements Type.
func (t *typeBase) IsCompatibleLayout(u Type) bool {
if t == u {
return true
}
if !t.IsScalarType() {
panic(internalErrorf("%s: IsCompatibleLayout of invalid type", t.Kind()))
}
if t.Kind() == u.Kind() {
return true
}
if t.Kind() == Enum && u.IsIntegerType() && t.Size() == u.Size() {
return true
}
return t.IsIntegerType() && u.Kind() == Enum && t.Size() == u.Size()
}
// IsPacked implements Type.
func (t *typeBase) IsPacked() bool {
return t.flags&fPacked != 0
}
// UnionCommon implements Type.
func (t *typeBase) UnionCommon() Kind {
panic(internalErrorf("%s: UnionCommon of invalid type", t.Kind()))
}
// IsAtomic implements Type.
func (t *typeBase) IsAtomic() bool { return t.flags&fAtomic != 0 }
// Attributes implements Type.
func (t *typeBase) Attributes() (a []*AttributeSpecifier) { return nil }
// Alias implements Type.
func (t *typeBase) Alias() Type { return t }
// IsAliasType implements Type.
func (t *typeBase) IsAliasType() bool { return false }
func (t *typeBase) AliasDeclarator() *Declarator {
panic(internalErrorf("%s: AliasDeclarator of invalid type", t.Kind()))
}
// IsTaggedType implements Type.
func (t *typeBase) IsTaggedType() bool { return false }
// Align implements Type.
func (t *typeBase) Align() int { return int(t.align) }
// BitField implements Type.
func (t *typeBase) BitField() Field {
if t.Kind() == Invalid {
return nil
}
panic(internalErrorf("%s: BitField of invalid type", t.Kind()))
}
// base implements Type.
func (t *typeBase) base() typeBase { return *t }
// baseP implements Type.
func (t *typeBase) baseP() *typeBase { return t }
// isVectorType implements Type.
func (t *typeBase) isVectorType() bool {
return false
}
// Decay implements Type.
func (t *typeBase) Decay() Type {
if t.Kind() != Array {
return t
}
panic(internalErrorf("%s: Decay of invalid type", t.Kind()))
}
// Elem implements Type.
func (t *typeBase) Elem() Type {
if t.Kind() == Invalid {
return t
}
panic(internalErrorf("%s: Elem of invalid type", t.Kind()))
}
// EnumType implements Type.
func (t *typeBase) EnumType() Type {
if t.Kind() == Invalid {
return t
}
panic(internalErrorf("%s: EnumType of invalid type", t.Kind()))
}
// hasConst implements Type.
func (t *typeBase) hasConst() bool { return t.flags&fConst != 0 }
// FieldAlign implements Type.
func (t *typeBase) FieldAlign() int { return int(t.fieldAlign) }
// FieldByIndex implements Type.
func (t *typeBase) FieldByIndex([]int) Field {
if t.Kind() == Invalid {
return nil
}
panic(internalErrorf("%s: FieldByIndex of invalid type", t.Kind()))
}
// NumField implements Type.
func (t *typeBase) NumField() int {
if t.Kind() == Invalid {
return 0
}
panic(internalErrorf("%s: NumField of invalid type", t.Kind()))
}
// FieldByName implements Type.
func (t *typeBase) FieldByName(StringID) (Field, bool) {
if t.Kind() == Invalid {
return nil, false
}
panic(internalErrorf("%s: FieldByName of invalid type", t.Kind()))
}
// FieldByName2 implements Type.
func (t *typeBase) FieldByName2(StringID) (Field, []int, bool) {
if t.Kind() == Invalid {
return nil, nil, false
}
panic(internalErrorf("%s: FieldByName2 of invalid type", t.Kind()))
}
// IsIncomplete implements Type.
func (t *typeBase) IsIncomplete() bool { return t.flags&fIncomplete != 0 }
// IsAggregate implements Type.
func (t *typeBase) IsAggregate() bool { return t.Kind() == Array || t.Kind() == Struct }
// Inline implements Type.
func (t *typeBase) Inline() bool { return t.flags&fInline != 0 }
// IsIntegerType implements Type.
func (t *typeBase) IsIntegerType() bool { return integerTypes[t.kind] }
// IsArithmeticType implements Type.
func (t *typeBase) IsArithmeticType() bool { return arithmeticTypes[t.Kind()] }
// IsComplexType implements Type.
func (t *typeBase) IsComplexType() bool { return complexTypes[t.Kind()] }
// IsComplexIntegerType implements Type.
func (t *typeBase) IsComplexIntegerType() bool { return complexIntegerTypes[t.Kind()] }
// IsBitFieldType implements Type.
func (t *typeBase) IsBitFieldType() bool { return false }
// IsRealType implements Type.
func (t *typeBase) IsRealType() bool { return realTypes[t.Kind()] }
// IsScalarType implements Type.
func (t *typeBase) IsScalarType() bool {
return (t.IsArithmeticType() || t.Kind() == Ptr) && !t.isVectorType()
}
// HasFlexibleMember implements Type.
func (t *typeBase) HasFlexibleMember() bool {
if t.Kind() == Invalid {
return false
}
panic(internalErrorf("%s: HasFlexibleMember of invalid type", t.Kind()))
}
// IsSignedType implements Type.
func (t *typeBase) IsSignedType() bool {
if !integerTypes[t.kind] {
panic(internalErrorf("%s: IsSignedType of non-integer type", t.Kind()))
}
return t.flags&fSigned != 0
}
// IsVariadic implements Type.
func (t *typeBase) IsVariadic() bool {
if t.Kind() == Invalid {
return false
}
panic(internalErrorf("%s: IsVariadic of invalid type", t.Kind()))
}
// IsVLA implements Type.
func (t *typeBase) IsVLA() bool {
if t.Kind() == Invalid {
return false
}
panic(internalErrorf("%s: IsVLA of invalid type", t.Kind()))
}
// Kind implements Type.
func (t *typeBase) Kind() Kind { return Kind(t.kind) }
// Len implements Type.
func (t *typeBase) Len() uintptr { panic(internalErrorf("%s: Len of non-array type", t.Kind())) }
// LenExpr implements Type.
func (t *typeBase) LenExpr() *AssignmentExpression {
panic(internalErrorf("%s: LenExpr of non-array type", t.Kind()))
}
// noReturn implements Type.
func (t *typeBase) noReturn() bool { return t.flags&fNoReturn != 0 }
// restrict implements Type.
func (t *typeBase) restrict() bool { return t.flags&fRestrict != 0 }
// Parameters implements Type.
func (t *typeBase) Parameters() []*Parameter {
if t.Kind() == Invalid {
return nil
}
panic(internalErrorf("%s: Parameters of invalid type", t.Kind()))
}
// Result implements Type.
func (t *typeBase) Result() Type {
if t.Kind() == Invalid {
return noType
}
panic(internalErrorf("%s: Result of invalid type", t.Kind()))
}
// Real implements Type
func (t *typeBase) Real() Field {
if t.Kind() == Invalid {
return nil
}
panic(internalErrorf("%s: Real of invalid type", t.Kind()))
}
// Imag implements Type
func (t *typeBase) Imag() Field {
if t.Kind() == Invalid {
return nil
}
panic(internalErrorf("%s: Imag of invalid type", t.Kind()))
}
// Size implements Type.
func (t *typeBase) Size() uintptr {
if t.IsIncomplete() {
panic(internalError())
}
return t.size
}
// setLen implements Type.
func (t *typeBase) setLen(uintptr) {
if t.Kind() == Invalid {
return
}
panic(internalErrorf("%s: setLen of non-array type", t.Kind()))
}
// setFnSpecs implements Type.
func (t *typeBase) setFnSpecs(inline, noret bool) {
t.flags &^= fInline | fNoReturn
if inline {
t.flags |= fInline
}
if noret {
t.flags |= fNoReturn
}
}
// setKind implements Type.
func (t *typeBase) setKind(k Kind) { t.kind = byte(k) }
// underlyingType implements Type.
func (t *typeBase) underlyingType() Type { return t }
// IsVolatile implements Type.
func (t *typeBase) IsVolatile() bool { return t.flags&fVolatile != 0 }
// String implements Type.
func (t *typeBase) String() string {
b := bytesBufferPool.Get().(*bytes.Buffer)
defer func() { b.Reset(); bytesBufferPool.Put(b) }()
t.string(b)
return strings.TrimSpace(b.String())
}
// Name implements Type.
func (t *typeBase) Name() StringID { return 0 }
// Tag implements Type.
func (t *typeBase) Tag() StringID {
panic(internalErrorf("%s: Tag of invalid type", t.Kind()))
}
// string implements Type.
func (t *typeBase) string(b *bytes.Buffer) {
spc := ""
if t.IsAtomic() {
b.WriteString("atomic")
spc = " "
}
if t.hasConst() {
b.WriteString(spc)
b.WriteString("const")
spc = " "
}
if t.Inline() {
b.WriteString(spc)
b.WriteString("inline")
spc = " "
}
if t.noReturn() {
b.WriteString(spc)
b.WriteString("_NoReturn")
spc = " "
}
if t.restrict() {
b.WriteString(spc)
b.WriteString("restrict")
spc = " "
}
if t.IsVolatile() {
b.WriteString(spc)
b.WriteString("volatile")
spc = " "
}
b.WriteString(spc)
switch k := t.Kind(); k {
case Enum:
b.WriteString("enum")
case Invalid:
// nop
case Struct:
b.WriteString("struct")
case Union:
b.WriteString("union")
case Ptr:
b.WriteString("pointer")
case typeofExpr, typeofType:
panic(internalError())
default:
b.WriteString(k.String())
}
}
type attributedType struct {
Type
attr []*AttributeSpecifier
}
// Alias implements Type.
func (t *attributedType) Alias() Type { return t }
// String implements Type.
func (t *attributedType) String() string {
b := bytesBufferPool.Get().(*bytes.Buffer)
defer func() { b.Reset(); bytesBufferPool.Put(b) }()
t.string(b)
return strings.TrimSpace(b.String())
}
// string implements Type.
func (t *attributedType) string(b *bytes.Buffer) {
t.Type.string(b)
for _, v := range t.attr {
b.WriteString(nodeSource(v))
}
}
// Attributes implements Type.
func (t *attributedType) Attributes() []*AttributeSpecifier { return t.attr }
type pointerType struct {
typeBase
elem Type
typeQualifiers Type
}
// IsAssingmentCompatible implements Type.
func (t *pointerType) IsAssingmentCompatible(rhs Type) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
if rhs = rhs.Alias().Decay(); t == rhs {
return true
}
// [0], 6.5.16.1 Simple assignment
//
// 1 One of the following shall hold:
//
// — the left operand has qualified or unqualified arithmetic type and the
// right has arithmetic type;
//
// — the left operand has a qualified or unqualified version of a structure or
// union type compatible with the type of the right;
//
// — both operands are pointers to qualified or unqualified versions of
// compatible types, and the type pointed to by the left has all the qualifiers
// of the type pointed to by the right;
//
// — one operand is a pointer to an object or incomplete type and the other is
// a pointer to a qualified or unqualified version of void, and the type
// pointed to by the left has all the qualifiers of the type pointed to by the
// right;
//
// — the left operand is a pointer and the right is a null pointer constant; or
//
// — the left operand has type _Bool and the right is a pointer.
if rhs.Kind() == Ptr {
v := rhs.(*pointerType)
a := t.Elem().Alias().Decay()
b := v.Elem().Alias().Decay()
// — one operand is a pointer to an object or incomplete type and the other is
// a pointer to a qualified or unqualified version of void, and the type
// pointed to by the left has all the qualifiers of the type pointed to by the
// right;
if a.Kind() == Void || b.Kind() == Void {
return true
}
x := a.base().flags & (fAtomic | fConst | fRestrict | fVolatile)
y := b.base().flags & (fAtomic | fConst | fRestrict | fVolatile)
if x&y == y {
// — both operands are pointers to qualified or unqualified versions of
// compatible types, and the type pointed to by the left has all the qualifiers
// of the type pointed to by the right;
if a.underlyingType() != nil && b.underlyingType() != nil && a.isCompatibleIgnoreQualifiers(b) {
return true
}
if a.IsIncomplete() || b.IsIncomplete() && a.Kind() == b.Kind() {
return true
}
if a.IsIntegerType() && b.IsIntegerType() {
return true
}
}
// trc("a %T %[1]v, x %#x, b %T %[3]v, y %#x, x&y %#x", a, x, b, y, x&y)
// trc("a %+v, b%+v", a.base(), b.base())
return false
}
return rhs.Kind() == Function && t.Elem().IsAssingmentCompatible(rhs)
}
// isAssingmentCompatibleOperand implements Type.
func (t *pointerType) isAssingmentCompatibleOperand(rhs Operand) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
rhsType := rhs.Type()
if rhsType.Kind() == Function {
if t.Elem().Kind() == Void {
return true
}
return t.Elem().IsCompatible(rhsType)
}
// — the left operand is a pointer and the right is a null pointer constant; or
return rhs.IsZero() || t.IsAssingmentCompatible(rhsType)
}
// IsCompatible implements Type.
func (t *pointerType) IsCompatible(u Type) (r bool) {
// defer func() {
// u0 := u
// if !r {
// trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO-
// }
// }()
if t == nil || u == nil {
return false
}
if t == u {
return true
}
if u = u.Alias().Decay(); t == u {
return true
}
if u.Kind() != Ptr {
return false
}
v := u.(*pointerType)
// [0], 6.7.5.1
//
// 2 For two pointer types to be compatible, both shall be identically
// qualified and both shall be pointers to compatible types.;
if t.typeBase.flags&(fAtomic|fConst|fRestrict|fVolatile|fSigned) != v.typeBase.flags&(fAtomic|fConst|fRestrict|fVolatile|fSigned) {
return false
}
return t.Elem().IsCompatible(v.Elem())
}
// isCompatibleIgnoreQualifiers implements Type.
func (t *pointerType) isCompatibleIgnoreQualifiers(u Type) (r bool) {
// defer func() {
// u0 := u
// if !r {
// trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO-
// }
// }()
if t == nil || u == nil {
return false
}
if t == u {
return true
}
if u = u.Alias().Decay(); t == u {
return true
}
if u.Kind() != Ptr {
return false
}
v := u.(*pointerType)
if t.Elem().Kind() == Void || v.Elem().Kind() == Void {
return true
}
return t.Elem().isCompatibleIgnoreQualifiers(v.Elem())
}
// Alias implements Type.
func (t *pointerType) Alias() Type { return t }
// Attributes implements Type.
func (t *pointerType) Attributes() (a []*AttributeSpecifier) { return t.elem.Attributes() }
// Decay implements Type.
func (t *pointerType) Decay() Type { return t }
// Elem implements Type.
func (t *pointerType) Elem() Type { return t.elem }
// underlyingType implements Type.
func (t *pointerType) underlyingType() Type { return t }
// String implements Type.
func (t *pointerType) String() string {
b := bytesBufferPool.Get().(*bytes.Buffer)
defer func() { b.Reset(); bytesBufferPool.Put(b) }()
t.string(b)
return strings.TrimSpace(b.String())
}
// string implements Type.
func (t *pointerType) string(b *bytes.Buffer) {
if t := t.typeQualifiers; t != nil {
t.string(b)
}
b.WriteString("pointer to ")
t.Elem().string(b)
}
type arrayType struct {
typeBase
expr *AssignmentExpression
decay Type
elem Type
length uintptr
vla bool
}
// IsAssingmentCompatible implements Type.
func (t *arrayType) IsAssingmentCompatible(rhs Type) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
if rhs = rhs.Alias().Decay(); t == rhs {
return true
}
// [0], 6.5.16.1 Simple assignment
//
// 1 One of the following shall hold:
//
// — the left operand has qualified or unqualified arithmetic type and the
// right has arithmetic type;
//
// — the left operand has a qualified or unqualified version of a structure or
// union type compatible with the type of the right;
//
// — both operands are pointers to qualified or unqualified versions of
// compatible types, and the type pointed to by the left has all the qualifiers
// of the type pointed to by the right;
//
// — one operand is a pointer to an object or incomplete type and the other is
// a pointer to a qualified or unqualified version of void, and the type
// pointed to by the left has all the qualifiers of the type pointed to by the
// right;
//
// — the left operand is a pointer and the right is a null pointer constant; or
//
// — the left operand has type _Bool and the right is a pointer.
if rhs.Kind() == Array {
rhs = rhs.Decay()
}
return t.Decay().IsAssingmentCompatible(t)
}
// isAssingmentCompatibleOperand implements Type.
func (t *arrayType) isAssingmentCompatibleOperand(rhs Operand) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
return t.IsAssingmentCompatible(rhs.Type())
}
// IsCompatible implements Type.
func (t *arrayType) IsCompatible(u Type) (r bool) {
// defer func() {
// u0 := u
// if !r {
// trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO-
// }
// }()
if t == nil || u == nil {
return false
}
if u = u.Alias().Decay(); t == u {
return true
}
if t.vla || u.Kind() != Array {
return false
}
v := u.(*arrayType)
// [0], 6.7.5.2
//
// 6 For two array types to be compatible, both shall have compatible element
// types, and if both size specifiers are present, and are integer constant
// expressions, then both size specifiers shall have the same constant value.
// If the two array types are used in a context which requires them to be
// compatible, it is undefined behavior if the two size specifiers evaluate to
// unequal values.
return !t.vla && !v.vla && t.length == v.length && t.elem.IsCompatible(v.elem)
}
// isCompatibleIgnoreQualifiers implements Type.
func (t *arrayType) isCompatibleIgnoreQualifiers(u Type) (r bool) {
return t.IsCompatible(u)
}
// IsCompatibleLayout implements Type.
func (t *arrayType) IsCompatibleLayout(u Type) bool {
if u = u.Alias().Decay(); t == u {
return true
}
if t.vla || u.Kind() != Array {
return false
}
v := u.(*arrayType)
return !t.vla && !v.vla && t.length == v.length && t.elem.IsCompatibleLayout(v.elem)
}
// Alias implements Type.
func (t *arrayType) Alias() Type { return t }
// IsVLA implements Type.
func (t *arrayType) IsVLA() bool { return t.vla || t.elem.Kind() == Array && t.Elem().IsVLA() }
// String implements Type.
func (t *arrayType) String() string {
b := bytesBufferPool.Get().(*bytes.Buffer)
defer func() { b.Reset(); bytesBufferPool.Put(b) }()
t.string(b)
return strings.TrimSpace(b.String())
}
// string implements Type.
func (t *arrayType) string(b *bytes.Buffer) {
b.WriteString("array of ")
if t.Len() != 0 {
fmt.Fprintf(b, "%d ", t.Len())
}
t.Elem().string(b)
}
// Attributes implements Type.
func (t *arrayType) Attributes() (a []*AttributeSpecifier) { return t.elem.Attributes() }
// Decay implements Type.
func (t *arrayType) Decay() Type { return t.decay }
// Elem implements Type.
func (t *arrayType) Elem() Type { return t.elem }
// Len implements Type.
func (t *arrayType) Len() uintptr { return t.length }
// LenExpr implements Type.
func (t *arrayType) LenExpr() *AssignmentExpression {
if !t.vla {
panic(internalErrorf("%s: LenExpr of non variable length array", t.Kind()))
}
return t.expr
}
// setLen implements Type.
func (t *arrayType) setLen(n uintptr) {
t.typeBase.flags &^= fIncomplete
t.length = n
if t.Elem() != nil {
t.size = t.length * t.Elem().Size()
}
}
// underlyingType implements Type.
func (t *arrayType) underlyingType() Type { return t }
type aliasType struct {
*typeBase
nm StringID
d *Declarator
}
// HasFlexibleMember implements Type.
func (t *aliasType) HasFlexibleMember() bool {
return t.d.Type().HasFlexibleMember()
}
// IsAssingmentCompatible implements Type.
func (t *aliasType) IsAssingmentCompatible(rhs Type) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
if t == rhs {
return true
}
if x, ok := rhs.(*aliasType); ok && t.nm == x.nm {
return true
}
if rhs = rhs.Alias().Decay(); t == rhs {
return true
}
// [0], 6.5.16.1 Simple assignment
//
// 1 One of the following shall hold:
//
// — the left operand has qualified or unqualified arithmetic type and the
// right has arithmetic type;
//
// — the left operand has a qualified or unqualified version of a structure or
// union type compatible with the type of the right;
//
// — both operands are pointers to qualified or unqualified versions of
// compatible types, and the type pointed to by the left has all the qualifiers
// of the type pointed to by the right;
//
// — one operand is a pointer to an object or incomplete type and the other is
// a pointer to a qualified or unqualified version of void, and the type
// pointed to by the left has all the qualifiers of the type pointed to by the
// right;
//
// — the left operand is a pointer and the right is a null pointer constant; or
//
// — the left operand has type _Bool and the right is a pointer.
return t.d.Type().IsAssingmentCompatible(rhs)
}
// isAssingmentCompatibleOperand implements Type.
func (t *aliasType) isAssingmentCompatibleOperand(rhs Operand) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
if x, ok := rhs.Type().(*aliasType); ok && t.nm == x.nm {
return true
}
rhsType := rhs.Type().Decay()
if t == rhsType {
return true
}
return t.d.Type().isAssingmentCompatibleOperand(rhs)
}
// IsCompatible implements Type.
func (t *aliasType) IsCompatible(u Type) (r bool) {
// defer func() {
// u0 := u
// if !r {
// trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO-
// }
// }()
if t == nil || u == nil {
return false
}
if x, ok := u.(*aliasType); ok && t.nm == x.nm {
return true
}
if u = u.Alias().Decay(); t == u {
return true
}
return t.d.Type().IsCompatible(u)
}
// isCompatibleIgnoreQualifiers implements Type.
func (t *aliasType) isCompatibleIgnoreQualifiers(u Type) (r bool) {
// defer func() {
// u0 := u
// if !r {
// trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO-
// }
// }()
if t == nil || u == nil {
return false
}
if x, ok := u.(*aliasType); ok && t.nm == x.nm {
return true
}
if u = u.Alias().Decay(); t == u {
return true
}
return t.d.Type().isCompatibleIgnoreQualifiers(u)
}
// IsCompatibleLayout implements Type.
func (t *aliasType) IsCompatibleLayout(u Type) bool {
if t == nil || u == nil {
return false
}
if x, ok := u.(*aliasType); ok && t.nm == x.nm {
return true
}
if u = u.Alias().Decay(); t == u {
return true
}
return t.d.Type().IsCompatibleLayout(u)
}
// IsPacked implements Type.
func (t *aliasType) IsPacked() bool {
if t == nil {
return false
}
return t.d.Type().IsPacked()
}
// UnionCommon implements Type.
func (t *aliasType) UnionCommon() Kind { return t.d.Type().UnionCommon() }
// IsAliasType implements Type.
func (t *aliasType) IsAliasType() bool { return true }
// IsAggregate implements Type.
func (t *aliasType) IsAggregate() bool { return t.d.Type().IsAggregate() }
func (t *aliasType) AliasDeclarator() *Declarator { return t.d }
// IsTaggedType implements Type.
func (t *aliasType) IsTaggedType() bool { return false }
// Alias implements Type.
func (t *aliasType) Alias() Type { return t.d.Type() }
// Align implements Type.
func (t *aliasType) Align() int { return t.d.Type().Align() }
// Attributes implements Type.
func (t *aliasType) Attributes() (a []*AttributeSpecifier) { return t.d.Type().Attributes() }
// BitField implements Type.
func (t *aliasType) BitField() Field { return t.d.Type().BitField() }
// EnumType implements Type.
func (t *aliasType) EnumType() Type { return t.d.Type().EnumType() }
// Decay implements Type.
func (t *aliasType) Decay() Type { return t.d.Type().Decay() }
// Elem implements Type.
func (t *aliasType) Elem() Type { return t.d.Type().Elem() }
// FieldAlign implements Type.
func (t *aliasType) FieldAlign() int { return t.d.Type().FieldAlign() }
// NumField implements Type.
func (t *aliasType) NumField() int { return t.d.Type().NumField() }
// FieldByIndex implements Type.
func (t *aliasType) FieldByIndex(i []int) Field { return t.d.Type().FieldByIndex(i) }
// FieldByName implements Type.
func (t *aliasType) FieldByName(s StringID) (Field, bool) { return t.d.Type().FieldByName(s) }
// FieldByName2 implements Type.
func (t *aliasType) FieldByName2(s StringID) (Field, []int, bool) { return t.d.Type().FieldByName2(s) }
// IsIncomplete implements Type.
func (t *aliasType) IsIncomplete() bool { return t.d.Type().IsIncomplete() }
// IsArithmeticType implements Type.
func (t *aliasType) IsArithmeticType() bool { return t.d.Type().IsArithmeticType() }
// IsComplexType implements Type.
func (t *aliasType) IsComplexType() bool { return t.d.Type().IsComplexType() }
// IsComplexIntegerType implements Type.
func (t *aliasType) IsComplexIntegerType() bool { return t.d.Type().IsComplexIntegerType() }
// IsBitFieldType implements Type.
func (t *aliasType) IsBitFieldType() bool { return t.d.Type().IsBitFieldType() }
// IsIntegerType implements Type.
func (t *aliasType) IsIntegerType() bool { return t.d.Type().IsIntegerType() }
// IsRealType implements Type.
func (t *aliasType) IsRealType() bool { return t.d.Type().IsRealType() }
// IsScalarType implements Type.
func (t *aliasType) IsScalarType() bool { return t.d.Type().IsScalarType() }
// IsVLA implements Type.
func (t *aliasType) IsVLA() bool { return t.d.Type().IsVLA() }
// IsVariadic implements Type.
func (t *aliasType) IsVariadic() bool { return t.d.Type().IsVariadic() }
// Kind implements Type.
func (t *aliasType) Kind() Kind { return t.d.Type().Kind() }
// Len implements Type.
func (t *aliasType) Len() uintptr { return t.d.Type().Len() }
// LenExpr implements Type.
func (t *aliasType) LenExpr() *AssignmentExpression { return t.d.Type().LenExpr() }
// Parameters implements Type.
func (t *aliasType) Parameters() []*Parameter { return t.d.Type().Parameters() }
// Result implements Type.
func (t *aliasType) Result() Type { return t.d.Type().Result() }
// Real implements Type
func (t *aliasType) Real() Field { return t.d.Type().Real() }
// Imag implements Type
func (t *aliasType) Imag() Field { return t.d.Type().Imag() }
// Size implements Type.
func (t *aliasType) Size() uintptr { return t.d.Type().Size() }
// String implements Type.
func (t *aliasType) String() string {
var a []string
if t.typeBase.IsAtomic() {
a = append(a, "atomic")
}
if t.typeBase.hasConst() {
a = append(a, "const")
}
if t.typeBase.Inline() {
a = append(a, "inline")
}
if t.typeBase.noReturn() {
a = append(a, "_NoReturn")
}
if t.typeBase.restrict() {
a = append(a, "restrict")
}
if t.typeBase.IsVolatile() {
a = append(a, "volatile")
}
a = append(a, t.nm.String())
return strings.Join(a, " ")
}
// Tag implements Type.
func (t *aliasType) Tag() StringID { return t.d.Type().Tag() }
// Name implements Type.
func (t *aliasType) Name() StringID { return t.nm }
// IsAtomic implements Type.
func (t *aliasType) IsAtomic() bool { return t.d.Type().IsAtomic() }
// Inline implements Type.
func (t *aliasType) Inline() bool { return t.d.Type().Inline() }
// IsSignedType implements Type.
func (t *aliasType) IsSignedType() bool { return t.d.Type().IsSignedType() }
// noReturn implements Type.
func (t *aliasType) noReturn() bool { return t.d.Type().noReturn() }
// restrict implements Type.
func (t *aliasType) restrict() bool { return t.d.Type().restrict() }
// setLen implements Type.
func (t *aliasType) setLen(n uintptr) { t.d.Type().setLen(n) }
// setKind implements Type.
func (t *aliasType) setKind(k Kind) { t.d.Type().setKind(k) }
// string implements Type.
func (t *aliasType) string(b *bytes.Buffer) { b.WriteString(t.String()) }
func (t *aliasType) underlyingType() Type { return t.d.Type().underlyingType() }
// IsVolatile implements Type.
func (t *aliasType) IsVolatile() bool { return t.d.Type().IsVolatile() }
func (t *aliasType) isVectorType() bool { return t.d.Type().isVectorType() }
func (t *aliasType) setFnSpecs(inline, noret bool) { t.d.Type().setFnSpecs(inline, noret) }
type field struct {
bitFieldMask uint64 // bits: 3, bitOffset: 2 -> 0x1c. Valid only when isBitField is true.
blockStart *field // First bit field of the block this bit field belongs to.
d *StructDeclarator
offset uintptr // In bytes from start of the struct.
parent Type
promote Type
typ Type
name StringID // Can be zero.
x int
xs []int
isBitField bool
isFlexible bool // https://en.wikipedia.org/wiki/Flexible_array_member
inUnion bool // directly or indirectly
bitFieldOffset byte // In bits from bit 0 within the field. Valid only when isBitField is true.
bitFieldWidth byte // Width of the bit field in bits. Valid only when isBitField is true.
blockWidth byte // Total width of the bit field block this bit field belongs to.
pad byte
}
func (f *field) BitFieldBlockFirst() Field { return f.blockStart }
func (f *field) BitFieldBlockWidth() int { return int(f.blockWidth) }
func (f *field) BitFieldOffset() int { return int(f.bitFieldOffset) }
func (f *field) BitFieldWidth() int { return int(f.bitFieldWidth) }
func (f *field) Declarator() *StructDeclarator { return f.d }
func (f *field) InUnion() bool { return f.inUnion }
func (f *field) Index() int { return f.x }
func (f *field) IsBitField() bool { return f.isBitField }
func (f *field) IsFlexible() bool { return f.isFlexible }
func (f *field) Mask() uint64 { return f.bitFieldMask }
func (f *field) Name() StringID { return f.name }
func (f *field) Offset() uintptr { return f.offset }
func (f *field) Padding() int { return int(f.pad) } // N/A for bitfields
func (f *field) Parent() Type { return f.parent }
func (f *field) Promote() Type { return f.promote }
func (f *field) Type() Type { return f.typ }
func (f *field) at(offDelta uintptr) *field { r := *f; r.offset += offDelta; return &r }
func (f *field) string(b *bytes.Buffer) {
b.WriteString(f.name.String())
if f.isBitField {
fmt.Fprintf(b, ":%d", f.bitFieldWidth)
}
b.WriteByte(' ')
f.typ.string(b)
}
type fieldPath struct {
fld *field
path []int
ambiguous bool
}
func (f *fieldPath) String() string {
return fmt.Sprintf("%q %v %v", f.fld.name, f.path, f.ambiguous)
}
type structType struct {
*typeBase
attr []*AttributeSpecifier
common Kind
fields []*field
m map[StringID]*field
paths map[StringID]*fieldPath
tag StringID
hasFlexibleMember bool
}
// HasFlexibleMember implements Type.
func (t *structType) HasFlexibleMember() bool { return t.hasFlexibleMember }
// IsAssingmentCompatible implements Type.
func (t *structType) IsAssingmentCompatible(rhs Type) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
if rhs = rhs.Alias().Decay(); t == rhs {
return true
}
// [0], 6.5.16.1 Simple assignment
//
// 1 One of the following shall hold:
//
// — the left operand has qualified or unqualified arithmetic type and the
// right has arithmetic type;
//
// — the left operand has a qualified or unqualified version of a structure or
// union type compatible with the type of the right;
//
// — both operands are pointers to qualified or unqualified versions of
// compatible types, and the type pointed to by the left has all the qualifiers
// of the type pointed to by the right;
//
// — one operand is a pointer to an object or incomplete type and the other is
// a pointer to a qualified or unqualified version of void, and the type
// pointed to by the left has all the qualifiers of the type pointed to by the
// right;
//
// — the left operand is a pointer and the right is a null pointer constant; or
//
// — the left operand has type _Bool and the right is a pointer.
return t.IsCompatible(rhs)
}
// isAssingmentCompatibleOperand implements Type.
func (t *structType) isAssingmentCompatibleOperand(rhs Operand) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
rhsType := rhs.Type().Decay()
if t == rhsType {
return true
}
return t.IsAssingmentCompatible(rhsType)
}
func (t *structType) firstUnionField() Field {
for _, f := range t.fields {
if f.Name() != 0 || !f.Type().IsBitFieldType() {
return f
}
}
panic(todo(""))
}
// IsCompatible implements Type.
func (t *structType) IsCompatible(u Type) (r bool) {
// defer func() {
// u0 := u
// if !r {
// trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO-
// }
// }()
if t == nil || u == nil {
return false
}
if t.Kind() == Union {
return t.firstUnionField().Type().IsCompatible(u)
}
if t.IsComplexType() && u.IsArithmeticType() {
return true
}
if u = u.Alias().Decay(); t == u {
return true
}
v, ok := u.(*structType)
if !ok || t.Kind() != v.Kind() {
return false
}
if t.tag != 0 && t.tag == v.tag {
return true
}
if t.tag != v.tag || len(t.fields) != len(v.fields) {
return false
}
if (t.IsIncomplete() || v.IsIncomplete()) && t.tag == v.tag {
return true
}
for i, f1 := range t.fields {
f2 := v.fields[i]
nm := f1.Name()
if f2.Name() != nm {
return false
}
ft1 := f1.Type()
ft2 := f2.Type()
if ft1.Size() != ft2.Size() ||
f1.IsBitField() != f2.IsBitField() ||
f1.BitFieldOffset() != f2.BitFieldOffset() ||
f1.BitFieldWidth() != f2.BitFieldWidth() {
return false
}
if !ft1.IsCompatible(ft2) {
return false
}
}
return true
}
// isCompatibleIgnoreQualifiers implements Type.
func (t *structType) isCompatibleIgnoreQualifiers(u Type) (r bool) {
return t.IsCompatible(u)
}
// IsCompatibleLayout implements Type.
func (t *structType) IsCompatibleLayout(u Type) bool {
if u = u.Alias().Decay(); t == u {
return true
}
v, ok := u.(*structType)
if !ok || t.Kind() != v.Kind() {
return false
}
if t.tag != v.tag || len(t.fields) != len(v.fields) {
return false
}
for i, f1 := range t.fields {
f2 := v.fields[i]
nm := f1.Name()
if f2.Name() != nm {
return false
}
ft1 := f1.Type()
ft2 := f2.Type()
if ft1.Size() != ft2.Size() ||
f1.IsBitField() != f2.IsBitField() ||
f1.BitFieldOffset() != f2.BitFieldOffset() ||
f1.BitFieldWidth() != f2.BitFieldWidth() {
return false
}
if ft1.IsCompatible(ft2) {
return false
}
}
return true
}
// UnionCommon implements Type.
func (t *structType) UnionCommon() Kind {
if t.Kind() != Union {
panic(internalErrorf("%s: UnionCommon of invalid type", t.Kind()))
}
return t.common
}
// Alias implements Type.
func (t *structType) Alias() Type { return t }
// Tag implements Type.
func (t *structType) Tag() StringID { return t.tag }
func (t *structType) check(ctx *context, n Node) *structType {
if t == nil {
return nil
}
// Reject ambiguous names.
for _, f := range t.fields {
f.parent = t
if f.Name() != 0 {
continue
}
switch x := f.Type().(type) {
case *structType:
for _, f2 := range x.fields {
nm := f2.Name()
if nm == 0 {
continue
}
if _, ok := t.m[nm]; ok {
ctx.errNode(n, "ambiguous field name %q", nm)
}
}
default:
//TODO report err
}
}
return ctx.cfg.ABI.layout(ctx, n, t)
}
// Real implements Type
func (t *structType) Real() Field {
if !complexTypes[t.Kind()] {
panic(internalErrorf("%s: Real of invalid type", t.Kind()))
}
f, ok := t.FieldByName(idReal)
if !ok {
panic(internalError())
}
return f
}
// Imag implements Type
func (t *structType) Imag() Field {
if !complexTypes[t.Kind()] {
panic(internalErrorf("%s: Real of invalid type", t.Kind()))
}
f, ok := t.FieldByName(idImag)
if !ok {
panic(internalError())
}
return f
}
// Decay implements Type.
func (t *structType) Decay() Type { return t }
func (t *structType) underlyingType() Type { return t }
// String implements Type.
func (t *structType) String() string {
b := bytesBufferPool.Get().(*bytes.Buffer)
defer func() { b.Reset(); bytesBufferPool.Put(b) }()
t.string(b)
return strings.TrimSpace(b.String())
}
// Name implements Type.
func (t *structType) Name() StringID { return t.tag }
// string implements Type.
func (t *structType) string(b *bytes.Buffer) {
switch {
case complexTypes[t.Kind()]:
b.WriteString(t.Kind().String())
return
default:
b.WriteString(t.Kind().String())
}
b.WriteByte(' ')
if t.tag != 0 {
b.WriteString(t.tag.String())
b.WriteByte(' ')
}
b.WriteByte('{')
for _, v := range t.fields {
v.string(b)
b.WriteString("; ")
}
b.WriteByte('}')
}
// FieldByIndex implements Type.
func (t *structType) FieldByIndex(i []int) Field {
if len(i) > 1 {
panic("TODO")
}
return t.fields[i[0]]
}
// FieldByName implements Type.
func (t *structType) FieldByName(name StringID) (Field, bool) {
if f := t.m[name]; f != nil {
return f, true
}
if t.paths == nil {
t.paths = map[StringID]*fieldPath{}
t.computePaths(0, t.paths, nil)
}
nfo := t.paths[name]
if nfo == nil || nfo.ambiguous {
return nil, false
}
return nfo.fld, true
}
// FieldByName2 implements Type.
func (t *structType) FieldByName2(name StringID) (Field, []int, bool) {
if f := t.m[name]; f != nil {
return f, f.xs, true
}
if t.paths == nil {
t.paths = map[StringID]*fieldPath{}
t.computePaths(0, t.paths, nil)
}
nfo := t.paths[name]
if nfo == nil || nfo.ambiguous {
return nil, nil, false
}
return nfo.fld, nfo.path, true
}
func (t *structType) computePaths(off uintptr, paths map[StringID]*fieldPath, path []int) {
path = append(path, 0)
for i, f := range t.fields {
nm := f.Name()
path[len(path)-1] = i
if nm != 0 {
switch ex := paths[nm]; {
case ex != nil:
switch {
case len(path) < len(ex.path):
ex.fld = f.at(off)
ex.path = append([]int(nil), path...)
ex.ambiguous = false
case len(path) == len(ex.path) && (off+f.Offset() != ex.fld.Offset() || f.Type().Size() != ex.fld.Type().Size()):
ex.ambiguous = true
}
default:
paths[nm] = &fieldPath{fld: f.at(off), path: append([]int(nil), path...)}
}
}
if x, ok := f.Type().underlyingType().(*structType); ok {
x.computePaths(off+f.Offset(), paths, path)
}
}
}
// NumField implements Type.
func (t *structType) NumField() int { return len(t.fields) }
type taggedType struct {
*typeBase
resolutionScope Scope
typ Type
tag StringID
}
// IsPacked implements Type.
func (t *taggedType) IsPacked() bool {
if t == nil {
return false
}
return t.underlyingType().IsPacked()
}
// HasFlexibleMember implements Type.
func (t *taggedType) HasFlexibleMember() bool {
return t.typ.HasFlexibleMember()
}
// IsAssingmentCompatible implements Type.
func (t *taggedType) IsAssingmentCompatible(rhs Type) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
if t == rhs {
return true
}
if t.Kind() == rhs.Kind() && t.tag != 0 && t.tag == rhs.Tag() {
return true
}
if rhs = rhs.Alias().Decay(); t == rhs {
return true
}
// [0], 6.5.16.1 Simple assignment
//
// 1 One of the following shall hold:
//
// — the left operand has qualified or unqualified arithmetic type and the
// right has arithmetic type;
//
// — the left operand has a qualified or unqualified version of a structure or
// union type compatible with the type of the right;
//
// — both operands are pointers to qualified or unqualified versions of
// compatible types, and the type pointed to by the left has all the qualifiers
// of the type pointed to by the right;
//
// — one operand is a pointer to an object or incomplete type and the other is
// a pointer to a qualified or unqualified version of void, and the type
// pointed to by the left has all the qualifiers of the type pointed to by the
// right;
//
// — the left operand is a pointer and the right is a null pointer constant; or
//
// — the left operand has type _Bool and the right is a pointer.
return t.typ.IsAssingmentCompatible(rhs)
}
// isAssingmentCompatibleOperand implements Type.
func (t *taggedType) isAssingmentCompatibleOperand(rhs Operand) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
rhsType := rhs.Type().Decay()
if t == rhsType {
return true
}
if t.Kind() == rhsType.Kind() && t.tag != 0 && t.tag == rhsType.Tag() {
return true
}
return t.IsAssingmentCompatible(rhsType)
}
// IsCompatible implements Type.
func (t *taggedType) IsCompatible(u Type) (r bool) {
defer func() {
// if !r {
// trc("TRACE %v <- %v: %v (%s)", t, u0, r, origin(2)) //TODO-
// }
}()
if t == nil || u == nil {
return false
}
if t == u {
return true
}
if u = u.Alias().Decay(); t == u {
return true
}
if t.Kind() == u.Kind() && t.tag != 0 && t.tag == u.Tag() {
return true
}
return t.typ.IsCompatible(u)
}
// isCompatibleIgnoreQualifiers implements Type.
func (t *taggedType) isCompatibleIgnoreQualifiers(u Type) (r bool) {
// defer func() {
// u0 := u
// if !r {
// trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO-
// }
// }()
if t == nil || u == nil {
return false
}
if t == u {
return true
}
if u = u.Alias().Decay(); t == u {
return true
}
if t.Kind() == u.Kind() && t.tag != 0 && t.tag == u.Tag() {
return true
}
return t.typ.isCompatibleIgnoreQualifiers(u)
}
// IsCompatibleLayout implements Type.
func (t *taggedType) IsCompatibleLayout(u Type) bool {
if u = u.Alias().Decay(); t == u {
return true
}
if t == nil || u == nil {
return false
}
if t == u {
return true
}
if u = u.Alias().Decay(); t == u {
return true
}
if t.Kind() == u.Kind() && t.tag != 0 && t.tag == u.Tag() {
return true
}
return t.typ.IsCompatibleLayout(u)
}
// UnionCommon implements Type.
func (t *taggedType) UnionCommon() Kind { return t.typ.UnionCommon() }
// IsTaggedType implements Type.
func (t *taggedType) IsTaggedType() bool { return true }
// Tag implements Type.
func (t *taggedType) Tag() StringID { return t.tag }
// Alias implements Type.
func (t *taggedType) Alias() Type { return t.underlyingType() }
// Decay implements Type.
func (t *taggedType) Decay() Type { return t }
// IsIncomplete implements Type.
func (t *taggedType) IsIncomplete() bool {
u := t.underlyingType()
return u == noType || u.IsIncomplete()
}
// String implements Type.
func (t *taggedType) String() string {
b := bytesBufferPool.Get().(*bytes.Buffer)
defer func() { b.Reset(); bytesBufferPool.Put(b) }()
t.string(b)
return strings.TrimSpace(b.String())
}
// Name implements Type.
func (t *taggedType) Name() StringID { return t.tag }
// NumField implements Type.
func (t *taggedType) NumField() int { return t.underlyingType().NumField() }
// FieldByIndex implements Type.
func (t *taggedType) FieldByIndex(i []int) Field { return t.underlyingType().FieldByIndex(i) }
// FieldByName implements Type.
func (t *taggedType) FieldByName(s StringID) (Field, bool) { return t.underlyingType().FieldByName(s) }
// FieldByName2 implements Type.
func (t *taggedType) FieldByName2(s StringID) (Field, []int, bool) {
return t.underlyingType().FieldByName2(s)
}
// IsSignedType implements Type.
func (t *taggedType) IsSignedType() bool { return t.underlyingType().IsSignedType() }
// EnumType implements Type.
func (t *taggedType) EnumType() Type { return t.underlyingType() }
// string implements Type.
func (t *taggedType) string(b *bytes.Buffer) {
t.typeBase.string(b)
b.WriteByte(' ')
b.WriteString(t.tag.String())
}
func (t *taggedType) underlyingType() Type {
if t.typ != nil {
return t.typ
}
k := t.Kind()
for s := t.resolutionScope; s != nil; s = s.Parent() {
for _, v := range s[t.tag] {
switch x := v.(type) {
case *Declarator, *StructDeclarator, *LabeledStatement:
// nop
case *EnumSpecifier:
if k == Enum && x.Case == EnumSpecifierDef {
t.typ = x.Type()
return t.typ.underlyingType()
}
case *StructOrUnionSpecifier:
if x.typ == nil {
break
}
switch k {
case Struct:
if typ := x.Type(); typ.Kind() == Struct {
t.typ = typ
return typ.underlyingType()
}
case Union:
if typ := x.Type(); typ.Kind() == Union {
t.typ = typ
return typ.underlyingType()
}
}
default:
panic(todo("internal error: %T", x))
}
}
}
t.typ = noType
return noType
}
// Size implements Type.
func (t *taggedType) Size() (r uintptr) {
return t.underlyingType().Size()
}
// Align implements Type.
func (t *taggedType) Align() int { return t.underlyingType().Align() }
// FieldAlign implements Type.
func (t *taggedType) FieldAlign() int { return t.underlyingType().FieldAlign() }
type functionType struct {
typeBase
params []*Parameter
paramList []StringID
result Type
variadic bool
}
// IsAssingmentCompatible implements Type.
func (t *functionType) IsAssingmentCompatible(rhs Type) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
if rhs = rhs.Alias().Decay(); t == rhs {
return true
}
// [0], 6.5.16.1 Simple assignment
//
// 1 One of the following shall hold:
//
// — the left operand has qualified or unqualified arithmetic type and the
// right has arithmetic type;
//
// — the left operand has a qualified or unqualified version of a structure or
// union type compatible with the type of the right;
//
// — both operands are pointers to qualified or unqualified versions of
// compatible types, and the type pointed to by the left has all the qualifiers
// of the type pointed to by the right;
//
// — one operand is a pointer to an object or incomplete type and the other is
// a pointer to a qualified or unqualified version of void, and the type
// pointed to by the left has all the qualifiers of the type pointed to by the
// right;
//
// — the left operand is a pointer and the right is a null pointer constant; or
//
// — the left operand has type _Bool and the right is a pointer.
if rhs.Kind() != Function {
return false
}
v := rhs.(*functionType)
if t.params != nil && v.params != nil || t.variadic != v.variadic {
if len(t.params) != len(v.params) {
return false
}
for i, x := range t.params {
if !x.Type().IsAssingmentCompatible(v.params[i].Type()) {
return false
}
}
}
return t.result.IsAssingmentCompatible(v.result)
}
// isAssingmentCompatibleOperand implements Type.
func (t *functionType) isAssingmentCompatibleOperand(rhs Operand) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
rhsType := rhs.Type().Decay()
if t == rhsType {
return true
}
return t.IsAssingmentCompatible(rhsType)
}
// IsCompatible implements Type.
func (t *functionType) IsCompatible(u Type) (r bool) {
// defer func() {
// u0 := u
// if !r {
// trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO-
// }
// }()
if t == nil || u == nil {
return false
}
if u = u.Alias().Decay(); t == u {
return true
}
if u.Kind() != Function {
return false
}
v := u.(*functionType)
// [0], 6.7.5.3
//
// 15 For two function types to be compatible, both shall specify compatible
// return types.
//
// Moreover, the parameter type lists, if both are present, shall agree in the
// number of parameters and in use of the ellipsis terminator; corresponding
// parameters shall have compatible types. If one type has a parameter type
// list and the other type is specified by a function declarator that is not
// part of a function definition and that contains an empty identifier list,
// the parameter list shall not have an ellipsis terminator and the type of
// each parameter shall be compatible with the type that results from the
// application of the default argument promotions. If one type has a parameter
// type list and the other type is specified by a function definition that
// contains a (possibly empty) identifier list, both shall agree in the number
// of parameters, and the type of each prototype parameter shall be compatible
// with the type that results from the application of the default argument
// promotions to the type of the corresponding identifier. (In the
// determination of type compatibility and of a composite type, each parameter
// declared with function or array type is taken as having the adjusted type
// and each parameter declared with qualified type is taken as having the
// unqualified version of its declared type.)
if t.params != nil && v.params != nil || t.variadic != v.variadic {
if len(t.params) != len(v.params) {
return false
}
for i, x := range t.params {
if !x.Type().IsCompatible(v.params[i].Type()) {
return false
}
}
}
return t.result.IsCompatible(v.result)
}
// isCompatibleIgnoreQualifiers implements Type.
func (t *functionType) isCompatibleIgnoreQualifiers(u Type) (r bool) {
return t.IsCompatible(u)
}
// Alias implements Type.
func (t *functionType) Alias() Type { return t }
// Decay implements Type.
func (t *functionType) Decay() Type { return t }
// String implements Type.
func (t *functionType) String() string {
b := bytesBufferPool.Get().(*bytes.Buffer)
defer func() { b.Reset(); bytesBufferPool.Put(b) }()
t.string(b)
return strings.TrimSpace(b.String())
}
// string implements Type.
func (t *functionType) string(b *bytes.Buffer) {
b.WriteString("function(")
for i, v := range t.params {
v.Type().string(b)
if i < len(t.params)-1 {
b.WriteString(", ")
}
}
if t.variadic {
b.WriteString(", ...")
}
b.WriteString(")")
if t.result != nil && t.result.Kind() != Void {
b.WriteString(" returning ")
t.result.string(b)
}
}
// Parameters implements Type.
func (t *functionType) Parameters() []*Parameter { return t.params }
// Result implements Type.
func (t *functionType) Result() Type { return t.result }
// IsVariadic implements Type.
func (t *functionType) IsVariadic() bool { return t.variadic }
type bitFieldType struct {
Type
field *field
}
// Alias implements Type.
func (t *bitFieldType) Alias() Type { return t }
// IsBitFieldType implements Type.
func (t *bitFieldType) IsBitFieldType() bool { return true }
// BitField implements Type.
func (t *bitFieldType) BitField() Field { return t.field }
type vectorType struct {
typeBase
elem Type
length uintptr
}
// IsAssingmentCompatible implements Type.
func (t *vectorType) IsAssingmentCompatible(rhs Type) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
if t == rhs {
return true
}
// [0], 6.5.16.1 Simple assignment
//
// 1 One of the following shall hold:
//
// — the left operand has qualified or unqualified arithmetic type and the
// right has arithmetic type;
//
// — the left operand has a qualified or unqualified version of a structure or
// union type compatible with the type of the right;
//
// — both operands are pointers to qualified or unqualified versions of
// compatible types, and the type pointed to by the left has all the qualifiers
// of the type pointed to by the right;
//
// — one operand is a pointer to an object or incomplete type and the other is
// a pointer to a qualified or unqualified version of void, and the type
// pointed to by the left has all the qualifiers of the type pointed to by the
// right;
//
// — the left operand is a pointer and the right is a null pointer constant; or
//
// — the left operand has type _Bool and the right is a pointer.
return t.IsCompatible(rhs)
}
// isAssingmentCompatibleOperand implements Type.
func (t *vectorType) isAssingmentCompatibleOperand(rhs Operand) (r bool) {
// defer func() {
// rhs0 := rhs
// if !r {
// trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO-
// }
// }()
if t == nil || rhs == nil {
return false
}
rhsType := rhs.Type()
if t == rhsType {
return true
}
return t.IsAssingmentCompatible(rhsType)
}
// IsCompatible implements Type.
func (t *vectorType) IsCompatible(u Type) (r bool) {
// defer func() {
// u0 := u
// if !r {
// trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO-
// }
// }()
if t == nil || u == nil {
return false
}
if t == u {
return true
}
if t == u {
return true
}
if u.Kind() != Vector {
return false
}
v := u.(*vectorType)
return t.length == v.length && t.elem.IsCompatible(v.elem)
}
// isCompatibleIgnoreQualifiers implements Type.
func (t *vectorType) isCompatibleIgnoreQualifiers(u Type) (r bool) {
return t.IsCompatible(u)
}
// IsCompatibleLayout implements Type.
func (t *vectorType) IsCompatibleLayout(u Type) bool {
if u = u.Alias().Decay(); t == u {
return true
}
if u.Kind() != Vector {
return false
}
v := u.(*vectorType)
return t.length == v.length && t.elem.IsCompatibleLayout(v.elem)
}
// Alias implements Type.
func (t *vectorType) Alias() Type { return t }
// IsVLA implements Type.
func (t *vectorType) IsVLA() bool { return false }
// String implements Type.
func (t *vectorType) String() string {
b := bytesBufferPool.Get().(*bytes.Buffer)
defer func() { b.Reset(); bytesBufferPool.Put(b) }()
t.string(b)
return strings.TrimSpace(b.String())
}
// string implements Type.
func (t *vectorType) string(b *bytes.Buffer) {
fmt.Fprintf(b, "vector of %d ", t.Len())
t.Elem().string(b)
}
// Attributes implements Type.
func (t *vectorType) Attributes() (a []*AttributeSpecifier) { return t.elem.Attributes() }
// Elem implements Type.
func (t *vectorType) Elem() Type { return t.elem }
// Len implements Type.
func (t *vectorType) Len() uintptr { return t.length }
// LenExpr implements Type.
func (t *vectorType) LenExpr() *AssignmentExpression {
panic(internalErrorf("%s: LenExpr of non variable length array", t.Kind()))
}
// setLen implements Type.
func (t *vectorType) setLen(n uintptr) {
panic("internal error")
}
// underlyingType implements Type.
func (t *vectorType) underlyingType() Type { return t }
func isCharType(t Type) bool {
switch t.Kind() {
case Char, SChar, UChar, Int8, UInt8:
return true
}
return false
}
func isWCharType(t Type) bool {
switch {
case t.IsAliasType():
id := t.AliasDeclarator().Name()
return id == idWcharT || id == idWinWchar
default:
return false
}
}
// Struct layout describes storage details of a struct/union type.
type StructLayout struct {
Offsets []uintptr // In field order.
OffsetToFields map[uintptr][]Field
PaddingsBefore map[Field]int
PaddingAfter int
t Type
NeedExplicitAlign bool
}
// NewStructLayout returns a newly created StructLayout for t, or nil if t is
// not a struct/union type.
func NewStructLayout(t Type) *StructLayout {
switch t.Kind() {
case Struct, Union:
// ok
default:
return nil
}
nf := t.NumField()
flds := map[uintptr][]Field{}
var maxAlign int
for idx := []int{0}; idx[0] < nf; idx[0]++ {
f := t.FieldByIndex(idx)
if f.IsBitField() && f.BitFieldWidth() == 0 {
continue
}
if a := f.Type().Align(); !f.IsBitField() && a > maxAlign {
maxAlign = a
}
off := f.Offset()
flds[off] = append(flds[off], f)
}
var offs []uintptr
for k := range flds {
offs = append(offs, k)
}
sort.Slice(offs, func(i, j int) bool { return offs[i] < offs[j] })
var pads map[Field]int
var pos uintptr
var forceAlign bool
for _, off := range offs {
f := flds[off][0]
ft := f.Type()
//trc("%q off %d pos %d %v %v %v", f.Name(), off, pos, ft, ft.Kind(), ft.IsIncomplete())
switch {
case ft.IsBitFieldType():
if p := int(off - pos); p != 0 {
if pads == nil {
pads = map[Field]int{}
}
pads[f] = p
pos = off
}
pos += uintptr(f.BitFieldBlockWidth()) >> 3
default:
var sz uintptr
switch {
case ft.Kind() != Array || ft.Len() != 0:
sz = ft.Size()
default:
forceAlign = true
}
if p := int(off - pos); p != 0 {
if pads == nil {
pads = map[Field]int{}
}
pads[f] = p
pos = off
}
pos += sz
}
}
return &StructLayout{
NeedExplicitAlign: forceAlign || maxAlign < t.Align(),
OffsetToFields: flds,
Offsets: offs,
PaddingAfter: int(t.Size() - pos),
PaddingsBefore: pads,
t: t,
}
}
func (x *StructLayout) String() string {
t := x.t
nf := t.NumField()
var a []string
w := 0
for i := 0; i < nf; i++ {
if n := len(t.FieldByIndex([]int{i}).Name().String()); n > w {
w = n
}
}
for i := 0; i < nf; i++ {
f := t.FieldByIndex([]int{i})
var bf StringID
if f.IsBitField() {
if bfbf := f.(*field).blockStart; bfbf != nil {
bf = bfbf.Name()
}
}
a = append(a, fmt.Sprintf("%3d: %*q: BitFieldOffset %3v, BitFieldWidth %3v, IsBitField %5v, Mask: %#016x, off: %3v, pad %2v, BitFieldBlockWidth: %2d, BitFieldBlockFirst: %s, %v",
i, w+2, f.Name(), f.BitFieldOffset(), f.BitFieldWidth(),
f.IsBitField(), f.Mask(), f.Offset(), f.Padding(),
f.BitFieldBlockWidth(), bf, f.Type(),
))
}
var b strings.Builder
fmt.Fprintf(&b, "%v\n%s\n----\n", t, strings.Join(a, "\n"))
fmt.Fprintf(&b, "size: %v\n", t.Size())
fmt.Fprintf(&b, "offs: %v\n", x.Offsets)
a = a[:0]
for k, v := range x.OffsetToFields {
var b []string
for _, w := range v {
b = append(b, fmt.Sprintf("%q padBefore: %d ", w.Name(), x.PaddingsBefore[w]))
}
a = append(a, fmt.Sprintf("%4d %s", k, b))
}
sort.Strings(a)
for _, v := range a {
fmt.Fprintf(&b, "%s\n", v)
}
fmt.Fprintf(&b, "padAfter: %v\n", x.PaddingAfter)
for i := 0; i < nf; i++ {
f := t.FieldByIndex([]int{i})
if x, ok := f.Type().(*structType); ok {
s := dumpLayout(x)
a := strings.Split(s, "\n")
fmt.Fprintf(&b, "====\n")
for _, v := range a {
fmt.Fprintf(&b, "%s\n", v)
}
}
}
return b.String()
}
func dumpLayout(t Type) string {
switch t.Kind() {
case Struct, Union:
// ok
default:
return t.String()
}
return NewStructLayout(t).String()
}