pub enum Ty {
Show 28 variants
Void,
Bool,
Char,
SChar,
UChar,
Short,
UShort,
Int,
UInt,
Long,
ULong,
LongLong,
ULongLong,
Int128,
UInt128,
Float,
Double,
ComplexFloat,
ComplexDouble,
Pointer(PointerId),
Array(ArrayId),
Func(FuncTyId),
Record(RecordId),
Enum(EnumId),
VaList,
Vector(VecTy),
Atomic(AtomicId),
Error,
}Expand description
A resolved C type.
long double is mapped onto Ty::Double when the type is resolved,
because there is no portable Rust type with the layout of an x87 extended
double; the mapping is documented rather than diagnosed, since a procedural
macro has no stable way to raise a warning.
Variants§
Void
void
Bool
_Bool
Char
Plain char, whose signedness is the target’s business and which is a
distinct type from both signed char and unsigned char.
SChar
signed char
UChar
unsigned char
Short
short
UShort
unsigned short
Int
int
UInt
unsigned int
Long
long
ULong
unsigned long
LongLong
long long
ULongLong
unsigned long long
Int128
GNU’s __int128 (also spelled __int128_t), which ranks above
long long and is generated as Rust’s i128.
UInt128
unsigned __int128 (also spelled __uint128_t), generated as u128.
Float
float
Double
double (and long double)
ComplexFloat
float _Complex, generated as cinrs_rt::Complex<f32>.
C calls the complex types floating types and therefore arithmetic
ones, but almost nothing in this crate wants them where a float or a
double goes: Ty::is_floating is deliberately the real floating
types only, and Ty::is_complex is the question to ask about these.
ComplexDouble
double _Complex (and long double _Complex), generated as
cinrs_rt::Complex<f64>.
Pointer(PointerId)
A pointer, including a pointer to a function.
Array(ArrayId)
An array of a known length.
Func(FuncTyId)
A function type. Only ever reached through a pointer or as the type of a function designator.
Record(RecordId)
A struct or union, complete or not.
Enum(EnumId)
A file-scope enum with a tag, which becomes a named c_int alias.
Every other enum is simply Ty::Int.
VaList
va_list (and its __builtin_va_list / __gnuc_va_list spellings),
which becomes core::ffi::VaList.
The type is opaque: it has no size, nothing may point at it, and it may
only be a local variable or a parameter — see crate::sema for why.
Vector(VecTy)
One of x86’s vector types: __m128, __m128i, __m128d, __m256,
__m256i or __m256d.
Opaque, exactly as C sees it: there is no arithmetic on one, no
conversion to or from one, and no way to reach a lane except through an
intrinsic or through a union. What it is is an object of a known size
and alignment — sixteen or thirty-two bytes, aligned to itself — which
is what makes it a member, an element, a parameter, a return value and
the thing a union { __m128i v; int i[4]; } punnes. Code generation
writes ::core::arch::x86_64::__m128i, whose layout is the same.
Atomic(AtomicId)
_Atomic T, for a scalar T (C11 6.7.2.4).
It is the type of an object, never of a value: reading an atomic
lvalue is an atomic load whose result has the underlying type, so
ExprKind::Load of an atomic place is typed Types::unatomic of
it and nothing downstream of the load ever meets this variant. Where it
does appear is a declared object, a member, a pointee and sizeof —
which is why it is a type rather than a flag on the declaration:
_Atomic int * and int * are different types, and a store through
the first one is atomic.
The alignment is the size (see Types::size_align), which is what
makes _Atomic long long eight-byte aligned on a target whose plain
long long is not.
Error
The type of something whose declaration was already reported as wrong.
It exists so that one bad declaration produces one diagnostic: an object
declared int a[n] still enters the symbol table, and every later use of
it is checked against a type that silences further complaints instead of
“use of undeclared identifier”.
Implementations§
Source§impl Ty
impl Ty
Sourcepub fn scalar_name(self) -> &'static str
pub fn scalar_name(self) -> &'static str
The C spelling of a scalar type.
Derived and tagged types need the arena; use Types::name for a type
that may be one of those.
Sourcepub fn is_pointer(self) -> bool
pub fn is_pointer(self) -> bool
Whether this is a pointer.
Sourcepub fn is_va_list(self) -> bool
pub fn is_va_list(self) -> bool
Whether this is va_list.
Sourcepub fn is_vector(self) -> bool
pub fn is_vector(self) -> bool
Whether this is one of x86’s vector types.
They are neither arithmetic nor scalar — nothing C does to a number can be done to one — so every operator asks this before complaining, and says “use an intrinsic” rather than the generic “invalid operands”.
Sourcepub fn is_error(self) -> bool
pub fn is_error(self) -> bool
Whether this stands for something already reported as ill formed.
Sourcepub fn is_integer(self) -> bool
pub fn is_integer(self) -> bool
Whether this is an integer type (_Bool and enum included, as C
requires).
Sourcepub fn is_int128(self) -> bool
pub fn is_int128(self) -> bool
Whether this is one of the two 128-bit integer types.
They are the only integers whose values do not all fit in the i128 a
constant is carried in, so the places that fold, print or emit one have
to know; see Ty::wrap.
Sourcepub fn is_floating(self) -> bool
pub fn is_floating(self) -> bool
Whether this is float or double — one of C’s real floating types.
The complex types are floating types too as far as the standard’s
wording goes; Ty::is_complex is the question about those, and
keeping them out of this one is what stops every existing floating-point
path from silently treating a Complex<f64> as an f64.
Sourcepub fn is_complex(self) -> bool
pub fn is_complex(self) -> bool
Whether this is one of the complex types.
Sourcepub fn complex_component(self) -> Ty
pub fn complex_component(self) -> Ty
The corresponding real type (C99 6.2.5p14) — the type of each part of a complex value, and the type itself for everything else.
Sourcepub fn complex_of(self) -> Ty
pub fn complex_of(self) -> Ty
The complex type whose parts have this real type (C99 6.2.5p13).
Anything that is not a real floating type gets double _Complex, which
is what the usual arithmetic conversions give an integer operand.
Sourcepub fn is_arithmetic(self) -> bool
pub fn is_arithmetic(self) -> bool
Whether this is an arithmetic type: an integer, a real floating type, or a complex one (C99 6.2.5p18).
Sourcepub fn is_scalar(self) -> bool
pub fn is_scalar(self) -> bool
Whether this is a scalar, i.e. something C can compare against zero.
An Ty::Atomic is not one: it is the type of an object, and a
value read out of one has the underlying type. Everything that asks
this question about a declared type therefore has to take the
_Atomic off first, with Types::unatomic.
Sourcepub fn is_signed(self, target: &TargetModel) -> bool
pub fn is_signed(self, target: &TargetModel) -> bool
Whether values of this type are signed.
Sourcepub fn bits(self, target: &TargetModel) -> u32
pub fn bits(self, target: &TargetModel) -> u32
The width of this type in bits.
Sourcepub fn size_bytes(self, target: &TargetModel) -> u64
pub fn size_bytes(self, target: &TargetModel) -> u64
sizeof this scalar type, in bytes.
Aggregates need the arena; use Types::size_of for a type that may be
one.
Sourcepub fn rank(self) -> u32
pub fn rank(self) -> u32
The conversion rank of an integer type (C99 6.3.1.1).
Only the ordering matters; the absolute values are arbitrary.
Sourcepub fn to_unsigned(self) -> Ty
pub fn to_unsigned(self) -> Ty
The unsigned type of the same rank.
Sourcepub fn min_value(self, target: &TargetModel) -> i128
pub fn min_value(self, target: &TargetModel) -> i128
The smallest value this integer type can hold.
Sourcepub fn max_value(self, target: &TargetModel) -> i128
pub fn max_value(self, target: &TargetModel) -> i128
The largest value this integer type can hold.
unsigned __int128 is the one type whose largest value does not fit in
the i128 this returns, and it is clamped to i128::MAX. Nothing
reads it: the only comparison of two maxima is the last step of the
usual arithmetic conversions, which is reached
only when the unsigned operand has the lower rank — and no integer
type ranks above unsigned __int128.
Sourcepub fn can_represent(self, value: i128, target: &TargetModel) -> bool
pub fn can_represent(self, value: i128, target: &TargetModel) -> bool
Whether value fits in this integer type without conversion.
Sourcepub fn wrap(self, value: i128, target: &TargetModel) -> i128
pub fn wrap(self, value: i128, target: &TargetModel) -> i128
Converts an integer value to this type the way C’s conversions do: modulo 2^N for unsigned types, and the same (implementation-defined) wrap-around for signed ones.
§How a 128-bit constant is carried
A folded constant is an i128, which holds every value of every type
this models except those of unsigned __int128 above i128::MAX. Such
a value is carried as its two’s-complement bit pattern, which is
what this returns unchanged for a 128-bit type: for every narrower type
the bit pattern and the mathematical value coincide, so the invariant is
“the value, except that an unsigned __int128 is reinterpreted”. The
places where the difference shows — division, remainder, a right shift,
a comparison and the literal that is finally emitted — dispatch on
Ty::is_signed instead of on the sign of the i128.
Sourcepub fn promote(self, target: &TargetModel) -> Ty
pub fn promote(self, target: &TargetModel) -> Ty
The integer promotions (C99 6.3.1.1p2).
Anything of lower rank than int becomes int when int can hold
every one of its values and unsigned int otherwise; an enum becomes
int; everything else is unchanged.
Sourcepub fn promote_bit_field(
self,
width: u32,
signed: bool,
target: &TargetModel,
) -> Ty
pub fn promote_bit_field( self, width: u32, signed: bool, target: &TargetModel, ) -> Ty
The integer promotions applied to a bit-field (C99 6.3.1.1p2, “as restricted by the width”).
The value of a bit-field of width width ranges over width bits
rather than over the whole declared type, so unsigned x : 31 promotes
to int — every value fits — while unsigned x : 32 promotes to
unsigned int. The standard only defines the promotions for a type
whose rank is at most int’s, which is the only case standard C allows
a bit-field to have; GCC and Clang apply the same width-restricted rule
to the wider types they accept as an extension, so unsigned long x : 31
is an int too and unsigned long x : 33 keeps its declared type. This
follows them.
signed is the signedness of the field, which is the declared type’s
except for an enum whose underlying type the implementation made
unsigned.
Sourcepub fn promote_argument(self, target: &TargetModel) -> Ty
pub fn promote_argument(self, target: &TargetModel) -> Ty
The default argument promotions, applied to the variable part of a
variadic call: float becomes double, and the integer promotions do
the rest.
Sourcepub fn usual_arithmetic(lhs: Ty, rhs: Ty, target: &TargetModel) -> Ty
pub fn usual_arithmetic(lhs: Ty, rhs: Ty, target: &TargetModel) -> Ty
The usual arithmetic conversions (C99 6.3.1.8): the common type two arithmetic operands are converted to.
With a complex operand the standard’s rule is in two steps: the common
real type is worked out from the two operands’ corresponding real
types, and the result is the complex type belonging to it if either
operand was complex. float _Complex + long is therefore
float _Complex, not double _Complex.
Sourcepub fn size_ty(target: &TargetModel) -> Ty
pub fn size_ty(target: &TargetModel) -> Ty
size_t for target.
The narrowest unsigned type as wide as a pointer, which is how GCC
picks it and therefore what __SIZE_TYPE__ says: unsigned int on
i686, unsigned long on LP64, unsigned long long on 64-bit Windows,
where long is only 32 bits.
Sourcepub fn ptrdiff_ty(target: &TargetModel) -> Ty
pub fn ptrdiff_ty(target: &TargetModel) -> Ty
ptrdiff_t for target, chosen the same way as Ty::size_ty.
Sourcepub fn wchar_ty(target: &TargetModel) -> Ty
pub fn wchar_ty(target: &TargetModel) -> Ty
wchar_t for target: unsigned short on Windows, unsigned int on
Arm outside Apple’s platforms, and int everywhere else.
This is the type L'x' and L"…" get, and what the bundled
<stddef.h> typedefs from __WCHAR_TYPE__; the two have to agree, or
a call passing L"…" to a const wchar_t * would be a type error.