Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constexpr returning array, gcc warning

I wrote a constexpr function that returns an array.

#include <iostream>

constexpr auto get_str(void)
-> const char(&)[4] {   
    return { 'T', 'E', 'S', 'T' };
}

constexpr int sum(const char(&str)[4]){
    return str[0] + str[1] + str[2] + str[3];
}

int main(void){

    constexpr int s = sum(get_str());

    std::cout << s << std::endl;

    return 0;
}

g++ 4.8 compiles the code correctly, but issues the following warning:

test.cpp: In function ‘constexpr const char (& get_str())[4]’:
test.cpp:5:30: warning: returning reference to temporary [-Wreturn-local-addr]
  return { 'T', 'E', 'S', 'T' };

Is the warning correct in this circumstance? Is it incorrect to return an array from a constexpr function like this even though the function is never actually called at runtime, only during compilation?

like image 418
Xeno Avatar asked Aug 31 '14 19:08

Xeno


People also ask

Is constexpr guaranteed?

A constexpr function that is eligible to be evaluated at compile-time will only be evaluated at compile-time if the return value is used where a constant expression is required. Otherwise, compile-time evaluation is not guaranteed.

What is constexpr in C?

The keyword constexpr was introduced in C++11 and improved in C++14. It means constant expression. Like const , it can be applied to variables: A compiler error is raised when any code attempts to modify the value. Unlike const , constexpr can also be applied to functions and class constructors.

Does constexpr improve performance?

Using constexpr to Improve Security, Performance and Encapsulation in C++ constexpr is a new C++11 keyword that rids you of the need to create macros and hardcoded literals. It also guarantees, under certain conditions, that objects undergo static initialization.

Can constexpr throw?

Even though try blocks and inline assembly are allowed in constexpr functions, throwing exceptions or executing the assembly is still disallowed in a constant expression.


2 Answers

clang 3.4 does not compile this code since sum(get_str()) is not a constexpr and as far as I can tell clang is correct here, this line (see it live):

constexpr int s = sum(get_str());

generates the following error:

error: constexpr variable 's' must be initialized by a constant expression
constexpr int s = sum(get_str());
              ^   ~~~~~~~~~~~~~~

note: read of temporary whose lifetime has ended
return str[0] + str[1] + str[2] + str[3] 
       ^

It is not a valid constexpr for two reasons. This invokes undefined behavior and this is explicitly disallowed in a constant expression, to summarize the draft C++ standard section 5.19 says:

A conditional-expression e is a core constant expression unless the evaluation of e,

and contains the following bullet:

an operation that would have undefined behavior

which accessing outside of its lifetime would be. We know the lifetime of the temporary is not extended in this case from section 12.2 Temporary objects which says:

The second context is when a reference is bound to a temporary.117 The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except

and includes the following bullet:

The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.

So although it is indeed true that a constant expression is not guaranteed to be evaluated at translation, we have a note in section 5.19 Constant expressions that mentions this (emphasis mine going forward):

Note: Constant expressions can be evaluated during translation.—end note ]

Even if it was guaranteed we still would not be allowed to invoke undefined behavior.

The second issue is that constexpr references must be either to objects of static storage duration or functions, cppreference mentions this in its core constant expression section:

Reference constant expression is an lvalue core constant expression that designates an object with static storage duration or a function

and as far as I can tell this is covered in section 5.19 Constant expressions paragraph 4 which says:

each non-static data member of reference type refers to an object with static storage duration or to a function,

like image 138
Shafik Yaghmour Avatar answered Oct 13 '22 00:10

Shafik Yaghmour


the function is never actually called at runtime, only during compilation?

Not guaranteed at all by Standard. The compiler is well within it's rights to invoke it at runtime.

constexpr temporaries never die if the compiler invokes it at compilation time. The compiler is under no obligation.

like image 1
Puppy Avatar answered Oct 13 '22 02:10

Puppy