String matching for conditional compilation

At the moment I'm working on providing the option to disable 128 bits integers in core for embedded targets via a feature named no_128_bit_nums (name subject to change). The implementation of the integer language types relies on many macro_rules! for simplicity, for example:

macro_rules! add {
    ($(Int:ty)+) => {$(
        impl Add for $Int { ... }
    )+};
}

add!(u8, u16, ..., i8, i16, ...);

Currently If I'd like to opt out expansions for i128 and u128 I'd have to either add single cases for both of them which can imply rewriting each macro or to conditionally configure each macro invocation with #[cfg(no_128_bit_nums)] and #[cfg(not(no_128_bit_nums))].

Personally I find it easier to conditionally add the cfg attributes inside the macro definition whether a macro variable contains 128, for example, $Int := i128 matches with 128 so the cfg(not(no_128_bit_nums)) attribute is included

// #[substr_attr(lhs, rhs, attrs)] will only add attributes if lhs contains rhs
macro_rules! add {
    ($(Int:ty)+) => {$(
        #[substr_attr($Int, 128, cfg(not(no_128_bit_nums)))]
        impl Add for $Int { ... }
    )+};
}

add!(u8, ..., u128, i8, ..., u128);

Personally I think one of C/C++'s many sins is making so many things optional. One thing I've enjoyed about Rust is that many things are not optional, i128/u128 being one of them. I'd be really sad if Rust started growing ways to turn off core/language features, thereby complicating general libraries that want to be truly cross-platform.

6 Likes

How I would write the macro:

macro_rules! add {
    ($( $(#[$attr:meta])* $Int:ty),+) => {$(
        $(#[$attr])*
        impl Add for $Int { }
    )+};
}

add!(
    u8,
    u16,
    u32,
    u64,
    #[cfg(feature = "128_bit_nums")]
    u128,
    usize,
    i8,
    i16,
    i32,
    i64,
    #[cfg(feature = "128_bit_nums")]
    i128,
    isize
);

I don't think allowing to disable i128/u128 is a good idea though….

What is the use case for disabling 128-bit integers, rather than supporting them via a lowered implementation that uses groups of 64-bit operations?

8 Likes

OK, I acknowledge that you can do it, but my question is 'is it useful?' I mean, if you don't use i128 or u128 anywhere in your code, does the compiler generate any code that requires it? I.e, wouldn't dead code stripping just remove anything using 128 bit integers anyways, simply because it isn't used?

Beyond that, I'm with @mjbshaw on this, disabling core language features has a terrible code smell to it.

1 Like

I do not believe that the Rust language is going to take that path right away for maintenance reasons. Punctually removing features i128/u128 solely in core only affects its testing and the Eisel-Lemire algorithm for float parsing. Disabling them for std would be a little different as the library depends on it in couple of places. But for the case of embedded programming I don't think that devs may run into many shortcomings when 128 bit integers are turned off.

Disabling 128bit ints doesn't just affect libcore, it also requires disabling them in compiler_builtins. How are you going to make sure that both are in sync?

1 Like

Beyond a couple of intrinsics in compiler_builtins I believe all 128bit int operation definitions are marked as #[inline] and thus only codegened if used. Libcore does use them in a couple of places (like float parsing and core::time), but as you said they will be removed by the linker unless you explicitly disable this. (except on windows where -Zfunction-sections has to default to no due to the COFF file format limiting section count to 64k.)

2 Likes

OK, so the only way 128 bit values will make it to the output binary is if you actually use it, correct (with the exception of Windows)? So maybe instead of turning off 128 bit values, what we need is a tool that can look at the output and warn you if you've got any 128 bit code in use. Probably would only work with non-stripped binaries (maybe only DWARF? Not sure).

I know that this isn't a 100% solution, I'm trying to come up with a starting point so that we can come up with a better solution that doesn't involve turning off core parts of the language.

EDIT

Grammar

1 Like