@@ -21,7 +21,7 @@ use std::ops::{Deref, DerefMut};
2121use std:: str:: FromStr ;
2222
2323use itertools:: { Either , Itertools } ;
24- use rustc_abi:: { CanonAbi , ExternAbi , InterruptKind } ;
24+ use rustc_abi:: { CVariadicStatus , CanonAbi , ExternAbi , InterruptKind } ;
2525use rustc_ast:: visit:: { AssocCtxt , BoundKind , FnCtxt , FnKind , Visitor , walk_list} ;
2626use rustc_ast:: * ;
2727use rustc_ast_pretty:: pprust:: { self , State } ;
@@ -35,6 +35,7 @@ use rustc_session::lint::builtin::{
3535 DEPRECATED_WHERE_CLAUSE_LOCATION , MISSING_ABI , MISSING_UNSAFE_ON_EXTERN ,
3636 PATTERNS_IN_FNS_WITHOUT_BODY ,
3737} ;
38+ use rustc_session:: parse:: feature_err;
3839use rustc_span:: { Ident , Span , kw, sym} ;
3940use rustc_target:: spec:: { AbiMap , AbiMapping } ;
4041use thin_vec:: thin_vec;
@@ -661,7 +662,7 @@ impl<'a> AstValidator<'a> {
661662 /// C-variadics must be:
662663 /// - Non-const
663664 /// - Either foreign, or free and `unsafe extern "C"` semantically
664- fn check_c_variadic_type ( & self , fk : FnKind < ' a > ) {
665+ fn check_c_variadic_type ( & self , fk : FnKind < ' a > , attrs : & ' a AttrVec ) {
665666 // `...` is already rejected when it is not the final parameter.
666667 let variadic_param = match fk. decl ( ) . inputs . last ( ) {
667668 Some ( param) if matches ! ( param. ty. kind, TyKind :: CVarArgs ) => param,
@@ -693,36 +694,92 @@ impl<'a> AstValidator<'a> {
693694
694695 match fn_ctxt {
695696 FnCtxt :: Foreign => return ,
696- FnCtxt :: Free | FnCtxt :: Assoc ( _) => match sig. header . ext {
697- Extern :: Implicit ( _) => {
698- if !matches ! ( sig. header. safety, Safety :: Unsafe ( _) ) {
699- self . dcx ( ) . emit_err ( errors:: CVariadicMustBeUnsafe {
700- span : variadic_param. span ,
701- unsafe_span : sig. safety_span ( ) ,
702- } ) ;
697+ FnCtxt :: Free | FnCtxt :: Assoc ( _) => {
698+ match sig. header . ext {
699+ Extern :: Implicit ( _) => {
700+ if !matches ! ( sig. header. safety, Safety :: Unsafe ( _) ) {
701+ self . dcx ( ) . emit_err ( errors:: CVariadicMustBeUnsafe {
702+ span : variadic_param. span ,
703+ unsafe_span : sig. safety_span ( ) ,
704+ } ) ;
705+ }
706+ }
707+ Extern :: Explicit ( StrLit { symbol_unescaped, .. } , _) => {
708+ // Just bail if the ABI is not even recognized.
709+ let Ok ( abi) = ExternAbi :: from_str ( symbol_unescaped. as_str ( ) ) else {
710+ return ;
711+ } ;
712+
713+ self . check_c_variadic_abi ( abi, attrs, variadic_param. span , sig) ;
714+
715+ if !matches ! ( sig. header. safety, Safety :: Unsafe ( _) ) {
716+ self . dcx ( ) . emit_err ( errors:: CVariadicMustBeUnsafe {
717+ span : variadic_param. span ,
718+ unsafe_span : sig. safety_span ( ) ,
719+ } ) ;
720+ }
721+ }
722+ Extern :: None => {
723+ let err = errors:: CVariadicNoExtern { span : variadic_param. span } ;
724+ self . dcx ( ) . emit_err ( err) ;
703725 }
704726 }
705- Extern :: Explicit ( StrLit { symbol_unescaped, .. } , _) => {
706- if !matches ! ( symbol_unescaped, sym:: C | sym:: C_dash_unwind ) {
707- self . dcx ( ) . emit_err ( errors:: CVariadicBadExtern {
708- span : variadic_param. span ,
709- abi : symbol_unescaped,
710- extern_span : sig. extern_span ( ) ,
711- } ) ;
727+ }
728+ }
729+ }
730+
731+ fn check_c_variadic_abi (
732+ & self ,
733+ abi : ExternAbi ,
734+ attrs : & ' a AttrVec ,
735+ dotdotdot_span : Span ,
736+ sig : & FnSig ,
737+ ) {
738+ // For naked functions we accept any ABI that is accepted on c-variadic
739+ // foreign functions, if the c_variadic_naked_functions feature is enabled.
740+ if attr:: contains_name ( attrs, sym:: naked) {
741+ match abi. supports_c_variadic ( ) {
742+ CVariadicStatus :: Stable if let ExternAbi :: C { .. } = abi => {
743+ // With `c_variadic` naked c-variadic `extern "C"` functions are allowed.
744+ }
745+ CVariadicStatus :: Stable => {
746+ // For e.g. aapcs or sysv64 `c_variadic_naked_functions` must also be enabled.
747+ if !self . features . enabled ( sym:: c_variadic_naked_functions) {
748+ let msg = format ! ( "Naked c-variadic `extern {abi}` functions are unstable" ) ;
749+ feature_err ( & self . sess , sym:: c_variadic_naked_functions, sig. span , msg)
750+ . emit ( ) ;
751+ }
752+ }
753+ CVariadicStatus :: Unstable { feature } => {
754+ // Some ABIs need additional features.
755+ if !self . features . enabled ( sym:: c_variadic_naked_functions) {
756+ let msg = format ! ( "Naked c-variadic `extern {abi}` functions are unstable" ) ;
757+ feature_err ( & self . sess , sym:: c_variadic_naked_functions, sig. span , msg)
758+ . emit ( ) ;
712759 }
713760
714- if !matches ! ( sig . header . safety , Safety :: Unsafe ( _ ) ) {
715- self . dcx ( ) . emit_err ( errors :: CVariadicMustBeUnsafe {
716- span : variadic_param . span ,
717- unsafe_span : sig . safety_span ( ) ,
718- } ) ;
761+ if !self . features . enabled ( feature ) {
762+ let msg = format ! (
763+ "C-variadic functions with the {abi} calling convention are unstable"
764+ ) ;
765+ feature_err ( & self . sess , feature , sig . span , msg ) . emit ( ) ;
719766 }
720767 }
721- Extern :: None => {
722- let err = errors:: CVariadicNoExtern { span : variadic_param. span } ;
723- self . dcx ( ) . emit_err ( err) ;
768+ CVariadicStatus :: NotSupported => {
769+ // Some ABIs, e.g. `extern "Rust"`, never support c-variadic functions.
770+ self . dcx ( ) . emit_err ( errors:: CVariadicBadNakedExtern {
771+ span : dotdotdot_span,
772+ abi : abi. as_str ( ) ,
773+ extern_span : sig. extern_span ( ) ,
774+ } ) ;
724775 }
725- } ,
776+ }
777+ } else if !matches ! ( abi, ExternAbi :: C { .. } ) {
778+ self . dcx ( ) . emit_err ( errors:: CVariadicBadExtern {
779+ span : dotdotdot_span,
780+ abi : abi. as_str ( ) ,
781+ extern_span : sig. extern_span ( ) ,
782+ } ) ;
726783 }
727784 }
728785
@@ -1106,7 +1163,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11061163 }
11071164
11081165 let kind = FnKind :: Fn ( FnCtxt :: Free , & item. vis , & * func) ;
1109- self . visit_fn ( kind, item. span , item. id ) ;
1166+ self . visit_fn ( kind, & item . attrs , item. span , item. id ) ;
11101167 }
11111168 ItemKind :: ForeignMod ( ForeignMod { extern_span, abi, safety, .. } ) => {
11121169 let old_item = mem:: replace ( & mut self . extern_mod_span , Some ( item. span ) ) ;
@@ -1473,7 +1530,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14731530 visit:: walk_param_bound ( self , bound)
14741531 }
14751532
1476- fn visit_fn ( & mut self , fk : FnKind < ' a > , span : Span , id : NodeId ) {
1533+ fn visit_fn ( & mut self , fk : FnKind < ' a > , attrs : & AttrVec , span : Span , id : NodeId ) {
14771534 // Only associated `fn`s can have `self` parameters.
14781535 let self_semantic = match fk. ctxt ( ) {
14791536 Some ( FnCtxt :: Assoc ( _) ) => SelfSemantic :: Yes ,
@@ -1492,7 +1549,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14921549 self . check_extern_fn_signature ( abi, ctxt, & fun. ident , & fun. sig ) ;
14931550 }
14941551
1495- self . check_c_variadic_type ( fk) ;
1552+ self . check_c_variadic_type ( fk, attrs ) ;
14961553
14971554 // Functions cannot both be `const async` or `const gen`
14981555 if let Some ( & FnHeader {
@@ -1643,7 +1700,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
16431700 {
16441701 self . visit_attrs_vis_ident ( & item. attrs , & item. vis , & func. ident ) ;
16451702 let kind = FnKind :: Fn ( FnCtxt :: Assoc ( ctxt) , & item. vis , & * func) ;
1646- self . visit_fn ( kind, item. span , item. id ) ;
1703+ self . visit_fn ( kind, & item . attrs , item. span , item. id ) ;
16471704 }
16481705 AssocItemKind :: Type ( _) => {
16491706 let disallowed = ( !parent_is_const) . then ( || match self . outer_trait_or_trait_impl {
0 commit comments