code707
code707

Reputation: 1701

Can constexpr function return pointer of local object?

A constexpr function is defined as (c++14)

A constexpr function must satisfy the following requirements:

  • it must not be virtual
  • its return type must be LiteralType each of its parameters must be LiteralType
  • there exists at least one set of argument values such that an invocation of the function could be an evaluated subexpression of a core constant expression (for constructors, use in a constant initializer is sufficient) (since C++14). No diagnostic is required for a violation of this bullet.

the function body must be either deleted or defaulted or contain any statements except:

  • an asm declaration
  • a goto statement
  • a statement with a label other than case and default
  • a try-block
  • a definition of a variable of non-literal type
  • a definition of a variable of static or thread storage duration
  • a definition of a variable for which no initialization is performed.

Now following func1 meets the requirement and compiles

constexpr int * func1 (int a)
{
  int b = 4;
  return &b;
}
int main()
{
    constexpr int * a = func1(3);
    int arr[*a];  
    std::cout << a << std::endl;
}

Now my question is how come func1 is constexpr. How does it know address of local variable at compile time?

I am using gcc 6.4.0

Upvotes: 5

Views: 1254

Answers (3)

Joseph D.
Joseph D.

Reputation: 12174

In your code, when func1() returns, b goes out of scope.
Thus, any usage relating to b outside func1() is undefined behavior.

constexpr int * func1 (int a)
{
  int b = 4; // remember: b is non-static
  return &b;
}

int * a = func1(3); // b is out of scope here

Also, from expr.const:

A core constant expression satisfies:

(5.2) if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object, the address of a function, or a null pointer value

Which in your case, b is not static, which means func1() is not a constant expression.

Upvotes: 1

max66
max66

Reputation: 66230

Now my question is how come func1 is constexpr.

Are you sure?

Try asking a compile time value saving it in a constexpr variable; by example

constexpr int * a = func1(3);

You should get a list of error/warnings like (from my clang++ 3.8.1)

tmp_003-14,gcc,clang.cpp:7:11: warning: address of stack memory associated with
      local variable 'b' returned [-Wreturn-stack-address]
  return &b;
          ^
tmp_003-14,gcc,clang.cpp:11:21: error: constexpr variable 'a' must be
      initialized by a constant expression
    constexpr int * a = func1(3);
                    ^   ~~~~~~~~
tmp_003-14,gcc,clang.cpp:11:21: note: pointer to 'b' is not a constant
      expression
tmp_003-14,gcc,clang.cpp:6:7: note: declared here
  int b = 4;
      ^

Well, actually, from my g++ 6.3.0 I get only a warning

tmp_003-14,gcc,clang.cpp: In function ‘constexpr int* func1(int)’:
tmp_003-14,gcc,clang.cpp:7:7: warning: address of local variable ‘b’ returned [-Wreturn-local-addr]
   int b = 4;
       ^

Upvotes: 4

Hatted Rooster
Hatted Rooster

Reputation: 36503

How does it know address of local variable at compile time?

It doesn't.

The third bullet in your quote is never satisfied:

There exists at least one set of argument values such that an invocation of the function could be an evaluated subexpression of a core constant expression (for constructors, use in a constant initializer is sufficient) (since C++14). No diagnostic is required for a violation of this bullet.

The compiler just doesn't complain about it because it's not required to, until you make it complain by trying to use func1 inside something that requires a correct constexpr function, for example:

std::array<int, func(3)> d;

This won't compile and your compiler will tell you why.

Upvotes: 5

Related Questions