@@ -633,46 +633,73 @@ impl<'a> AstValidator<'a> {
633
633
/// - Non-const
634
634
/// - Either foreign, or free and `unsafe extern "C"` semantically
635
635
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 ( ) ;
643
638
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 {
645
642
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
+ } ) ;
646
657
}
647
658
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
+ } ) ;
658
666
}
659
667
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
+ } ;
674
686
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
+ }
676
703
}
677
704
678
705
fn check_item_named ( & self , ident : Ident , kind : & str ) {
0 commit comments