Why can't const functions in Rust make calls to associated functions? - static

This:
const fn pow2(exp: u32) -> u32 {
u32::pow(exp, 2)
}
Results in a compiler error:
error[E0015]: calls in constant functions are limited to constant functions, struct and enum constructors
Is there a way to do this?
I'd like to do:
pub const MY_BITMASK: u32 = pow2(4);

A const function cannot call a non-const function. This is because const functions need to be able to run during compilation, so they can't call a non-const function which can only be evaluated at runtime. Since u32::pow is not a const function, you can't call it from a const function.
The question now becomes: Why isn't u32::pow a const function? And the reason for that is a current limitation of const functions: They can only contain a subset of the language. Notably, they can't contain loops or assignments. Since u32::pow uses both of these, it can't be marked as const and therefore can't be called from const functions.
Note that there isn't any limitation of calling associated functions from const functions, as long as the associated function is marked const. And u32::pow is not an associated function in any case: you can call it as e.g. x.pow(y).
Update: Const functions gained a lot more language features they can use in Rust 1.46 (including if, while, &&, etc.), and the integer types' pow functions were made const in Rust 1.50.

Related

Does inline have any effect when using const function attribute?

Take this function
__attribute_const__ static inline int mul(int a, int b)
{
return a * b;
}
versus this one
__attribute_const__ static int mul(int a, int b)
{
return a * b;
}
Is there a reason to use inline when using a const attribute? Does it help the compiler at all to use inline here?
None of the attributes necessarily help here, because a static function would be inlined anyway regardless of inline if the compiler so decides, and because it is a static function then the source would be present in the translation unit where it would be used, then the compiler can also see that it calculates the product of the two arguments and compilers are smart enough to conclude that the product of two arguments depends only the values of those arguments.
The inline case gets more interesting in the case of inline/extern inline. Also, the attribute case gets more interesting when the compiler cannot see the code (because the function is defined only in another translation unit), or cannot deduce its behaviour properly - for example a const function might touch some common lookup tables initialized in the beginning of the program but the compiler wouldn't be able to ensure that they will remain constant.
The inline functions are substituted where they are called (at compilation time) and the attribute const is telling the compiler that further calls to the function using the same parameters could be avoided, because the result will be the same. If you are marking the const function as inline then you are loosing the const behavior since the inline is not per se a "call" and the const optimization relays on repeated calls

Passing non const variables to a function with const arguments in C

I have a function as below
void foo(const foo_type* x)
{...}
I am calling this function in other function.
void foo1(int z)
{
foo_type y = z;
foo(&y);
}
This is not throwing any error in c but i feel something is not correct.
What happens when i pass non const variable to function that expects const variable as arguments.
The introduction of const in the way you have is absolutely fine and even desirable.
You have told the compiler explicitly that the function will not modify the parameter passed as const. That could even help with a compiler's optimisation strategy.
The removal of const is, in general, a bad idea though. (Which you're not doing in this case.) The behaviour on modifying a variable via the removal of const that was originally declared as const is undefined.

Using pure/const attributes with return-arguments in C with GCC?

Is it possible to declare a function as pure or const (using the GCC attributes),
With return arguments ? (where an argument is used for a return value).
For example:
void mid_v3_v3v3(float r_out[3], v0[3], v1[3])
{
r_out[0] = (v0[0] + v1[0]) * 0.5f;
r_out[1] = (v0[1] + v1[1]) * 0.5f;
r_out[2] = (v0[2] + v1[2]) * 0.5f;
}
With the exception of r_out, this function is const, is there some way to tag an argument as a return value, but otherwise treat the function as const?
see:
https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Function-Attributes.html
Your own link partly answers the question. Regarding const:
Many functions do not examine any values except their arguments, and have no effects except the return value. Basically this is just slightly more strict class than the pure attribute below, since function is not allowed to read global memory.
Note that a function that has pointer arguments and examines the data pointed to must not be declared const. Likewise, a function that calls a non-const function usually must not be const. It does not make sense for a const function to return void.
The documentation for pure is actually wrong and self-contradictory; it says the function can only access its parameters and/or global variables, but then gives strlen (which accesses the member pointed to by its parameter) as an example.
Anyway, for your "return arguments" usage, I don't think either of these approaches is viable. What you could do, however, is use a function returning a structure containing the results array; then the pure attribute should apply (assuming the examples, and not the text, for pure are correct).

What are some practical uses for const-qualified variables in C?

As has been discussed in several recent questions, declaring const-qualified variables in C (as opposed to const variables in C++, or pointers to const in C) usually serves very little purpose. Most importantly, they cannot be used in constant expressions.
With that said, what are some legitimate uses of const qualified variables in C? I can think of a few which have come up recently in code I've worked with, but surely there must be others. Here's my list:
Using their addresses as special sentinel values for a pointer, so as never to compare equal to any other pointer. For example: char *sentinel(void) { static const char s; return &s; } or simply const char sentinel[1]; Since we only care about the address and it actually wouldn't matter if the object were written to, the only benefit of const is that compilers will generally store it in read-only memory that's backed by mmap of the executable file or a copy of the zero page.
Using const qualified variables to export values from a library (especially shared libraries), when the values could change with new versions of the library. In such cases, simply using #define in the library's interface header would not be a good approach because it would make the application dependent on the values of the constants in the particular version of the library it was built with.
Closely related to the previous use, sometimes you want to expose pre-defined objects from a library to the application (the quintessential examples being stdin, stdout, and stderr from the standard library). Using that example, extern FILE __stdin; #define stdin (&__stdin) would be a very bad implementation due to the way most systems implement shared libraries - usually they require the entire object (here, FILE) to be copied to an address determined when the application is linked, and introduce a dependency on the size of the object (the program will break if the library is rebuilt and the size of the object changes). Using a const pointer (not pointer-to-const) here fixes all the problems: extern FILE *const stdin;, where the const pointer is initialized to point to the pre-defined object (which itself is likely declared static) somewhere internal to the library.
Lookup tables for mathematical functions, character properties, etc. This is the obvious one I originally forgot to include, probably because I was thinking of individual const variables of arithmetic/pointer type, as that's where the question topic first came up. Thanks to Aidan for triggering me to remember.
As a variant on lookup tables, implementation of state machines. Aidan provided a detailed example as an answer. I've found the same concept is also often very useful without any function pointers, if you can encode the behavior/transitions from each state in terms of a few numeric parameters.
Anyone else have some clever, practical uses for const-qualified variables in C?
const is quite often used in embedded programming for mapping onto GPIO pins of a microcontroller. For example:
typedef unsigned char const volatile * const tInPort;
typedef unsigned char * const tOutPort;
tInPort my_input = (tInPort)0x00FA;
tOutPort my_output = (tOutPort)0x00FC;
Both of these prevent the programmer from accidentally changing the pointer itself which could be disastrous in some cases. The tInPort declaration also prevents the programmer from changing the input value.
Using volatile prevents the compiler from assuming that the most recent value for my_input will exist in cache. So any read from my_input will go directly to the bus and hence always read from the IO pins of the device.
For example:
void memset_type_thing(char *first, char *const last, const char value) {
while (first != last) *(first++) = value;
}
The fact that last can't be part of a constant-expression is neither here nor there. const is part of the type system, used to indicate a variable whose value will not change. There's no reason to modify the value of last in my function, so I declare it const.
I could not bother declaring it const, but then I could not bother using a statically typed language at all ;-)
PC-lint warning 429 follows from the expectation that a local pointer to an allocated object should be consumed
by copying it to another pointer or
by passing it to a "dirty" function (this should strip the "custodial" property of the pointer) or
by freeing it or
by passing it up the caller through a return statement or a pass-by-pointer parameter.
By "dirty" I mean a function whose corresponding pointer parameter has a non-const base type. The description of the warning absolves library functions such as strcpy() from the "dirty" label, apparently because none of such library functions takes ownership of the pointed object.
So when using static analysis tools such as PC-lint, the const qualifier of parameters of called functions keeps locally allocated memory regions accounted.
const can be useful for some cases where we use data to direct code in a specific way. For example, here's a pattern I use when writing state machines:
typedef enum { STATE1, STATE2, STATE3 } FsmState;
struct {
FsmState State;
int (*Callback)(void *Arg);
} const FsmCallbacks[] = {
{ STATE1, State1Callback },
{ STATE2, State2Callback },
{ STATE3, State3Callback }
};
int dispatch(FsmState State, void *Arg) {
int Index;
for(Index = 0; Index < sizeof(FsmCallbacks)/sizeof(FsmCallbacks[0]); Index++)
if(FsmCallbacks[Index].State == State)
return (*FsmCallbacks[Index].Callback)(Arg);
}
This is analogous to something like:
int dispatch(FsmState State, void *Arg) {
switch(State) {
case STATE1:
return State1Callback(Arg);
case STATE2:
return State2Callback(Arg);
case STATE3:
return State3Callback(Arg);
}
}
but is easier for me to maintain, especially in cases where there's more complicated behavior associated with the states. For example, if we wanted to have a state-specific abort mechanism, we'd change the struct definition to:
struct {
FsmState State;
int (*Callback)(void *Arg);
void (*Abort)(void *Arg);
} const FsmCallbacks[] = {...};
and I don't need to modify both the abort and dispatch routines for the new state. I use const to prevent the table from changing at runtime.
A const variable is useful when the type is not one that has usable literals, i.e., anything other than a number. For pointers, you already give an example (stdin and co) where you could use #define, but you'd get an lvalue that could easily be assigned to. Another example is struct and union types, for which there are no assignable literals (only initializers). Consider for instance a reasonable C89 implementation of complex numbers:
typedef struct {double Re; double Im;} Complex;
const Complex Complex_0 = {0, 0};
const Complex Complex_I = {0, 1}; /* etc. */
Sometimes you just need to have a stored object and not a literal, because you need to pass the data to a polymorphic function that expects a void* and a size_t. Here's an example from the cryptoki API (a.k.a. PKCS#11): many functions require a list of arguments passed as an array of CK_ATTRIBUTE, which is basically defined as
typedef struct {
CK_ATTRIBUTE_TYPE type;
void *pValue;
unsigned long ulValueLen;
} CK_ATTRIBUTE;
typedef unsigned char CK_BBOOL;
so in your application, for a boolean-valued attribute you need to pass a pointer to a byte containing 0 or 1:
CK_BBOOL ck_false = 0;
CK_ATTRIBUTE template[] = {
{CKA_PRIVATE, &ck_false, sizeof(ck_false)},
... };
They can be used for memory-mapped peripherals or registers that cannot be changed by user code, only some internal mechanism of the microprocessor. Eg. on the PIC32MX, certain registers indicating program state are qualified const volatile - so you can read them, and the compiler won't try to optimise out, say, repeated accesses, but your code cannot write to them.
(I don't any code to hand, so I can't cite a good example right now.)

C const/non-const versions of same function

Suppose in C I have the functions
type* func (type*);
const type* func_const (const type*);
such that they both have the exact same internal logic.
Is there a way I can merge the two into one function, where if given a const type, it returns a const type; and if given a non-const type, it returns a non-const type? If not, what is a good way of dealing with this? Define one in terms of the other via explicit casting perhaps?
You can't automate it, but you can certainly have the logic in a single location:
const type* func_const (const type*)
{
/* actual implementation goes here */
}
type* func (type* param)
{
/* just call the const function where the "meat" is */
return (type*)func_const(param);
}
Do like the standard C library functions do and just take a const-qualified argument while returning a non-const-qualified result. (See strchr, strstr, etc.) It's the most practical.

Resources