Bug 94264 - Array-to-pointer conversion not performed on array prvalues
Summary: Array-to-pointer conversion not performed on array prvalues
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 9.3.0
: P3 normal
Target Milestone: 14.0
Assignee: Jason Merrill
Keywords: rejects-valid
: 89931 102568 (view as bug list)
Depends on: 53220
  Show dependency treegraph
Reported: 2020-03-23 00:21 UTC by Nick Krempel
Modified: 2023-12-19 20:54 UTC (History)
6 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed: 2021-08-24 00:00:00


Note You need to log in before you can comment on or make changes to this bug.
Description Nick Krempel 2020-03-23 00:21:15 UTC
I think the most clearcut example is:

int main() {
  using T = int[];
  T{1, 2} == nullptr;

This compiles fine with clang, and is supported by the standard: the == operator explicitly performs array-to-pointer conversion (https://eel.is/c++draft/expr#eq-1), and array-to-pointer conversion is explicitly defined for rvalue arrays (https://eel.is/c++draft/expr#conv.array).

Other examples (which again all compile with clang) are:

+T{1, 2};
  Here the standard wording seems to have a minor bug, as unary "+" does not explicitly perform the array-to-pointer conversion, and the general rubric for applying it (https://eel.is/c++draft/expr#basic.lval-6) only applies to glvalues as written.

T{1, 2} + 1;

*(T{1, 2} + 1);
  Interesting as T{1, 2}[1] should be equivalent to this (modulo the value category of the result, https://eel.is/c++draft/expr#sub), yet the former is rejected by gcc and the latter accepted.
Comment 1 Marek Polacek 2020-04-18 16:33:54 UTC
cp_build_binary_op calls cp_default_conversion on its operands and that calls decay_conversion which has:

 2153       /* Don't let an array compound literal decay to a pointer.  It can
 2154          still be used to initialize an array or bind to a reference.  */
 2155       if (TREE_CODE (exp) == TARGET_EXPR)
 2156         {
 2157           if (complain & tf_error)
 2158             error_at (loc, "taking address of temporary array");
 2159           return error_mark_node;
 2160         }

convert_like_real does

+   /* Take the address explicitly rather than via decay_conversion
+      to avoid the error about taking the address of a temporary.  */
+   array = cp_build_addr_expr (array, complain);
+   array = cp_convert (build_pointer_type (elttype), array);

to avoid that error.
Comment 2 Andrew Pinski 2021-08-10 03:43:02 UTC
*** Bug 89931 has been marked as a duplicate of this bug. ***
Comment 3 Andrew Pinski 2021-10-02 20:01:11 UTC
*** Bug 102568 has been marked as a duplicate of this bug. ***
Comment 4 Fedor Chelnokov 2023-10-08 07:31:01 UTC
Related discussion: https://stackoverflow.com/q/77051011/7325599

And an example from it:

int main() {
    using U = int(&&)[1];
    (void) *U{}; //ok everywhere

    using T = int[1];
    (void) *T{}; //error in GCC

Online demo: https://godbolt.org/z/4s8v9PPqT
Comment 5 Jiang An 2023-10-09 02:07:40 UTC
Comment 6 Andrew Pinski 2023-10-09 02:19:27 UTC
(In reply to Nick Krempel from comment #0)
> T{1, 2} + 1;
>   Ditto.

That is what clang's issue: https://github.com/llvm/llvm-project/issues/54016 is about even.
Comment 7 Jason Merrill 2023-11-28 18:05:49 UTC
This is due to my PR53220 change to discourage use of compound-literals in ways that produce a dangling pointer when the C++ compiler treats them as prvalues, unlike C where they have variable lifetime.

I think the change was always wrong, but wasn't really a problem until we added array prvalues in C++17.
Comment 8 GCC Commits 2023-11-28 21:29:26 UTC
The trunk branch has been updated by Jason Merrill <jason@gcc.gnu.org>:


commit r14-5941-g305a2686c99bf9b57490419f25c79f6fb3ae0feb
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Nov 28 13:54:47 2023 -0500

    c++: prvalue array decay [PR94264]
    My change for PR53220 made array to pointer decay for prvalue arrays
    ill-formed to catch well-defined C code that produces a dangling pointer in
    C++ due to the shorter lifetime of compound literals.  This wasn't really
    correct, but wasn't a problem until C++17 added prvalue arrays, at which
    point it started rejecting valid C++ code.
    I wanted to make sure that we still diagnose the problematic code;
    -Wdangling-pointer covers the array-lit.c case, but I needed to extend
    -Wreturn-local-addr to handle the return case.
            PR c++/94264
            PR c++/53220
            * c-typeck.cc (array_to_pointer_conversion): Adjust -Wc++-compat
            * call.cc (convert_like_internal): Remove obsolete comment.
            * typeck.cc (decay_conversion): Allow array prvalue.
            (maybe_warn_about_returning_address_of_local): Check
            for returning pointer to temporary.
            * c-c++-common/array-lit.c: Adjust.
            * g++.dg/cpp1z/array-prvalue1.C: New test.
            * g++.dg/ext/complit17.C: New test.
Comment 9 GCC Commits 2023-12-08 18:34:51 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:


commit r14-6342-g5764825aed613f201a8bc47e5b239027a39691f0
Author: Patrick Palka <ppalka@redhat.com>
Date:   Fri Dec 8 13:33:55 2023 -0500

    c++: undiagnosed error_mark_node from cp_build_c_cast [PR112658]
    When cp_build_c_cast commits to an erroneous const_cast, we neglect to
    replay errors from build_const_cast_1 which can lead to us incorrectly
    accepting (and "miscompiling") the cast, or triggering the assert in
    This patch fixes this oversight.  This was the original fix for the ICE
    in PR112658 before r14-5941-g305a2686c99bf9 made us accept the testcase
    there after all.  I wasn't able to come up with an alternate testcase for
    which this fix has an effect anymore, but below is a reduced version of
    the PR112658 testcase (accepted ever since r14-5941) for good measure.
            PR c++/112658
            PR c++/94264
            * typeck.cc (cp_build_c_cast): If we're committed to a const_cast
            and the result is erroneous, call build_const_cast_1 a second
            time to issue errors.  Use complain=tf_none instead of =false.
            * g++.dg/cpp0x/initlist-array20.C: New test.
Comment 10 Jason Merrill 2023-12-19 20:54:34 UTC
Fixed for GCC 14.