Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can C's restrict keyword be emulated using strict aliasing in C++?

Tags:

The Problem

The restrict keyword in C is missing in C++, so out of interest I was looking for a way to emulate the same feature in C++.

Specifically, I would like the following to be equivalent:

// C void func(S *restrict a, S *restrict b)  // C++ void func(noalias<S, 1> a, noalias<S, 2> b) 

where noalias<T, n>

  • behaves just like T* when accessed with -> and *
  • can be constructed from an T* (so that the function can be called as func(t1, t2), where t1 and t2 are both of type T*)
  • the index n specifies the "aliasing class" of the variable, so that variables of type noalias<T, n> and noalias<T, m> may be assumed never to alias for n != m.

An Attempt

Here is my deeply flawed solution:

template <typename T, int n> class noalias {     struct T2 : T {};     T *t;  public:     noalias(T *t_) : t(t_) {}     T2 *operator->() const {return static_cast<T2*>(t);} // <-- UB }; 

When accessed with ->, it casts the internally-stored T* to a noalias<T, n>::T2* and returns that instead. Since this is a different type for each n, the strict aliasing rule ensures that they will never alias. Also, since T2 derives from T, the returned pointer behaves just like a T*. Great!

Even better, the code compiles and the assembly output confirms that it has the desired effect.

The problem is the static_cast. If t were really pointing to an object of type T2 then this would be fine. But t points to a T so this is UB. In practice, since T2 is a subclass which adds nothing extra to T it will probably have the same data layout, and so member accesses on the T2* will look for members at the same offsets as they occur in T and everything will be fine.

But having an n-dependent class is necessary for strict aliasing, and that this class derives from T is also necessary so that the pointer can be treated like a T*. So UB seems unavoidable.

Questions

  • Can this be done in c++14 without invoking UB - possibly using a completely different idea?

  • If not, then I have heard about a "dot operator" in c++1z; would it be possible with this?

  • If the above, will something similar to noalias be appearing in the standard library?

like image 963
PBS Avatar asked Jun 18 '16 20:06

PBS


People also ask

Does C have strict aliasing?

From the article: "Strict aliasing is an assumption, made by the C (or C++) compiler, that dereferencing pointers to objects of different types will never refer to the same memory location (i.e. alias each other.)"

What are the restrictions of keywords in C?

In the C programming language (after 99 standard), a new keyword is introduced known as restrict. restrict keyword is mainly used in pointer declarations as a type qualifier for pointers. It doesn't add any new functionality. It is only a way for programmer to inform about an optimization that compiler can make.

Which keyword is used for restriction purpose?

C # in Telugu The restrict keyword is used for pointer declarations as a type quantifier of the pointer. This keyword does not add new functionalities. Using this the programmer can inform about an optimization that compiler can make.

What is restricted pointer in C?

In the C programming language, restrict is a keyword, introduced by the C99 standard, that can be used in pointer declarations. By adding this type qualifier, a programmer hints to the compiler that for the lifetime of the pointer, no other pointer will be used to access the object to which it points.


1 Answers

You could use the __restrict__ GCC extension for un/aliasing.

From the docs

In addition to allowing restricted pointers, you can specify restricted references, which indicate that the reference is not aliased in the local context.

void fn (int *__restrict__ rptr, int &__restrict__ rref) { /* ... */ } 

In the body of fn, rptr points to an unaliased integer and rref refers to a (different) unaliased integer. You may also specify whether a member function's this pointer is unaliased by using __restrict__ as a member function qualifier.

void T::fn () __restrict__ { /* ... */ } 

Within the body of T::fn, this will have the effective definition T *__restrict__ const this. Notice that the interpretation of a __restrict__ member function qualifier is different to that of const or volatile qualifier, in that it is applied to the pointer rather than the object. This is consistent with other compilers which implement restricted pointers.

As with all outermost parameter qualifiers, __restrict__ is ignored in function definition matching. This means you only need to specify __restrict__ in a function definition, rather than in a function prototype as well.

like image 60
Edison Avatar answered Sep 28 '22 01:09

Edison