@@ -802,3 +802,83 @@ macro_rules! impl_size_eq {
802802 } ;
803803 } ;
804804}
805+
806+ macro_rules! const_fn {
807+ (
808+ $vis: vis $name: ident $( < $( $tyvar: ident) ,* >) ?
809+ ( $( $arg: ident: $argty: ty) ,* ) -> $retty: ty
810+ $(
811+ where $( $wheretyvar: ident: $wherebound: path, ) *
812+ ) ?
813+ $body: block
814+ ) => {
815+ #[ allow( non_camel_case_types) ]
816+ $vis trait $name $( < $( $tyvar) ,* >) ?
817+ where Self : crate :: util:: macros:: HasArgs <( $( $argty, ) * ) , Args = ( $( $argty, ) * ) >,
818+ $(
819+ $( $wheretyvar: $wherebound) ,*
820+ ) ?
821+ {
822+ const ARGS : Self :: Args ;
823+
824+ const __RETURN: $retty = {
825+ let ( $( $arg) ,* ) = Self :: ARGS ;
826+ loop {
827+ break $body;
828+ }
829+ } ;
830+ }
831+ } ;
832+ }
833+
834+ macro_rules! call_const_fn {
835+ (
836+ $name: ident $( :: $names: ident) * $( :: < $( $ty: ty) ,* >) ? ( $( $arg: expr) ,* )
837+ ) => {
838+ {
839+ enum Call { }
840+
841+ impl $name $( :: $names) * $( < $( $ty) ,* >) ? for Call {
842+ const ARGS : Self :: Args = ( $( $arg, ) * ) ;
843+ }
844+
845+ <Call as $name $( :: $names) * $( :: < $( $ty) ,* >) ?>:: __RETURN
846+ }
847+ } ;
848+ }
849+
850+ // Used in the implementation of `const_fn!`.
851+ pub ( crate ) trait HasArgs < A > {
852+ type Args ;
853+ }
854+
855+ impl < A , T > HasArgs < A > for T {
856+ type Args = A ;
857+ }
858+
859+ mod tests {
860+ #[ test]
861+ fn test_const_fn ( ) {
862+ trait Foo {
863+ const N : usize ;
864+ }
865+
866+ impl Foo for ( ) {
867+ const N : usize = 5 ;
868+ }
869+
870+ const_fn ! ( foobar<T >( _t: T , n: usize ) -> usize
871+ where
872+ T : Foo ,
873+ T : Copy ,
874+ {
875+ T :: N * n
876+ } ) ;
877+
878+ const BLAH : usize = call_const_fn ! ( foobar:: <( ) >( ( ) , 4 ) ) ;
879+
880+ const _: ( ) = {
881+ static_assert ! ( => BLAH == 20 ) ;
882+ } ;
883+ }
884+ }
0 commit comments