Bug 92181 - initializer_list & string_view result in "modification of '<temporary>' is not a constant expression
Summary: initializer_list & string_view result in "modification of '<temporary>' is no...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 9.0
: P3 normal
Target Milestone: 12.3
Assignee: Not yet assigned to anyone
URL: https://godbolt.org/z/baRg-1
Keywords: rejects-valid
Depends on: 107079
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2019-10-22 16:14 UTC by Robrecht Dewaele
Modified: 2023-06-30 14:11 UTC (History)
7 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-01-29 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Robrecht Dewaele 2019-10-22 16:14:56 UTC

    
Comment 1 Robrecht Dewaele 2019-10-22 16:27:52 UTC
The following code was tested on most clang and GCC compilers available on Godbolt, and my local machine running Arch Linux, gcc (GCC) 9.2.0.

Starting from GCC version 9, the following code results in a compile-time error:
"modification of '<temporary>' is not a constant expression"
on the line with the closing brace of the initializer_list initialization.

Code on Godbolt (has some extras compared to the minimal version below): https://godbolt.org/z/baRg-1

// start of source code
#include <string_view>
#include <initializer_list>

struct S { const int i; };

constexpr std::initializer_list<S> foo{
    { []() { return std::string_view("").compare(""); }() }
};
// end of source code

Another version I tested with used a constexpr function rather than a lambda, with the same failing result.
I have also tried replacing the lambda body with a simple "return true;" which fixes the error.
Comment 2 Marek Polacek 2019-10-22 16:41:52 UTC
Changed in r261086.
Comment 3 Erich Erstu 2020-07-14 12:42:43 UTC
I started getting the same error after upgrading to GCC 9.3.0.

The problem in my case is either related to the use of std::pair in constexpr or the fact that I have nested instances of std::initializer_list.

The workaround was to replace std::pair with a custom struct as seen here:

struct zone_name_root_variant_type {
    const char *name;
    std::initializer_list<ZONE_NAME_AFFIX> affixes;
};

struct zone_name_root_type {
    ZONE_NAME_ROOT index;
    const char *region;
    std::initializer_list<
        zone_name_root_variant_type
        /*
        std::pair<
            const char*,
            std::initializer_list<ZONE_NAME_AFFIX>
        >
        */
    > variants;
};

static constexpr const zone_name_root_type zone_name_root_table[] = {
    {
        ZONE_NAME_ROOT::UNKNOWN, "Region",
        {
            {  "",     { ZONE_NAME_AFFIX::UNKNOWN } }
        }
    },
    { ZONE_NAME_ROOT::NONE, "", { } }
};
Comment 4 Erich Erstu 2020-07-14 13:39:55 UTC
I also found out that when I try to populate a constexpr array using a trivial constexpr function that passes on the argument initializer list then I get the same error.

This does not work any more within the definition of a constexpr array:

constexpr room_desc_part_type make(
    ROOM_DESC_PART part, std::initializer_list<const char *> args
) {
    return
#if __cplusplus <= 201703L
    __extension__
#endif // __cplusplus
    room_desc_part_type{
        .index = part,
        .arguments = args
    };
}
Comment 5 Patrick Palka 2023-06-30 14:11:52 UTC
Looks like this is fixed for GCC 12.3+ by the fix for PR107079.