@@ -633,46 +633,59 @@ impl<'a> AstValidator<'a> {
633633 /// - Non-const
634634 /// - Either foreign, or free and `unsafe extern "C"` semantically
635635 fn check_c_variadic_type ( & self , fk : FnKind < ' a > ) {
636- let variadic_spans: Vec < _ > = fk
637- . decl ( )
638- . inputs
639- . iter ( )
640- . filter ( |arg| matches ! ( arg. ty. kind, TyKind :: CVarArgs ) )
641- . map ( |arg| arg. span )
642- . collect ( ) ;
636+ let variadic_params: Vec < _ > =
637+ fk. decl ( ) . inputs . iter ( ) . filter ( |arg| matches ! ( arg. ty. kind, TyKind :: CVarArgs ) ) . collect ( ) ;
643638
644- if variadic_spans. is_empty ( ) {
639+ // The parser already rejects `...` if it's not the final argument, but we still want to
640+ // emit the errors below, so we only consider the final `...` here.
641+ let Some ( variadic_param) = variadic_params. last ( ) else {
645642 return ;
646- }
643+ } ;
647644
648- if let Some ( header) = fk. header ( ) {
649- if let Const :: Yes ( const_span) = header. constness {
650- let mut spans = variadic_spans. clone ( ) ;
651- spans. push ( const_span) ;
652- self . dcx ( ) . emit_err ( errors:: ConstAndCVariadic {
653- spans,
654- const_span,
655- variadic_spans : variadic_spans. clone ( ) ,
656- } ) ;
657- }
645+ let FnKind :: Fn ( fn_ctxt, _, Fn { sig, .. } ) = fk else {
646+ // Unreachable because the parser already rejects `...` in closures.
647+ unreachable ! ( "C variable argument list cannot be used in closures" )
648+ } ;
649+
650+ // C-variadics are not yet implemented in const evaluation.
651+ if let Const :: Yes ( const_span) = sig. header . constness {
652+ self . dcx ( ) . emit_err ( errors:: ConstAndCVariadic {
653+ span : const_span. to ( variadic_param. span ) ,
654+ const_span,
655+ variadic_span : variadic_param. span ,
656+ } ) ;
658657 }
659658
660- match ( fk. ctxt ( ) , fk. header ( ) ) {
661- ( Some ( FnCtxt :: Foreign ) , _) => return ,
662- ( Some ( FnCtxt :: Free ) , Some ( header) ) => match header. ext {
663- Extern :: Explicit ( StrLit { symbol_unescaped : sym:: C , .. } , _)
664- | Extern :: Explicit ( StrLit { symbol_unescaped : sym:: C_dash_unwind , .. } , _)
665- | Extern :: Implicit ( _)
666- if matches ! ( header. safety, Safety :: Unsafe ( _) ) =>
667- {
668- return ;
659+ match fn_ctxt {
660+ FnCtxt :: Free => {
661+ let is_extern_c_abi = match sig. header . ext {
662+ Extern :: Explicit ( StrLit { symbol_unescaped, .. } , _) => {
663+ matches ! ( symbol_unescaped, sym:: C | sym:: C_dash_unwind )
664+ }
665+ Extern :: Implicit ( _) => true ,
666+ Extern :: None => false ,
667+ } ;
668+
669+ if !is_extern_c_abi {
670+ self . dcx ( ) . emit_err ( errors:: CVariadicBadExtern { span : variadic_param. span } ) ;
669671 }
670- _ => { }
671- } ,
672- _ => { }
673- } ;
674672
675- self . dcx ( ) . emit_err ( errors:: BadCVariadic { span : variadic_spans } ) ;
673+ if !matches ! ( sig. header. safety, Safety :: Unsafe ( _) ) {
674+ self . dcx ( ) . emit_err ( errors:: CVariadicMustBeUnsafe {
675+ span : variadic_param. span ,
676+ unsafe_span : sig. safety_span ( ) ,
677+ } ) ;
678+ }
679+ }
680+ FnCtxt :: Assoc ( _) => {
681+ // For now, C variable argument lists are unsupported in associated functions.
682+ self . dcx ( )
683+ . emit_err ( errors:: CVariadicAssociatedFunction { span : variadic_param. span } ) ;
684+ }
685+ FnCtxt :: Foreign => {
686+ // Whether the ABI supports C variable argument lists is checked later.
687+ }
688+ }
676689 }
677690
678691 fn check_item_named ( & self , ident : Ident , kind : & str ) {
0 commit comments