@@ -2858,6 +2858,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
2858
2858
} else if attr. has_name ( sym:: link_name) {
2859
2859
codegen_fn_attrs. link_name = attr. value_str ( ) ;
2860
2860
} else if attr. has_name ( sym:: link_ordinal) {
2861
+ if link_ordinal_span. is_some ( ) {
2862
+ tcx. sess
2863
+ . struct_span_err (
2864
+ attr. span ,
2865
+ "multiple `link_ordinal` attributes on a single definition" ,
2866
+ )
2867
+ . emit ( ) ;
2868
+ }
2861
2869
link_ordinal_span = Some ( attr. span ) ;
2862
2870
if let ordinal @ Some ( _) = check_link_ordinal ( tcx, attr) {
2863
2871
codegen_fn_attrs. link_ordinal = ordinal;
@@ -3153,22 +3161,41 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
3153
3161
false
3154
3162
}
3155
3163
3156
- fn check_link_ordinal ( tcx : TyCtxt < ' _ > , attr : & ast:: Attribute ) -> Option < usize > {
3164
+ fn check_link_ordinal ( tcx : TyCtxt < ' _ > , attr : & ast:: Attribute ) -> Option < u16 > {
3157
3165
use rustc_ast:: { Lit , LitIntType , LitKind } ;
3158
3166
let meta_item_list = attr. meta_item_list ( ) ;
3159
3167
let meta_item_list: Option < & [ ast:: NestedMetaItem ] > = meta_item_list. as_ref ( ) . map ( Vec :: as_ref) ;
3160
3168
let sole_meta_list = match meta_item_list {
3161
3169
Some ( [ item] ) => item. literal ( ) ,
3170
+ Some ( _) => {
3171
+ tcx. sess
3172
+ . struct_span_err ( attr. span , "incorrect number of arguments to `#[link_ordinal]`" )
3173
+ . note ( "the attribute requires exactly one argument" )
3174
+ . emit ( ) ;
3175
+ return None ;
3176
+ }
3162
3177
_ => None ,
3163
3178
} ;
3164
3179
if let Some ( Lit { kind : LitKind :: Int ( ordinal, LitIntType :: Unsuffixed ) , .. } ) = sole_meta_list {
3165
- if * ordinal <= usize:: MAX as u128 {
3166
- Some ( * ordinal as usize )
3180
+ // According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header,
3181
+ // the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
3182
+ // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information
3183
+ // to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
3184
+ //
3185
+ // FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for this:
3186
+ // both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies
3187
+ // a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library
3188
+ // for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import
3189
+ // library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I don't know yet
3190
+ // if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment
3191
+ // about LINK.EXE failing.)
3192
+ if * ordinal <= u16:: MAX as u128 {
3193
+ Some ( * ordinal as u16 )
3167
3194
} else {
3168
3195
let msg = format ! ( "ordinal value in `link_ordinal` is too large: `{}`" , & ordinal) ;
3169
3196
tcx. sess
3170
3197
. struct_span_err ( attr. span , & msg)
3171
- . note ( "the value may not exceed `usize ::MAX`" )
3198
+ . note ( "the value may not exceed `u16 ::MAX`" )
3172
3199
. emit ( ) ;
3173
3200
None
3174
3201
}
0 commit comments