Class: Rubycc::Type::StructType

Inherits:
Object
  • Object
show all
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

Instance Method Summary collapse

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

#kindObject (readonly)

Returns the value of attribute kind.



791
792
793
# File 'lib/rubycc/type.rb', line 791

def kind
  @kind
end

#membersObject (readonly)

Returns the value of attribute members.



791
792
793
# File 'lib/rubycc/type.rb', line 791

def members
  @members
end

#tagObject (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

#alignmentObject

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

Returns:

  • (Boolean)


822
823
824
# File 'lib/rubycc/type.rb', line 822

def arithmetic?
  false
end

#array?Boolean

Returns:

  • (Boolean)


830
831
832
# File 'lib/rubycc/type.rb', line 830

def array?
  false
end

#bool?Boolean

Returns:

  • (Boolean)


826
827
828
# File 'lib/rubycc/type.rb', line 826

def bool?
  false
end

#char?Boolean

Returns:

  • (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.

Returns:

  • (Boolean)


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.

Returns:

  • (Boolean)


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

Returns:

  • (Boolean)


848
849
850
# File 'lib/rubycc/type.rb', line 848

def float?
  false
end

#function?Boolean

Returns:

  • (Boolean)


844
845
846
# File 'lib/rubycc/type.rb', line 844

def function?
  false
end

#int?Boolean

Returns:

  • (Boolean)


806
807
808
# File 'lib/rubycc/type.rb', line 806

def int?
  false
end

#integer?Boolean

Returns:

  • (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

Returns:

  • (Boolean)


802
803
804
# File 'lib/rubycc/type.rb', line 802

def pointer?
  false
end

#sizeObject

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.

Returns:

  • (Boolean)


840
841
842
# File 'lib/rubycc/type.rb', line 840

def struct?
  true
end

#to_sObject

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.

Returns:

  • (Boolean)


854
855
856
# File 'lib/rubycc/type.rb', line 854

def union?
  @kind == :union
end

#void?Boolean

Returns:

  • (Boolean)


814
815
816
# File 'lib/rubycc/type.rb', line 814

def void?
  false
end