@@ -46,17 +46,23 @@ pub enum PassMode {
4646 ///
4747 /// The argument has a layout abi of `ScalarPair`.
4848 Pair ( ArgAttributes , ArgAttributes ) ,
49- /// Pass the argument after casting it. See the `CastTarget` docs for details. The bool
50- /// indicates if a `Reg::i32()` dummy argument is emitted before the real argument.
49+ /// Pass the argument after casting it. See the `CastTarget` docs for details.
50+ ///
51+ /// `pad_i32` indicates if a `Reg::i32()` dummy argument is emitted before the real argument.
5152 Cast { pad_i32 : bool , cast : Box < CastTarget > } ,
5253 /// Pass the argument indirectly via a hidden pointer.
54+ ///
5355 /// The `meta_attrs` value, if any, is for the metadata (vtable or length) of an unsized
5456 /// argument. (This is the only mode that supports unsized arguments.)
57+ ///
5558 /// `on_stack` defines that the value should be passed at a fixed stack offset in accordance to
5659 /// the ABI rather than passed using a pointer. This corresponds to the `byval` LLVM argument
57- /// attribute (using a byte array type with the same size as the Rust type [which ensures that
58- /// padding is preserved and that we do not rely on LLVM's struct layout], and with alignment
59- /// determined in a complex, target-specific manner [see callers of `make_indirect_byval`]).
60+ /// attribute. The `byval` argument will use a byte array with the same size as the Rust type
61+ /// (which ensures that padding is preserved and that we do not rely on LLVM's struct layout),
62+ /// and will use the alignment specified in `attrs.pointee_align` (if `Some`) or the type's
63+ /// alignment, depending on the target's ABI. This means that the alignment will not always
64+ /// match the Rust type's alignment; see documentation of `make_indirect_byval` for more info.
65+ ///
6066 /// `on_stack` cannot be true for unsized arguments, i.e., when `meta_attrs` is `Some`.
6167 Indirect { attrs : ArgAttributes , meta_attrs : Option < ArgAttributes > , on_stack : bool } ,
6268}
@@ -598,6 +604,8 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
598604 }
599605 }
600606
607+ /// Pass this argument indirectly, by passing a (thin or fat) pointer to the argument instead.
608+ /// This is valid for both sized and unsized arguments.
601609 pub fn make_indirect ( & mut self ) {
602610 match self . mode {
603611 PassMode :: Direct ( _) | PassMode :: Pair ( _, _) => {
@@ -611,7 +619,26 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
611619 }
612620 }
613621
622+ /// Pass this argument indirectly, by placing it at a fixed stack offset.
623+ /// This corresponds to the `byval` LLVM argument attribute.
624+ /// This is only valid for sized arguments.
625+ ///
626+ /// `byval_align` specifies the alignment of the `byval` stack slot, which does not need to
627+ /// correspond to the type's alignment. This will be `Some` if the target's ABI specifies that
628+ /// stack slots used for arguments passed by-value have specific alignment requirements which
629+ /// differ from the alignment used in other situations.
630+ ///
631+ /// If `None`, the type's alignment is used.
632+ ///
633+ /// If the resulting alignment differs from the type's alignment,
634+ /// the argument will be copied to an alloca with sufficient alignment,
635+ /// either in the caller (if the type's alignment is lower than the byval alignment)
636+ /// or in the callee† (if the type's alignment is higher than the byval alignment),
637+ /// to ensure that Rust code never sees an underaligned pointer.
638+ ///
639+ /// † This is currently broken, see <https://github.com/rust-lang/rust/pull/122212>.
614640 pub fn make_indirect_byval ( & mut self , byval_align : Option < Align > ) {
641+ assert ! ( !self . layout. is_unsized( ) , "used byval ABI for unsized layout" ) ;
615642 self . make_indirect ( ) ;
616643 match self . mode {
617644 PassMode :: Indirect { ref mut attrs, meta_attrs : _, ref mut on_stack } => {
0 commit comments