Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC allows arrays to be returned from function - bug or feature?

Tags:

c++

arrays

gcc

I was amazed to find out that GCC allows functions to return arrays when trailing return type is used instead of normal one. As you probably knows arrays can't be copied so this is quite limited but let me show you some cool example.

#include <iostream>
#include <typeinfo>

using namespace std;

auto func() -> int [5]
{
    return {4, 56, 78, 4, 0};
}

int main()
{
    cout << func()[2] << endl;
    cout << typeid(func).name() << endl;
}

Is this a compiler bug or some new feature?

Interestingly 'typeid' returns 'FA5_ivE' which is demangled as 'int (()) [5]' and this means exactly what you think an function returning array of 5 int's.

EDIT: I tried bounding the returned array into rvalue reference but without any success (used most of the possible forms):

auto &&refArrayTemp{ func() };

Seems that this extensions is rather useless.

like image 650
AnArrayOfFunctions Avatar asked Apr 14 '15 13:04

AnArrayOfFunctions


2 Answers

This was a bug in gcc (fixed as of 2017-07-03), caused by inconsistent treatment of trailing-return-types.

First note the difference in error message between two attempts to declare a function returning a function:

using Fv = void(); Fv f1();             // error: 'f1' declared as function returning a function auto f2() -> Fv;     // error: function return type cannot be function 

The first error comes from decl.c, handling declarators, while the second is a lot deeper into the internals, from tree.c, attempting to build the function type preparatory to generating code.

Trailing-return-types are handled in decl.c 30 lines below the above error - too late to catch it with the above error code, and it is not handled separately.

With arrays, similarly using a trailing-return-type allows us to skip the checks in decl.c, the difference being that function-returning-array is actually valid in terms of gcc's internal representation.

Note that you can't do much with it; gcc doesn't allow you to assign, reference-bind, decay or pass the result of func() to another function:

auto a1 = func(); // error: invalid use of non-lvalue array  auto& a2 = func(); // error: invalid initialization of non-const reference of type 'int (&)[5]' from an rvalue of type 'int [5]'  auto&& a3 = func(); // error: lvalue required as unary '&' operand 

Indeed, even your code is rejected at -Wpedantic:

warning: ISO C++ forbids subscripting non-lvalue array 

Finally, by exploiting a similar bug (qualifiers are stripped from scalars before handling of trailing-return-types) we can create a function with type int const volatile():

int const volatile g1();          // warning: type qualifiers ignored on function return type auto g2() -> int const volatile;  // OK!! 
like image 80
ecatmur Avatar answered Sep 18 '22 19:09

ecatmur


Latest draft, [dcl.array]/p10:

Functions shall not have a return type of type array or function, although they may have a return type of type pointer or reference to such things. There shall be no arrays of functions, although there can be arrays of pointers to functions.

This could be a non-standard GCC extension. It doesn't compile in the trunk version of clang. However, this may also be a bug since it has inconsistent behavior with a non-trailing return type.

like image 38
David G Avatar answered Sep 20 '22 19:09

David G