Class: Rubycc::Type::StructType
- Inherits:
-
Object
- Object
- Rubycc::Type::StructType
- Defined in:
- lib/rubycc/type.rb
Overview
A structure or a union type. Both are aggregates (6.7.2.1) that share this
one class, told apart by kind (:struct or :union); a union differs only
in its layout (every member at offset 0, sized to hold the widest one).
Unlike every other type here, one compares by identity, not by value: two
such types are the same type exactly when they are the same object, which
is the object a single tag definition produces. That is what C means by
struct/union type identity (a redeclared "struct point" refers to the one
definition, never a structurally equal copy) and it is also what keeps
equality and #to_s from looping on a self-referential struct, whose
members point back at itself.
A StructType is born incomplete: tag (the name after "struct"/"union",
or nil for an anonymous one) and kind are fixed, but its members are
unknown until #define lays them out. This mutability is deliberate — a
forward declaration ("struct node;") and, above all, a self-referential
pointer ("struct node *next;" inside "struct node"'s own body) both take a
reference to the still-incomplete object, and #define later fills in the
very same object, so those earlier references observe the completed
layout. Until then #size and #alignment raise and #complete? is false, so
the generator can reject an incomplete type (a variable, a sizeof, a
by-value member) with a proper diagnostic rather than lay out nonsense.
Instance Attribute Summary collapse
-
#kind ⇒ Object
readonly
Returns the value of attribute kind.
-
#members ⇒ Object
readonly
Returns the value of attribute members.
-
#tag ⇒ Object
readonly
Returns the value of attribute tag.
Instance Method Summary collapse
-
#==(other) ⇒ Object
Two struct types are identical only when they are the same object (the same tag definition); a comparison with any other type, or with a different struct, is false.
-
#alignment ⇒ Object
The struct's alignment (its widest member's), guarded exactly like #size against an incomplete struct.
- #arithmetic? ⇒ Boolean
- #array? ⇒ Boolean
- #bool? ⇒ Boolean
- #char? ⇒ Boolean
-
#complete? ⇒ Boolean
Whether the tag's body has been laid out yet.
-
#define(raw_members, packed: false, aligned: nil, unnamed_bitfields_align: false) ⇒ Object
Lays out the aggregate from
raw_members(an array of [name, Type, bit_width, alignas] entries in declaration order; an anonymous struct/union member has a nil name, a plain member a nil bit_width — see #layout_struct for how a bit-field is placed — andalignasis the boundary a C11 _Alignas asked for on that one member, nil for none, a trailing field a caller with no such member may leave off entirely). -
#flexible_array_member? ⇒ Boolean
Whether this aggregate ends in a flexible array member (an unbounded "[]", 6.7.2.1p18).
- #float? ⇒ Boolean
- #function? ⇒ Boolean
-
#initialize(tag, kind: :struct) ⇒ StructType
constructor
A new instance of StructType.
- #int? ⇒ Boolean
- #integer? ⇒ Boolean
-
#member(name) ⇒ Object
The member named
name, or nil when there is none — the generator uses the nil to diagnose "no member named ...". - #pointer? ⇒ Boolean
-
#size ⇒ Object
The laid-out byte size.
-
#struct? ⇒ Boolean
True for a union as well as a struct: both are aggregates that reuse the same lvalue, member-access and whole-object-copy paths, so every generator site that means "an aggregate" (member address, :memcpy copy, by-value rejection) asks #struct? and needs no union-specific branch.
-
#to_s ⇒ Object
Renders as a C type name for diagnostics.
-
#union? ⇒ Boolean
Distinguishes a union from a struct; the two share this class and differ only in layout and in the wording of tag-kind diagnostics.
- #void? ⇒ Boolean
Constructor Details
#initialize(tag, kind: :struct) ⇒ StructType
Returns a new instance of StructType.
793 794 795 796 797 798 799 800 |
# File 'lib/rubycc/type.rb', line 793 def initialize(tag, kind: :struct) @tag = tag @kind = kind @members = nil @size = nil @alignment = nil @complete = false end |
Instance Attribute Details
#kind ⇒ Object (readonly)
Returns the value of attribute kind.
791 792 793 |
# File 'lib/rubycc/type.rb', line 791 def kind @kind end |
#members ⇒ Object (readonly)
Returns the value of attribute members.
791 792 793 |
# File 'lib/rubycc/type.rb', line 791 def members @members end |
#tag ⇒ Object (readonly)
Returns the value of attribute tag.
791 792 793 |
# File 'lib/rubycc/type.rb', line 791 def tag @tag end |
Instance Method Details
#==(other) ⇒ Object
Two struct types are identical only when they are the same object (the same tag definition); a comparison with any other type, or with a different struct, is false. Identity avoids walking members, so a self-referential struct compares without recursing.
972 973 974 |
# File 'lib/rubycc/type.rb', line 972 def ==(other) equal?(other) end |
#alignment ⇒ Object
The struct's alignment (its widest member's), guarded exactly like #size against an incomplete struct.
962 963 964 965 966 |
# File 'lib/rubycc/type.rb', line 962 def alignment raise "incomplete struct has no alignment" unless @complete @alignment end |
#arithmetic? ⇒ Boolean
822 823 824 |
# File 'lib/rubycc/type.rb', line 822 def arithmetic? false end |
#array? ⇒ Boolean
830 831 832 |
# File 'lib/rubycc/type.rb', line 830 def array? false end |
#bool? ⇒ Boolean
826 827 828 |
# File 'lib/rubycc/type.rb', line 826 def bool? false end |
#char? ⇒ Boolean
810 811 812 |
# File 'lib/rubycc/type.rb', line 810 def char? false end |
#complete? ⇒ Boolean
Whether the tag's body has been laid out yet. A struct only used through a pointer may stay incomplete forever; every other use is a diagnostic error the generator raises against this flag.
861 862 863 |
# File 'lib/rubycc/type.rb', line 861 def complete? @complete end |
#define(raw_members, packed: false, aligned: nil, unnamed_bitfields_align: false) ⇒ Object
Lays out the aggregate from raw_members (an array of [name, Type,
bit_width, alignas] entries in declaration order; an anonymous
struct/union member has a nil name, a plain member a nil bit_width — see
#layout_struct for how a bit-field is placed — and alignas is the
boundary a C11 _Alignas asked for on that one member, nil for none, a
trailing field a caller with no such member may leave off entirely).
A struct follows the System V AMD64 rules:
each member starts at
the next offset that satisfies its own alignment (inserting padding as
needed), the alignment is the widest member's, and the size is rounded
up to that alignment so arrays keep every element aligned. A union
overlays every member at offset 0, so its alignment is still the widest
member's but its size is the largest member's rounded up to that
alignment. Completing the type in place means any reference taken while
it was incomplete now sees the finished layout.
packed and aligned carry the GNU attribute layout overrides
(Step 28). packed drops every member to a 1-byte boundary — no padding
between members and no tail padding — and, on its own, the whole
aggregate to alignment 1. aligned (a power-of-two integer, or nil for
none) raises the aggregate's alignment to at least that value, rounding
the size up to it; combined with packed the members stay packed while
the aggregate takes aligned as its boundary and tail-rounding.
A member's own alignas overrides both of those for that one member: it
is placed at the boundary the _Alignas names and joins the aggregate's
alignment as any member's does, even under packed (measured: gcc gives
"struct attribute((packed)) { char c; _Alignas(8) int a; char b; }"
size 16, alignment 8 and "a" at offset 8).
unnamed_bitfields_align selects the one layout rule the two supported
ABIs spell differently (see #layout_struct): whether an unnamed
bit-field's declared type raises the aggregate's alignment. It does not
under the x86-64 System V psABI (the default) and does under AAPCS64.
941 942 943 944 945 946 947 948 949 |
# File 'lib/rubycc/type.rb', line 941 def define(raw_members, packed: false, aligned: nil, unnamed_bitfields_align: false) @members, @size, @alignment = if union? layout_union(raw_members, packed, aligned, unnamed_bitfields_align) else layout_struct(raw_members, packed, aligned, unnamed_bitfields_align) end @complete = true end |
#flexible_array_member? ⇒ Boolean
Whether this aggregate ends in a flexible array member (an unbounded "[]", 6.7.2.1p18). A struct with one taints its uses: it may not be an array element or (this subset) laid out by value inside another aggregate, since its true size depends on a run-time element count the enclosing layout cannot know. Only a defined struct can carry one, so an incomplete type (no members yet) answers false.
871 872 873 874 875 876 |
# File 'lib/rubycc/type.rb', line 871 def flexible_array_member? return false unless @members last = @members.last !last.nil? && last.type.array? && last.type.incomplete? end |
#float? ⇒ Boolean
848 849 850 |
# File 'lib/rubycc/type.rb', line 848 def float? false end |
#function? ⇒ Boolean
844 845 846 |
# File 'lib/rubycc/type.rb', line 844 def function? false end |
#int? ⇒ Boolean
806 807 808 |
# File 'lib/rubycc/type.rb', line 806 def int? false end |
#integer? ⇒ Boolean
818 819 820 |
# File 'lib/rubycc/type.rb', line 818 def integer? false end |
#member(name) ⇒ Object
The member named name, or nil when there is none — the generator uses
the nil to diagnose "no member named ...". A named member wins directly;
failing that, an anonymous struct/union member (name nil, an aggregate
per C11 6.7.2.1p13) is searched transparently, and a hit there is
returned as a synthesized Member whose offset folds the anonymous
member's own offset into the inner one. The search recurses, so an
anonymous member nested inside another resolves in the same single step;
because the returned Member carries a ready-made offset and type, the
generator's "." and "->" lowering reaches a nested field with no
awareness that it came through an anonymous member.
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 |
# File 'lib/rubycc/type.rb', line 888 def member(name) return nil unless @members direct = @members.find { |m| m.name == name } return direct if direct @members.each do |m| next unless m.name.nil? && m.type.struct? inner = m.type.member(name) if inner return Member.new(name: inner.name, type: inner.type, offset: m.offset + inner.offset, bit_width: inner.bit_width, bit_offset: inner.bit_offset && inner.bit_offset + m.offset * 8) end end nil end |
#pointer? ⇒ Boolean
802 803 804 |
# File 'lib/rubycc/type.rb', line 802 def pointer? false end |
#size ⇒ Object
The laid-out byte size. Guarded like Type::Void's: every path that could reach an incomplete struct here rejects it first with a CompileError, so a raise means a missing guard.
954 955 956 957 958 |
# File 'lib/rubycc/type.rb', line 954 def size raise "incomplete struct has no size" unless @complete @size end |
#struct? ⇒ Boolean
True for a union as well as a struct: both are aggregates that reuse the same lvalue, member-access and whole-object-copy paths, so every generator site that means "an aggregate" (member address, :memcpy copy, by-value rejection) asks #struct? and needs no union-specific branch. #union? draws the distinction where the layout or a diagnostic depends on it.
840 841 842 |
# File 'lib/rubycc/type.rb', line 840 def struct? true end |
#to_s ⇒ Object
Renders as a C type name for diagnostics. Never inspects members, so a self-referential struct renders in one step; an anonymous struct has no tag to name.
979 980 981 982 |
# File 'lib/rubycc/type.rb', line 979 def to_s keyword = union? ? "union" : "struct" tag ? "#{keyword} #{tag}" : "#{keyword} <anonymous>" end |
#union? ⇒ Boolean
Distinguishes a union from a struct; the two share this class and differ only in layout and in the wording of tag-kind diagnostics.
854 855 856 |
# File 'lib/rubycc/type.rb', line 854 def union? @kind == :union end |
#void? ⇒ Boolean
814 815 816 |
# File 'lib/rubycc/type.rb', line 814 def void? false end |