Skip to content

Rust preventing calculations on const generics #82319

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
raphaelcohn opened this issue Feb 20, 2021 · 4 comments
Closed

Rust preventing calculations on const generics #82319

raphaelcohn opened this issue Feb 20, 2021 · 4 comments

Comments

@raphaelcohn
Copy link

I'm wrapping an AVX512 intrinsic, one of whose arguments needed to be const. So, far, so good. However, the wrapper of my wrapper needs to do a simple const calculation before use, and my old friend, [E0401]: can't use generic parameters from outer function (which has always struck me as broken regarding const, especially when it relates to a generic parameter as part of a struct's impl, when it's not an outer function, but I digress), prevents this code from working:-

#![feature(stdsimd)]
use std::arch::x86_64::_mm512_extract_epi32;

#[inline(always)]
pub unsafe fn _mm512_extract_epi32<const index: i32>(a: __m512i) -> i32
{
	_mm512_cvtsi512_si32(_mm512_alignr_epi32(a, a, index))
}

#[inline(always)]
pub unsafe fn _mm512_extract_epi16<const index: i32>(a: __m512i) -> i32
{
	let shift = if (index % 2) == 0
	{
		0
	}
	else
	{
		16
	};
	
       // THIS IS NOT ALLOWED and gives E0401.
	const Epi32Index: i32 = index / 2;
	(_mm512_extract_epi32::<Epi32Index>(a) >> shift) & 0xFFFF
}

I've raised a related issue about const generics on the stdsimd working group issues (rust-lang/stdarch#1011), but this is potentially a wider issue. Now, this may be by design, but to me as an user, it's a bug. Why? Because it's naturally the code I'd write in about 30 seconds to do what I wanted.

Thoughts?

@SkiFire13
Copy link
Contributor

which has always struck me as broken regarding const, especially when it relates to a generic parameter as part of a struct's impl, when it's not an outer function, but I digress

consts are items, and they (excluding impl and trait items) can't inherit generic parameters from the thing they're defined in. The exact same "issue" is present with statics that use a generic type from the environment.

If you want to do calculations with const generics you'll need the const_evaluatable_checked feature, however it is currently incomplete and very unstable.

@raphaelcohn
Copy link
Author

@jonas-schievink You've closed this without even having the common courtesy to explain to me why that is; I don't appreciate that.

@SkiFire13 I'm aware of the link you've made. It doesn't stop me thinking it's a bug. Rust's const have never been particularly satisfying or rational as a consumer of the the language (can be declared after use in a method; adding a generic parameter to a function or impl suddenly causes Self::const_value to no longer compile; static can't exist at the level of an impl) but so be it; I'm an outsider. I'll take what I'm given and make it sing.

@SkiFire13
Copy link
Contributor

It doesn't stop me thinking it's a bug.

It may be counterintuitive but it's definitely intended behaviour, so I wouldn't call it a bug. This however doesn't mean that the language is not open to changes, there's always the internals forum to propose and discuss them.

can be declared after use in a method

This is however perfectly intuitive if it's declared outside a function.

adding a generic parameter to a function or impl suddenly causes Self::const_value to no longer compile

I don't think I understand how this may happen other than shadowing a global const with a const generic parameter.

static can't exist at the level of an impl

I agree this is counterintuitive, however AFAIK there's a reason we can't have generic static, and that's because we need to support the dylib crate type which makes it impossible to monomorphize them.

@raphaelcohn
Copy link
Author

raphaelcohn commented Feb 21, 2021

@SkiFire13 Thanks for the explanation. We're going to disagree on the use of the word bug. That's ok; my view comes from a much wider perspective, and I understand where you're coming from.

This is however perfectly intuitive if it's declared outside a function.

I agree, and I wouldn't want any language to repeat C's need to declare before use; it's verbose and violates pyramid thinking and how we usually process information we read.
It does violate common human intuition within a function.

I don't think I understand how this may happen ...

I probably haven't been as clear as I could have been in my terse description. If you're like me, you find examples easier to follow than descriptions. I often find discussing code akin to trying to write down the feelings a dream gives; an impossible thing to communicate. Regardless, it'd be getting well off the topic of this issue if we discussed it further on this issue report.

I agree this is counterintuitive .. dylib.

Thank you for the explanation. That makes quite a lot of sense. Personally, I've not been a fan of dynamic loading of libraries for over 5 years, ever since a very nasty cyber attack raised my awareness of their weaknesses (and, also, how few of us appreciate that things like dlunload (from memory) don't work or don't work reliably (depending on your libc) - including engineers at Intel... However, they'll always need to exist, at least in the mobile space, where there's an advantage to sharing a library in memory.

From a software versioning and reliability point of view, it's frequently much better to just ship one statically linked binary; it makes it impossible for versioning changes on the end use machine to break it. From a patching point of view, they're actually an anti-pattern; an average sysadmin has no idea which applications to restart if a particular dylib is updated. I've yet to meet one yet who knows he has to restart everything if libc changes version because of a security fix - and very busy sysadmins frequently can't track stuff as granular as that. Indeed, the whole idea that the state of the system is mutated by a package manager gives me the shivers... and it's a common entry to attack. Immutable in-memory OS distros are the way to go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants