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