mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-07-07 22:35:45 +00:00
ed46224573
* Add SQLite support, fix un-thread-safe DB caches, small performance fixes Signed-off-by: kim (grufwub) <grufwub@gmail.com> * add SQLite licenses to README Signed-off-by: kim (grufwub) <grufwub@gmail.com> * appease the linter, and fix my dumbass-ery Signed-off-by: kim (grufwub) <grufwub@gmail.com> * make requested changes Signed-off-by: kim (grufwub) <grufwub@gmail.com> * add back comment Signed-off-by: kim (grufwub) <grufwub@gmail.com>
3272 lines
85 KiB
Go
3272 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
|
|
|
|
// atomic reports whether type has type qualifier "_Atomic".
|
|
atomic() 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)
|
|
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)
|
|
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()))
|
|
}
|
|
|
|
// atomic implements Type.
|
|
func (t *typeBase) atomic() 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.atomic() {
|
|
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.atomic() {
|
|
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 }
|
|
|
|
// atomic implements Type.
|
|
func (t *aliasType) atomic() bool { return t.d.Type().atomic() }
|
|
|
|
// 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() {
|
|
// 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.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 f.BitFieldOffset() != 0 {
|
|
break
|
|
}
|
|
|
|
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()
|
|
}
|