Can you dereference a temporary array?

385 Views Asked by At

Consider the following code:

void foo() {
    int arr[1];
    *arr; // OK

    using T = int[1];
    *T{}; // OK for Clang and MSVC
          // GCC error: taking address of temporary array
}

See live code at Compiler Explorer.

My intuition is that *T{} should result in array-to-pointer conversion, and the indirection is well-formed. However, I'm not entirely sure about this.

Is GCC right, or is this a bug? Is it intentional, to prevent developers from making mistakes? After all, you don't usually dereference arrays. Is this documented anywhere?

Disclaimer
CWG Issue 2548 has confirmed that "indirection through an array prvalue is also not valid today". The answer by @StoryTeller is wrong, and misinterprets the meaning of destination type by assuming that this also applies to *T{}, but this expression is not initialization of a pointer.

More discussion at editorial issue EDIT 6555

2

There are 2 best solutions below

7
Language Lawyer On BEST ANSWER

GCC is right because indirection can only be applied to pointers. [expr.unary.op]/1:

The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result [...]

Note: CWG 1642 and EDIT 3945 makes indirection apply to a prvalue operand.

*arr is OK because arr is an lvalue, and [basic.lval]/6:

Whenever a glvalue appears as an operand of an operator that expects a prvalue for that operand, the lvalue-to-rvalue, array-to-pointer, or function-to-pointer standard conversions are applied to convert the expression to a prvalue.

Array-to-pointer conversion ([conv.array]) is applied toarr.

T{} is already a prvalue (of array type), and there is no wording which necessitates array-to-pointer conversion here, so *T{} is not OK.

15
StoryTeller - Unslander Monica On

It seems well-defined to me, and Clang and MSVC do it as required.

[expr.unary.op] (emphasis mine)

1 The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points.

Then we have this sentence that tells us when and where a standard conversion sequence can be applied:

[conv.general]

1 Standard conversions are implicit conversions with built-in meaning. [conv] enumerates the full set of such conversions. A standard conversion sequence is a sequence of standard conversions in the following order:

  • Zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion, and function-to-pointer conversion.

...

A standard conversion sequence will be applied to an expression if necessary to convert it to a required destination type.

Which tells us that a standard conversion sequence can be applied to convert an operand to a type required by an expression. That's how it works with *arr, and so we need only check if the array-to-pointer conversion can be applied to our prvalue array.

[conv.array]

1 An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The temporary materialization conversion ([conv.rval]) is applied. The result is a pointer to the first element of the array.

And it can, as the standard even explicitly requires a temporary array to materialize and for the pointer to point at its first element. All in all, GCC reject valid code, so one can say it has a bug.