@@ -633,46 +633,73 @@ impl<'a> AstValidator<'a> {
633633/// - Non-const 
634634/// - Either foreign, or free and `unsafe extern "C"` semantically 
635635fn  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 ; 
643+         } ; 
644+ 
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+             } ) ; 
646657        } 
647658
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-             } 
659+         if  let  Some ( coroutine_kind)  = sig. header . coroutine_kind  { 
660+             self . dcx ( ) . emit_err ( errors:: CoroutineAndCVariadic  { 
661+                 span :  coroutine_kind. span ( ) . to ( variadic_param. span ) , 
662+                 coroutine_kind :  coroutine_kind. as_str ( ) , 
663+                 coroutine_span :  coroutine_kind. span ( ) , 
664+                 variadic_span :  variadic_param. span , 
665+             } ) ; 
658666        } 
659667
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 ; 
669-                 } 
670-                 _ => { } 
671-             } , 
672-             _ => { } 
673-         } ; 
668+         match  fn_ctxt { 
669+             FnCtxt :: Free  => { 
670+                 match  sig. header . ext  { 
671+                     Extern :: Implicit ( _)  => {  /* defaults to "C" */  } 
672+                     Extern :: Explicit ( StrLit  {  symbol_unescaped,  .. } ,  _)  => { 
673+                         if  !matches ! ( symbol_unescaped,  sym:: C  | sym:: C_dash_unwind )  { 
674+                             self . dcx ( ) . emit_err ( errors:: CVariadicBadExtern  { 
675+                                 span :  variadic_param. span , 
676+                                 abi :  symbol_unescaped, 
677+                                 extern_span :  sig. extern_span ( ) , 
678+                             } ) ; 
679+                         } 
680+                     } 
681+                     Extern :: None  => { 
682+                         self . dcx ( ) 
683+                             . emit_err ( errors:: CVariadicNoExtern  {  span :  variadic_param. span  } ) ; 
684+                     } 
685+                 } ; 
674686
675-         self . dcx ( ) . emit_err ( errors:: BadCVariadic  {  span :  variadic_spans } ) ; 
687+                 if  !matches ! ( sig. header. safety,  Safety :: Unsafe ( _) )  { 
688+                     self . dcx ( ) . emit_err ( errors:: CVariadicMustBeUnsafe  { 
689+                         span :  variadic_param. span , 
690+                         unsafe_span :  sig. safety_span ( ) , 
691+                     } ) ; 
692+                 } 
693+             } 
694+             FnCtxt :: Assoc ( _)  => { 
695+                 // For now, C variable argument lists are unsupported in associated functions. 
696+                 self . dcx ( ) 
697+                     . emit_err ( errors:: CVariadicAssociatedFunction  {  span :  variadic_param. span  } ) ; 
698+             } 
699+             FnCtxt :: Foreign  => { 
700+                 // Whether the ABI supports C variable argument lists is checked later. 
701+             } 
702+         } 
676703    } 
677704
678705    fn  check_item_named ( & self ,  ident :  Ident ,  kind :  & str )  { 
0 commit comments